Merge pull request #2597 from lonvia/reorganise-interpolations

Reorganise interpolation code
This commit is contained in:
Sarah Hoffmann
2022-01-28 08:40:08 +01:00
committed by GitHub
21 changed files with 390 additions and 324 deletions

View File

@@ -40,7 +40,7 @@ jobs:
ubuntu: [18, 20] ubuntu: [18, 20]
include: include:
- ubuntu: 18 - ubuntu: 18
postgresql: 9.5 postgresql: 9.6
postgis: 2.5 postgis: 2.5
pytest: pytest pytest: pytest
php: 7.2 php: 7.2

View File

@@ -79,7 +79,7 @@ When running the import you may get a version mismatch:
pg_config seems to use bad includes sometimes when multiple versions pg_config seems to use bad includes sometimes when multiple versions
of PostgreSQL are available in the system. Make sure you remove the of PostgreSQL are available in the system. Make sure you remove the
server development libraries (`postgresql-server-dev-9.5` on Ubuntu) server development libraries (`postgresql-server-dev-13` on Ubuntu)
and recompile (`cmake .. && make`). and recompile (`cmake .. && make`).

View File

@@ -41,7 +41,7 @@ For compiling:
For running Nominatim: For running Nominatim:
* [PostgreSQL](https://www.postgresql.org) (9.5+ will work, 11+ strongly recommended) * [PostgreSQL](https://www.postgresql.org) (9.6+ will work, 11+ strongly recommended)
* [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended) * [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended)
* [Python 3](https://www.python.org/) (3.6+) * [Python 3](https://www.python.org/) (3.6+)
* [Psycopg2](https://www.psycopg.org) (2.7+) * [Psycopg2](https://www.psycopg.org) (2.7+)

View File

@@ -348,7 +348,9 @@ class PlaceLookup
$sSQL .= ' null::text AS extra_place '; $sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM ('; $sSQL .= ' FROM (';
$sSQL .= ' SELECT place_id, '; // interpolate the Tiger housenumbers here $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 .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place'; $sSQL .= ' housenumber_for_place';
$sSQL .= ' FROM ('; $sSQL .= ' FROM (';
@@ -405,7 +407,7 @@ class PlaceLookup
$sSQL .= ' CASE '; // interpolate the housenumbers here $sSQL .= ' CASE '; // interpolate the housenumbers here
$sSQL .= ' WHEN startnumber != endnumber '; $sSQL .= ' WHEN startnumber != endnumber ';
$sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) '; $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 .= ' END as centroid, ';
$sSQL .= ' parent_place_id, '; $sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place '; $sSQL .= ' housenumber_for_place ';

View File

@@ -64,8 +64,8 @@ class ReverseGeocode
{ {
Debug::newFunction('lookupInterpolation'); Debug::newFunction('lookupInterpolation');
$sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,'; $sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
$sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,'; $sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
$sSQL .= ' startnumber, endnumber, interpolationtype,'; $sSQL .= ' startnumber, endnumber, step,';
$sSQL .= ' ST_Distance(linegeo,'.$sPointSQL.') as distance'; $sSQL .= ' ST_Distance(linegeo,'.$sPointSQL.') as distance';
$sSQL .= ' FROM location_property_osmline'; $sSQL .= ' FROM location_property_osmline';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')'; $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
@@ -327,9 +327,9 @@ class ReverseGeocode
&& $this->iMaxRank >= 28 && $this->iMaxRank >= 28
) { ) {
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,'; $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
$sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,'; $sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
$sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,'; $sSQL .= ' startnumber, endnumber, step,';
$sSQL .= 'startnumber,endnumber,interpolationtype'; $sSQL .= ' ST_Distance('.$sPointSQL.', linegeo) as distance';
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId; $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)'; $sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
$sSQL .= ' ORDER BY distance ASC limit 1'; $sSQL .= ' ORDER BY distance ASC limit 1';
@@ -341,7 +341,11 @@ class ReverseGeocode
if ($aPlaceTiger) { if ($aPlaceTiger) {
$aPlace = $aPlaceTiger; $aPlace = $aPlaceTiger;
$oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER); $oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
$oResult->iHouseNumber = closestHouseNumber($aPlaceTiger); $iRndNum = max(0, round($aPlaceTiger['fhnr'] / $aPlaceTiger['step']) * $aPlaceTiger['step']);
$oResult->iHouseNumber = $aPlaceTiger['startnumber'] + $iRndNum;
if ($oResult->iHouseNumber > $aPlaceTiger['endnumber']) {
$oResult->iHouseNumber = $aPlaceTiger['endnumber'];
}
$iRankAddress = 30; $iRankAddress = 30;
} }
} }
@@ -363,7 +367,11 @@ class ReverseGeocode
if ($aHouse) { if ($aHouse) {
$oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE); $oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
$oResult->iHouseNumber = closestHouseNumber($aHouse); $iRndNum = max(0, round($aHouse['fhnr'] / $aHouse['step']) * $aHouse['step']);
$oResult->iHouseNumber = $aHouse['startnumber'] + $iRndNum;
if ($oResult->iHouseNumber > $aHouse['endnumber']) {
$oResult->iHouseNumber = $aHouse['endnumber'];
}
$aPlace = $aHouse; $aPlace = $aHouse;
} }
} }

View File

