ubuntu: [18, 20]
include:
- ubuntu: 18
- postgresql: 9.5
+ postgresql: 9.6
postgis: 2.5
pytest: pytest
php: 7.2
pg_config seems to use bad includes sometimes when multiple versions
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`).
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)
* [Python 3](https://www.python.org/) (3.6+)
* [Psycopg2](https://www.psycopg.org) (2.7+)
$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 .= ' 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 ';
{
Debug::newFunction('lookupInterpolation');
$sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
- $sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
- $sSQL .= ' startnumber, endnumber, interpolationtype,';
+ $sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
+ $sSQL .= ' startnumber, endnumber, step,';
$sSQL .= ' ST_Distance(linegeo,'.$sPointSQL.') as distance';
$sSQL .= ' FROM location_property_osmline';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
&& $this->iMaxRank >= 28
) {
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
- $sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
- $sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,';
- $sSQL .= 'startnumber,endnumber,interpolationtype';
+ $sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
+ $sSQL .= ' startnumber, endnumber, step,';
+ $sSQL .= ' ST_Distance('.$sPointSQL.', linegeo) as distance';
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
$sSQL .= ' ORDER BY distance ASC limit 1';
if ($aPlaceTiger) {
$aPlace = $aPlaceTiger;
$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;
}
}
if ($aHouse) {
$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;
}
}
// if nothing found, search in the interpolation line table
$sSQL = 'SELECT distinct place_id FROM location_property_osmline';
$sSQL .= ' WHERE startnumber is not NULL';
- $sSQL .= ' AND parent_place_id in ('.$sRoadPlaceIDs.') AND (';
- if ($iHousenumber % 2 == 0) {
- // If housenumber is even, look for housenumber in streets
- // 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 .= ' and parent_place_id in ('.$sRoadPlaceIDs.')';
+ $sSQL .= ' and ('.$iHousenumber.' - startnumber) % step = 0';
+ $sSQL .= ' and '.$iHousenumber.' between startnumber and endnumber';
$sSQL .= $this->oContext->excludeSQL(' AND place_id');
Debug::printSQL($sSQL);
// If nothing found then search in Tiger data (location_property_tiger)
if (CONST_Use_US_Tiger_Data && $sRoadPlaceIDs && $bIsIntHouseNumber && empty($aResults)) {
$sSQL = 'SELECT place_id FROM location_property_tiger';
- $sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.') and (';
- if ($iHousenumber % 2 == 0) {
- $sSQL .= "interpolationtype='even'";
- } else {
- $sSQL .= "interpolationtype='odd'";
- }
- $sSQL .= " or interpolationtype='all') and ";
- $sSQL .= $iHousenumber.'>=startnumber and ';
- $sSQL .= $iHousenumber.'<=endnumber';
+ $sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.')';
+ $sSQL .= ' and ('.$iHousenumber.' - startnumber) % step = 0';
+ $sSQL .= ' and '.$iHousenumber.' between startnumber and endnumber';
$sSQL .= $this->oContext->excludeSQL(' AND place_id');
Debug::printSQL($sSQL);
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')) {
function array_key_last(array $array)
{
-- 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)
RETURNS HSTORE
IF parent_place_id is null THEN
FOR location IN SELECT place_id FROM placex
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,1))) ASC limit 1
+ ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1)))
+ ELSE ST_distance(placex.geometry, geom) END
+ ASC
+ LIMIT 1
LOOP
parent_place_id := location.place_id;
END LOOP;
LANGUAGE plpgsql STABLE;
-CREATE OR REPLACE FUNCTION osmline_reinsert(node_id BIGINT, geom GEOMETRY)
- RETURNS BOOLEAN
+CREATE OR REPLACE FUNCTION reinsert_interpolation(way_id BIGINT, addr HSTORE,
+ geom GEOMETRY)
+ RETURNS INT
AS $$
DECLARE
- existingline RECORD;
+ existing BIGINT[];
BEGIN
- SELECT w.id FROM planet_osm_ways w, location_property_osmline p
- WHERE p.linegeo && geom and p.osm_id = w.id and p.indexed_status = 0
- and node_id = any(w.nodes) INTO existingline;
-
- IF existingline.id is not NULL THEN
- DELETE FROM location_property_osmline WHERE osm_id = existingline.id;
- INSERT INTO location_property_osmline (osm_id, address, linegeo)
- SELECT osm_id, address, geometry FROM place
- WHERE osm_type = 'W' and osm_id = existingline.id;
- END IF;
-
- RETURN true;
+ -- Get the existing entry from the interpolation table.
+ SELECT array_agg(place_id) INTO existing
+ FROM location_property_osmline WHERE osm_id = way_id;
+
+ IF existing IS NULL or array_length(existing, 1) = 0 THEN
+ INSERT INTO location_property_osmline (osm_id, address, linegeo)
+ VALUES (way_id, addr, geom);
+ ELSE
+ -- Update the interpolation table:
+ -- 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 1;
END;
$$
LANGUAGE plpgsql;
IF NEW.indexed_status IS NULL THEN
IF NEW.address is NULL OR NOT NEW.address ? 'interpolation'
- OR NEW.address->'interpolation' NOT IN ('odd', 'even', 'all') THEN
- -- other interpolation types than odd/even/all (e.g. numeric ones) are not supported
+ OR NOT (NEW.address->'interpolation' in ('odd', 'even', 'all')
+ or NEW.address->'interpolation' similar to '[1-9]')
+ THEN
+ -- alphabetic interpolation is not supported
RETURN NULL;
END IF;
RETURNS TRIGGER
AS $$
DECLARE
- place_centroid GEOMETRY;
waynodes BIGINT[];
prevnode RECORD;
nextnode RECORD;
startnumber INTEGER;
endnumber INTEGER;
- housenum INTEGER;
+ newstart INTEGER;
+ newend INTEGER;
+ moddiff SMALLINT;
linegeo GEOMETRY;
splitline GEOMETRY;
sectiongeo GEOMETRY;
interpol_postcode TEXT;
postcode TEXT;
+ stepmod SMALLINT;
BEGIN
-- deferred delete
IF OLD.indexed_status = 100 THEN
RETURN NEW;
END IF;
- NEW.interpolationtype = NEW.address->'interpolation';
-
- place_centroid := ST_PointOnSurface(NEW.linegeo);
- NEW.parent_place_id = get_interpolation_parent(NEW.token_info, NEW.partition,
- place_centroid, NEW.linegeo);
+ NEW.parent_place_id := get_interpolation_parent(NEW.token_info, NEW.partition,
+ ST_PointOnSurface(NEW.linegeo),
+ NEW.linegeo);
interpol_postcode := token_normalized_postcode(NEW.address->'postcode');
NEW.token_info := token_strip_info(NEW.token_info);
IF NEW.address ? '_inherited' THEN
- NEW.address := hstore('interpolation', NEW.interpolationtype);
+ NEW.address := hstore('interpolation', NEW.address->'interpolation');
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
- select nodes from planet_osm_ways where id = NEW.osm_id INTO waynodes;
-
- IF array_upper(waynodes, 1) IS NULL THEN
- RETURN NEW;
+ 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;
+
+ SELECT nodes INTO waynodes
+ 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;
- linegeo := NEW.linegeo;
- startnumber := NULL;
-
- FOR nodeidpos in 1..array_upper(waynodes, 1) LOOP
-
- select osm_id, address, geometry
- from place where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
- and address is not NULL and address ? 'housenumber' limit 1 INTO nextnode;
- --RAISE NOTICE 'Nextnode.place_id: %s', nextnode.place_id;
- IF nextnode.osm_id IS NOT NULL THEN
- --RAISE NOTICE 'place_id is not null';
- IF nodeidpos > 1 and nodeidpos < array_upper(waynodes, 1) THEN
- -- Make sure that the point is actually on the line. That might
- -- 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);
+ IF prevnode.hnr is not null
+ -- Check if there are housenumbers to interpolate between the
+ -- regularly mapped housenumbers.
+ -- (Conveniently also fails if one of the house numbers is not a number.)
+ and abs(prevnode.hnr - nextnode.hnr) > NEW.step
+ THEN
+ IF prevnode.hnr < nextnode.hnr THEN
+ startnumber := prevnode.hnr;
+ endnumber := nextnode.hnr;
+ ELSE
+ startnumber := nextnode.hnr;
+ endnumber := prevnode.hnr;
+ sectiongeo := ST_Reverse(sectiongeo);
+ END IF;
+
+ -- 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
- 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;
+ 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;
- -- 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;
+ -- 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;
- startnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
- prevnode := nextnode;
+ -- 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 LOOP;
+ END IF;
+
+ prevnode := nextnode;
+ END LOOP;
END IF;
- -- marking descendants for reparenting is not needed, because there are
- -- actually no descendants for interpolation lines
RETURN NEW;
END;
$$
country RECORD;
existing RECORD;
existingplacex RECORD;
- existingline RECORD;
- result BOOLEAN;
+ existingline BIGINT[];
+ interpol RECORD;
BEGIN
{% if debug %}
RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
IF NEW.class='place' and NEW.type='houses'
and NEW.osm_type='W' and ST_GeometryType(NEW.geometry) = 'ST_LineString'
THEN
- -- Get the existing entry from the interpolation table.
- 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);
+ PERFORM reinsert_interpolation(NEW.osm_id, NEW.address, NEW.geometry);
-- Now invalidate all address nodes on the line.
-- They get their parent from the interpolation.
RETURN null;
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.
SELECT * INTO existingplacex
FROM placex
geometry = NEW.geometry
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.
IF existingplacex.linked_place_id is not NULL THEN
UPDATE placex x
BEGIN
-- For POI nodes, check if the address should be derived from a surrounding
-- 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;
- ELSE
+ ELSEIF p.address is null THEN
-- The additional && condition works around the misguided query
-- planner of postgis 3.0.
SELECT placex.address || hstore('_inherited', '') INTO result.address
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')
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;
result.address := result.address - '_unlisted_place'::TEXT;
END IF;
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
SELECT p.place_id, p.osm_id, p.rank_search, p.address,
coalesce(p.centroid, ST_Centroid(p.geometry)) as centroid
{% if not disable_diff_updates %}
-- 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
- -- might be part of an interpolation
- result := osmline_reinsert(NEW.osm_id, NEW.geometry);
- ELSEIF NEW.rank_address > 0 THEN
+ IF NEW.rank_address > 0 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
IF st_area(NEW.geometry) < 1 THEN
-- 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);
-- 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
-- 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');
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
- 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
ON location_property_osmline USING BTREE (osm_id) {{db.tablespace.search_index}};
CREATE UNIQUE INDEX IF NOT EXISTS idx_place_osm_unique
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 %}
-- Indices only needed for search.
{% if postgres.has_index_non_key_column %}
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
- 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 %}
parent_place_id BIGINT,
startnumber INTEGER,
endnumber INTEGER,
+ step SMALLINT,
partition SMALLINT,
linegeo GEOMETRY,
- interpolationtype TEXT,
postcode TEXT);
GRANT SELECT ON location_property_tiger TO "{{config.DATABASE_WEBUSER}}";
indexed_date TIMESTAMP,
startnumber INTEGER,
endnumber INTEGER,
+ step SMALLINT,
partition SMALLINT,
indexed_status SMALLINT,
linegeo GEOMETRY,
- interpolationtype TEXT,
address HSTORE,
token_info JSONB, -- custom column for tokenizer use only
postcode TEXT,
){{db.tablespace.search_data}};
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_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}}";
drop table IF EXISTS search_name;
CREATE INDEX IF NOT EXISTS idx_location_property_tiger_parent_place_id_imp
ON location_property_tiger_import (parent_place_id)
{% if postgres.has_index_non_key_column %}
- INCLUDE (startnumber, endnumber)
+ INCLUDE (startnumber, endnumber, step)
{% endif %}
{{db.tablespace.aux_index}};
CREATE UNIQUE INDEX IF NOT EXISTS idx_location_property_tiger_place_id_imp
-- Copyright (C) 2022 by the Nominatim developer community.
-- For a full list of authors see the git log.
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,
in_endnumber INTEGER, interpolationtype TEXT,
BEGIN
IF in_endnumber > in_startnumber THEN
- startnumber = in_startnumber;
- endnumber = in_endnumber;
+ startnumber := in_startnumber;
+ endnumber := in_endnumber;
ELSE
- startnumber = in_endnumber;
- endnumber = in_startnumber;
+ startnumber := in_endnumber;
+ endnumber := in_startnumber;
+ linegeo := ST_Reverse(linegeo);
END IF;
IF startnumber < 0 THEN
END IF;
-- Filter out really broken tiger data
- IF numberrange > 0 AND (numberrange::float/stepsize::float > 500)
- AND ST_length(linegeo)/(numberrange::float/stepsize::float) < 0.000001 THEN
+ IF numberrange > 0
+ 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,
ST_length(linegeo)/(numberrange::float/stepsize::float);
RETURN 0;
END IF;
--insert street(line) into import table
-insert into location_property_tiger_import (linegeo, place_id, partition, parent_place_id, startnumber, endnumber, interpolationtype, postcode)
-values (linegeo, nextval('seq_place'), out_partition, out_parent_place_id, startnumber, endnumber, interpolationtype, in_postcode);
+insert into location_property_tiger_import (linegeo, place_id, partition,
+ 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;
END;
# 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
"/usr/pgsql-${suffix}/bin")
endforeach()
ON location_property_tiger
USING btree(parent_place_id)
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
+ """)
# 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
# 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.
#
# 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)
POSTGIS_REQUIRED_VERSION = (2, 2)
| way | place | house |
And result addresses contain
| house_number | road | postcode | country_code |
- | 697 | Upper Kingston Road | 36067 | us |
+ | 707 | Upper Kingston Road | 36067 | us |
@Tiger
Scenario: No TIGER house number for zoom < 18
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 6 | 1 1, 1 1.001 |
+ | 4 | 4 | 1 1.0005 |
Scenario: Backwards even two point interpolation line
Given the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 2 | 1 1 |
- | N2 | place | house | 6 | 1 1.001 |
+ | N2 | place | house | 8 | 1 1.003 |
And the places
| 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
| id | nodes |
| 1 | 2,1 |
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 6 | 1 1, 1 1.001 |
+ | 4 | 6 | 1 1.001, 1 1.002 |
Scenario: Simple odd two point interpolation
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 1 | 11 | 1 1, 1 1.001 |
+ | 3 | 9 | 1 1.0002, 1 1.0008 |
Scenario: Simple all two point interpolation
Given the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 1 | 1 1 |
- | N2 | place | house | 3 | 1 1.001 |
+ | N2 | place | house | 4 | 1 1.003 |
And the places
| 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
| id | nodes |
| 1 | 1,2 |
When importing
Then W1 expands to interpolation
| 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
Given the places
When importing
Then W1 expands to interpolation
| 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
Given the places
When importing
Then W1 expands to interpolation
| 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
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 10 | 1 1, 1 1.001 |
- | 10 | 14 | 1 1.001, 1.001 1.001 |
+ | 4 | 8 | 1 1.00025, 1 1.00075 |
+ | 12 | 12 | 1.0005 1.001 |
Scenario: Simple even four point interpolation line
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 10 | 1 1, 1 1.001 |
- | 10 | 14 | 1 1.001, 1.001 1.001 |
- | 14 | 18 | 1.001 1.001, 1.001 1.002 |
+ | 4 | 8 | 1 1.00025, 1 1.00075 |
+ | 12 | 12 | 1.0005 1.001 |
+ | 16 | 16 | 1.001 1.0015 |
Scenario: Reverse simple even three point interpolation line
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 10 | 1 1, 1 1.001 |
- | 10 | 14 | 1 1.001, 1.001 1.001 |
+ | 4 | 8 | 1 1.00025, 1 1.00075 |
+ | 12 | 12 | 1.0005 1.001 |
Scenario: Even three point interpolation line with odd center point
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 7 | 1 1, 1 1.001 |
- | 7 | 8 | 1 1.001, 1.001 1.001 |
+ | 4 | 6 | 1 1.0004, 1 1.0008 |
Scenario: Interpolation line with self-intersecting way
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 6 | 0 0, 0 0.001 |
- | 6 | 10 | 0 0.001, 0 0.002 |
- | 6 | 10 | 0 0.001, 0 0.002 |
+ | 4 | 4 | 0 0.0005 |
+ | 8 | 8 | 0 0.0015 |
+ | 8 | 8 | 0 0.0015 |
Scenario: Interpolation line with self-intersecting way II
Given the places
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 6 | 0 0, 0 0.001 |
+ | 4 | 4 | 0 0.0005 |
Scenario: addr:street on interpolation way
Given the scene parallel-road
| N4 | W3 |
Then W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
Then W11 expands to interpolation
| parent_place_id | start | end |
- | W3 | 12 | 16 |
+ | W3 | 14 | 14 |
When sending search query "16 Cloud Street"
Then results contain
| ID | osm_type | osm_id |
| N4 | W3 |
Then W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
Then W11 expands to interpolation
| parent_place_id | start | end |
- | W3 | 12 | 16 |
+ | W3 | 14 | 14 |
When sending search query "16 Cloud Street"
Then results contain
| ID | osm_type | osm_id |
When importing
Then W1 expands to interpolation
| start | end | geometry |
- | 2 | 6 | 144.9629794 -37.7630755, 144.9630541 -37.7628174 |
- | 6 | 10 | 144.9630541 -37.7628174, 144.9632341 -37.76163 |
+ | 4 | 4 | 144.963016 -37.762946 |
+ | 8 | 8 | 144.963144 -37.7622237 |
Scenario: Place with missing address information
Given the grid
When importing
Then W1 expands to interpolation
| 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
Given the places
Given the places
| osm | class | type | housenr | geometry |
| N1 | place | house | 0 | 1 1 |
- | N2 | place | house | 2 | 1 1.001 |
+ | N2 | place | house | 10 | 1 1.001 |
And the places
| osm | class | type | addr+interpolation | geometry |
| W1 | place | houses | even | 1 1, 1 1.001 |
When importing
Then W1 expands to interpolation
| 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
Then results contain
| ID | osm_type | osm_id | type | display_name |
- | 0 | way | 1 | house | 0 |
-
+ | 0 | node | 1 | house | 0 |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
Scenario: addr:street added to interpolation
Given the scene parallel-road
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
When updating places
| osm | class | type | addr+interpolation | street | geometry |
| W10 | place | houses | even | Cloud Street | :w-middle |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W3 | 2 | 6 |
+ | W3 | 4 | 4 |
Scenario: addr:street added to housenumbers
Given the scene parallel-road
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
When updating places
| osm | class | type | street | housenr | geometry |
| N1 | place | house | Cloud Street| 2 | :n-middle-w |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W3 | 2 | 6 |
+ | W3 | 4 | 4 |
Scenario: interpolation tag removed
Given the scene parallel-road
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
When marking for delete W10
Then W10 expands to no interpolation
And placex contains
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
When updating places
| osm | class | type | name | geometry |
| W3 | highway | unclassified | Cloud Street | :w-south |
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W3 | 2 | 6 |
+ | W3 | 4 | 4 |
Scenario: referenced road deleted
Given the scene parallel-road
| N2 | W3 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W3 | 2 | 6 |
+ | W3 | 4 | 4 |
When marking for delete W3
Then placex contains
| object | parent_place_id |
| N2 | W2 |
And W10 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
Scenario: building becomes interpolation
Given the scene building-with-parallel-streets
Then placex has no entry for W1
And W1 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
Scenario: interpolation becomes building
Given the scene building-with-parallel-streets
Then placex has no entry for W1
And W1 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
When updating places
| osm | class | type | housenr | geometry |
| W1 | place | house | 3 | :w-building |
| W1 | place | houses | even | Cloud Street| :w-north |
Then W1 expands to interpolation
| parent_place_id | start | end |
- | W2 | 2 | 6 |
+ | W2 | 4 | 4 |
Scenario: housenumber added in middle of interpolation
Given the grid
| N5 | place | house | 10 |
When importing
Then W2 expands to interpolation
- | parent_place_id | start | end | geometry |
- | W1 | 2 | 10 | 3,4,5 |
+ | parent_place_id | start | end |
+ | W1 | 4 | 8 |
When updating places
| osm | class | type | housenr |
| N4 | place | house | 6 |
Then W2 expands to interpolation
- | parent_place_id | start | end | geometry |
- | W1 | 2 | 6 | 3,4 |
- | W1 | 6 | 10 | 4,5 |
+ | parent_place_id | start | end |
+ | W1 | 4 | 4 |
+ | W1 | 8 | 8 |
@Fail
Scenario: housenumber removed in middle of interpolation
| N5 | place | house | 10 |
When importing
Then W2 expands to interpolation
- | parent_place_id | start | end | geometry |
- | W1 | 2 | 6 | 3,4 |
- | W1 | 6 | 10 | 4,5 |
+ | parent_place_id | start | end |
+ | W1 | 4 | 4 |
+ | W1 | 8 | 8 |
When marking for delete N4
Then W2 expands to interpolation
- | parent_place_id | start | end | geometry |
- | W1 | 2 | 10 | 3,4,5 |
+ | parent_place_id | start | end |
+ | W1 | 4 | 8 |
Scenario: Change the start housenumber
Given the grid
| N4 | place | house | 6 |
When importing
Then W2 expands to interpolation
- | parent_place_id | start | end | geometry |
- | W1 | 2 | 6 | 3,4 |
+ | parent_place_id | start | end |
+ | W1 | 4 | 4 |
When updating places
| osm | class | type | housenr |
| N4 | place | house | 8 |
Then W2 expands to interpolation
- | parent_place_id | start | end | geometry |
- | W1 | 2 | 8 | 3,4 |
+ | parent_place_id | start | end |
+ | W1 | 4 | 6 |
$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));
- }
}