1 -- Functions for address interpolation objects in location_property_osmline.
3 -- Splits the line at the given point and returns the two parts
4 -- in a multilinestring.
5 CREATE OR REPLACE FUNCTION split_line_on_node(line GEOMETRY, point GEOMETRY)
9 RETURN ST_Split(ST_Snap(line, point, 0.0005), point);
12 LANGUAGE plpgsql IMMUTABLE;
15 -- find the parent road of the cut road parts
16 CREATE OR REPLACE FUNCTION get_interpolation_parent(wayid BIGINT, street TEXT,
17 place TEXT, partition INTEGER,
18 centroid GEOMETRY, geom GEOMETRY)
24 parent_place_id BIGINT;
25 address_street_word_ids INTEGER[];
34 IF addr_street is null and addr_place is null THEN
35 select nodes from planet_osm_ways where id = wayid INTO waynodes;
36 FOR location IN SELECT placex.address from placex
37 where osm_type = 'N' and osm_id = ANY(waynodes)
38 and placex.address is not null
39 and (placex.address ? 'street' or placex.address ? 'place')
40 and indexed_status < 100
42 addr_street = location.address->'street';
43 addr_place = location.address->'place';
47 IF addr_street IS NOT NULL THEN
48 address_street_word_ids := get_name_ids(make_standard_name(addr_street));
49 IF address_street_word_ids IS NOT NULL THEN
50 FOR location IN SELECT place_id from getNearestNamedRoadFeature(partition, centroid, address_street_word_ids) LOOP
51 parent_place_id := location.place_id;
56 IF parent_place_id IS NULL AND addr_place IS NOT NULL THEN
57 address_street_word_ids := get_name_ids(make_standard_name(addr_place));
58 IF address_street_word_ids IS NOT NULL THEN
59 FOR location IN SELECT place_id from getNearestNamedPlaceFeature(partition, centroid, address_street_word_ids) LOOP
60 parent_place_id := location.place_id;
65 IF parent_place_id is null THEN
66 FOR location IN SELECT place_id FROM placex
67 WHERE ST_DWithin(geom, placex.geometry, 0.001) and placex.rank_search = 26
68 ORDER BY (ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0))+
69 ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0.5))+
70 ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1))) ASC limit 1
72 parent_place_id := location.place_id;
76 IF parent_place_id is null THEN
80 RETURN parent_place_id;
83 LANGUAGE plpgsql STABLE;
86 CREATE OR REPLACE FUNCTION osmline_reinsert(node_id BIGINT, geom GEOMETRY)
92 SELECT w.id FROM planet_osm_ways w, location_property_osmline p
93 WHERE p.linegeo && geom and p.osm_id = w.id and p.indexed_status = 0
94 and node_id = any(w.nodes) INTO existingline;
96 IF existingline.id is not NULL THEN
97 DELETE FROM location_property_osmline WHERE osm_id = existingline.id;
98 INSERT INTO location_property_osmline (osm_id, address, linegeo)
99 SELECT osm_id, address, geometry FROM place
100 WHERE osm_type = 'W' and osm_id = existingline.id;
109 CREATE OR REPLACE FUNCTION osmline_insert()
113 NEW.place_id := nextval('seq_place');
114 NEW.indexed_date := now();
116 IF NEW.indexed_status IS NULL THEN
117 IF NEW.address is NULL OR NOT NEW.address ? 'interpolation'
118 OR NEW.address->'interpolation' NOT IN ('odd', 'even', 'all') THEN
119 -- other interpolation types than odd/even/all (e.g. numeric ones) are not supported
123 NEW.indexed_status := 1; --STATUS_NEW
124 NEW.country_code := lower(get_country_code(NEW.linegeo));
126 NEW.partition := get_partition(NEW.country_code);
127 NEW.geometry_sector := geometry_sector(NEW.partition, NEW.linegeo);
136 CREATE OR REPLACE FUNCTION osmline_update()
140 place_centroid GEOMETRY;
150 interpol_postcode TEXT;
154 IF OLD.indexed_status = 100 THEN
155 delete from location_property_osmline where place_id = OLD.place_id;
159 IF NEW.indexed_status != 0 OR OLD.indexed_status = 0 THEN
163 NEW.interpolationtype = NEW.address->'interpolation';
165 place_centroid := ST_PointOnSurface(NEW.linegeo);
166 NEW.parent_place_id = get_interpolation_parent(NEW.osm_id, NEW.address->'street',
167 NEW.address->'place',
168 NEW.partition, place_centroid, NEW.linegeo);
170 IF NEW.address is not NULL AND NEW.address ? 'postcode' AND NEW.address->'postcode' not similar to '%(,|;)%' THEN
171 interpol_postcode := NEW.address->'postcode';
172 housenum := getorcreate_postcode_id(NEW.address->'postcode');
174 interpol_postcode := NULL;
177 -- if the line was newly inserted, split the line as necessary
178 IF OLD.indexed_status = 1 THEN
179 select nodes from planet_osm_ways where id = NEW.osm_id INTO waynodes;
181 IF array_upper(waynodes, 1) IS NULL THEN
185 linegeo := NEW.linegeo;
188 FOR nodeidpos in 1..array_upper(waynodes, 1) LOOP
190 select osm_id, address, geometry
191 from place where osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
192 and address is not NULL and address ? 'housenumber' limit 1 INTO nextnode;
193 --RAISE NOTICE 'Nextnode.place_id: %s', nextnode.place_id;
194 IF nextnode.osm_id IS NOT NULL THEN
195 --RAISE NOTICE 'place_id is not null';
196 IF nodeidpos > 1 and nodeidpos < array_upper(waynodes, 1) THEN
197 -- Make sure that the point is actually on the line. That might
198 -- be a bit paranoid but ensures that the algorithm still works
199 -- should osm2pgsql attempt to repair geometries.
200 splitline := split_line_on_node(linegeo, nextnode.geometry);
201 sectiongeo := ST_GeometryN(splitline, 1);
202 linegeo := ST_GeometryN(splitline, 2);
204 sectiongeo = linegeo;
206 endnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
208 IF startnumber IS NOT NULL AND endnumber IS NOT NULL
209 AND startnumber != endnumber
210 AND ST_GeometryType(sectiongeo) = 'ST_LineString' THEN
212 IF (startnumber > endnumber) THEN
213 housenum := endnumber;
214 endnumber := startnumber;
215 startnumber := housenum;
216 sectiongeo := ST_Reverse(sectiongeo);
219 -- determine postcode
220 postcode := coalesce(interpol_postcode,
221 prevnode.address->'postcode',
222 nextnode.address->'postcode',
225 IF postcode is NULL THEN
226 SELECT placex.postcode FROM placex WHERE place_id = NEW.parent_place_id INTO postcode;
228 IF postcode is NULL THEN
229 postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
232 IF NEW.startnumber IS NULL THEN
233 NEW.startnumber := startnumber;
234 NEW.endnumber := endnumber;
235 NEW.linegeo := sectiongeo;
236 NEW.postcode := upper(trim(postcode));
238 insert into location_property_osmline
239 (linegeo, partition, osm_id, parent_place_id,
240 startnumber, endnumber, interpolationtype,
241 address, postcode, country_code,
242 geometry_sector, indexed_status)
243 values (sectiongeo, NEW.partition, NEW.osm_id, NEW.parent_place_id,
244 startnumber, endnumber, NEW.interpolationtype,
245 NEW.address, postcode,
246 NEW.country_code, NEW.geometry_sector, 0);
250 -- early break if we are out of line string,
251 -- might happen when a line string loops back on itself
252 IF ST_GeometryType(linegeo) != 'ST_LineString' THEN
256 startnumber := substring(nextnode.address->'housenumber','[0-9]+')::integer;
257 prevnode := nextnode;
262 -- marking descendants for reparenting is not needed, because there are
263 -- actually no descendants for interpolation lines