@@ -769,18 +769,9 @@ class SearchDescription
// if nothing found, search in the interpolation line table // if nothing found, search in the interpolation line table
$sSQL = 'SELECT distinct place_id FROM location_property_osmline'; $sSQL = 'SELECT distinct place_id FROM location_property_osmline';
$sSQL .= ' WHERE startnumber is not NULL'; $sSQL .= ' WHERE startnumber is not NULL';
$sSQL .= ' AND parent_place_id in ('.$sRoadPlaceIDs.') AND ('; $sSQL .= ' and parent_place_id in ('.$sRoadPlaceIDs.')';
if ($iHousenumber % 2 == 0) { $sSQL .= ' and ('.$iHousenumber.' - startnumber) % step = 0';
// If housenumber is even, look for housenumber in streets $sSQL .= ' and '.$iHousenumber.' between startnumber and endnumber';
// with interpolationtype even or all.
$sSQL .= "interpolationtype='even'";
} else {
// Else look for housenumber with interpolationtype odd or all.
$sSQL .= "interpolationtype='odd'";
}
$sSQL .= " or interpolationtype='all') and ";
$sSQL .= $iHousenumber.'>=startnumber and ';
$sSQL .= $iHousenumber.'<=endnumber';
$sSQL .= $this->oContext->excludeSQL(' AND place_id'); $sSQL .= $this->oContext->excludeSQL(' AND place_id');
Debug::printSQL($sSQL); Debug::printSQL($sSQL);
@@ -795,15 +786,9 @@ class SearchDescription
// If nothing found then search in Tiger data (location_property_tiger) // If nothing found then search in Tiger data (location_property_tiger)
if (CONST_Use_US_Tiger_Data && $sRoadPlaceIDs && $bIsIntHouseNumber && empty($aResults)) { if (CONST_Use_US_Tiger_Data && $sRoadPlaceIDs && $bIsIntHouseNumber && empty($aResults)) {
$sSQL = 'SELECT place_id FROM location_property_tiger'; $sSQL = 'SELECT place_id FROM location_property_tiger';
$sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.') and ('; $sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.')';
if ($iHousenumber % 2 == 0) { $sSQL .= ' and ('.$iHousenumber.' - startnumber) % step = 0';
$sSQL .= "interpolationtype='even'"; $sSQL .= ' and '.$iHousenumber.' between startnumber and endnumber';
} else {
$sSQL .= "interpolationtype='odd'";
}
$sSQL .= " or interpolationtype='all') and ";
$sSQL .= $iHousenumber.'>=startnumber and ';
$sSQL .= $iHousenumber.'<=endnumber';
$sSQL .= $this->oContext->excludeSQL(' AND place_id'); $sSQL .= $this->oContext->excludeSQL(' AND place_id');
Debug::printSQL($sSQL); Debug::printSQL($sSQL);

View File

@@ -206,26 +206,6 @@ function parseLatLon($sQuery)
return array($sFound, $fQueryLat, $fQueryLon); return array($sFound, $fQueryLat, $fQueryLon);
} }
function closestHouseNumber($aRow)
{
$fHouse = $aRow['startnumber']
+ ($aRow['endnumber'] - $aRow['startnumber']) * $aRow['fraction'];
switch ($aRow['interpolationtype']) {
case 'odd':
$iHn = (int)($fHouse/2) * 2 + 1;
break;
case 'even':
$iHn = (int)(round($fHouse/2)) * 2;
break;
default:
$iHn = (int)(round($fHouse));
break;
}
return max(min($aRow['endnumber'], $iHn), $aRow['startnumber']);
}
if (!function_exists('array_key_last')) { if (!function_exists('array_key_last')) {
function array_key_last(array $array) function array_key_last(array $array)
{ {

View File

@@ -7,17 +7,6 @@
-- Functions for address interpolation objects in location_property_osmline. -- Functions for address interpolation objects in location_property_osmline.
-- Splits the line at the given point and returns the two parts
-- in a multilinestring.
CREATE OR REPLACE FUNCTION split_line_on_node(line GEOMETRY, point GEOMETRY)
RETURNS GEOMETRY
AS $$
BEGIN
RETURN ST_Split(ST_Snap(line, point, 0.0005), point);
END;
$$
LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION get_interpolation_address(in_address HSTORE, wayid BIGINT) CREATE OR REPLACE FUNCTION get_interpolation_address(in_address HSTORE, wayid BIGINT)
RETURNS HSTORE RETURNS HSTORE
@@ -64,9 +53,13 @@ BEGIN
IF parent_place_id is null THEN IF parent_place_id is null THEN
FOR location IN SELECT place_id FROM placex FOR location IN SELECT place_id FROM placex
WHERE ST_DWithin(geom, placex.geometry, 0.001) and placex.rank_search = 26 WHERE ST_DWithin(geom, placex.geometry, 0.001) and placex.rank_search = 26
ORDER BY (ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0))+ ORDER BY CASE WHEN ST_GeometryType(geom) = 'ST_Line' THEN
(ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0))+
ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0.5))+ ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0.5))+
ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1))) ASC limit 1 ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1)))
ELSE ST_distance(placex.geometry, geom) END
ASC
LIMIT 1
LOOP LOOP
parent_place_id := location.place_id; parent_place_id := location.place_id;
END LOOP; END LOOP;
@@ -82,24 +75,38 @@ $$
LANGUAGE plpgsql STABLE; LANGUAGE plpgsql STABLE;
CREATE OR REPLACE FUNCTION osmline_reinsert(node_id BIGINT, geom GEOMETRY) CREATE OR REPLACE FUNCTION reinsert_interpolation(way_id BIGINT, addr HSTORE,
RETURNS BOOLEAN geom GEOMETRY)
RETURNS INT
AS $$ AS $$
DECLARE DECLARE
existingline RECORD; existing BIGINT[];
BEGIN BEGIN
SELECT w.id FROM planet_osm_ways w, location_property_osmline p -- Get the existing entry from the interpolation table.
WHERE p.linegeo && geom and p.osm_id = w.id and p.indexed_status = 0 SELECT array_agg(place_id) INTO existing
and node_id = any(w.nodes) INTO existingline; FROM location_property_osmline WHERE osm_id = way_id;
IF existingline.id is not NULL THEN IF existing IS NULL or array_length(existing, 1) = 0 THEN
DELETE FROM location_property_osmline WHERE osm_id = existingline.id; INSERT INTO location_property_osmline (osm_id, address, linegeo)
INSERT INTO location_property_osmline (osm_id, address, linegeo) VALUES (way_id, addr, geom);
SELECT osm_id, address, geometry FROM place ELSE
WHERE osm_type = 'W' and osm_id = existingline.id; -- Update the interpolation table:
END IF; -- The first entry gets the original data, all other entries
-- are removed and will be recreated on indexing.
-- (An interpolation can be split up, if it has more than 2 address nodes)
UPDATE location_property_osmline
SET address = addr,
linegeo = geom,
startnumber = null,
indexed_status = 1
WHERE place_id = existing[1];
IF array_length(existing, 1) > 1 THEN
DELETE FROM location_property_osmline
WHERE place_id = any(existing[2:]);
END IF;
END IF;
RETURN true; RETURN 1;
END; END;
$$ $$
LANGUAGE plpgsql; LANGUAGE plpgsql;
@@ -114,8 +121,10 @@ BEGIN
IF NEW.indexed_status IS NULL THEN IF NEW.indexed_status IS NULL THEN
IF NEW.address is NULL OR NOT NEW.address ? 'interpolation' IF NEW.address is NULL OR NOT NEW.address ? 'interpolation'
OR NEW.address->'interpolation' NOT IN ('odd', 'even', 'all') THEN OR NOT (NEW.address->'interpolation' in ('odd', 'even', 'all')
-- other interpolation types than odd/even/all (e.g. numeric ones) are not supported or NEW.address->'interpolation' similar to '[1-9]')
THEN
-- alphabetic interpolation is not supported
RETURN NULL; RETURN NULL;
END IF; END IF;
@@ -136,18 +145,20 @@ CREATE OR REPLACE FUNCTION osmline_update()
RETURNS TRIGGER RETURNS TRIGGER
AS $$ AS $$
DECLARE DECLARE
place_centroid GEOMETRY;
waynodes BIGINT[]; waynodes BIGINT[];
prevnode RECORD; prevnode RECORD;
nextnode RECORD; nextnode RECORD;
startnumber INTEGER; startnumber INTEGER;
endnumber INTEGER; endnumber INTEGER;
housenum INTEGER; newstart INTEGER;
newend INTEGER;
moddiff SMALLINT;
linegeo GEOMETRY; linegeo GEOMETRY;
splitline GEOMETRY; splitline GEOMETRY;
sectiongeo GEOMETRY; sectiongeo GEOMETRY;
interpol_postcode TEXT; interpol_postcode TEXT;
postcode TEXT; postcode TEXT;
stepmod SMALLINT;
BEGIN BEGIN
-- deferred delete -- deferred delete
IF OLD.indexed_status = 100 THEN IF OLD.indexed_status = 100 THEN
@@ -159,107 +170,139 @@ BEGIN
RETURN NEW; RETURN NEW;
END IF; END IF;
NEW.interpolationtype = NEW.address->'interpolation'; NEW.parent_place_id := get_interpolation_parent(NEW.token_info, NEW.partition,
ST_PointOnSurface(NEW.linegeo),
place_centroid := ST_PointOnSurface(NEW.linegeo); NEW.linegeo);
NEW.parent_place_id = get_interpolation_parent(NEW.token_info, NEW.partition,
place_centroid, NEW.linegeo);
interpol_postcode := token_normalized_postcode(NEW.address->'postcode'); interpol_postcode := token_normalized_postcode(NEW.address->'postcode');
NEW.token_info := token_strip_info(NEW.token_info); NEW.token_info := token_strip_info(NEW.token_info);
IF NEW.address ? '_inherited' THEN IF NEW.address ? '_inherited' THEN
NEW.address := hstore('interpolation', NEW.interpolationtype); NEW.address := hstore('interpolation', NEW.address->'interpolation');
END IF; END IF;
-- if the line was newly inserted, split the line as necessary -- If the line was newly inserted, split the line as necessary.
IF OLD.indexed_status = 1 THEN IF OLD.indexed_status = 1 THEN
select nodes from planet_osm_ways where id = NEW.osm_id INTO waynodes; IF NEW.address->'interpolation' in ('odd', 'even') THEN
NEW.step := 2;
stepmod := CASE WHEN NEW.address->'interpolation' = 'odd' THEN 1 ELSE 0 END;
ELSE
NEW.step := CASE WHEN NEW.address->'interpolation' = 'all'
THEN 1
ELSE (NEW.address->'interpolation')::SMALLINT END;
stepmod := NULL;
END IF;
IF array_upper(waynodes, 1) IS NULL THEN SELECT nodes INTO waynodes
RETURN NEW; FROM planet_osm_ways WHERE id = NEW.osm_id;
IF array_upper(waynodes, 1) IS NULL THEN
RETURN NEW;
END IF;
linegeo := null;
SELECT null::integer as hnr INTO prevnode;
-- Go through all nodes on the interpolation line that have a housenumber.
FOR nextnode IN
SELECT DISTINCT ON (nodeidpos)
osm_id, address, geometry,
substring(address->'housenumber','[0-9]+')::integer as hnr
FROM placex, generate_series(1, array_upper(waynodes, 1)) nodeidpos
WHERE osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
and address is not NULL and address ? 'housenumber'
ORDER BY nodeidpos
LOOP
RAISE WARNING 'processing point % (%)', nextnode.hnr, ST_AsText(nextnode.geometry);
IF linegeo is null THEN
linegeo := NEW.linegeo;
ELSE
splitline := ST_Split(ST_Snap(linegeo, nextnode.geometry, 0.0005), nextnode.geometry);
sectiongeo := ST_GeometryN(splitline, 1);
linegeo := ST_GeometryN(splitline, 2);
END IF; END IF;
linegeo := NEW.linegeo; IF prevnode.hnr is not null
startnumber := NULL; -- Check if there are housenumbers to interpolate between the
-- regularly mapped housenumbers.
FOR nodeidpos in 1..array_upper(waynodes, 1) LOOP -- (Conveniently also fails if one of the house numbers is not a number.)
and abs(prevnode.hnr - nextnode.hnr) > NEW.step
select osm_id, address, geometry THEN
from place where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT IF prevnode.hnr < nextnode.hnr THEN
and address is not NULL and address ? 'housenumber' limit 1 INTO nextnode; startnumber := prevnode.hnr;
--RAISE NOTICE 'Nextnode.place_id: %s', nextnode.place_id; endnumber := nextnode.hnr;
IF nextnode.osm_id IS NOT NULL THEN ELSE
--RAISE NOTICE 'place_id is not null'; startnumber := nextnode.hnr;
IF nodeidpos > 1 and nodeidpos < array_upper(waynodes, 1) THEN endnumber := prevnode.hnr;
-- Make sure that the point is actually on the line. That might sectiongeo := ST_Reverse(sectiongeo);
-- be a bit paranoid but ensures that the algorithm still works
-- should osm2pgsql attempt to repair geometries.
splitline := split_line_on_node(linegeo, nextnode.geometry);
sectiongeo := ST_GeometryN(splitline, 1);
linegeo := ST_GeometryN(splitline, 2);
ELSE
sectiongeo = linegeo;
END IF;
endnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
IF startnumber IS NOT NULL AND endnumber IS NOT NULL
AND startnumber != endnumber
AND ST_GeometryType(sectiongeo) = 'ST_LineString' THEN
IF (startnumber > endnumber) THEN
housenum := endnumber;
endnumber := startnumber;
startnumber := housenum;
sectiongeo := ST_Reverse(sectiongeo);
END IF;
-- determine postcode
postcode := coalesce(interpol_postcode,
token_normalized_postcode(prevnode.address->'postcode'),
token_normalized_postcode(nextnode.address->'postcode'),
postcode);
IF postcode is NULL THEN
SELECT token_normalized_postcode(placex.postcode)
FROM placex WHERE place_id = NEW.parent_place_id INTO postcode;
END IF;
IF postcode is NULL THEN
postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
END IF;
IF NEW.startnumber IS NULL THEN
NEW.startnumber := startnumber;
NEW.endnumber := endnumber;
NEW.linegeo := sectiongeo;
NEW.postcode := postcode;
ELSE
insert into location_property_osmline
(linegeo, partition, osm_id, parent_place_id,
startnumber, endnumber, interpolationtype,
address, postcode, country_code,
geometry_sector, indexed_status)
values (sectiongeo, NEW.partition, NEW.osm_id, NEW.parent_place_id,
startnumber, endnumber, NEW.interpolationtype,
NEW.address, postcode,
NEW.country_code, NEW.geometry_sector, 0);
END IF;
END IF;
-- early break if we are out of line string,
-- might happen when a line string loops back on itself
IF ST_GeometryType(linegeo) != 'ST_LineString' THEN
RETURN NEW;
END IF;
startnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
prevnode := nextnode;
END IF; END IF;
END LOOP;
-- Adjust the interpolation, so that only inner housenumbers
-- are taken into account.
IF stepmod is null THEN
newstart := startnumber + NEW.step;
ELSE
newstart := startnumber + 1;
moddiff := newstart % NEW.step - stepmod;
IF moddiff < 0 THEN
newstart := newstart + (NEW.step + moddiff);
ELSE
newstart := newstart + moddiff;
END IF;
END IF;
newend := newstart + ((endnumber - 1 - newstart) / NEW.step) * NEW.step;
-- If newstart and newend are the same, then this returns a point.
sectiongeo := ST_LineSubstring(sectiongeo,
(newstart - startnumber)::float / (endnumber - startnumber)::float,
(newend - startnumber)::float / (endnumber - startnumber)::float);
startnumber := newstart;
endnumber := newend;
-- determine postcode
postcode := coalesce(interpol_postcode,
token_normalized_postcode(prevnode.address->'postcode'),
token_normalized_postcode(nextnode.address->'postcode'),
postcode);
IF postcode is NULL THEN
SELECT token_normalized_postcode(placex.postcode)
FROM placex WHERE place_id = NEW.parent_place_id INTO postcode;
END IF;
IF postcode is NULL THEN
postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
END IF;
-- Add the interpolation. If this is the first segment, just modify
-- the interpolation to be inserted, otherwise add an additional one
-- (marking it indexed already).
IF NEW.startnumber IS NULL THEN
NEW.startnumber := startnumber;
NEW.endnumber := endnumber;
NEW.linegeo := sectiongeo;
NEW.postcode := postcode;
ELSE
INSERT INTO location_property_osmline
(linegeo, partition, osm_id, parent_place_id,
startnumber, endnumber, step,
address, postcode, country_code,
geometry_sector, indexed_status)
VALUES (sectiongeo, NEW.partition, NEW.osm_id, NEW.parent_place_id,
startnumber, endnumber, NEW.step,
NEW.address, postcode,
NEW.country_code, NEW.geometry_sector, 0);
END IF;
-- early break if we are out of line string,
-- might happen when a line string loops back on itself
IF ST_GeometryType(linegeo) != 'ST_LineString' THEN
RETURN NEW;
END IF;
END IF;
prevnode := nextnode;
END LOOP;
END IF; END IF;
-- marking descendants for reparenting is not needed, because there are
-- actually no descendants for interpolation lines
RETURN NEW; RETURN NEW;
END; END;
$$ $$

