X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/6a7e0d652b1d40a397e1c1386d500101796676c4..4a8b78985bc0b20b67204633a776a8eb60eba02c:/lib-php/PlaceLookup.php diff --git a/lib-php/PlaceLookup.php b/lib-php/PlaceLookup.php index 6d7b6be1..895a30df 100644 --- a/lib-php/PlaceLookup.php +++ b/lib-php/PlaceLookup.php @@ -1,4 +1,12 @@ bIncludePolygonAsSVG ? 1 : 0); if ($iWantedTypes > CONST_PolygonOutput_MaximumTypes) { if (CONST_PolygonOutput_MaximumTypes) { - userError('Select only '.CONST_PolygonOutput_MaximumTypes.' polgyon output option'); + userError('Select only '.CONST_PolygonOutput_MaximumTypes.' polygon output option'); } else { userError('Polygon output is disabled'); } @@ -89,20 +97,36 @@ class PlaceLookup { $aParams = array(); - if ($this->bAddressDetails) $aParams['addressdetails'] = '1'; - if ($this->bExtraTags) $aParams['extratags'] = '1'; - if ($this->bNameDetails) $aParams['namedetails'] = '1'; + if ($this->bAddressDetails) { + $aParams['addressdetails'] = '1'; + } + if ($this->bExtraTags) { + $aParams['extratags'] = '1'; + } + if ($this->bNameDetails) { + $aParams['namedetails'] = '1'; + } - if ($this->bIncludePolygonAsText) $aParams['polygon_text'] = '1'; - if ($this->bIncludePolygonAsGeoJSON) $aParams['polygon_geojson'] = '1'; - if ($this->bIncludePolygonAsKML) $aParams['polygon_kml'] = '1'; - if ($this->bIncludePolygonAsSVG) $aParams['polygon_svg'] = '1'; + if ($this->bIncludePolygonAsText) { + $aParams['polygon_text'] = '1'; + } + if ($this->bIncludePolygonAsGeoJSON) { + $aParams['polygon_geojson'] = '1'; + } + if ($this->bIncludePolygonAsKML) { + $aParams['polygon_kml'] = '1'; + } + if ($this->bIncludePolygonAsSVG) { + $aParams['polygon_svg'] = '1'; + } if ($this->fPolygonSimplificationThreshold > 0.0) { $aParams['polygon_threshold'] = $this->fPolygonSimplificationThreshold; } - if (!$this->bDeDupe) $aParams['dedupe'] = '0'; + if (!$this->bDeDupe) { + $aParams['dedupe'] = '0'; + } return $aParams; } @@ -147,8 +171,9 @@ class PlaceLookup private function langAddressSql($sHousenumber) { - if ($this->bAddressDetails) + if ($this->bAddressDetails) { return ''; // langaddress will be computed from address details + } return 'get_address_by_language(place_id,'.$sHousenumber.','.$this->aLangPrefOrderSql.') AS langaddress,'; } @@ -162,12 +187,12 @@ class PlaceLookup return null; } - $aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID))); + $aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID)), 0, 30, true); return empty($aResults) ? null : reset($aResults); } - public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30) + public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30, $bAllowLinked = false) { Debug::newFunction('Place lookup'); @@ -222,7 +247,9 @@ class PlaceLookup if ($this->sAllowedTypesSQLList) { $sSQL .= 'AND placex.class in '.$this->sAllowedTypesSQLList; } - $sSQL .= ' AND linked_place_id is null '; + if (!$bAllowLinked) { + $sSQL .= ' AND linked_place_id is null '; + } $sSQL .= ' GROUP BY '; $sSQL .= ' osm_type, '; $sSQL .= ' osm_id, '; @@ -234,12 +261,20 @@ class PlaceLookup $sSQL .= ' housenumber,'; $sSQL .= ' country_code, '; $sSQL .= ' importance, '; - if (!$this->bDeDupe) $sSQL .= 'place_id,'; - if (!$this->bAddressDetails) $sSQL .= 'langaddress, '; + if (!$this->bDeDupe) { + $sSQL .= 'place_id,'; + } + if (!$this->bAddressDetails) { + $sSQL .= 'langaddress, '; + } $sSQL .= ' placename, '; $sSQL .= ' ref, '; - if ($this->bExtraTags) $sSQL .= 'extratags, '; - if ($this->bNameDetails) $sSQL .= 'name, '; + if ($this->bExtraTags) { + $sSQL .= 'extratags, '; + } + if ($this->bNameDetails) { + $sSQL .= 'name, '; + } $sSQL .= ' extra_place '; $aSubSelects[] = $sSQL; @@ -260,8 +295,12 @@ class PlaceLookup $sSQL .= $this->langAddressSql('-1'); $sSQL .= ' postcode as placename,'; $sSQL .= ' postcode as ref,'; - if ($this->bExtraTags) $sSQL .= 'null::text AS extra,'; - if ($this->bNameDetails) $sSQL .= 'null::text AS names,'; + if ($this->bExtraTags) { + $sSQL .= 'null::text AS extra,'; + } + if ($this->bNameDetails) { + $sSQL .= 'null::text AS names,'; + } $sSQL .= ' ST_x(geometry) AS lon, ST_y(geometry) AS lat,'; $sSQL .= ' (0.75-(rank_search::float/40)) AS importance, '; $sSQL .= $this->addressImportanceSql('geometry', 'lp.parent_place_id'); @@ -298,8 +337,12 @@ class PlaceLookup $sSQL .= $this->langAddressSql('housenumber_for_place'); $sSQL .= ' null::text AS placename, '; $sSQL .= ' null::text AS ref, '; - if ($this->bExtraTags) $sSQL .= 'null::text AS extra,'; - if ($this->bNameDetails) $sSQL .= 'null::text AS names,'; + if ($this->bExtraTags) { + $sSQL .= 'null::text AS extra,'; + } + if ($this->bNameDetails) { + $sSQL .= 'null::text AS names,'; + } $sSQL .= ' st_x(centroid) AS lon, '; $sSQL .= ' st_y(centroid) AS lat,'; $sSQL .= ' -1.15 AS importance, '; @@ -307,7 +350,9 @@ class PlaceLookup $sSQL .= ' null::text AS extra_place '; $sSQL .= ' FROM ('; $sSQL .= ' SELECT place_id, '; // interpolate the Tiger housenumbers here - $sSQL .= ' ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) AS centroid, '; + $sSQL .= ' CASE WHEN startnumber != endnumber'; + $sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float)'; + $sSQL .= ' ELSE ST_LineInterpolatePoint(linegeo, 0.5) END AS centroid, '; $sSQL .= ' parent_place_id, '; $sSQL .= ' housenumber_for_place'; $sSQL .= ' FROM ('; @@ -344,8 +389,12 @@ class PlaceLookup $sSQL .= $this->langAddressSql('housenumber_for_place'); $sSQL .= ' null::text AS placename, '; $sSQL .= ' null::text AS ref, '; - if ($this->bExtraTags) $sSQL .= 'null::text AS extra, '; - if ($this->bNameDetails) $sSQL .= 'null::text AS names, '; + if ($this->bExtraTags) { + $sSQL .= 'null::text AS extra, '; + } + if ($this->bNameDetails) { + $sSQL .= 'null::text AS names, '; + } $sSQL .= ' st_x(centroid) AS lon, '; $sSQL .= ' st_y(centroid) AS lat, '; // slightly smaller than the importance for normal houses @@ -360,7 +409,7 @@ class PlaceLookup $sSQL .= ' CASE '; // interpolate the housenumbers here $sSQL .= ' WHEN startnumber != endnumber '; $sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) '; - $sSQL .= ' ELSE ST_LineInterpolatePoint(linegeo, 0.5) '; + $sSQL .= ' ELSE linegeo '; $sSQL .= ' END as centroid, '; $sSQL .= ' parent_place_id, '; $sSQL .= ' housenumber_for_place '; @@ -373,42 +422,6 @@ class PlaceLookup $aSubSelects[] = $sSQL; } - - if (CONST_Use_Aux_Location_data) { - $sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_AUX); - if ($sPlaceIDs) { - $sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_AUX); - $sSQL = ' SELECT '; - $sSQL .= " 'L' AS osm_type, "; - $sSQL .= ' place_id AS osm_id, '; - $sSQL .= " 'place' AS class,"; - $sSQL .= " 'house' AS type, "; - $sSQL .= ' null::smallint AS admin_level, '; - $sSQL .= ' 30 AS rank_search,'; - $sSQL .= ' 30 AS rank_address, '; - $sSQL .= ' place_id,'; - $sSQL .= ' parent_place_id, '; - $sSQL .= ' housenumber,'; - $sSQL .= " 'us' AS country_code, "; - $sSQL .= $this->langAddressSql('-1'); - $sSQL .= ' null::text AS placename, '; - $sSQL .= ' null::text AS ref, '; - if ($this->bExtraTags) $sSQL .= 'null::text AS extra, '; - if ($this->bNameDetails) $sSQL .= 'null::text AS names, '; - $sSQL .= ' ST_X(centroid) AS lon, '; - $sSQL .= ' ST_Y(centroid) AS lat, '; - $sSQL .= ' -1.10 AS importance, '; - $sSQL .= $this->addressImportanceSql( - 'centroid', - 'location_property_aux.parent_place_id' - ); - $sSQL .= ' null::text AS extra_place '; - $sSQL .= ' FROM location_property_aux '; - $sSQL .= " WHERE place_id in ($sPlaceIDs) "; - - $aSubSelects[] = $sSQL; - } - } } if (empty($aSubSelects)) { @@ -434,18 +447,14 @@ class PlaceLookup if ($this->bExtraTags) { if ($aPlace['extra']) { - $aPlace['sExtraTags'] = json_decode($aPlace['extra']); + $aPlace['sExtraTags'] = json_decode($aPlace['extra'], true); } else { $aPlace['sExtraTags'] = (object) array(); } } if ($this->bNameDetails) { - if ($aPlace['names']) { - $aPlace['sNameDetails'] = json_decode($aPlace['names']); - } else { - $aPlace['sNameDetails'] = (object) array(); - } + $aPlace['sNameDetails'] = $this->extractNames($aPlace['names']); } $aPlace['addresstype'] = ClassTypes\getLabelTag( @@ -468,6 +477,33 @@ class PlaceLookup return $aResults; } + + private function extractNames($sNames) + { + if (!$sNames) { + return (object) array(); + } + + $aFullNames = json_decode($sNames, true); + $aNames = array(); + + foreach ($aFullNames as $sKey => $sValue) { + if (strpos($sKey, '_place_') === 0) { + $sSubKey = substr($sKey, 7); + if (array_key_exists($sSubKey, $aFullNames)) { + $aNames[$sKey] = $sValue; + } else { + $aNames[$sSubKey] = $sValue; + } + } else { + $aNames[$sKey] = $sValue; + } + } + + return $aNames; + } + + /* returns an array which will contain the keys * aBoundingBox * and may also contain one or more of the keys @@ -478,41 +514,46 @@ class PlaceLookup * lat * lon */ - - public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null, $fLonReverse = null, $fLatReverse = null) { $aOutlineResult = array(); - if (!$iPlaceID) return $aOutlineResult; + if (!$iPlaceID) { + return $aOutlineResult; + } // 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 .= ' 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,'; - } + $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) $sSQL .= ',ST_AsText(geometry) as astext'; + 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) { + $sSQL .= ',ST_AsText(geometry) as astext'; + } + + $sSQL .= ' FROM (SELECT place_id'; 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))'; - $sFrom .=' ELSE centroid END AS closest_point'; - $sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx'; + $sSQL .= ',CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN '; + $sSQL .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))'; + $sSQL .=' ELSE centroid END AS centroid'; } else { - $sFrom = ' from placex where place_id = '.$iPlaceID; + $sSQL .= ',centroid'; } if ($this->fPolygonSimplificationThreshold > 0) { - $sSQL .= ' from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'.$sFrom.') as plx'; + $sSQL .= ',ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'; } else { - $sSQL .= $sFrom; + $sSQL .= ',geometry'; } + $sSQL .= ' FROM placex where place_id = '.$iPlaceID.') as plx'; $aPointPolygon = $this->oDB->getRow($sSQL, null, 'Could not get outline'); @@ -522,10 +563,18 @@ class PlaceLookup $aOutlineResult['lon'] = $aPointPolygon['centrelon']; } - if ($this->bIncludePolygonAsGeoJSON) $aOutlineResult['asgeojson'] = $aPointPolygon['asgeojson']; - if ($this->bIncludePolygonAsKML) $aOutlineResult['askml'] = $aPointPolygon['askml']; - if ($this->bIncludePolygonAsSVG) $aOutlineResult['assvg'] = $aPointPolygon['assvg']; - if ($this->bIncludePolygonAsText) $aOutlineResult['astext'] = $aPointPolygon['astext']; + if ($this->bIncludePolygonAsGeoJSON) { + $aOutlineResult['asgeojson'] = $aPointPolygon['asgeojson']; + } + if ($this->bIncludePolygonAsKML) { + $aOutlineResult['askml'] = $aPointPolygon['askml']; + } + if ($this->bIncludePolygonAsSVG) { + $aOutlineResult['assvg'] = $aPointPolygon['assvg']; + } + if ($this->bIncludePolygonAsText) { + $aOutlineResult['astext'] = $aPointPolygon['astext']; + } if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 0.0000001) { $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius;