if (NOT EXISTS "${CMAKE_SOURCE_DIR}/osm2pgsql/CMakeLists.txt")
message(FATAL_ERROR "The osm2pgsql directory is empty.\
Did you forget to check out Nominatim recursively?\
- \nTry updating submodules with: git submodules update --init")
+ \nTry updating submodules with: git submodule update --init")
endif()
add_subdirectory(osm2pgsql)
additional packages:
sudo yum install -y python-pip python-Levenshtein python-psycopg2 \
- php-phpunit-PHPUnit
+ python-numpy php-phpunit-PHPUnit
pip install --user --upgrade pip setuptools lettuce==0.2.18 six==1.9 \
haversine Shapely pytidylib
+ sudo pear install PHP_CodeSniffer
System Configuration
<Directory "$USERHOME/Nominatim/build/website">
Options FollowSymLinks MultiViews
AddType text/html .php
+ DirectoryIndex search.php
Require all granted
</Directory>
+
+
+
*Note:* these installation instructions are also available in executable
form for use with vagrant under vagrant/install-on-ubuntu-16.sh.
Make sure all packages are are up-to-date by running:
+
sudo apt-get update -qq
- sudo apt-get upgrade -y
Now you can install all packages needed for Nominatim:
If you want to run the test suite, you need to install the following
additional packages:
- sudo apt-get install -y python-dev python-pip python-levenshtein python-shapely \
- python-psycopg2 tidy python-nose python-tidylib \
- phpunit
+ sudo apt-get install -y python3-dev python3-pip python3-psycopg2 python3-tidylib phpunit
- pip install --user lettuce==0.2.18 six==1.7 haversine
+ pip3 install --user behave nose # urllib3
+ sudo pear install PHP_CodeSniffer
System Configuration
<Directory "$USERHOME/Nominatim/build/website">
Options FollowSymLinks MultiViews
AddType text/html .php
+ DirectoryIndex search.php
Require all granted
</Directory>
$this->aLangPrefOrder = $aLangPref;
}
- public function getIncludeAddressDetails()
+ public function getMoreUrlParams()
{
- return $this->bIncludeAddressDetails;
- }
+ if ($this->aStructuredQuery) {
+ $aParams = $this->aStructuredQuery;
+ } else {
+ $aParams = array('q' => $this->sQuery);
+ }
- public function getIncludeExtraTags()
- {
- return $this->bIncludeExtraTags;
- }
+ if ($this->aExcludePlaceIDs) {
+ $aParams['exclude_place_ids'] = implode(',', $this->aExcludePlaceIDs);
+ }
- public function getIncludeNameDetails()
- {
- return $this->bIncludeNameDetails;
+ if ($this->bIncludeAddressDetails) $aParams['addressdetails'] = '1';
+ if ($this->bIncludeExtraTags) $aParams['extratags'] = '1';
+ if ($this->bIncludeNameDetails) $aParams['namedetails'] = '1';
+
+ if ($this->bIncludePolygonAsPoints) $aParams['polygon'] = '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->bBoundedSearch) $aParams['bounded'] = '1';
+ if (!$this->bDeDupe) $aParams['dedupe'] = '0';
+
+ if ($this->aCountryCodes) {
+ $aParams['countrycodes'] = implode(',', $this->aCountryCodes);
+ }
+
+ if ($this->aViewBox) {
+ $aParams['viewbox'] = $this->aViewBox[0].','.$this->aViewBox[3]
+ .','.$this->aViewBox[2].','.$this->aViewBox[1];
+ }
+
+ return $aParams;
}
public function setIncludePolygonAsPoints($b = true)
$this->iLimit = $iLimit + min($iLimit, 10);
}
- public function getExcludedPlaceIDs()
- {
- return $this->aExcludePlaceIDs;
- }
-
-
- public function getCountryCodes()
- {
- return $this->aCountryCodes;
- }
-
- public function getViewBoxString()
- {
- if (!$this->aViewBox) return null;
- return $this->aViewBox[0].','.$this->aViewBox[3].','.$this->aViewBox[2].','.$this->aViewBox[1];
- }
-
public function setFeatureType($sFeatureType)
{
switch ($sFeatureType) {
return true;
}
- public function setStructuredQuery($sAmentiy = false, $sStreet = false, $sCity = false, $sCounty = false, $sState = false, $sCountry = false, $sPostalCode = false)
+ public function setStructuredQuery($sAmenity = false, $sStreet = false, $sCity = false, $sCounty = false, $sState = false, $sCountry = false, $sPostalCode = false)
{
$this->sQuery = false;
$this->aStructuredQuery = array();
$this->sAllowedTypesSQLList = '';
- $this->loadStructuredAddressElement($sAmentiy, 'amenity', 26, 30, false);
+ $this->loadStructuredAddressElement($sAmenity, 'amenity', 26, 30, false);
$this->loadStructuredAddressElement($sStreet, 'street', 26, 30, false);
$this->loadStructuredAddressElement($sCity, 'city', 14, 24, false);
$this->loadStructuredAddressElement($sCounty, 'county', 9, 13, false);
public function lookup()
{
- if (!$this->sQuery && !$this->aStructuredQuery) return false;
+ if (!$this->sQuery && !$this->aStructuredQuery) return array();
$sLanguagePrefArraySQL = "ARRAY[".join(',', array_map("getDBQuoted", $this->aLangPrefOrder))."]";
$sCountryCodesSQL = false;
<div class="form-group search-button-group">
<button type="submit" class="btn btn-primary btn-sm">Search</button>
<?php if (CONST_Search_AreaPolygons) { ?>
- <!-- <input type="checkbox" value="1" name="polygon_geojson" <?php if ($bAsGeoJSON) echo "checked='checked'"; ?>/> Highlight -->
<input type="hidden" value="1" name="polygon_geojson" />
<?php } ?>
- <input type="hidden" name="viewbox" value="<?php echo $sViewBox; ?>" />
+ <input type="hidden" name="viewbox" value="<?php if (isset($aMoreParams['viewbox'])) echo ($aMoreParams['viewbox']); ?>" />
<div class="checkbox-inline">
- <input type="checkbox" id="use_viewbox" <?php if ($sViewBox) echo "checked='checked'"; ?>>
+ <input type="checkbox" id="use_viewbox" <?php if (isset($aMoreParams['viewbox'])) echo "checked='checked'"; ?>>
<label for="use_viewbox">apply viewbox</label>
</div>
</div>
{
$aPlace['boundingbox'] = $aPointDetails['aBoundingBox'];
- if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
+ if (isset($aPointDetails['aPolyPoints']))
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
{
$aPlace['boundingbox'] = $aPointDetails['aBoundingBox'];
- if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
+ if (isset($aPointDetails['aPolyPoints']))
{
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
echo " timestamp='".date(DATE_RFC822)."'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " querystring='".htmlspecialchars($sQuery, ENT_QUOTES)."'";
-if ($sViewBox) echo " viewbox='".htmlspecialchars($sViewBox, ENT_QUOTES)."'";
-echo " polygon='".($bShowPolygons?'true':'false')."'";
-if (sizeof($aExcludePlaceIDs))
+if (isset($aMoreParams['viewbox'])) echo " viewbox='".htmlspecialchars($aMoreParams['viewbox'], ENT_QUOTES)."'";
+echo " polygon='".(isset($aMoreParams['polygon'])?'true':'false')."'";
+if (isset($aMoreParams['exclude_place_ids']))
{
- echo " exclude_place_ids='".htmlspecialchars(join(',',$aExcludePlaceIDs))."'";
-}
-if ($sMoreURL)
-{
- echo " more_url='".htmlspecialchars($sMoreURL)."'";
+ echo " exclude_place_ids='".htmlspecialchars($aMoreParams['exclude_place_ids'])."'";
}
+echo " more_url='".htmlspecialchars($sMoreURL)."'";
echo ">\n";
foreach($aSearchResults as $iResNum => $aResult)
echo join(',',$aResult['aBoundingBox']);
echo '"';
- if ($bShowPolygons && isset($aResult['aPolyPoints']))
+ if (isset($aResult['aPolyPoints']))
{
echo ' polygonpoints=\'';
echo json_encode($aResult['aPolyPoints']);
select nodes from planet_osm_ways where id = NEW.osm_id INTO waynodes;
IF array_upper(waynodes, 1) IS NULL THEN
- RETURN 0;
+ RETURN NEW;
END IF;
linegeo := NEW.linegeo;
-- RAISE WARNING ' getNearFeatures(%,''%'',%,''%'')',NEW.partition, place_centroid, search_maxrank, isin_tokens;
FOR location IN
SELECT * from getNearFeatures(NEW.partition,
- CASE WHEN NEW.rank_search >= 26 THEN NEW.geometry
- ELSE place_centroid END,
+ CASE WHEN NEW.rank_search >= 26
+ AND NEW.rank_search < 30
+ THEN NEW.geometry
+ ELSE place_centroid END,
search_maxrank, isin_tokens)
LOOP
CREATE TRIGGER place_before_insert BEFORE INSERT ON place
FOR EACH ROW EXECUTE PROCEDURE place_insert();
-DROP SEQUENCE seq_postcodes;
+DROP SEQUENCE IF EXISTS seq_postcodes;
CREATE SEQUENCE seq_postcodes start 1;
-drop table import_polygon_error;
+DROP TABLE IF EXISTS import_polygon_error;
CREATE TABLE import_polygon_error (
osm_type char(1),
osm_id INTEGER,
CREATE INDEX idx_import_polygon_error_osmid ON import_polygon_error USING BTREE (osm_type, osm_id);
GRANT SELECT ON import_polygon_error TO "{www-user}";
-drop table import_polygon_delete;
+DROP TABLE IF EXISTS import_polygon_delete;
CREATE TABLE import_polygon_delete (
osm_type char(1),
osm_id INTEGER,
CREATE INDEX idx_import_polygon_delete_osmid ON import_polygon_delete USING BTREE (osm_type, osm_id);
GRANT SELECT ON import_polygon_delete TO "{www-user}";
-drop sequence file;
+DROP SEQUENCE IF EXISTS file;
CREATE SEQUENCE file start 1;
-- null table so it won't error
| attr | value |
| querystring | xnznxvcx |
| polygon | false |
- | more_url | .*format=xml.*q=xnznxvcx.* |
+ | more_url | .*q=xnznxvcx.*format=xml |
Scenario: Empty XML search with special XML characters
When sending xml search query "xfdghn&zxn"xvbyx<vxx>cssdex"
| attr | value |
| querystring | xfdghn&zxn"xvbyx<vxx>cssdex |
| polygon | false |
- | more_url | .*format=xml.*q=xfdghn%26zxn%22xvbyx%3Cvxx%3Ecssdex.* |
+ | more_url | .*q=xfdghn%26zxn%22xvbyx%3Cvxx%3Ecssdex.*format=xml |
Scenario: Empty XML search with viewbox
When sending xml search query "xnznxvcx"
| pl,1,,invalid,undefined,%3Cb%3E,bo,, |
Then result header contains
| attr | value |
- | more_url | .*&countrycodes=pl,bo&.* |
+ | more_url | .*&countrycodes=pl%2Cbo&.* |
Then W1 expands to interpolation
| start | end | geometry |
| 23 | 29 | 0.0001 0.0001, 0.0001 0.0002, 0.0001 0.0004 |
+
+ Scenario: Ways without node entries are ignored
+ Given the places
+ | osm | class | type | housenr | geometry |
+ | W1 | place | houses | even | 1 1, 1 1.001 |
+ When importing
+ Then W1 expands to no interpolation
+
+ Scenario: Ways without nodes without housenumbers are ignored
+ Given the places
+ | osm | class | type | housenr | geometry |
+ | N1 | place | house | | 1 1 |
+ | N2 | place | house | | 1 1.001 |
+ | W1 | place | houses | even | 1 1, 1 1.001 |
+ When importing
+ Then W1 expands to no interpolation
+
$hLog = logStart($oDB, 'search', $oGeocode->getQueryString(), $aLangPrefOrder);
$aSearchResults = $oGeocode->lookup();
-if ($aSearchResults === false) $aSearchResults = array();
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"));
logEnd($oDB, $hLog, sizeof($aSearchResults));
$sQuery = $oGeocode->getQueryString();
-$sViewBox = $oGeocode->getViewBoxString();
-$bShowPolygons = (isset($_GET['polygon']) && $_GET['polygon']);
-$aExcludePlaceIDs = $oGeocode->getExcludedPlaceIDs();
-
-$sMoreURL = CONST_Website_BaseURL.'search.php?format='.urlencode($sOutputFormat).'&exclude_place_ids='.join(',', $aExcludePlaceIDs);
-if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) $sMoreURL .= '&accept-language='.$_SERVER["HTTP_ACCEPT_LANGUAGE"];
-if ($bShowPolygons) $sMoreURL .= '&polygon=1';
-if ($oGeocode->getIncludeAddressDetails()) $sMoreURL .= '&addressdetails=1';
-if ($oGeocode->getIncludeExtraTags()) $sMoreURL .= '&extratags=1';
-if ($oGeocode->getIncludeNameDetails()) $sMoreURL .= '&namedetails=1';
-if ($oGeocode->getCountryCodes()) $sMoreURL .= '&countrycodes='.join(',', $oGeocode->getCountryCodes());
-if ($sViewBox) $sMoreURL .= '&viewbox='.urlencode($sViewBox);
-if (isset($_GET['nearlat']) && isset($_GET['nearlon'])) $sMoreURL .= '&nearlat='.(float)$_GET['nearlat'].'&nearlon='.(float)$_GET['nearlon'];
-$sMoreURL .= '&q='.urlencode($sQuery);
+
+$aMoreParams = $oGeocode->getMoreUrlParams();
+if ($sOutputFormat != 'html') $aMoreParams['format'] = $sOutputFormat;
+if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
+ $aMoreParams['accept-language'] = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
+}
+$sMoreURL = CONST_Website_BaseURL.'search.php?'.http_build_query($aMoreParams);
if (CONST_Debug) exit;