So far we've used a buffer around a place node to define its
potential address reach. This had two problems: the buffer was
so large that addresses often contain false positives and the
buffer is really distorted when getting closer to the poles.
Change the buffer here to draw a bounndig box at a certain
distance in meter. This means that we always use the same
box everywhere on the planet and can make the extent much
smaller. Using a box has the advantage that it is much faster
to figure out if a point is within the box.
{ "tags" : {
"place" : {
"sea" : [2, 0],
{ "tags" : {
"place" : {
"sea" : [2, 0],
+ "island" : [17, 0],
+ "islet" : [20, 0],
"continent" : [2, 0],
"country" : [4, 0],
"state" : [8, 0],
"continent" : [2, 0],
"country" : [4, 0],
"state" : [8, 0],
"county" : 12,
"municipality" : [17, 14],
"city" : 16,
"county" : 12,
"municipality" : [17, 14],
"city" : 16,
"village" : [19, 16],
"district" : [19, 16],
"village" : [19, 16],
"district" : [19, 16],
"croft" : 20,
"subdivision" : 20,
"croft" : 20,
"subdivision" : 20,
- "isolated_dwelling" : 20,
- "farm" : [20, 0],
- "locality" : [20, 0],
- "islet" : [20, 0],
- "mountain_pass" : [20, 0],
- "neighbourhood" : 22,
- "quarter" : 22,
+ "neighbourhood" : [20, 22],
+ "quarter" : [20, 22],
+ "isolated_dwelling" : [22, 20],
+ "mountain_pass" : [20, 0],
+ "houses" : [28, 0],
+ "farm" : [20, 0],
+ "locality" : [20, 0]
},
"boundary" : {
"administrative2" : 4,
},
"boundary" : {
"administrative2" : 4,
+CREATE OR REPLACE FUNCTION near_feature_rank_distance(rank_search INTEGER)
+ RETURNS FLOAT
+ AS $$
+BEGIN
+ IF rank_search <= 16 THEN -- city
+ RETURN 7500;
+ ELSIF rank_search <= 18 THEN -- town
+ RETURN 4000;
+ ELSIF rank_search <= 19 THEN -- village
+ RETURN 2000;
+ ELSIF rank_search <= 20 THEN -- hamlet
+ RETURN 1000;
+ END IF;
+
+ RETURN 500;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
CREATE OR REPLACE FUNCTION add_location(place_id BIGINT, country_code varchar(2),
partition INTEGER, keywords INTEGER[],
CREATE OR REPLACE FUNCTION add_location(place_id BIGINT, country_code varchar(2),
partition INTEGER, keywords INTEGER[],
DECLARE
locationid INTEGER;
centroid GEOMETRY;
DECLARE
locationid INTEGER;
centroid GEOMETRY;
- diameter FLOAT;
- x BOOLEAN;
- splitGeom RECORD;
secgeo GEOMETRY;
postcode TEXT;
BEGIN
secgeo GEOMETRY;
postcode TEXT;
BEGIN
-
- IF rank_search > 25 THEN
- RAISE EXCEPTION 'Adding location with rank > 25 (% rank %)', place_id, rank_search;
- END IF;
-
- x := deleteLocationArea(partition, place_id, rank_search);
+ PERFORM deleteLocationArea(partition, place_id, rank_search);
-- add postcode only if it contains a single entry, i.e. ignore postcode lists
postcode := NULL;
-- add postcode only if it contains a single entry, i.e. ignore postcode lists
postcode := NULL;
centroid := ST_Centroid(geometry);
FOR secgeo IN select split_geometry(geometry) AS geom LOOP
centroid := ST_Centroid(geometry);
FOR secgeo IN select split_geometry(geometry) AS geom LOOP
- x := insertLocationAreaLarge(partition, place_id, country_code, keywords, rank_search, rank_address, false, postcode, centroid, secgeo);
+ PERFORM insertLocationAreaLarge(partition, place_id, country_code, keywords, rank_search, rank_address, false, postcode, centroid, secgeo);
- ELSE
-
- diameter := 0.02;
- IF rank_address = 0 THEN
- diameter := 0.02;
- ELSEIF rank_search <= 14 THEN
- diameter := 1.2;
- ELSEIF rank_search <= 15 THEN
- diameter := 1;
- ELSEIF rank_search <= 16 THEN
- diameter := 0.5;
- ELSEIF rank_search <= 17 THEN
- diameter := 0.2;
- ELSEIF rank_search <= 21 THEN
- diameter := 0.05;
- ELSEIF rank_search = 25 THEN
- diameter := 0.005;
- END IF;
-
--- RAISE WARNING 'adding % diameter %', place_id, diameter;
+ ELSEIF ST_GeometryType(geometry) = 'ST_Point' THEN
+ radius := near_feature_rank_distance(rank_search);
+ --DEBUG: RAISE WARNING 'adding % diameter %', place_id, diameter;
- secgeo := ST_Buffer(geometry, diameter);
- x := insertLocationAreaLarge(partition, place_id, country_code, keywords, rank_search, rank_address, true, postcode, ST_Centroid(geometry), secgeo);
+ -- Create a bounding box with an extent computed from the radius (in meters).
+ secgeo := ST_Envelope(ST_Collect(
+ ST_Project(geometry, radius, 0.785398)::geometry,
+ ST_Project(geometry, radius, 3.9269908)::geometry));
+ PERFORM insertLocationAreaLarge(partition, place_id, country_code, keywords, rank_search, rank_address, true, postcode, geometry, secgeo);