View File

@@ -13,8 +13,8 @@ DECLARE
country RECORD; country RECORD;
existing RECORD; existing RECORD;
existingplacex RECORD; existingplacex RECORD;
existingline RECORD; existingline BIGINT[];
result BOOLEAN; interpol RECORD;
BEGIN BEGIN
{% if debug %} {% if debug %}
RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry); RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
@@ -57,19 +57,7 @@ BEGIN
IF NEW.class='place' and NEW.type='houses' IF NEW.class='place' and NEW.type='houses'
and NEW.osm_type='W' and ST_GeometryType(NEW.geometry) = 'ST_LineString' and NEW.osm_type='W' and ST_GeometryType(NEW.geometry) = 'ST_LineString'
THEN THEN
-- Get the existing entry from the interpolation table. PERFORM reinsert_interpolation(NEW.osm_id, NEW.address, NEW.geometry);
SELECT * INTO existingline
FROM location_property_osmline WHERE osm_id = NEW.osm_id;
-- Update the interpolation table:
-- delete all old interpolation lines with same osm_id
-- and insert the new one(s) (they can be split up, if they have > 2 nodes)
IF existingline.osm_id IS NOT NULL THEN
DELETE FROM location_property_osmline where osm_id = NEW.osm_id;
END IF;
INSERT INTO location_property_osmline (osm_id, address, linegeo)
VALUES (NEW.osm_id, NEW.address, NEW.geometry);
-- Now invalidate all address nodes on the line. -- Now invalidate all address nodes on the line.
-- They get their parent from the interpolation. -- They get their parent from the interpolation.
@@ -156,6 +144,28 @@ BEGIN
RETURN null; RETURN null;
END IF; END IF;
-- If an address node is part of a interpolation line and changes or is
-- newly inserted (happens when the node already existed but now gets address
-- information), then mark the interpolation line for reparenting.
-- (Already here, because interpolation lines are reindexed before nodes,
-- so in the second call it would be too late.)
IF NEW.osm_type='N'
and coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
THEN
FOR interpol IN
SELECT DISTINCT osm_id, address, geometry FROM place, planet_osm_ways w
WHERE NEW.geometry && place.geometry
and place.osm_type = 'W'
and exists (SELECT * FROM location_property_osmline
WHERE osm_id = place.osm_id
and indexed_status in (0, 2))
and w.id = place.osm_id and NEW.osm_id = any (w.nodes)
LOOP
PERFORM reinsert_interpolation(interpol.osm_id, interpol.address,
interpol.geometry);
END LOOP;
END IF;
-- Get the existing placex entry. -- Get the existing placex entry.
SELECT * INTO existingplacex SELECT * INTO existingplacex
FROM placex FROM placex
@@ -278,16 +288,6 @@ BEGIN
geometry = NEW.geometry geometry = NEW.geometry
WHERE place_id = existingplacex.place_id; WHERE place_id = existingplacex.place_id;
-- If an address node which is part of a interpolation line changes
-- mark this line for reparenting.
-- (Already here, because interpolation lines are reindexed before nodes,
-- so in the second call it would be too late.)
IF NEW.osm_type='N'
and coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
THEN
result:= osmline_reinsert(NEW.osm_id, NEW.geometry);
END IF;
-- Invalidate linked places: they potentially get a new name and addresses. -- Invalidate linked places: they potentially get a new name and addresses.
IF existingplacex.linked_place_id is not NULL THEN IF existingplacex.linked_place_id is not NULL THEN
UPDATE placex x UPDATE placex x

