inherit tags from interpolation not parent

Nodes on an interpolation now only get the address tags of
interpolations and then compute their own parent from that. They no
longer inherit the parent directly.
This commit is contained in:
Sarah Hoffmann
2022-01-26 12:05:04 +01:00
parent 83d2c440d5
commit fea4dbba50
3 changed files with 144 additions and 116 deletions

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
@@ -128,8 +117,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;
@@ -150,18 +141,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
@@ -173,107 +166,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

@@ -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,17 +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 startnumber is not null
and x.id = q.osm_id and poi_osm_id = any(x.nodes)
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

View File

@@ -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,