<?php
+/**
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * This file is part of Nominatim. (https://nominatim.org)
+ *
+ * Copyright (C) 2022 by the Nominatim developer community.
+ * For a full list of authors see the git log.
+ */
namespace Nominatim;
($this->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');
}
{
$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;
}
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,';
}
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');
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, ';
$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;
$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');
$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, ';
$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 (';
$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
$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 ';
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(
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
* 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');
$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;