View File

@@ -29,9 +29,9 @@ DECLARE
BEGIN BEGIN
-- For POI nodes, check if the address should be derived from a surrounding -- For POI nodes, check if the address should be derived from a surrounding
-- building. -- building.
IF p.rank_search < 30 OR p.osm_type != 'N' OR p.address is not null THEN IF p.rank_search < 30 OR p.osm_type != 'N' THEN
result.address := p.address; result.address := p.address;
ELSE ELSEIF p.address is null THEN
-- The additional && condition works around the misguided query -- The additional && condition works around the misguided query
-- planner of postgis 3.0. -- planner of postgis 3.0.
SELECT placex.address || hstore('_inherited', '') INTO result.address SELECT placex.address || hstore('_inherited', '') INTO result.address
@@ -42,6 +42,20 @@ BEGIN
and (placex.address ? 'housenumber' or placex.address ? 'street' or placex.address ? 'place') and (placex.address ? 'housenumber' or placex.address ? 'street' or placex.address ? 'place')
and rank_search = 30 AND ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') and rank_search = 30 AND ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon')
LIMIT 1; LIMIT 1;
ELSE
result.address := p.address;
-- See if we can inherit addtional address tags from an interpolation.
-- These will become permanent.
FOR location IN
SELECT (address - 'interpolation'::text - 'housenumber'::text) as address
FROM place, planet_osm_ways w
WHERE place.osm_type = 'W' and place.address ? 'interpolation'
and place.geometry && p.geometry
and place.osm_id = w.id
and p.osm_id = any(w.nodes)
LOOP
result.address := location.address || result.address;
END LOOP;
END IF; END IF;
result.address := result.address - '_unlisted_place'::TEXT; result.address := result.address - '_unlisted_place'::TEXT;
@@ -131,18 +145,6 @@ BEGIN
END IF; END IF;
IF parent_place_id is null and poi_osm_type = 'N' THEN IF parent_place_id is null and poi_osm_type = 'N' THEN
-- Is this node part of an interpolation?
FOR location IN
SELECT q.parent_place_id
FROM location_property_osmline q, planet_osm_ways x
WHERE q.linegeo && bbox and x.id = q.osm_id
and poi_osm_id = any(x.nodes)
LIMIT 1
LOOP
{% if debug %}RAISE WARNING 'Get parent from interpolation: %', location.parent_place_id;{% endif %}
RETURN location.parent_place_id;
END LOOP;
FOR location IN FOR location IN
SELECT p.place_id, p.osm_id, p.rank_search, p.address, SELECT p.place_id, p.osm_id, p.rank_search, p.address,
coalesce(p.centroid, ST_Centroid(p.geometry)) as centroid coalesce(p.centroid, ST_Centroid(p.geometry)) as centroid
@@ -626,10 +628,7 @@ BEGIN
{% if not disable_diff_updates %} {% if not disable_diff_updates %}
-- The following is not needed until doing diff updates, and slows the main index process down -- The following is not needed until doing diff updates, and slows the main index process down
IF NEW.osm_type = 'N' and NEW.rank_search > 28 THEN IF NEW.rank_address > 0 THEN
-- might be part of an interpolation
result := osmline_reinsert(NEW.osm_id, NEW.geometry);
ELSEIF NEW.rank_address > 0 THEN
IF (ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_IsValid(NEW.geometry)) THEN IF (ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_IsValid(NEW.geometry)) THEN
-- Performance: We just can't handle re-indexing for country level changes -- Performance: We just can't handle re-indexing for country level changes
IF st_area(NEW.geometry) < 1 THEN IF st_area(NEW.geometry) < 1 THEN
@@ -656,7 +655,7 @@ BEGIN
-- roads may cause reparenting for >27 rank places -- roads may cause reparenting for >27 rank places
update placex set indexed_status = 2 where indexed_status = 0 and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter); update placex set indexed_status = 2 where indexed_status = 0 and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter);
-- reparenting also for OSM Interpolation Lines (and for Tiger?) -- reparenting also for OSM Interpolation Lines (and for Tiger?)
update location_property_osmline set indexed_status = 2 where indexed_status = 0 and ST_DWithin(location_property_osmline.linegeo, NEW.geometry, diameter); update location_property_osmline set indexed_status = 2 where indexed_status = 0 and startnumber is not null and ST_DWithin(location_property_osmline.linegeo, NEW.geometry, diameter);
ELSEIF NEW.rank_search >= 16 THEN ELSEIF NEW.rank_search >= 16 THEN
-- up to rank 16, street-less addresses may need reparenting -- up to rank 16, street-less addresses may need reparenting
update placex set indexed_status = 2 where indexed_status = 0 and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter) and (rank_search < 28 or name is not null or address ? 'place'); update placex set indexed_status = 2 where indexed_status = 0 and rank_search > NEW.rank_search and ST_DWithin(placex.geometry, NEW.geometry, diameter) and (rank_search < 28 or name is not null or address ? 'place');

