From d0741f21b1b8225cd6339b846eb65e04b6a8dad4 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Fri, 20 Apr 2018 10:00:27 +0200 Subject: [PATCH 01/33] changed reverse geocode algorithm --- lib/ReverseGeocode.php | 210 +++++++++++++++++++---------------------- 1 file changed, 99 insertions(+), 111 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 27f8c89c..a2416929 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -68,6 +68,50 @@ class ReverseGeocode 'Could not determine closest housenumber on an osm interpolation line.' ); } + + protected function lookupPolygon($sPointSQL, $iMaxRank) + { + $sSQL = 'select place_id,parent_place_id,rank_search,country_code, geometry'; + $sSQL .= ' FROM placex'; + $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\')'; + $sSQL .= ' AND rank_search <= LEAST(25, '.$iMaxRank.')'; + $sSQL .= ' AND ST_CONTAINS(geometry, '.$sPointSQL.' )'; + $sSQL .= ' AND type != \'postcode\' '; + $sSQL .= ' AND name IS NOT NULL '; + $sSQL .= ' ORDER BY rank_search DESC LIMIT 1'; + + $aPoly = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine polygon containing the point.' + ); + if ($aPoly) { + $iParentPlaceID = $aPoly['parent_place_id']; + $iRankSearch = $aPoly['rank_search']; + $iGeometry = $aPoly['geometry']; + + $sSQL = 'select place_id,parent_place_id,rank_search,country_code,'; + $sSQL .=' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= ' FROM placex'; + $sSQL .= ' WHERE osm_type = \'N\''; + $sSQL .= ' AND rank_search >= '.$iRankSearch; + $sSQL .= ' AND rank_search <= LEAST(25, '.$iMaxRank.')'; + $sSQL .= ' AND ST_CONTAINS(\''.$iGeometry.'\'::geometry, geometry )'; + $sSQL .= ' AND type != \'postcode\''; + $sSQL .= ' AND name IS NOT NULL '; + $sSQL .= ' ORDER BY distance ASC,'; + $sSQL .= ' rank_search DESC'; + $sSQL .= ' limit 1'; + if (CONST_Debug) var_dump($sSQL); + $aPlacNode = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine place node.' + ); + if ($aPlacNode) { + return $aPlacNode; + } + } + return $aPoly; + } public function lookup($fLat, $fLon, $bDoInterpolation = true) { @@ -79,61 +123,36 @@ class ReverseGeocode public function lookupPoint($sPointSQL, $bDoInterpolation = true) { + $iMaxRank = $this->iMaxRank; // Find the nearest point - $fSearchDiam = 0.0004; + $fSearchDiam = 0.006; $oResult = null; $aPlace = null; $fMaxAreaDistance = 1; $bIsTigerStreet = false; - while ($oResult === null && $fSearchDiam < $fMaxAreaDistance) { - $fSearchDiam = $fSearchDiam * 2; - - // If we have to expand the search area by a large amount then we need a larger feature - // then there is a limit to how small the feature should be - if ($fSearchDiam > 2 && $iMaxRank > 4) $iMaxRank = 4; - if ($fSearchDiam > 1 && $iMaxRank > 9) $iMaxRank = 8; - if ($fSearchDiam > 0.8 && $iMaxRank > 10) $iMaxRank = 10; - if ($fSearchDiam > 0.6 && $iMaxRank > 12) $iMaxRank = 12; - if ($fSearchDiam > 0.2 && $iMaxRank > 17) $iMaxRank = 17; - if ($fSearchDiam > 0.1 && $iMaxRank > 18) $iMaxRank = 18; - if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22; - if ($fSearchDiam > 0.001 && $iMaxRank > 26) { - // try with interpolations before continuing - if ($bDoInterpolation) { - $aHouse = $this->lookupInterpolation($sPointSQL, $fSearchDiam/2); - - if ($aHouse) { - $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); - $oResult->iHouseNumber = closestHouseNumber($aHouse); - - $aPlace = $aHouse; - $iParentPlaceID = $aHouse['parent_place_id']; // the street - $iMaxRank = 30; - - break; - } - } - // no interpolation found, continue search - $iMaxRank = 26; - } - + + // for POI or street level + if ( $iMaxRank >= 26 ) { + $sSQL = 'select place_id,parent_place_id,rank_search,country_code,'; - $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= 'CASE WHEN ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\') THEN ST_distance('.$sPointSQL.', centroid)'; + $sSQL .= ' ELSE ST_distance('.$sPointSQL.', geometry) '; + $sSQL .= ' END as distance'; $sSQL .= ' FROM '; - if ($fSearchDiam < 0.01) { - $sSQL .= ' placex'; - $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; - $sSQL .= ' AND'; + $sSQL .= ' placex'; + $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; + $sSQL .= ' AND'; + // only streets + if ($iMaxRank == 26) { + $sSQL .= ' rank_search != 28 and rank_search = 26'; } else { - $sSQL .= ' (SELECT * FROM placex '; - $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; - $sSQL .= ' LIMIT 1000) as p WHERE'; + $sSQL .= ' rank_search != 28 and rank_search >= 26'; } - $sSQL .= ' rank_search != 28 and rank_search >= '.$iMaxRank; $sSQL .= ' and (name is not null or housenumber is not null'; $sSQL .= ' or rank_search between 26 and 27)'; + $sSQL .= ' and type not in (\'proposed\')'; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; @@ -144,80 +163,49 @@ class ReverseGeocode $this->oDB->getRow($sSQL), 'Could not determine closest place.' ); + if ($aPlace) { - $oResult = new Result($aPlace['place_id']); - $iParentPlaceID = $aPlace['parent_place_id']; - if ($bDoInterpolation) { - if ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27) { - $bIsTigerStreet = ($aPlace['country_code'] == 'us'); - } elseif ($aPlace['rank_search'] == 30) { - // If a house was found, make sure there isn't an - // interpolation line that is closer. - $aHouse = $this->lookupInterpolation( - $sPointSQL, - $aPlace['distance'] + $iPlaceID = $aPlace['place_id']; + $oResult = new Result($iPlaceID); + $iParentPlaceID = $aPlace['parent_place_id']; + // if street and maxrank > streetlevel + if (($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 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_search,country_code,'; + $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= ' FROM '; + $sSQL .= ' placex'; + // radius ? + $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.003)'; + $sSQL .= ' AND parent_place_id = '.$iPlaceID; + $sSQL .= ' and (name is not null or housenumber is not null)'; + $sSQL .= ' ORDER BY distance ASC limit 1'; + if (CONST_Debug) var_dump($sSQL); + $aStreet = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine closest place.' ); - if ($aHouse && $aPlace['distance'] < $aHouse['distance']) { - $oResult = new Result( - $aHouse['place_id'], - Result::TABLE_OSMLINE - ); - $oResult->iHouseNumber = closestHouseNumber($aHouse); - - $aPlace = $aHouse; - $iParentPlaceID = $aHouse['parent_place_id']; + if ($aStreet) { + $iPlaceID = $aStreet['place_id']; + $oResult = new Result($iPlaceID); + $iParentPlaceID = $aStreet['parent_place_id']; } + } + }else{ + $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); } } + // lower than street level ($iMaxRank < 26 ) + }else{ + $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); } - } - - // Only street found? In the US we can check TIGER data for nearest housenumber - if (CONST_Use_US_Tiger_Data && $bIsTigerStreet && $this->iMaxRank >= 28) { - $fSearchDiam = $aPlace['rank_search'] > 28 ? $aPlace['distance'] : 0.001; - $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 .= ' ORDER BY distance ASC limit 1'; - - if (CONST_Debug) var_dump($sSQL); - - $aPlaceTiger = chksql( - $this->oDB->getRow($sSQL), - 'Could not determine closest Tiger place.' - ); - if ($aPlaceTiger) { - if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger); - $aPlace = $aPlaceTiger; - $oResult = new Result($aPlace['place_id'], Result::TABLE_TIGER); - $oResult->iHouseNumber = closestHouseNumber($aPlaceTiger); - $iParentPlaceID = $aPlace['parent_place_id']; - $iMaxRank = 30; - } - } - - // The point we found might be too small - use the address to find what it is a child of - if ($oResult !== null && $iMaxRank < 28) { - if ($aPlace['rank_search'] > 28 && $iParentPlaceID) { - $iPlaceID = $iParentPlaceID; - } else { - $iPlaceID = $oResult->iId; - } - $sSQL = 'select a.address_place_id'; - $sSQL .= ' FROM place_addressline a, placex p'; - $sSQL .= " WHERE a.place_id = $iPlaceID and a.address_place_id = p.place_id"; - $sSQL .= ' AND p.linked_place_id is null'; - $sSQL .= " ORDER BY abs(cached_rank_address - $iMaxRank) asc,cached_rank_address desc,isaddress desc,distance desc"; - $sSQL .= ' LIMIT 1'; - $iPlaceID = chksql($this->oDB->getOne($sSQL), 'Could not get parent for place.'); - if ($iPlaceID) { - $oResult = new Result($iPlaceID); - } - } - + + } return $oResult; } -} + +} \ No newline at end of file From 237e31b3ce8b1dd7012a5d89e7de5b322dfefdd4 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Fri, 20 Apr 2018 14:35:24 +0200 Subject: [PATCH 02/33] use the linked_place_id for adress search if a place node is found with a linked_place_id --- lib/ReverseGeocode.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index a2416929..ae7c8527 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -89,7 +89,7 @@ class ReverseGeocode $iRankSearch = $aPoly['rank_search']; $iGeometry = $aPoly['geometry']; - $sSQL = 'select place_id,parent_place_id,rank_search,country_code,'; + $sSQL = 'select place_id,parent_place_id,rank_search,country_code, linked_place_id,'; $sSQL .=' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; @@ -194,17 +194,26 @@ class ReverseGeocode }else{ $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { - $oResult = new Result($aPlace['place_id']); + // if place node is found adress goes over linked_place_id + if (!empty($aPlace['linked_place_id'])) { + $oResult = new Result($aPlace['linked_place_id']); + }else{ + $oResult = new Result($aPlace['place_id']); + } } } // lower than street level ($iMaxRank < 26 ) }else{ $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { - $oResult = new Result($aPlace['place_id']); + // if place node is found adress goes over linked_place_id + if (!empty($aPlace['linked_place_id'])) { + $oResult = new Result($aPlace['linked_place_id']); + }else{ + $oResult = new Result($aPlace['place_id']); + } + } } - - } return $oResult; } From cb76635da768d0ba63f12eb8e8d53b6d0d29c373 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Mon, 23 Apr 2018 14:32:54 +0200 Subject: [PATCH 03/33] better performance for place node search --- lib/ReverseGeocode.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index ae7c8527..83f6c7e3 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -87,7 +87,7 @@ class ReverseGeocode if ($aPoly) { $iParentPlaceID = $aPoly['parent_place_id']; $iRankSearch = $aPoly['rank_search']; - $iGeometry = $aPoly['geometry']; + $iPlaceID = $aPoly['place_id']; $sSQL = 'select place_id,parent_place_id,rank_search,country_code, linked_place_id,'; $sSQL .=' ST_distance('.$sPointSQL.', geometry) as distance'; @@ -95,9 +95,10 @@ class ReverseGeocode $sSQL .= ' WHERE osm_type = \'N\''; $sSQL .= ' AND rank_search >= '.$iRankSearch; $sSQL .= ' AND rank_search <= LEAST(25, '.$iMaxRank.')'; - $sSQL .= ' AND ST_CONTAINS(\''.$iGeometry.'\'::geometry, geometry )'; + $sSQL .= ' AND ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; + $sSQL .= ' AND class not in ( \'waterway\')'; $sSQL .= ' ORDER BY distance ASC,'; $sSQL .= ' rank_search DESC'; $sSQL .= ' limit 1'; From 723bb4d0b966d9e766153bdc3b2a6db725d67fa0 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 3 May 2018 10:01:49 +0200 Subject: [PATCH 04/33] changing to from rank_search to rank_address --- lib/ReverseGeocode.php | 47 ++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 83f6c7e3..b6369643 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -71,14 +71,17 @@ class ReverseGeocode protected function lookupPolygon($sPointSQL, $iMaxRank) { - $sSQL = 'select place_id,parent_place_id,rank_search,country_code, geometry'; + $sSQL = 'select place_id,parent_place_id,rank_address,country_code, geometry'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\')'; - $sSQL .= ' AND rank_search <= LEAST(25, '.$iMaxRank.')'; + $sSQL .= ' AND rank_address <= LEAST(25, '.$iMaxRank.')'; $sSQL .= ' AND ST_CONTAINS(geometry, '.$sPointSQL.' )'; $sSQL .= ' AND type != \'postcode\' '; - $sSQL .= ' AND name IS NOT NULL '; - $sSQL .= ' ORDER BY rank_search DESC LIMIT 1'; + $sSQL .= ' and rank_address != 28'; + $sSQL .= ' and (name is not null or housenumber is not null'; + $sSQL .= ' or rank_address between 26 and 27)'; + $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' ORDER BY rank_address DESC LIMIT 1'; $aPoly = chksql( $this->oDB->getRow($sSQL), @@ -86,21 +89,21 @@ class ReverseGeocode ); if ($aPoly) { $iParentPlaceID = $aPoly['parent_place_id']; - $iRankSearch = $aPoly['rank_search']; + $iRankAddress = $aPoly['rank_address']; $iPlaceID = $aPoly['place_id']; - $sSQL = 'select place_id,parent_place_id,rank_search,country_code, linked_place_id,'; + $sSQL = 'select place_id,parent_place_id,rank_address,country_code, linked_place_id,'; $sSQL .=' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; - $sSQL .= ' AND rank_search >= '.$iRankSearch; - $sSQL .= ' AND rank_search <= LEAST(25, '.$iMaxRank.')'; + $sSQL .= ' AND rank_address >= '.$iRankAddress; + $sSQL .= ' AND rank_address <= LEAST(25, '.$iMaxRank.')'; $sSQL .= ' AND ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; - $sSQL .= ' AND class not in ( \'waterway\')'; - $sSQL .= ' ORDER BY distance ASC,'; - $sSQL .= ' rank_search DESC'; + $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' ORDER BY rank_address DESC,'; + $sSQL .= ' distance ASC'; $sSQL .= ' limit 1'; if (CONST_Debug) var_dump($sSQL); $aPlacNode = chksql( @@ -137,7 +140,7 @@ class ReverseGeocode // for POI or street level if ( $iMaxRank >= 26 ) { - $sSQL = 'select place_id,parent_place_id,rank_search,country_code,'; + $sSQL = 'select place_id,parent_place_id,rank_address,country_code,'; $sSQL .= 'CASE WHEN ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\') THEN ST_distance('.$sPointSQL.', centroid)'; $sSQL .= ' ELSE ST_distance('.$sPointSQL.', geometry) '; $sSQL .= ' END as distance'; @@ -147,13 +150,13 @@ class ReverseGeocode $sSQL .= ' AND'; // only streets if ($iMaxRank == 26) { - $sSQL .= ' rank_search != 28 and rank_search = 26'; + $sSQL .= ' rank_address != 28 and rank_address = 26'; } else { - $sSQL .= ' rank_search != 28 and rank_search >= 26'; + $sSQL .= ' rank_address != 28 and rank_address >= 26'; } $sSQL .= ' and (name is not null or housenumber is not null'; - $sSQL .= ' or rank_search between 26 and 27)'; - $sSQL .= ' and type not in (\'proposed\')'; + $sSQL .= ' or rank_address between 26 and 27)'; + //$sSQL .= ' and type not in (\'proposed\')'; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; @@ -170,16 +173,20 @@ class ReverseGeocode $oResult = new Result($iPlaceID); $iParentPlaceID = $aPlace['parent_place_id']; // if street and maxrank > streetlevel - if (($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27)&& $iMaxRank > 27 ) { + if (($aPlace['rank_address'] == 26 || $aPlace['rank_address'] == 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_search,country_code,'; + $sSQL = ' select place_id,parent_place_id,rank_address,country_code,'; $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM '; $sSQL .= ' placex'; // radius ? - $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.003)'; + $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)'; $sSQL .= ' AND parent_place_id = '.$iPlaceID; - $sSQL .= ' and (name is not null or housenumber is not null)'; + $sSQL .= ' and rank_address != 28'; + $sSQL .= ' and (name is not null or housenumber is not null'; + $sSQL .= ' or rank_address between 26 and 27)'; + $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; $sSQL .= ' ORDER BY distance ASC limit 1'; if (CONST_Debug) var_dump($sSQL); $aStreet = chksql( From 71c9adfdba238bb55a43fb69da0290c5b0e6e159 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 3 May 2018 16:57:01 +0200 Subject: [PATCH 05/33] performence update through subquerry --- lib/ReverseGeocode.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index b6369643..f720eea3 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -92,19 +92,24 @@ class ReverseGeocode $iRankAddress = $aPoly['rank_address']; $iPlaceID = $aPoly['place_id']; - $sSQL = 'select place_id,parent_place_id,rank_address,country_code, linked_place_id,'; - $sSQL .=' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL = 'SELECT *'; + $sSQL .= ' FROM ('; + $sSQL .= ' SELECT place_id, rank_address,country_code, linked_place_id, geometry,'; + $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; $sSQL .= ' AND rank_address >= '.$iRankAddress; $sSQL .= ' AND rank_address <= LEAST(25, '.$iMaxRank.')'; - $sSQL .= ' AND ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; - $sSQL .= ' ORDER BY rank_address DESC,'; - $sSQL .= ' distance ASC'; - $sSQL .= ' limit 1'; + $sSQL .= ' ORDER BY distance ASC,'; + $sSQL .= ' rank_address DESC'; + $sSQL .= ' limit 500) as a'; + $sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; + $sSQL .= ' ORDER BY distance ASC, rank_address DESC'; + $sSQL .= ' LIMIT 1'; + if (CONST_Debug) var_dump($sSQL); $aPlacNode = chksql( $this->oDB->getRow($sSQL), From 424c0d0ebb8b76a933d5e255ad7e406310990bb2 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 3 May 2018 17:44:18 +0200 Subject: [PATCH 06/33] faster query through bbox preselection --- lib/ReverseGeocode.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index f720eea3..9576fafc 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -103,6 +103,8 @@ class ReverseGeocode $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + // preselection through bbox + $sSQL .= ' AND (SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.') && geometry'; $sSQL .= ' ORDER BY distance ASC,'; $sSQL .= ' rank_address DESC'; $sSQL .= ' limit 500) as a'; From 5f2410119de1125f228e69627a362ea7fa1d9557 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 9 May 2018 11:39:05 +0200 Subject: [PATCH 07/33] better performance --- lib/ReverseGeocode.php | 87 ++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 9576fafc..7e23d1c2 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -70,17 +70,19 @@ class ReverseGeocode } protected function lookupPolygon($sPointSQL, $iMaxRank) - { - $sSQL = 'select place_id,parent_place_id,rank_address,country_code, geometry'; + { + $sSQL = 'SELECT * FROM'; + $sSQL .= '(select place_id,parent_place_id,rank_address,country_code, geometry'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\')'; - $sSQL .= ' AND rank_address <= LEAST(25, '.$iMaxRank.')'; - $sSQL .= ' AND ST_CONTAINS(geometry, '.$sPointSQL.' )'; + $sSQL .= ' AND rank_address <= '.Min(25,$iMaxRank); + $sSQL .= ' AND geometry && '.$sPointSQL; $sSQL .= ' AND type != \'postcode\' '; - $sSQL .= ' and rank_address != 28'; - $sSQL .= ' and (name is not null or housenumber is not null'; - $sSQL .= ' or rank_address between 26 and 27)'; - $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' AND name is not null'; + $sSQL .= ' AND class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' AND indexed_status = 0 and linked_place_id is null'; + $sSQL .= ' ORDER BY rank_address DESC LIMIT 50 ) as a'; + $sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )'; $sSQL .= ' ORDER BY rank_address DESC LIMIT 1'; $aPoly = chksql( @@ -92,33 +94,36 @@ class ReverseGeocode $iRankAddress = $aPoly['rank_address']; $iPlaceID = $aPoly['place_id']; - $sSQL = 'SELECT *'; - $sSQL .= ' FROM ('; - $sSQL .= ' SELECT place_id, rank_address,country_code, linked_place_id, geometry,'; - $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; - $sSQL .= ' FROM placex'; - $sSQL .= ' WHERE osm_type = \'N\''; - $sSQL .= ' AND rank_address >= '.$iRankAddress; - $sSQL .= ' AND rank_address <= LEAST(25, '.$iMaxRank.')'; - $sSQL .= ' AND type != \'postcode\''; - $sSQL .= ' AND name IS NOT NULL '; - $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; - // preselection through bbox - $sSQL .= ' AND (SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.') && geometry'; - $sSQL .= ' ORDER BY distance ASC,'; - $sSQL .= ' rank_address DESC'; - $sSQL .= ' limit 500) as a'; - $sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; - $sSQL .= ' ORDER BY distance ASC, rank_address DESC'; - $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 ($iRankAddress != $iMaxRank) { + $sSQL = 'SELECT *'; + $sSQL .= ' FROM ('; + $sSQL .= ' SELECT place_id, rank_address,country_code, geometry,'; + $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= ' FROM placex'; + $sSQL .= ' WHERE osm_type = \'N\''; + $sSQL .= ' AND rank_address > '.$iRankAddress; + $sSQL .= ' AND rank_address <= '.Min(25,$iMaxRank); + $sSQL .= ' AND type != \'postcode\''; + $sSQL .= ' AND name IS NOT NULL '; + $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; + // preselection through bbox + $sSQL .= ' AND (SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.') && geometry'; + $sSQL .= ' ORDER BY distance ASC,'; + $sSQL .= ' rank_address DESC'; + $sSQL .= ' limit 500) as a'; + $sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )'; + $sSQL .= ' ORDER BY distance ASC, rank_address DESC'; + $sSQL .= ' LIMIT 1'; + + if (CONST_Debug) var_dump($sSQL); + $aPlacNode = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine place node.' + ); + if ($aPlacNode) { + return $aPlacNode; + } } } return $aPoly; @@ -209,24 +214,14 @@ class ReverseGeocode }else{ $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { - // if place node is found adress goes over linked_place_id - if (!empty($aPlace['linked_place_id'])) { - $oResult = new Result($aPlace['linked_place_id']); - }else{ - $oResult = new Result($aPlace['place_id']); - } + $oResult = new Result($aPlace['place_id']); } } // lower than street level ($iMaxRank < 26 ) }else{ $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { - // if place node is found adress goes over linked_place_id - if (!empty($aPlace['linked_place_id'])) { - $oResult = new Result($aPlace['linked_place_id']); - }else{ $oResult = new Result($aPlace['place_id']); - } } } return $oResult; From 625018b65420af0af436e999770275788b19f674 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 9 May 2018 13:18:37 +0200 Subject: [PATCH 08/33] adapted the coding style with phpcs --- lib/ReverseGeocode.php | 80 ++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 7e23d1c2..c3356392 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -70,12 +70,12 @@ class ReverseGeocode } protected function lookupPolygon($sPointSQL, $iMaxRank) - { + { $sSQL = 'SELECT * FROM'; $sSQL .= '(select place_id,parent_place_id,rank_address,country_code, geometry'; $sSQL .= ' FROM placex'; - $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\')'; - $sSQL .= ' AND rank_address <= '.Min(25,$iMaxRank); + $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')'; + $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); $sSQL .= ' AND geometry && '.$sPointSQL; $sSQL .= ' AND type != \'postcode\' '; $sSQL .= ' AND name is not null'; @@ -102,7 +102,7 @@ class ReverseGeocode $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; $sSQL .= ' AND rank_address > '.$iRankAddress; - $sSQL .= ' AND rank_address <= '.Min(25,$iMaxRank); + $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; @@ -150,8 +150,7 @@ class ReverseGeocode $bIsTigerStreet = false; // for POI or street level - if ( $iMaxRank >= 26 ) { - + if ($iMaxRank >= 26) { $sSQL = 'select place_id,parent_place_id,rank_address,country_code,'; $sSQL .= 'CASE WHEN ST_GeometryType(geometry) in (\'ST_Polygon\',\'ST_MultiPolygon\') THEN ST_distance('.$sPointSQL.', centroid)'; $sSQL .= ' ELSE ST_distance('.$sPointSQL.', geometry) '; @@ -185,46 +184,45 @@ class ReverseGeocode $oResult = new Result($iPlaceID); $iParentPlaceID = $aPlace['parent_place_id']; // if street and maxrank > streetlevel - if (($aPlace['rank_address'] == 26 || $aPlace['rank_address'] == 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 .= ' ST_distance('.$sPointSQL.', geometry) as distance'; - $sSQL .= ' FROM '; - $sSQL .= ' placex'; - // radius ? - $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)'; - $sSQL .= ' AND parent_place_id = '.$iPlaceID; - $sSQL .= ' and rank_address != 28'; - $sSQL .= ' and (name is not null or housenumber is not null'; - $sSQL .= ' or rank_address between 26 and 27)'; - $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; - $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; - $sSQL .= ' ORDER BY distance ASC limit 1'; - if (CONST_Debug) var_dump($sSQL); - $aStreet = chksql( - $this->oDB->getRow($sSQL), - 'Could not determine closest place.' - ); - if ($aStreet) { - $iPlaceID = $aStreet['place_id']; - $oResult = new Result($iPlaceID); - $iParentPlaceID = $aStreet['parent_place_id']; - } - } - }else{ - $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); - if ($aPlace) { - $oResult = new Result($aPlace['place_id']); + if (($aPlace['rank_address'] == 26 || $aPlace['rank_address'] == 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 .= ' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= ' FROM '; + $sSQL .= ' placex'; + // radius ? + $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)'; + $sSQL .= ' AND parent_place_id = '.$iPlaceID; + $sSQL .= ' and rank_address != 28'; + $sSQL .= ' and (name is not null or housenumber is not null'; + $sSQL .= ' or rank_address between 26 and 27)'; + $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; + $sSQL .= ' ORDER BY distance ASC limit 1'; + if (CONST_Debug) var_dump($sSQL); + $aStreet = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine closest place.' + ); + if ($aStreet) { + $iPlaceID = $aStreet['place_id']; + $oResult = new Result($iPlaceID); + $iParentPlaceID = $aStreet['parent_place_id']; } } - // lower than street level ($iMaxRank < 26 ) - }else{ + } else { $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { - $oResult = new Result($aPlace['place_id']); + $oResult = new Result($aPlace['place_id']); } } + // lower than street level ($iMaxRank < 26 ) + } else { + $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); + } + } return $oResult; } - -} \ No newline at end of file +} From 4d073b0350b5314698286becc4c0faf13b54bf1a Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 16 May 2018 13:17:56 +0200 Subject: [PATCH 09/33] new query to search place nodes if no polygon was found --- lib/ReverseGeocode.php | 59 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index c3356392..a6d4b76f 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -69,8 +69,56 @@ class ReverseGeocode ); } + protected function noPolygonfound($sPointSQL, $iMaxRank) + { + // search_rank => search diameter + $aRankDiam = array( + 18 => 0.2, + 17 => 0.6, + 12 => 0.8, + 10 => 1, + 8 => 2, + 4 => 3, + ); + + foreach ($aRankDiam as $key => $value) { + if ($key > $iMaxRank) continue; + + $sSQL = 'SELECT *'; + $sSQL .= ' FROM ('; + $sSQL .= ' SELECT place_id, rank_address,country_code, geometry,'; + $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= ' FROM placex'; + $sSQL .= ' WHERE osm_type = \'N\''; + $sSQL .= ' AND rank_address > 0'; + $sSQL .= ' AND rank_address <= ' .$key; + $sSQL .= ' AND type != \'postcode\''; + $sSQL .= ' AND name IS NOT NULL '; + $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; + $sSQL .= ' ORDER BY rank_address DESC, distance ASC'; + $sSQL .= ' limit 500) as a'; + $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$value.')'; + $sSQL .= ' ORDER BY rank_address 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; + break; + } + } + } + protected function lookupPolygon($sPointSQL, $iMaxRank) { + + $oResult = null; + $aPlace = null; + $sSQL = 'SELECT * FROM'; $sSQL .= '(select place_id,parent_place_id,rank_address,country_code, geometry'; $sSQL .= ' FROM placex'; @@ -79,7 +127,6 @@ class ReverseGeocode $sSQL .= ' AND geometry && '.$sPointSQL; $sSQL .= ' AND type != \'postcode\' '; $sSQL .= ' AND name is not null'; - $sSQL .= ' AND class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' AND indexed_status = 0 and linked_place_id is null'; $sSQL .= ' ORDER BY rank_address DESC LIMIT 50 ) as a'; $sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )'; @@ -105,7 +152,6 @@ class ReverseGeocode $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; - $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; // preselection through bbox $sSQL .= ' AND (SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.') && geometry'; @@ -125,6 +171,8 @@ class ReverseGeocode return $aPlacNode; } } + }else{ + return $this->noPolygonfound ($sPointSQL, $iMaxRank); } return $aPoly; } @@ -161,13 +209,12 @@ class ReverseGeocode $sSQL .= ' AND'; // only streets if ($iMaxRank == 26) { - $sSQL .= ' rank_address != 28 and rank_address = 26'; + $sSQL .= ' rank_address = 26'; } else { - $sSQL .= ' rank_address != 28 and rank_address >= 26'; + $sSQL .= ' rank_address >= 26'; } $sSQL .= ' and (name is not null or housenumber is not null'; $sSQL .= ' or rank_address between 26 and 27)'; - //$sSQL .= ' and type not in (\'proposed\')'; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; @@ -220,7 +267,7 @@ class ReverseGeocode } else { $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { - $oResult = new Result($aPlace['place_id']); + $oResult = new Result($aPlace['place_id']); } } return $oResult; From 10897787af9a3863645ca9b37cf76570bb57b1ed Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 17 May 2018 14:24:03 +0200 Subject: [PATCH 10/33] deleted query for place nodes search if no polygon is found and added search for interpolation lines --- lib/ReverseGeocode.php | 64 +++++++++++------------------------------- 1 file changed, 17 insertions(+), 47 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index a6d4b76f..93da7caf 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -68,51 +68,7 @@ class ReverseGeocode 'Could not determine closest housenumber on an osm interpolation line.' ); } - - protected function noPolygonfound($sPointSQL, $iMaxRank) - { - // search_rank => search diameter - $aRankDiam = array( - 18 => 0.2, - 17 => 0.6, - 12 => 0.8, - 10 => 1, - 8 => 2, - 4 => 3, - ); - - foreach ($aRankDiam as $key => $value) { - if ($key > $iMaxRank) continue; - - $sSQL = 'SELECT *'; - $sSQL .= ' FROM ('; - $sSQL .= ' SELECT place_id, rank_address,country_code, geometry,'; - $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; - $sSQL .= ' FROM placex'; - $sSQL .= ' WHERE osm_type = \'N\''; - $sSQL .= ' AND rank_address > 0'; - $sSQL .= ' AND rank_address <= ' .$key; - $sSQL .= ' AND type != \'postcode\''; - $sSQL .= ' AND name IS NOT NULL '; - $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; - $sSQL .= ' ORDER BY rank_address DESC, distance ASC'; - $sSQL .= ' limit 500) as a'; - $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$value.')'; - $sSQL .= ' ORDER BY rank_address 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; - break; - } - } - } - + protected function lookupPolygon($sPointSQL, $iMaxRank) { @@ -171,8 +127,6 @@ class ReverseGeocode return $aPlacNode; } } - }else{ - return $this->noPolygonfound ($sPointSQL, $iMaxRank); } return $aPoly; } @@ -197,6 +151,22 @@ class ReverseGeocode $fMaxAreaDistance = 1; $bIsTigerStreet = false; + // try with interpolations before continuing + if ($bDoInterpolation && $iMaxRank >= 30 ) { + $aHouse = $this->lookupInterpolation($sPointSQL, $fSearchDiam/3); + + if ($aHouse) { + $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); + $oResult->iHouseNumber = closestHouseNumber($aHouse); + + $aPlace = $aHouse; + $iParentPlaceID = $aHouse['parent_place_id']; // the street + $iMaxRank = 30; + + return $oResult; + } + }// no interpolation found, continue search + // for POI or street level if ($iMaxRank >= 26) { $sSQL = 'select place_id,parent_place_id,rank_address,country_code,'; From 6b8c99a2759c8aa60d50aa61957ac14172e4a06d Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Fri, 18 May 2018 15:34:50 +0200 Subject: [PATCH 11/33] rebase --- lib/PlaceLookup.php | 49 +++++++++++++++++++++++++++------------------ website/reverse.php | 14 ++++++------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 98af69f2..5ae1da21 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -164,21 +164,19 @@ class PlaceLookup $aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID))); - return empty($aResults) ? null : reset($aResults); + return sizeof($aResults) ? reset($aResults) : null; } public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30) { - Debug::newFunction('Place lookup'); - - if (empty($aResults)) { + if (!sizeof($aResults)) { return array(); } $aSubSelects = array(); $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_PLACEX); + if (CONST_Debug) var_dump('PLACEX', $sPlaceIDs); if ($sPlaceIDs) { - Debug::printVar('Ids from placex', $sPlaceIDs); $sSQL = 'SELECT '; $sSQL .= ' osm_type,'; $sSQL .= ' osm_id,'; @@ -248,7 +246,6 @@ class PlaceLookup // postcode table $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_POSTCODE); if ($sPlaceIDs) { - Debug::printVar('Ids from location_postcode', $sPlaceIDs); $sSQL = 'SELECT'; $sSQL .= " 'P' as osm_type,"; $sSQL .= ' (SELECT osm_id from placex p WHERE p.place_id = lp.parent_place_id) as osm_id,'; @@ -279,7 +276,6 @@ class PlaceLookup if (CONST_Use_US_Tiger_Data) { $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_TIGER); if ($sPlaceIDs) { - Debug::printVar('Ids from Tiger table', $sPlaceIDs); $sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_TIGER); // Tiger search only if a housenumber was searched and if it was found // (realized through a join) @@ -325,7 +321,6 @@ class PlaceLookup // osmline - interpolated housenumbers $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_OSMLINE); if ($sPlaceIDs) { - Debug::printVar('Ids from interpolation', $sPlaceIDs); $sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_OSMLINE); // interpolation line search only if a housenumber was searched // (realized through a join) @@ -411,13 +406,16 @@ class PlaceLookup } } - if (empty($aSubSelects)) { + if (CONST_Debug) var_dump($aSubSelects); + + if (!sizeof($aSubSelects)) { return array(); } - $sSQL = join(' UNION ', $aSubSelects); - Debug::printSQL($sSQL); - $aPlaces = chksql($this->oDB->getAll($sSQL), 'Could not lookup place'); + $aPlaces = chksql( + $this->oDB->getAll(join(' UNION ', $aSubSelects)), + 'Could not lookup place' + ); $aClassType = getClassTypes(); foreach ($aPlaces as &$aPlace) { @@ -459,12 +457,12 @@ class PlaceLookup $aPlace['addresstype'] = $sAddressType; } - Debug::printVar('Places', $aPlaces); + if (CONST_Debug) var_dump($aPlaces); return $aPlaces; } - public function getAddressDetails($iPlaceID, $bAll = false, $sHousenumber = -1) + private function getAddressDetails($iPlaceID, $bAll, $sHousenumber) { $sSQL = 'SELECT *,'; $sSQL .= ' get_name_by_language(name,'.$this->aLangPrefOrderSql.') as localname'; @@ -528,7 +526,7 @@ class PlaceLookup */ - public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null) + public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null, $fLonReverse = null, $fLatReverse = null) { $aOutlineResult = array(); @@ -536,10 +534,23 @@ class PlaceLookup if (CONST_Search_AreaPolygons) { // Get the bounding box and outline polygon - $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; - $sSQL .= 'ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,'; - $sSQL .= 'ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,'; - $sSQL .= 'ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon'; + $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; + if ($fLonReverse != null && $fLatReverse != null) { + $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; + $sSQL .= ' ST_Y(ST_LineInterpolatePoint(geometry,'; + $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; + $sSQL .= ' ELSE ST_Y(centroid) '; + $sSQL .= ' END as centrelat, '; + $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; + $sSQL .= ' ST_X(ST_LineInterpolatePoint(geometry,'; + $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; + $sSQL .= ' ELSE ST_X(centroid) '; + $sSQL .= ' END as centrelon, '; + } else { + $sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,'; + } + $sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,'; + $sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon'; if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ',ST_AsGeoJSON(geometry) as asgeojson'; if ($this->bIncludePolygonAsKML) $sSQL .= ',ST_AsKML(geometry) as askml'; if ($this->bIncludePolygonAsSVG) $sSQL .= ',ST_AsSVG(geometry) as assvg'; diff --git a/website/reverse.php b/website/reverse.php index 3bcac2ce..3ce7a20d 100755 --- a/website/reverse.php +++ b/website/reverse.php @@ -41,7 +41,7 @@ if ($sOsmType && $iOsmId > 0) { if ($oLookup) { $aPlaces = $oPlaceLookup->lookup(array($oLookup->iId => $oLookup)); - if (!empty($aPlaces)) { + if (sizeof($aPlaces)) { $aPlace = reset($aPlaces); } } @@ -55,14 +55,16 @@ if (isset($aPlace)) { $aPlace['place_id'], $aPlace['lon'], $aPlace['lat'], - $fRadius + $fRadius, + $fLat, + $fLon ); if ($aOutlineResult) { $aPlace = array_merge($aPlace, $aOutlineResult); } } else { - $aPlace = array(); + $aPlace = []; } @@ -72,10 +74,8 @@ if (CONST_Debug) { } if ($sOutputFormat == 'html') { - $sDataDate = chksql($oDB->getOne("select TO_CHAR(lastimportdate,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1")); + $sDataDate = chksql($oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1")); $sTileURL = CONST_Map_Tile_URL; $sTileAttribution = CONST_Map_Tile_Attribution; } - -$sOutputTemplate = ($sOutputFormat=='jsonv2' ? 'json' : $sOutputFormat); -include(CONST_BasePath.'/lib/template/address-'.$sOutputTemplate.'.php'); +include(CONST_BasePath.'/lib/template/address-'.$sOutputFormat.'.php'); From ab5bcd6d2f288244ff7febaf0955933af0e9ff0a Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Tue, 22 May 2018 12:22:15 +0200 Subject: [PATCH 12/33] rebase --- lib/PlaceLookup.php | 60 +++++++++++++++++++++++---------------------- website/reverse.php | 14 +++++------ 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 5ae1da21..93ffd6a0 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -164,19 +164,21 @@ class PlaceLookup $aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID))); - return sizeof($aResults) ? reset($aResults) : null; + return empty($aResults) ? null : reset($aResults); } public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30) { - if (!sizeof($aResults)) { + Debug::newFunction('Place lookup'); + + if (empty($aResults)) { return array(); } $aSubSelects = array(); $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_PLACEX); - if (CONST_Debug) var_dump('PLACEX', $sPlaceIDs); if ($sPlaceIDs) { + Debug::printVar('Ids from placex', $sPlaceIDs); $sSQL = 'SELECT '; $sSQL .= ' osm_type,'; $sSQL .= ' osm_id,'; @@ -246,6 +248,7 @@ class PlaceLookup // postcode table $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_POSTCODE); if ($sPlaceIDs) { + Debug::printVar('Ids from location_postcode', $sPlaceIDs); $sSQL = 'SELECT'; $sSQL .= " 'P' as osm_type,"; $sSQL .= ' (SELECT osm_id from placex p WHERE p.place_id = lp.parent_place_id) as osm_id,'; @@ -276,6 +279,7 @@ class PlaceLookup if (CONST_Use_US_Tiger_Data) { $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_TIGER); if ($sPlaceIDs) { + Debug::printVar('Ids from Tiger table', $sPlaceIDs); $sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_TIGER); // Tiger search only if a housenumber was searched and if it was found // (realized through a join) @@ -321,6 +325,7 @@ class PlaceLookup // osmline - interpolated housenumbers $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_OSMLINE); if ($sPlaceIDs) { + Debug::printVar('Ids from interpolation', $sPlaceIDs); $sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_OSMLINE); // interpolation line search only if a housenumber was searched // (realized through a join) @@ -406,16 +411,13 @@ class PlaceLookup } } - if (CONST_Debug) var_dump($aSubSelects); - - if (!sizeof($aSubSelects)) { + if (empty($aSubSelects)) { return array(); } - $aPlaces = chksql( - $this->oDB->getAll(join(' UNION ', $aSubSelects)), - 'Could not lookup place' - ); + $sSQL = join(' UNION ', $aSubSelects); + Debug::printSQL($sSQL); + $aPlaces = chksql($this->oDB->getAll($sSQL), 'Could not lookup place'); $aClassType = getClassTypes(); foreach ($aPlaces as &$aPlace) { @@ -457,12 +459,12 @@ class PlaceLookup $aPlace['addresstype'] = $sAddressType; } - if (CONST_Debug) var_dump($aPlaces); + Debug::printVar('Places', $aPlaces); return $aPlaces; } - private function getAddressDetails($iPlaceID, $bAll, $sHousenumber) + public function getAddressDetails($iPlaceID, $bAll = false, $sHousenumber = -1) { $sSQL = 'SELECT *,'; $sSQL .= ' get_name_by_language(name,'.$this->aLangPrefOrderSql.') as localname'; @@ -534,23 +536,23 @@ class PlaceLookup if (CONST_Search_AreaPolygons) { // Get the bounding box and outline polygon - $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; - if ($fLonReverse != null && $fLatReverse != null) { - $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; - $sSQL .= ' ST_Y(ST_LineInterpolatePoint(geometry,'; - $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; - $sSQL .= ' ELSE ST_Y(centroid) '; - $sSQL .= ' END as centrelat, '; - $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; - $sSQL .= ' ST_X(ST_LineInterpolatePoint(geometry,'; - $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; - $sSQL .= ' ELSE ST_X(centroid) '; - $sSQL .= ' END as centrelon, '; - } else { - $sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,'; - } - $sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,'; - $sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon'; + $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; + if ($fLonReverse != null && $fLatReverse != null) { + $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; + $sSQL .= ' ST_Y(ST_LineInterpolatePoint(geometry,'; + $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; + $sSQL .= ' ELSE ST_Y(centroid) '; + $sSQL .= ' END as centrelat, '; + $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; + $sSQL .= ' ST_X(ST_LineInterpolatePoint(geometry,'; + $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; + $sSQL .= ' ELSE ST_X(centroid) '; + $sSQL .= ' END as centrelon, '; + } else { + $sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,'; + } + $sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,'; + $sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon'; if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ',ST_AsGeoJSON(geometry) as asgeojson'; if ($this->bIncludePolygonAsKML) $sSQL .= ',ST_AsKML(geometry) as askml'; if ($this->bIncludePolygonAsSVG) $sSQL .= ',ST_AsSVG(geometry) as assvg'; diff --git a/website/reverse.php b/website/reverse.php index 3ce7a20d..3bcac2ce 100755 --- a/website/reverse.php +++ b/website/reverse.php @@ -41,7 +41,7 @@ if ($sOsmType && $iOsmId > 0) { if ($oLookup) { $aPlaces = $oPlaceLookup->lookup(array($oLookup->iId => $oLookup)); - if (sizeof($aPlaces)) { + if (!empty($aPlaces)) { $aPlace = reset($aPlaces); } } @@ -55,16 +55,14 @@ if (isset($aPlace)) { $aPlace['place_id'], $aPlace['lon'], $aPlace['lat'], - $fRadius, - $fLat, - $fLon + $fRadius ); if ($aOutlineResult) { $aPlace = array_merge($aPlace, $aOutlineResult); } } else { - $aPlace = []; + $aPlace = array(); } @@ -74,8 +72,10 @@ if (CONST_Debug) { } if ($sOutputFormat == 'html') { - $sDataDate = chksql($oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1")); + $sDataDate = chksql($oDB->getOne("select TO_CHAR(lastimportdate,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1")); $sTileURL = CONST_Map_Tile_URL; $sTileAttribution = CONST_Map_Tile_Attribution; } -include(CONST_BasePath.'/lib/template/address-'.$sOutputFormat.'.php'); + +$sOutputTemplate = ($sOutputFormat=='jsonv2' ? 'json' : $sOutputFormat); +include(CONST_BasePath.'/lib/template/address-'.$sOutputTemplate.'.php'); From 43ee4a8faf984382d718bbab25a3752ce19a5b97 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Tue, 22 May 2018 12:31:53 +0200 Subject: [PATCH 13/33] changed parameters for lookup function in the reverse.php --- website/reverse.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/reverse.php b/website/reverse.php index 3bcac2ce..e131a844 100755 --- a/website/reverse.php +++ b/website/reverse.php @@ -55,7 +55,9 @@ if (isset($aPlace)) { $aPlace['place_id'], $aPlace['lon'], $aPlace['lat'], - $fRadius + $fRadius, + $fLat, + $fLon ); if ($aOutlineResult) { From ee54ebfe77ef4c52a51c5326952f6a98299a3a68 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 23 May 2018 13:37:18 +0200 Subject: [PATCH 14/33] new query if no polygon is found the new query searchs in the country_osm_grid table for a polygon --- lib/ReverseGeocode.php | 49 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 93da7caf..42215931 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -68,7 +68,42 @@ class ReverseGeocode 'Could not determine closest housenumber on an osm interpolation line.' ); } - + + protected function noPolygonFound($sPointSQL, $iMaxRank) + { + $sSQL = 'SELECT * FROM country_osm_grid'; + $sSQL .= ' WHERE ST_CONTAINS (geometry, '.$sPointSQL.' )'; + + $aPoly = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine polygon containing the point.' + ); + if ($aPoly) { + $sCountryCode = $aPoly['country_code']; + + $sSQL = 'SELECT *, ST_distance('.$sPointSQL.', geometry) as distance'; + $sSQL .= ' FROM placex'; + $sSQL .= ' WHERE osm_type = \'N\''; + $sSQL .= ' AND country_code = \''.$sCountryCode.'\''; + $sSQL .= ' AND rank_address > 0'; + $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); + $sSQL .= ' AND type != \'postcode\''; + $sSQL .= ' AND name IS NOT NULL '; + $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; + $sSQL .= ' ORDER BY distance ASC, rank_address DESC'; + $sSQL .= ' LIMIT 1'; + + if (CONST_Debug) var_dump($sSQL); + $aPlacNode = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine place node.' + ); + if ($aPlacNode) { + return $aPlacNode; + } + } + } + protected function lookupPolygon($sPointSQL, $iMaxRank) { @@ -152,7 +187,7 @@ class ReverseGeocode $bIsTigerStreet = false; // try with interpolations before continuing - if ($bDoInterpolation && $iMaxRank >= 30 ) { + if ($bDoInterpolation && $iMaxRank >= 30) { $aHouse = $this->lookupInterpolation($sPointSQL, $fSearchDiam/3); if ($aHouse) { @@ -231,6 +266,11 @@ class ReverseGeocode $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); + } else { + $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); + } } } // lower than street level ($iMaxRank < 26 ) @@ -238,6 +278,11 @@ class ReverseGeocode $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); + } else { + $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); + } } } return $oResult; From 7585d378181184f973454020ad07b1b973c243ed Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 23 May 2018 13:37:58 +0200 Subject: [PATCH 15/33] edited test --- test/bdd/api/reverse/simple.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bdd/api/reverse/simple.feature b/test/bdd/api/reverse/simple.feature index 3f4bd6eb..ecaca483 100644 --- a/test/bdd/api/reverse/simple.feature +++ b/test/bdd/api/reverse/simple.feature @@ -70,7 +70,7 @@ Feature: Simple Reverse Tests Scenario Outline: Boundingbox is returned When sending reverse coordinates 14.62,108.1 | zoom | - | 4 | + | 8 | Then result has bounding box in 9,20,102,113 Examples: From f0e5cf53b80a2649d750cb963deb237a58b65029 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 23 May 2018 15:29:41 +0200 Subject: [PATCH 16/33] only starts the search in country_osm_grid if $iMaxRank > 4 --- lib/ReverseGeocode.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 42215931..0c0a394e 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -266,7 +266,7 @@ class ReverseGeocode $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); - } else { + } elseif(!$aPlace && $iMaxRank > 4) { $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); @@ -278,7 +278,7 @@ class ReverseGeocode $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); - } else { + } elseif(!$aPlace && $iMaxRank > 4) { $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); From 82b6245aaa581d628da51219f6637c022a322a18 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 24 May 2018 13:45:45 +0200 Subject: [PATCH 17/33] better place node search with rank_search --- lib/ReverseGeocode.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 0c0a394e..977c56f2 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -70,7 +70,8 @@ class ReverseGeocode } protected function noPolygonFound($sPointSQL, $iMaxRank) - { + { + // searches for polygon in table country_osm_grid which contains the searchpoint $sSQL = 'SELECT * FROM country_osm_grid'; $sSQL .= ' WHERE ST_CONTAINS (geometry, '.$sPointSQL.' )'; @@ -111,7 +112,7 @@ class ReverseGeocode $aPlace = null; $sSQL = 'SELECT * FROM'; - $sSQL .= '(select place_id,parent_place_id,rank_address,country_code, geometry'; + $sSQL .= '(select place_id,parent_place_id,rank_address, rank_search, country_code, geometry'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')'; $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); @@ -130,6 +131,7 @@ class ReverseGeocode if ($aPoly) { $iParentPlaceID = $aPoly['parent_place_id']; $iRankAddress = $aPoly['rank_address']; + $iRankSearch = $aPoly['rank_search']; $iPlaceID = $aPoly['place_id']; if ($iRankAddress != $iMaxRank) { @@ -139,8 +141,15 @@ class ReverseGeocode $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; - $sSQL .= ' AND rank_address > '.$iRankAddress; - $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); + if ($iRankAddress = 16){ + // using rank_search beacause of a better differentiation for place nodes at rank_address 16 + $sSQL .= ' AND rank_search > '.$iRankSearch; + $sSQL .= ' AND rank_search <= ' .Min(25, $iMaxRank); + $sSQL .= ' AND class = \'place\''; + }else{ + $sSQL .= ' AND rank_address > '.$iRankAddress; + $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); + } $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; From 796f069d74af5a038afb47047aaa92e8004dda20 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Tue, 5 Jun 2018 11:07:51 +0200 Subject: [PATCH 18/33] test adjusting --- lib/ReverseGeocode.php | 2 +- test/bdd/api/reverse/queries.feature | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 977c56f2..b69e6446 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -142,7 +142,7 @@ class ReverseGeocode $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; if ($iRankAddress = 16){ - // using rank_search beacause of a better differentiation for place nodes at rank_address 16 + // using rank_search because of a better differentiation for place nodes at rank_address 16 $sSQL .= ' AND rank_search > '.$iRankSearch; $sSQL .= ' AND rank_search <= ' .Min(25, $iMaxRank); $sSQL .= ' AND class = \'place\''; diff --git a/test/bdd/api/reverse/queries.feature b/test/bdd/api/reverse/queries.feature index 049dd1f4..a9ee2b17 100644 --- a/test/bdd/api/reverse/queries.feature +++ b/test/bdd/api/reverse/queries.feature @@ -48,6 +48,8 @@ Feature: Reverse geocoding Scenario: Location off the coast When sending jsonv2 reverse coordinates 54.046489113,8.5546870529 + | zoom | + | 5 | Then results contain | display_name | | ^.*Hamburg, Deutschland | From 398467b2f442cbe2c41c399f0871b94a34339033 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 13 Jun 2018 13:22:37 +0200 Subject: [PATCH 19/33] using ST_ClosestPoint and a subquery --- lib/PlaceLookup.php | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 93ffd6a0..ca7a48cf 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -536,28 +536,27 @@ class PlaceLookup if (CONST_Search_AreaPolygons) { // Get the bounding box and outline polygon - $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; - if ($fLonReverse != null && $fLatReverse != null) { - $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; - $sSQL .= ' ST_Y(ST_LineInterpolatePoint(geometry,'; - $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; - $sSQL .= ' ELSE ST_Y(centroid) '; - $sSQL .= ' END as centrelat, '; - $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; - $sSQL .= ' ST_X(ST_LineInterpolatePoint(geometry,'; - $sSQL .= ' ST_LineLocatePoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))))'; - $sSQL .= ' ELSE ST_X(centroid) '; - $sSQL .= ' END as centrelon, '; - } else { - $sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,'; - } - $sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,'; - $sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon'; + $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; + if ($fLonReverse != null && $fLatReverse != null) { + $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; + $sSQL .= ' ST_Y(closest_point)'; + $sSQL .= ' ELSE ST_Y(centroid) '; + $sSQL .= ' END as centrelat, '; + $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; + $sSQL .= ' ST_X(closest_point)'; + $sSQL .= ' ELSE ST_X(centroid) '; + $sSQL .= ' END as centrelon, '; + } else { + $sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,'; + } + $sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,'; + $sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon'; if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ',ST_AsGeoJSON(geometry) as asgeojson'; 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'; - $sFrom = ' from placex where place_id = '.$iPlaceID; + $sFrom = ' from (SELECT * , ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) AS closest_point'; + $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; if ($this->fPolygonSimplificationThreshold > 0) { $sSQL .= ' from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'.$sFrom.') as plx'; } else { From be091b17d9a46dcf4741d7e13c5c30b10c2e9962 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 13 Jun 2018 16:33:16 +0200 Subject: [PATCH 20/33] better search for interpolated housenumbers --- lib/ReverseGeocode.php | 65 ++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index b69e6446..b2c2d170 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -52,7 +52,7 @@ class ReverseGeocode * * @return Record of the interpolation or null. */ - protected function lookupInterpolation($sPointSQL, $fSearchDiam) + protected function lookupInterpolation($sPointSQL, $fSearchDiam, $iParentPlaceID = null) { $sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,'; $sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,'; @@ -61,6 +61,9 @@ 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( @@ -70,7 +73,7 @@ class ReverseGeocode } protected function noPolygonFound($sPointSQL, $iMaxRank) - { + { // searches for polygon in table country_osm_grid which contains the searchpoint $sSQL = 'SELECT * FROM country_osm_grid'; $sSQL .= ' WHERE ST_CONTAINS (geometry, '.$sPointSQL.' )'; @@ -141,12 +144,12 @@ class ReverseGeocode $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE osm_type = \'N\''; - if ($iRankAddress = 16){ - // using rank_search because of a better differentiation for place nodes at rank_address 16 + if ($iRankAddress = 16) { + // using rank_search because of a better differentiation for place nodes at rank_address 16 $sSQL .= ' AND rank_search > '.$iRankSearch; $sSQL .= ' AND rank_search <= ' .Min(25, $iMaxRank); $sSQL .= ' AND class = \'place\''; - }else{ + } else { $sSQL .= ' AND rank_address > '.$iRankAddress; $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); } @@ -194,23 +197,7 @@ class ReverseGeocode $aPlace = null; $fMaxAreaDistance = 1; $bIsTigerStreet = false; - - // try with interpolations before continuing - if ($bDoInterpolation && $iMaxRank >= 30) { - $aHouse = $this->lookupInterpolation($sPointSQL, $fSearchDiam/3); - - if ($aHouse) { - $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); - $oResult->iHouseNumber = closestHouseNumber($aHouse); - - $aPlace = $aHouse; - $iParentPlaceID = $aHouse['parent_place_id']; // the street - $iMaxRank = 30; - - return $oResult; - } - }// no interpolation found, continue search - + // for POI or street level if ($iMaxRank >= 26) { $sSQL = 'select place_id,parent_place_id,rank_address,country_code,'; @@ -241,10 +228,21 @@ class ReverseGeocode ); if ($aPlace) { - $iPlaceID = $aPlace['place_id']; - $oResult = new Result($iPlaceID); - $iParentPlaceID = $aPlace['parent_place_id']; - // if street and maxrank > streetlevel + + $iDistance = $aPlace['distance']; + $iPlaceID = $aPlace['place_id']; + $oResult = new Result($iPlaceID); + $iParentPlaceID = $aPlace['parent_place_id']; + + if ($bDoInterpolation && $iMaxRank >= 30) { + $aHouse = $this->lookupInterpolation($sPointSQL, $iDistance); + + if ($aHouse) { + $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); + $oResult->iHouseNumber = closestHouseNumber($aHouse); + } + } + // if street and maxrank > streetlevel if (($aPlace['rank_address'] == 26 || $aPlace['rank_address'] == 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,'; @@ -266,16 +264,27 @@ class ReverseGeocode 'Could not determine closest place.' ); if ($aStreet) { + $iDistance = $aPlace['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 no POI or street is found ... } else { $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); - } elseif(!$aPlace && $iMaxRank > 4) { + } elseif (!$aPlace && $iMaxRank > 4) { $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); @@ -287,7 +296,7 @@ class ReverseGeocode $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); - } elseif(!$aPlace && $iMaxRank > 4) { + } elseif (!$aPlace && $iMaxRank > 4) { $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); if ($aPlace) { $oResult = new Result($aPlace['place_id']); From 41249377d25c9c0df1855c6750f9b9e21a16a650 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 14 Jun 2018 14:39:51 +0200 Subject: [PATCH 21/33] fixed getoutlines function if no coordinates are passed --- lib/PlaceLookup.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index ca7a48cf..7620ac0d 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -555,7 +555,11 @@ class PlaceLookup 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'; - $sFrom = ' from (SELECT * , ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) AS closest_point'; + if ($fLonReverse != null && $fLatReverse != null) { + $sFrom = ' from (SELECT * , ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) AS closest_point'; + } else { + $sFrom = $sFrom = ' from placex where place_id = '.$iPlaceID; + } $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; if ($this->fPolygonSimplificationThreshold > 0) { $sSQL .= ' from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'.$sFrom.') as plx'; From 07eb108a6d1ec64152cc8b0478cc87cdd4da8f6e Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 14 Jun 2018 15:06:47 +0200 Subject: [PATCH 22/33] fixed typo --- lib/PlaceLookup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 7620ac0d..ade073e5 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -558,7 +558,7 @@ class PlaceLookup if ($fLonReverse != null && $fLatReverse != null) { $sFrom = ' from (SELECT * , ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) AS closest_point'; } else { - $sFrom = $sFrom = ' from placex where place_id = '.$iPlaceID; + $sFrom = ' from placex where place_id = '.$iPlaceID; } $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; if ($this->fPolygonSimplificationThreshold > 0) { From 0996fdfb55ec0152a61a2534d04fe7372ed39fae Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Mon, 18 Jun 2018 16:19:38 +0200 Subject: [PATCH 23/33] improvements for pull request --- lib/ReverseGeocode.php | 77 ++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index b2c2d170..44ab2bdf 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -47,8 +47,9 @@ 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 string $sPointSQL Reverse geocoding point as SQL + * @param float $fSearchDiam Search diameter + * @param integer $iParentPlaceID Id of parent object * * @return Record of the interpolation or null. */ @@ -72,6 +73,22 @@ class ReverseGeocode ); } + protected function polygonFunctions($sPointSQL, $iMaxRank) + { + $oResult = null; + + $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); + } elseif (!$aPlace && $iMaxRank > 4) { + $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); + if ($aPlace) { + $oResult = new Result($aPlace['place_id']); + } + } + return $oResult; + } + protected function noPolygonFound($sPointSQL, $iMaxRank) { // searches for polygon in table country_osm_grid which contains the searchpoint @@ -177,6 +194,7 @@ class ReverseGeocode } return $aPoly; } + public function lookup($fLat, $fLon, $bDoInterpolation = true) { @@ -212,11 +230,11 @@ class ReverseGeocode if ($iMaxRank == 26) { $sSQL .= ' rank_address = 26'; } else { - $sSQL .= ' rank_address >= 26'; + $sSQL .= ' rank_address between 26 and '.$iMaxRank; } $sSQL .= ' and (name is not null or housenumber is not null'; $sSQL .= ' or rank_address between 26 and 27)'; - $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' and class not in (\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; $sSQL .= ' OR ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.'))'; @@ -242,8 +260,9 @@ class ReverseGeocode $oResult->iHouseNumber = closestHouseNumber($aHouse); } } + // if street and maxrank > streetlevel - if (($aPlace['rank_address'] == 26 || $aPlace['rank_address'] == 27)&& $iMaxRank > 27) { + if (($aPlace['rank_address'] <=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 .= ' ST_distance('.$sPointSQL.', geometry) as distance'; @@ -253,9 +272,8 @@ class ReverseGeocode $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)'; $sSQL .= ' AND parent_place_id = '.$iPlaceID; $sSQL .= ' and rank_address != 28'; - $sSQL .= ' and (name is not null or housenumber is not null'; - $sSQL .= ' or rank_address between 26 and 27)'; - $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; + $sSQL .= ' and (name is not null or housenumber is not null)'; + $sSQL .= ' and class not in (\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; $sSQL .= ' ORDER BY distance ASC limit 1'; if (CONST_Debug) var_dump($sSQL); @@ -279,29 +297,36 @@ class ReverseGeocode } } } - // if no POI or street is found ... - } else { - $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); - if ($aPlace) { - $oResult = new Result($aPlace['place_id']); - } elseif (!$aPlace && $iMaxRank > 4) { - $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); - if ($aPlace) { - $oResult = new Result($aPlace['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_search'] > 28 ? $aPlace['distance'] : 0.001; + $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 .= ' ORDER BY distance ASC limit 1'; + if (CONST_Debug) var_dump($sSQL); + $aPlaceTiger = chksql( + $this->oDB->getRow($sSQL), + 'Could not determine closest Tiger place.' + ); + if ($aPlaceTiger) { + if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger); + $aPlace = $aPlaceTiger; + $oResult = new Result($aPlace['place_id'], Result::TABLE_TIGER); + $oResult->iHouseNumber = closestHouseNumber($aPlaceTiger); } } + // if no POI or street is found ... + } else { + $oResult = $this->PolygonFunctions($sPointSQL, $iMaxRank); } // lower than street level ($iMaxRank < 26 ) } else { - $aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank); - if ($aPlace) { - $oResult = new Result($aPlace['place_id']); - } elseif (!$aPlace && $iMaxRank > 4) { - $aPlace = $this->noPolygonFound($sPointSQL, $iMaxRank); - if ($aPlace) { - $oResult = new Result($aPlace['place_id']); - } - } + $oResult = $this->PolygonFunctions($sPointSQL, $iMaxRank); } return $oResult; } From d5e39260b36ba343626d8a2cdc502dedc99b8052 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Tue, 19 Jun 2018 10:30:37 +0200 Subject: [PATCH 24/33] updated indices for reverse geocoding --- sql/indices.src.sql | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sql/indices.src.sql b/sql/indices.src.sql index 8f6b7b51..6d08c73a 100644 --- a/sql/indices.src.sql +++ b/sql/indices.src.sql @@ -14,7 +14,14 @@ CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search) {ts:sear CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address) {ts:search-index}; CREATE INDEX idx_placex_pendingsector ON placex USING BTREE (rank_search,geometry_sector) {ts:address-index} where indexed_status > 0; CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) {ts:search-index} where parent_place_id IS NOT NULL; -CREATE INDEX idx_placex_reverse_geometry ON placex USING gist (geometry) {ts:search-index} where rank_search != 28 and (name is not null or housenumber is not null or rank_search between 26 and 27) and class not in ('waterway','railway','tunnel','bridge','man_made'); +CREATE INDEX idx_placex_geometry_reverse_lookupPoint ON placex USING gist (geometry) {ts:search-index} +where (name is not null or housenumber is not null or) and class not in ('waterway','railway','tunnel','bridge','man_made') and rank_address >= 26 and indexed_status = 0 and linked_place_id is null; +CREATE INDEX idx_placex_geometry_reverse_lookupPolygon ON placex USING gist (geometry) {ts:search-index} where St_GeometryType(geometry) in ('ST_Polygon', 'ST_MultiPolygon') and rank_address <= 25 and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; +CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_search ON placex USING gist (geometry) {ts:search-index} where +osm_type = 'N' and rank_search > 0 and rank_search <= 25 and class = 'place' and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; +CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_address ON placex USING gist (geometry) {ts:search-index} where +osm_type = 'N' and rank_address > 0 and rank_address <= 25 and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; + CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_osmline_parent_place_id ON location_property_osmline USING BTREE (parent_place_id) {ts:search-index}; From a5750a6ef673c3f707364ac827063b69f94b26ce Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 20 Jun 2018 11:35:51 +0200 Subject: [PATCH 25/33] fixed getoutlinesfunction --- lib/PlaceLookup.php | 2 +- lib/ReverseGeocode.php | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index ade073e5..44161a7e 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -557,10 +557,10 @@ class PlaceLookup if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ',ST_AsText(geometry) as astext'; if ($fLonReverse != null && $fLatReverse != null) { $sFrom = ' from (SELECT * , ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) AS closest_point'; + $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; } else { $sFrom = ' from placex where place_id = '.$iPlaceID; } - $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; if ($this->fPolygonSimplificationThreshold > 0) { $sSQL .= ' from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'.$sFrom.') as plx'; } else { diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 44ab2bdf..91a043da 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -127,10 +127,6 @@ class ReverseGeocode protected function lookupPolygon($sPointSQL, $iMaxRank) { - - $oResult = null; - $aPlace = null; - $sSQL = 'SELECT * FROM'; $sSQL .= '(select place_id,parent_place_id,rank_address, rank_search, country_code, geometry'; $sSQL .= ' FROM placex'; @@ -253,6 +249,9 @@ class ReverseGeocode $iParentPlaceID = $aPlace['parent_place_id']; if ($bDoInterpolation && $iMaxRank >= 30) { + if ($aPlace['rank_address'] <=27) { + $iDistance = 0.001; + } $aHouse = $this->lookupInterpolation($sPointSQL, $iDistance); if ($aHouse) { @@ -282,7 +281,7 @@ class ReverseGeocode 'Could not determine closest place.' ); if ($aStreet) { - $iDistance = $aPlace['distance']; + $iDistance = $aStreet['distance']; $iPlaceID = $aStreet['place_id']; $oResult = new Result($iPlaceID); $iParentPlaceID = $aStreet['parent_place_id']; From 71e3d8b1de863731ca506f7d999d4d3ae82e7ccd Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Wed, 20 Jun 2018 14:46:42 +0200 Subject: [PATCH 26/33] GRANT SELECT ON Table country_osm_grid --- sql/indices.src.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/indices.src.sql b/sql/indices.src.sql index 6d08c73a..907bb172 100644 --- a/sql/indices.src.sql +++ b/sql/indices.src.sql @@ -21,6 +21,7 @@ CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_search ON placex USING g osm_type = 'N' and rank_search > 0 and rank_search <= 25 and class = 'place' and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_address ON placex USING gist (geometry) {ts:search-index} where osm_type = 'N' and rank_address > 0 and rank_address <= 25 and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; +GRANT SELECT ON Table country_osm_grid to "www-data"; CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; From 229ad01042bb93d834e5f1459a738ce0d1f895aa Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 21 Jun 2018 13:26:04 +0200 Subject: [PATCH 27/33] added search diameter for the place node search, depending on rank --- lib/ReverseGeocode.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index 91a043da..bceb59be 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -150,6 +150,15 @@ class ReverseGeocode $iRankSearch = $aPoly['rank_search']; $iPlaceID = $aPoly['place_id']; + //search diameter for the place node search + if ($iMaxRank <= 30) $fSearchDiam = 0.1; + if ($iMaxRank <= 18) $fSearchDiam = 0.2; + if ($iMaxRank <= 17) $fSearchDiam = 0.6; + if ($iMaxRank <= 12) $fSearchDiam = 0.8; + if ($iMaxRank <= 10) $fSearchDiam = 1; + if ($iMaxRank <= 8) $fSearchDiam = 2; + if ($iMaxRank <= 4) $fSearchDiam = 4; + if ($iRankAddress != $iMaxRank) { $sSQL = 'SELECT *'; $sSQL .= ' FROM ('; @@ -166,6 +175,7 @@ class ReverseGeocode $sSQL .= ' AND rank_address > '.$iRankAddress; $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); } + $sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; From 426e108b3422533f885045f3b0488206b9a68a34 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 21 Jun 2018 14:33:22 +0200 Subject: [PATCH 28/33] added case when for highways in subquery --- lib/PlaceLookup.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 44161a7e..270e2745 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -556,7 +556,8 @@ class PlaceLookup if ($this->bIncludePolygonAsSVG) $sSQL .= ',ST_AsSVG(geometry) as assvg'; if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ',ST_AsText(geometry) as astext'; if ($fLonReverse != null && $fLatReverse != null) { - $sFrom = ' from (SELECT * , ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) AS closest_point'; + $sFrom = ' from (SELECT * , CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN '; + $sFrom .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) END AS closest_point'; $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; } else { $sFrom = ' from placex where place_id = '.$iPlaceID; From 144c3b3eb2c0d6fe0ffb8966abebfeb137a5fe4b Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Thu, 21 Jun 2018 14:46:36 +0200 Subject: [PATCH 29/33] fixed syntax error --- sql/indices.src.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/indices.src.sql b/sql/indices.src.sql index 907bb172..a04bc05d 100644 --- a/sql/indices.src.sql +++ b/sql/indices.src.sql @@ -15,7 +15,7 @@ CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address) {ts:se CREATE INDEX idx_placex_pendingsector ON placex USING BTREE (rank_search,geometry_sector) {ts:address-index} where indexed_status > 0; CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) {ts:search-index} where parent_place_id IS NOT NULL; CREATE INDEX idx_placex_geometry_reverse_lookupPoint ON placex USING gist (geometry) {ts:search-index} -where (name is not null or housenumber is not null or) and class not in ('waterway','railway','tunnel','bridge','man_made') and rank_address >= 26 and indexed_status = 0 and linked_place_id is null; +where (name is not null or housenumber is not null) and class not in ('waterway','railway','tunnel','bridge','man_made') and rank_address >= 26 and indexed_status = 0 and linked_place_id is null; CREATE INDEX idx_placex_geometry_reverse_lookupPolygon ON placex USING gist (geometry) {ts:search-index} where St_GeometryType(geometry) in ('ST_Polygon', 'ST_MultiPolygon') and rank_address <= 25 and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_search ON placex USING gist (geometry) {ts:search-index} where osm_type = 'N' and rank_search > 0 and rank_search <= 25 and class = 'place' and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; From f108eac527fb3b4244b4f9f79f34747c15364180 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Fri, 22 Jun 2018 14:08:45 +0200 Subject: [PATCH 30/33] changed the lookupPolygon function - Search for Polygons begins at rank_address 4 - $iMaxRank changed to 25 if its higher --- lib/ReverseGeocode.php | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index bceb59be..a950643f 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -107,7 +107,7 @@ class ReverseGeocode $sSQL .= ' WHERE osm_type = \'N\''; $sSQL .= ' AND country_code = \''.$sCountryCode.'\''; $sSQL .= ' AND rank_address > 0'; - $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); + $sSQL .= ' AND rank_address <= ' .$iMaxRank; $sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' and indexed_status = 0 and linked_place_id is null'; @@ -127,11 +127,14 @@ class ReverseGeocode protected function lookupPolygon($sPointSQL, $iMaxRank) { + + if ($iMaxRank > 25) $iMaxRank = 25; + $sSQL = 'SELECT * FROM'; $sSQL .= '(select place_id,parent_place_id,rank_address, rank_search, country_code, geometry'; $sSQL .= ' FROM placex'; $sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')'; - $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); + $sSQL .= ' AND rank_address Between 4 AND ' .$iMaxRank; $sSQL .= ' AND geometry && '.$sPointSQL; $sSQL .= ' AND type != \'postcode\' '; $sSQL .= ' AND name is not null'; @@ -150,16 +153,24 @@ class ReverseGeocode $iRankSearch = $aPoly['rank_search']; $iPlaceID = $aPoly['place_id']; - //search diameter for the place node search - if ($iMaxRank <= 30) $fSearchDiam = 0.1; - if ($iMaxRank <= 18) $fSearchDiam = 0.2; - if ($iMaxRank <= 17) $fSearchDiam = 0.6; - if ($iMaxRank <= 12) $fSearchDiam = 0.8; - if ($iMaxRank <= 10) $fSearchDiam = 1; - if ($iMaxRank <= 8) $fSearchDiam = 2; - if ($iMaxRank <= 4) $fSearchDiam = 4; - if ($iRankAddress != $iMaxRank) { + //search diameter for the place node search + if ($iMaxRank <= 4) { + $fSearchDiam = 4; + } elseif ($iMaxRank <= 8) { + $fSearchDiam = 2; + } elseif ($iMaxRank <= 10) { + $fSearchDiam = 1; + } elseif ($iMaxRank <= 12) { + $fSearchDiam = 0.8; + } elseif ($iMaxRank <= 17) { + $fSearchDiam = 0.6; + } elseif ($iMaxRank <= 18) { + $fSearchDiam = 0.2; + } elseif ($iMaxRank <= 25) { + $fSearchDiam = 0.1; + } + $sSQL = 'SELECT *'; $sSQL .= ' FROM ('; $sSQL .= ' SELECT place_id, rank_address,country_code, geometry,'; @@ -169,11 +180,11 @@ class ReverseGeocode if ($iRankAddress = 16) { // using rank_search because of a better differentiation for place nodes at rank_address 16 $sSQL .= ' AND rank_search > '.$iRankSearch; - $sSQL .= ' AND rank_search <= ' .Min(25, $iMaxRank); + $sSQL .= ' AND rank_search <= ' .$iMaxRank; $sSQL .= ' AND class = \'place\''; } else { $sSQL .= ' AND rank_address > '.$iRankAddress; - $sSQL .= ' AND rank_address <= ' .Min(25, $iMaxRank); + $sSQL .= ' AND rank_address <= ' .$iMaxRank; } $sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; $sSQL .= ' AND type != \'postcode\''; From 97b665618246f4f379f8232f3a84fa3fa1c697c0 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Fri, 22 Jun 2018 14:30:32 +0200 Subject: [PATCH 31/33] no polygon search over country-level --- lib/ReverseGeocode.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index a950643f..fbea17c5 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -127,8 +127,10 @@ class ReverseGeocode protected function lookupPolygon($sPointSQL, $iMaxRank) { - + // polygon search begins at suburb-level if ($iMaxRank > 25) $iMaxRank = 25; + // no polygon search over country-level + if ($iMaxRank < 4) $iMaxRank = 4; $sSQL = 'SELECT * FROM'; $sSQL .= '(select place_id,parent_place_id,rank_address, rank_search, country_code, geometry'; From 1d7ed6737e1351a5ca25af485c7e51a757649d92 Mon Sep 17 00:00:00 2001 From: gemo1011 Date: Tue, 26 Jun 2018 15:16:19 +0200 Subject: [PATCH 32/33] added comments and improved geOutline function --- lib/PlaceLookup.php | 13 ++++--------- lib/ReverseGeocode.php | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 270e2745..cf744929 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -538,14 +538,8 @@ class PlaceLookup // Get the bounding box and outline polygon $sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,'; if ($fLonReverse != null && $fLatReverse != null) { - $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; - $sSQL .= ' ST_Y(closest_point)'; - $sSQL .= ' ELSE ST_Y(centroid) '; - $sSQL .= ' END as centrelat, '; - $sSQL .= ' CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN'; - $sSQL .= ' ST_X(closest_point)'; - $sSQL .= ' ELSE ST_X(centroid) '; - $sSQL .= ' END as centrelon, '; + $sSQL .= ' ST_Y(closest_point) as centrelat,'; + $sSQL .= ' ST_X(closest_point) as centrelon,'; } else { $sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,'; } @@ -557,7 +551,8 @@ class PlaceLookup if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ',ST_AsText(geometry) as astext'; if ($fLonReverse != null && $fLatReverse != null) { $sFrom = ' from (SELECT * , CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN '; - $sFrom .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326)) END AS closest_point'; + $sFrom .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))'; + $sFrom .=' ELSE centroid END AS closest_point'; $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; } else { $sFrom = ' from placex where place_id = '.$iPlaceID; diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index fbea17c5..41da2667 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -75,11 +75,14 @@ class ReverseGeocode protected function polygonFunctions($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 ($aPlace) { @@ -92,6 +95,7 @@ class ReverseGeocode protected function noPolygonFound($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 * FROM country_osm_grid'; $sSQL .= ' WHERE ST_CONTAINS (geometry, '.$sPointSQL.' )'; @@ -127,11 +131,14 @@ class ReverseGeocode 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 if ($iMaxRank < 4) $iMaxRank = 4; - + // search for polygon $sSQL = 'SELECT * FROM'; $sSQL .= '(select place_id,parent_place_id,rank_address, rank_search, country_code, geometry'; $sSQL .= ' FROM placex'; @@ -150,6 +157,7 @@ class ReverseGeocode 'Could not determine polygon containing the point.' ); if ($aPoly) { + // if a polygon is found, search for placenodes begins ... $iParentPlaceID = $aPoly['parent_place_id']; $iRankAddress = $aPoly['rank_address']; $iRankSearch = $aPoly['rank_search']; @@ -225,7 +233,10 @@ class ReverseGeocode public function lookupPoint($sPointSQL, $bDoInterpolation = true) { - + // starts if the search is on POI or street level, + // searches for the nearest POI or street, + // if a street is found and a POI is searched for, + // the nearest POI which the found street is a parent of is choosen. $iMaxRank = $this->iMaxRank; // Find the nearest point @@ -322,7 +333,7 @@ class ReverseGeocode // 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_search'] > 28 ? $aPlace['distance'] : 0.001; + $fSearchDiam = $aPlace['rank_address'] > 28 ? $aPlace['distance'] : 0.001; $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,'; From ec6a427e0a7272445c992f6f046ae8cb5f5a534d Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 28 Jun 2018 11:34:19 +0200 Subject: [PATCH 33/33] edited indices an setup file to grant select for table country_osm_grid --- sql/indices.src.sql | 2 +- utils/setup.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/indices.src.sql b/sql/indices.src.sql index a04bc05d..cd09c9bf 100644 --- a/sql/indices.src.sql +++ b/sql/indices.src.sql @@ -21,7 +21,7 @@ CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_search ON placex USING g osm_type = 'N' and rank_search > 0 and rank_search <= 25 and class = 'place' and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; CREATE INDEX idx_placex_geometry_reverse_placeNode_rank_address ON placex USING gist (geometry) {ts:search-index} where osm_type = 'N' and rank_address > 0 and rank_address <= 25 and type != 'postcode' and name is not null and indexed_status = 0 and linked_place_id is null; -GRANT SELECT ON Table country_osm_grid to "www-data"; +GRANT SELECT ON Table country_osm_grid to "{www-user}"; CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; diff --git a/utils/setup.php b/utils/setup.php index 259ddf2d..4925a4e5 100755 --- a/utils/setup.php +++ b/utils/setup.php @@ -596,6 +596,7 @@ if ($aCMDResult['create-search-indices'] || $aCMDResult['all']) { $bDidSomething = true; $sTemplate = file_get_contents(CONST_BasePath.'/sql/indices.src.sql'); + $sTemplate = str_replace('{www-user}', CONST_Database_Web_User, $sTemplate); $sTemplate = replace_tablespace( '{ts:address-index}', CONST_Tablespace_Address_Index,