View File

@@ -28,7 +28,8 @@ CREATE INDEX IF NOT EXISTS idx_placex_geometry_reverse_lookupPolygon
AND name is not null AND indexed_status = 0 AND linked_place_id is null; AND name is not null AND indexed_status = 0 AND linked_place_id is null;
CREATE INDEX IF NOT EXISTS idx_osmline_parent_place_id CREATE INDEX IF NOT EXISTS idx_osmline_parent_place_id
ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}}; ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}}
WHERE parent_place_id is not null;
CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id
ON location_property_osmline USING BTREE (osm_id) {{db.tablespace.search_index}}; ON location_property_osmline USING BTREE (osm_id) {{db.tablespace.search_index}};
@@ -48,6 +49,10 @@ CREATE INDEX IF NOT EXISTS idx_postcode_postcode
CREATE UNIQUE INDEX IF NOT EXISTS idx_place_osm_unique CREATE UNIQUE INDEX IF NOT EXISTS idx_place_osm_unique
ON place USING btree(osm_id, osm_type, class, type) {{db.tablespace.address_index}}; ON place USING btree(osm_id, osm_type, class, type) {{db.tablespace.address_index}};
CREATE INDEX IF NOT EXISTS idx_place_interpolations
ON place USING gist(geometry) {{db.tablespace.address_index}}
WHERE osm_type = 'W' and address ? 'interpolation';
{% endif %} {% endif %}
-- Indices only needed for search. -- Indices only needed for search.
@@ -62,8 +67,12 @@ CREATE INDEX IF NOT EXISTS idx_postcode_postcode
{% if postgres.has_index_non_key_column %} {% if postgres.has_index_non_key_column %}
CREATE INDEX IF NOT EXISTS idx_placex_housenumber CREATE INDEX IF NOT EXISTS idx_placex_housenumber
ON placex USING btree (parent_place_id) INCLUDE (housenumber) WHERE housenumber is not null; ON placex USING btree (parent_place_id) {{db.tablespace.search_index}}
INCLUDE (housenumber)
WHERE housenumber is not null;
CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id_with_hnr CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id_with_hnr
ON location_property_osmline USING btree(parent_place_id) INCLUDE (startnumber, endnumber); ON location_property_osmline USING btree(parent_place_id) {{db.tablespace.search_index}}
INCLUDE (startnumber, endnumber)
WHERE startnumber is not null;
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@@ -80,9 +80,9 @@ CREATE TABLE location_property_tiger (
parent_place_id BIGINT, parent_place_id BIGINT,
startnumber INTEGER, startnumber INTEGER,
endnumber INTEGER, endnumber INTEGER,
step SMALLINT,
partition SMALLINT, partition SMALLINT,
linegeo GEOMETRY, linegeo GEOMETRY,
interpolationtype TEXT,
postcode TEXT); postcode TEXT);
GRANT SELECT ON location_property_tiger TO "{{config.DATABASE_WEBUSER}}"; GRANT SELECT ON location_property_tiger TO "{{config.DATABASE_WEBUSER}}";
@@ -95,10 +95,10 @@ CREATE TABLE location_property_osmline (
indexed_date TIMESTAMP, indexed_date TIMESTAMP,
startnumber INTEGER, startnumber INTEGER,
endnumber INTEGER, endnumber INTEGER,
step SMALLINT,
partition SMALLINT, partition SMALLINT,
indexed_status SMALLINT, indexed_status SMALLINT,
linegeo GEOMETRY, linegeo GEOMETRY,
interpolationtype TEXT,
address HSTORE, address HSTORE,
token_info JSONB, -- custom column for tokenizer use only token_info JSONB, -- custom column for tokenizer use only
postcode TEXT, postcode TEXT,
@@ -106,7 +106,8 @@ CREATE TABLE location_property_osmline (
){{db.tablespace.search_data}}; ){{db.tablespace.search_data}};
CREATE UNIQUE INDEX idx_osmline_place_id ON location_property_osmline USING BTREE (place_id) {{db.tablespace.search_index}}; CREATE UNIQUE INDEX idx_osmline_place_id ON location_property_osmline USING BTREE (place_id) {{db.tablespace.search_index}};
CREATE INDEX idx_osmline_geometry_sector ON location_property_osmline USING BTREE (geometry_sector) {{db.tablespace.address_index}}; CREATE INDEX idx_osmline_geometry_sector ON location_property_osmline USING BTREE (geometry_sector) {{db.tablespace.address_index}};
CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {{db.tablespace.search_index}}; CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {{db.tablespace.search_index}}
WHERE startnumber is not null;
GRANT SELECT ON location_property_osmline TO "{{config.DATABASE_WEBUSER}}"; GRANT SELECT ON location_property_osmline TO "{{config.DATABASE_WEBUSER}}";
drop table IF EXISTS search_name; drop table IF EXISTS search_name;

View File

@@ -9,7 +9,7 @@
CREATE INDEX IF NOT EXISTS idx_location_property_tiger_parent_place_id_imp CREATE INDEX IF NOT EXISTS idx_location_property_tiger_parent_place_id_imp
ON location_property_tiger_import (parent_place_id) ON location_property_tiger_import (parent_place_id)
{% if postgres.has_index_non_key_column %} {% if postgres.has_index_non_key_column %}
INCLUDE (startnumber, endnumber) INCLUDE (startnumber, endnumber, step)
{% endif %} {% endif %}
{{db.tablespace.aux_index}}; {{db.tablespace.aux_index}};
CREATE UNIQUE INDEX IF NOT EXISTS idx_location_property_tiger_place_id_imp CREATE UNIQUE INDEX IF NOT EXISTS idx_location_property_tiger_place_id_imp

View File

@@ -5,7 +5,15 @@
-- Copyright (C) 2022 by the Nominatim developer community. -- Copyright (C) 2022 by the Nominatim developer community.
-- For a full list of authors see the git log. -- For a full list of authors see the git log.
DROP TABLE IF EXISTS location_property_tiger_import; DROP TABLE IF EXISTS location_property_tiger_import;
CREATE TABLE location_property_tiger_import (linegeo GEOMETRY, place_id BIGINT, partition INTEGER, parent_place_id BIGINT, startnumber INTEGER, endnumber INTEGER, interpolationtype TEXT, postcode TEXT); CREATE TABLE location_property_tiger_import (
linegeo GEOMETRY,
place_id BIGINT,
partition INTEGER,
parent_place_id BIGINT,
startnumber INTEGER,
endnumber INTEGER,
step SMALLINT,
postcode TEXT);
CREATE OR REPLACE FUNCTION tiger_line_import(linegeo GEOMETRY, in_startnumber INTEGER, CREATE OR REPLACE FUNCTION tiger_line_import(linegeo GEOMETRY, in_startnumber INTEGER,
in_endnumber INTEGER, interpolationtype TEXT, in_endnumber INTEGER, interpolationtype TEXT,
@@ -24,11 +32,12 @@ DECLARE
BEGIN BEGIN
IF in_endnumber > in_startnumber THEN IF in_endnumber > in_startnumber THEN
startnumber = in_startnumber; startnumber := in_startnumber;
endnumber = in_endnumber; endnumber := in_endnumber;
ELSE ELSE
startnumber = in_endnumber; startnumber := in_endnumber;
endnumber = in_startnumber; endnumber := in_startnumber;
linegeo := ST_Reverse(linegeo);
END IF; END IF;
IF startnumber < 0 THEN IF startnumber < 0 THEN
@@ -50,8 +59,10 @@ BEGIN
END IF; END IF;
-- Filter out really broken tiger data -- Filter out really broken tiger data
IF numberrange > 0 AND (numberrange::float/stepsize::float > 500) IF numberrange > 0
AND ST_length(linegeo)/(numberrange::float/stepsize::float) < 0.000001 THEN and numberrange::float/stepsize::float > 500
and ST_length(linegeo)/(numberrange::float/stepsize::float) < 0.000001
THEN
RAISE WARNING 'Road too short for number range % to % (%)',startnumber,endnumber, RAISE WARNING 'Road too short for number range % to % (%)',startnumber,endnumber,
ST_length(linegeo)/(numberrange::float/stepsize::float); ST_length(linegeo)/(numberrange::float/stepsize::float);
RETURN 0; RETURN 0;
@@ -74,8 +85,12 @@ BEGIN
END IF; END IF;
--insert street(line) into import table --insert street(line) into import table
insert into location_property_tiger_import (linegeo, place_id, partition, parent_place_id, startnumber, endnumber, interpolationtype, postcode) insert into location_property_tiger_import (linegeo, place_id, partition,
values (linegeo, nextval('seq_place'), out_partition, out_parent_place_id, startnumber, endnumber, interpolationtype, in_postcode); parent_place_id, startnumber, endnumber,
step, postcode)
values (linegeo, nextval('seq_place'), out_partition,
out_parent_place_id, startnumber, endnumber,
stepsize, in_postcode);
RETURN 1; RETURN 1;
END; END;

View File

@@ -1,6 +1,6 @@
# just use the pgxs makefile # just use the pgxs makefile
foreach(suffix ${PostgreSQL_ADDITIONAL_VERSIONS} "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3") foreach(suffix ${PostgreSQL_ADDITIONAL_VERSIONS} "14" "13" "12" "11" "10" "9.6")
list(APPEND PG_CONFIG_HINTS list(APPEND PG_CONFIG_HINTS
"/usr/pgsql-${suffix}/bin") "/usr/pgsql-${suffix}/bin")
endforeach() endforeach()

View File

@@ -216,3 +216,58 @@ def create_tiger_housenumber_index(conn, **_):
ON location_property_tiger ON location_property_tiger
USING btree(parent_place_id) USING btree(parent_place_id)
INCLUDE (startnumber, endnumber) """) INCLUDE (startnumber, endnumber) """)
@_migration(4, 0, 99, 1)
def create_interpolation_index_on_place(conn, **_):
""" Create idx_place_interpolations for lookup of interpolation lines
on updates.
"""
with conn.cursor() as cur:
cur.execute("""CREATE INDEX IF NOT EXISTS idx_place_interpolations
ON place USING gist(geometry)
WHERE osm_type = 'W' and address ? 'interpolation'""")
@_migration(4, 0, 99, 2)
def add_step_column_for_interpolation(conn, **_):
""" Add a new column 'step' to the interpolations table.
Also convers the data into the stricter format which requires that
startnumbers comply with the odd/even requirements.
"""
with conn.cursor() as cur:
# Mark invalid all interpolations with no intermediate numbers.
cur.execute("""UPDATE location_property_osmline SET startnumber = null
WHERE endnumber - startnumber <= 1 """)
# Align the start numbers where odd/even does not match.
cur.execute("""UPDATE location_property_osmline
SET startnumber = startnumber + 1,
linegeo = ST_LineSubString(linegeo,
1.0 / (endnumber - startnumber)::float,
1)
WHERE (interpolationtype = 'odd' and startnumber % 2 = 0)
or (interpolationtype = 'even' and startnumber % 2 = 1)
""")
# Mark invalid odd/even interpolations with no intermediate numbers.
cur.execute("""UPDATE location_property_osmline SET startnumber = null
WHERE interpolationtype in ('odd', 'even')
and endnumber - startnumber = 2""")
# Finally add the new column and populate it.
cur.execute("ALTER TABLE location_property_osmline ADD COLUMN step SMALLINT")
cur.execute("""UPDATE location_property_osmline
SET step = CASE WHEN interpolationtype = 'all'
THEN 1 ELSE 2 END
""")
@_migration(4, 0, 99, 3)
def add_step_column_for_tiger(conn, **_):
""" Add a new column 'step' to the tiger data table.
"""
with conn.cursor() as cur:
cur.execute("ALTER TABLE location_property_tiger ADD COLUMN step SMALLINT")
cur.execute("""UPDATE location_property_tiger
SET step = CASE WHEN interpolationtype = 'all'
THEN 1 ELSE 2 END
""")

View File

@@ -20,11 +20,11 @@ Version information for Nominatim.
# to 99 to make sure that the migration is applied when updating from a # to 99 to make sure that the migration is applied when updating from a
# patch release to the next minor version. Patch releases usually shouldn't # patch release to the next minor version. Patch releases usually shouldn't
# have migrations in them. When they are needed, then make sure that the # have migrations in them. When they are needed, then make sure that the
# migration can reapplied and set the migration version to the appropriate # migration can be reapplied and set the migration version to the appropriate
# patch level when cherry-picking the commit with the migration. # patch level when cherry-picking the commit with the migration.
# #
# Released versions always have a database patch level of 0. # Released versions always have a database patch level of 0.
NOMINATIM_VERSION = (4, 0, 99, 1) NOMINATIM_VERSION = (4, 0, 99, 4)
POSTGRESQL_REQUIRED_VERSION = (9, 5) POSTGRESQL_REQUIRED_VERSION = (9, 5)
POSTGIS_REQUIRED_VERSION = (2, 2) POSTGIS_REQUIRED_VERSION = (2, 2)

View File

@@ -10,7 +10,7 @@ Feature: Reverse geocoding
| way | place | house | | way | place | house |
And result addresses contain And result addresses contain
| house_number | road | postcode | country_code | | house_number | road | postcode | country_code |
| 697 | Upper Kingston Road | 36067 | us | | 707 | Upper Kingston Road | 36067 | us |
@Tiger @Tiger
Scenario: No TIGER house number for zoom < 18 Scenario: No TIGER house number for zoom < 18

View File

@@ -16,23 +16,23 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 6 | 1 1, 1 1.001 | | 4 | 4 | 1 1.0005 |
Scenario: Backwards even two point interpolation line Scenario: Backwards even two point interpolation line
Given the places Given the places
| osm | class | type | housenr | geometry | | osm | class | type | housenr | geometry |
| N1 | place | house | 2 | 1 1 | | N1 | place | house | 2 | 1 1 |
| N2 | place | house | 6 | 1 1.001 | | N2 | place | house | 8 | 1 1.003 |
And the places And the places
| osm | class | type | addr+interpolation | geometry | | osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1 1.001, 1 1 | | W1 | place | houses | even | 1 1.003, 1 1 |
And the ways And the ways
| id | nodes | | id | nodes |
| 1 | 2,1 | | 1 | 2,1 |
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 6 | 1 1, 1 1.001 | | 4 | 6 | 1 1.001, 1 1.002 |
Scenario: Simple odd two point interpolation Scenario: Simple odd two point interpolation
Given the places Given the places
@@ -48,23 +48,23 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 1 | 11 | 1 1, 1 1.001 | | 3 | 9 | 1 1.0002, 1 1.0008 |
Scenario: Simple all two point interpolation Scenario: Simple all two point interpolation
Given the places Given the places
| osm | class | type | housenr | geometry | | osm | class | type | housenr | geometry |
| N1 | place | house | 1 | 1 1 | | N1 | place | house | 1 | 1 1 |
| N2 | place | house | 3 | 1 1.001 | | N2 | place | house | 4 | 1 1.003 |
And the places And the places
| osm | class | type | addr+interpolation | geometry | | osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | all | 1 1, 1 1.001 | | W1 | place | houses | all | 1 1, 1 1.003 |
And the ways And the ways
| id | nodes | | id | nodes |
| 1 | 1,2 | | 1 | 1,2 |
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 1 | 3 | 1 1, 1 1.001 | | 2 | 3 | 1 1.001, 1 1.002 |
Scenario: Even two point interpolation line with intermediate empty node Scenario: Even two point interpolation line with intermediate empty node
Given the places Given the places
@@ -80,7 +80,7 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 10 | 1 1, 1 1.001, 1.001 1.001 | | 4 | 8 | 1 1.0005, 1 1.001, 1.0005 1.001 |
Scenario: Even two point interpolation line with intermediate duplicated empty node Scenario: Even two point interpolation line with intermediate duplicated empty node
Given the places Given the places
@@ -96,7 +96,7 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 10 | 1 1, 1 1.001, 1.001 1.001 | | 4 | 8 | 1 1.0005, 1 1.001, 1.0005 1.001 |
Scenario: Simple even three point interpolation line Scenario: Simple even three point interpolation line
Given the places Given the places
@@ -113,8 +113,8 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 10 | 1 1, 1 1.001 | | 4 | 8 | 1 1.00025, 1 1.00075 |
| 10 | 14 | 1 1.001, 1.001 1.001 | | 12 | 12 | 1.0005 1.001 |
Scenario: Simple even four point interpolation line Scenario: Simple even four point interpolation line
Given the places Given the places
@@ -132,9 +132,9 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 10 | 1 1, 1 1.001 | | 4 | 8 | 1 1.00025, 1 1.00075 |
| 10 | 14 | 1 1.001, 1.001 1.001 | | 12 | 12 | 1.0005 1.001 |
| 14 | 18 | 1.001 1.001, 1.001 1.002 | | 16 | 16 | 1.001 1.0015 |
Scenario: Reverse simple even three point interpolation line Scenario: Reverse simple even three point interpolation line
Given the places Given the places
@@ -151,8 +151,8 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 10 | 1 1, 1 1.001 | | 4 | 8 | 1 1.00025, 1 1.00075 |
| 10 | 14 | 1 1.001, 1.001 1.001 | | 12 | 12 | 1.0005 1.001 |
Scenario: Even three point interpolation line with odd center point Scenario: Even three point interpolation line with odd center point
Given the places Given the places
@@ -169,8 +169,7 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 7 | 1 1, 1 1.001 | | 4 | 6 | 1 1.0004, 1 1.0008 |
| 7 | 8 | 1 1.001, 1.001 1.001 |
Scenario: Interpolation line with self-intersecting way Scenario: Interpolation line with self-intersecting way
Given the places Given the places
@@ -187,9 +186,9 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 6 | 0 0, 0 0.001 | | 4 | 4 | 0 0.0005 |
| 6 | 10 | 0 0.001, 0 0.002 | | 8 | 8 | 0 0.0015 |
| 6 | 10 | 0 0.001, 0 0.002 | | 8 | 8 | 0 0.0015 |
Scenario: Interpolation line with self-intersecting way II Scenario: Interpolation line with self-intersecting way II
Given the places Given the places
@@ -205,7 +204,7 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 6 | 0 0, 0 0.001 | | 4 | 4 | 0 0.0005 |
Scenario: addr:street on interpolation way Scenario: addr:street on interpolation way
Given the scene parallel-road Given the scene parallel-road
@@ -236,10 +235,10 @@ Feature: Import of address interpolations
| N4 | W3 | | N4 | W3 |
Then W10 expands to interpolation Then W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
Then W11 expands to interpolation Then W11 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W3 | 12 | 16 | | W3 | 14 | 14 |
When sending search query "16 Cloud Street" When sending search query "16 Cloud Street"
Then results contain Then results contain
| ID | osm_type | osm_id | | ID | osm_type | osm_id |
@@ -278,10 +277,10 @@ Feature: Import of address interpolations
| N4 | W3 | | N4 | W3 |
Then W10 expands to interpolation Then W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
Then W11 expands to interpolation Then W11 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W3 | 12 | 16 | | W3 | 14 | 14 |
When sending search query "16 Cloud Street" When sending search query "16 Cloud Street"
Then results contain Then results contain
| ID | osm_type | osm_id | | ID | osm_type | osm_id |
@@ -306,8 +305,8 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 2 | 6 | 144.9629794 -37.7630755, 144.9630541 -37.7628174 | | 4 | 4 | 144.963016 -37.762946 |
| 6 | 10 | 144.9630541 -37.7628174, 144.9632341 -37.76163 | | 8 | 8 | 144.963144 -37.7622237 |
Scenario: Place with missing address information Scenario: Place with missing address information
Given the grid Given the grid
@@ -326,7 +325,7 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 23 | 29 | 1,2,3 | | 25 | 27 | 0.000016 0,0.00002 0,0.000033 0 |
Scenario: Ways without node entries are ignored Scenario: Ways without node entries are ignored
Given the places Given the places
@@ -348,7 +347,7 @@ Feature: Import of address interpolations
Given the places Given the places
| osm | class | type | housenr | geometry | | osm | class | type | housenr | geometry |
| N1 | place | house | 0 | 1 1 | | N1 | place | house | 0 | 1 1 |
| N2 | place | house | 2 | 1 1.001 | | N2 | place | house | 10 | 1 1.001 |
And the places And the places
| osm | class | type | addr+interpolation | geometry | | osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1 1, 1 1.001 | | W1 | place | houses | even | 1 1, 1 1.001 |
@@ -358,9 +357,8 @@ Feature: Import of address interpolations
When importing When importing
Then W1 expands to interpolation Then W1 expands to interpolation
| start | end | geometry | | start | end | geometry |
| 0 | 2 | 1 1, 1 1.001 | | 2 | 8 | 1 1.0002, 1 1.0008 |
When sending jsonv2 reverse coordinates 1,1 When sending jsonv2 reverse coordinates 1,1
Then results contain Then results contain
| ID | osm_type | osm_id | type | display_name | | ID | osm_type | osm_id | type | display_name |
| 0 | way | 1 | house | 0 | | 0 | node | 1 | house | 0 |

View File

@@ -26,7 +26,7 @@ Feature: Update of address interpolations
| N2 | W2 | | N2 | W2 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
Scenario: addr:street added to interpolation Scenario: addr:street added to interpolation
Given the scene parallel-road Given the scene parallel-road
@@ -51,7 +51,7 @@ Feature: Update of address interpolations
| N2 | W2 | | N2 | W2 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
When updating places When updating places
| osm | class | type | addr+interpolation | street | geometry | | osm | class | type | addr+interpolation | street | geometry |
| W10 | place | houses | even | Cloud Street | :w-middle | | W10 | place | houses | even | Cloud Street | :w-middle |
@@ -61,7 +61,7 @@ Feature: Update of address interpolations
| N2 | W3 | | N2 | W3 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W3 | 2 | 6 | | W3 | 4 | 4 |
Scenario: addr:street added to housenumbers Scenario: addr:street added to housenumbers
Given the scene parallel-road Given the scene parallel-road
@@ -86,7 +86,7 @@ Feature: Update of address interpolations
| N2 | W2 | | N2 | W2 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
When updating places When updating places
| osm | class | type | street | housenr | geometry | | osm | class | type | street | housenr | geometry |
| N1 | place | house | Cloud Street| 2 | :n-middle-w | | N1 | place | house | Cloud Street| 2 | :n-middle-w |
@@ -97,7 +97,7 @@ Feature: Update of address interpolations
| N2 | W3 | | N2 | W3 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W3 | 2 | 6 | | W3 | 4 | 4 |
Scenario: interpolation tag removed Scenario: interpolation tag removed
Given the scene parallel-road Given the scene parallel-road
@@ -122,7 +122,7 @@ Feature: Update of address interpolations
| N2 | W2 | | N2 | W2 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
When marking for delete W10 When marking for delete W10
Then W10 expands to no interpolation Then W10 expands to no interpolation
And placex contains And placex contains
@@ -152,7 +152,7 @@ Feature: Update of address interpolations
| N2 | W2 | | N2 | W2 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
When updating places When updating places
| osm | class | type | name | geometry | | osm | class | type | name | geometry |
| W3 | highway | unclassified | Cloud Street | :w-south | | W3 | highway | unclassified | Cloud Street | :w-south |
@@ -162,7 +162,7 @@ Feature: Update of address interpolations
| N2 | W3 | | N2 | W3 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W3 | 2 | 6 | | W3 | 4 | 4 |
Scenario: referenced road deleted Scenario: referenced road deleted
Given the scene parallel-road Given the scene parallel-road
@@ -187,7 +187,7 @@ Feature: Update of address interpolations
| N2 | W3 | | N2 | W3 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W3 | 2 | 6 | | W3 | 4 | 4 |
When marking for delete W3 When marking for delete W3
Then placex contains Then placex contains
| object | parent_place_id | | object | parent_place_id |
@@ -195,7 +195,7 @@ Feature: Update of address interpolations
| N2 | W2 | | N2 | W2 |
And W10 expands to interpolation And W10 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
Scenario: building becomes interpolation Scenario: building becomes interpolation
Given the scene building-with-parallel-streets Given the scene building-with-parallel-streets
@@ -222,7 +222,7 @@ Feature: Update of address interpolations
Then placex has no entry for W1 Then placex has no entry for W1
And W1 expands to interpolation And W1 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
Scenario: interpolation becomes building Scenario: interpolation becomes building
Given the scene building-with-parallel-streets Given the scene building-with-parallel-streets
@@ -243,7 +243,7 @@ Feature: Update of address interpolations
Then placex has no entry for W1 Then placex has no entry for W1
And W1 expands to interpolation And W1 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
When updating places When updating places
| osm | class | type | housenr | geometry | | osm | class | type | housenr | geometry |
| W1 | place | house | 3 | :w-building | | W1 | place | house | 3 | :w-building |
@@ -273,7 +273,7 @@ Feature: Update of address interpolations
| W1 | place | houses | even | Cloud Street| :w-north | | W1 | place | houses | even | Cloud Street| :w-north |
Then W1 expands to interpolation Then W1 expands to interpolation
| parent_place_id | start | end | | parent_place_id | start | end |
| W2 | 2 | 6 | | W2 | 4 | 4 |
Scenario: housenumber added in middle of interpolation Scenario: housenumber added in middle of interpolation
Given the grid Given the grid
@@ -294,15 +294,15 @@ Feature: Update of address interpolations
| N5 | place | house | 10 | | N5 | place | house | 10 |
When importing When importing
Then W2 expands to interpolation Then W2 expands to interpolation
| parent_place_id | start | end | geometry | | parent_place_id | start | end |
| W1 | 2 | 10 | 3,4,5 | | W1 | 4 | 8 |
When updating places When updating places
| osm | class | type | housenr | | osm | class | type | housenr |
| N4 | place | house | 6 | | N4 | place | house | 6 |
Then W2 expands to interpolation Then W2 expands to interpolation
| parent_place_id | start | end | geometry | | parent_place_id | start | end |
| W1 | 2 | 6 | 3,4 | | W1 | 4 | 4 |
| W1 | 6 | 10 | 4,5 | | W1 | 8 | 8 |
@Fail @Fail
Scenario: housenumber removed in middle of interpolation Scenario: housenumber removed in middle of interpolation
@@ -325,13 +325,13 @@ Feature: Update of address interpolations
| N5 | place | house | 10 | | N5 | place | house | 10 |
When importing When importing
Then W2 expands to interpolation Then W2 expands to interpolation
| parent_place_id | start | end | geometry | | parent_place_id | start | end |
| W1 | 2 | 6 | 3,4 | | W1 | 4 | 4 |
| W1 | 6 | 10 | 4,5 | | W1 | 8 | 8 |
When marking for delete N4 When marking for delete N4
Then W2 expands to interpolation Then W2 expands to interpolation
| parent_place_id | start | end | geometry | | parent_place_id | start | end |
| W1 | 2 | 10 | 3,4,5 | | W1 | 4 | 8 |
Scenario: Change the start housenumber Scenario: Change the start housenumber
Given the grid Given the grid
@@ -352,12 +352,12 @@ Feature: Update of address interpolations
| N4 | place | house | 6 | | N4 | place | house | 6 |
When importing When importing
Then W2 expands to interpolation Then W2 expands to interpolation
| parent_place_id | start | end | geometry | | parent_place_id | start | end |
| W1 | 2 | 6 | 3,4 | | W1 | 4 | 4 |
When updating places When updating places
| osm | class | type | housenr | | osm | class | type | housenr |
| N4 | place | house | 8 | | N4 | place | house | 8 |
Then W2 expands to interpolation Then W2 expands to interpolation
| parent_place_id | start | end | geometry | | parent_place_id | start | end |
| W1 | 2 | 8 | 3,4 | | W1 | 4 | 6 |

View File

@@ -91,33 +91,4 @@ class LibTest extends \PHPUnit\Framework\TestCase
$this->assertEquals($sQuery, $aRes[0]); $this->assertEquals($sQuery, $aRes[0]);
} }
} }
private function closestHouseNumberEvenOddOther($startnumber, $endnumber, $fraction, $aExpected)
{
foreach (array('even', 'odd', 'other') as $itype) {
$this->assertEquals(
$aExpected[$itype],
closestHouseNumber(array(
'startnumber' => $startnumber,
'endnumber' => $endnumber,
'fraction' => $fraction,
'interpolationtype' => $itype
)),
"$startnumber => $endnumber, $fraction, $itype"
);
}
}
public function testClosestHouseNumber()
{
$this->closestHouseNumberEvenOddOther(50, 100, 0.5, array('even' => 76, 'odd' => 75, 'other' => 75));
// upper bound
$this->closestHouseNumberEvenOddOther(50, 100, 1.5, array('even' => 100, 'odd' => 100, 'other' => 100));
// lower bound
$this->closestHouseNumberEvenOddOther(50, 100, -0.5, array('even' => 50, 'odd' => 50, 'other' => 50));
// fraction 0
$this->closestHouseNumberEvenOddOther(50, 100, 0, array('even' => 50, 'odd' => 51, 'other' => 50));
// start == end
$this->closestHouseNumberEvenOddOther(50, 50, 0.5, array('even' => 50, 'odd' => 50, 'other' => 50));
}
} }