1- -- Deploy pgosm-flex-faker:001 to pg
1+ -- Deploy pgosm-flex-faker:point-in-place-landuse to pg
2+ -- requires: basics
23
34BEGIN ;
45
5- CREATE SCHEMA geofaker ;
6-
76
87CREATE PROCEDURE geofaker .point_in_place_landuse ()
98LANGUAGE plpgsql
@@ -223,8 +222,9 @@ BEGIN
223222
224223 DROP TABLE IF EXISTS faker_store_location;
225224 CREATE TEMP TABLE faker_store_location AS
226- SELECT ROW_NUMBER() OVER () AS store_id, a .place_osm_id , a .place_osm_type , a .place_name , a .road_osm_id ,
227- r .osm_type AS road_osm_type, r .name AS road_name, r .ref AS road_ref,
225+ SELECT ROW_NUMBER() OVER () AS store_id, a .place_name AS city,
226+ r .name AS street_name, r .ref AS road_ref,
227+ pgfaker .company (), pgfaker .slogan (), pgfaker .phone (),
228228 public .ST_LineInterpolatePoint (public .ST_LineMerge (r .geom ), random()) AS geom
229229 FROM selected_roads a
230230 INNER JOIN osm .road_line r ON a .road_osm_id = r .osm_id
@@ -239,149 +239,4 @@ COMMENT ON PROCEDURE geofaker.point_in_place_landuse IS 'Uses osm.landuse_polygo
239239;
240240
241241
242- CREATE FUNCTION geofaker .n_points_in_polygon(geom geometry, num_points integer )
243- RETURNS SETOF geometry
244- LANGUAGE plpgsql VOLATILE
245- COST 100
246- ROWS 1000
247- AS $$
248- DECLARE
249- target_proportion numeric ;
250- n_ret integer := 0 ;
251- loops integer := 0 ;
252- x_min float8;
253- y_min float8;
254- x_max float8;
255- y_max float8;
256- srid integer ;
257- rpoint geometry;
258- BEGIN
259- -- Get envelope and SRID of source polygon
260- SELECT ST_XMin(geom), ST_YMin(geom), ST_XMax(geom), ST_YMax(geom), ST_SRID(geom)
261- INTO x_min, y_min, x_max, y_max, srid;
262- -- Get the area proportion of envelope size to determine if a
263- -- result can be returned in a reasonable amount of time
264- SELECT ST_Area(geom)/ ST_Area(ST_Envelope(geom)) INTO target_proportion;
265- RAISE DEBUG ' geom: SRID %, NumGeometries %, NPoints %, area proportion within envelope %' ,
266- srid, ST_NumGeometries(geom), ST_NPoints(geom),
267- round(100 .0 * target_proportion, 2 ) || ' %' ;
268- IF target_proportion < 0 .0001 THEN
269- RAISE EXCEPTION ' Target area proportion of geometry is too low (%)' ,
270- 100 .0 * target_proportion || ' %' ;
271- END IF;
272- RAISE DEBUG ' bounds: % % % %' , x_min, y_min, x_max, y_max;
273-
274- WHILE n_ret < num_points LOOP
275- loops := loops + 1 ;
276- SELECT ST_SetSRID(ST_MakePoint(random()* (x_max - x_min) + x_min,
277- random()* (y_max - y_min) + y_min),
278- srid) INTO rpoint;
279- IF ST_Contains(geom, rpoint) THEN
280- n_ret := n_ret + 1 ;
281- RETURN NEXT rpoint;
282- END IF;
283- END LOOP;
284- RAISE DEBUG ' determined in % loops (% efficiency)' , loops, round(100 .0 * num_points/ loops, 2 ) || ' %' ;
285- END
286- $$
287- ;
288-
289- COMMENT ON FUNCTION geofaker.n_points_in_polygon(GEOMETRY, INT) IS ' Creates N points randomly within the given polygon. From: https://trac.osgeo.org/postgis/wiki/UserWikiRandomPoint' ;
290-
291-
292-
293- -- Ensure the required temp table exists, avoids deploy failure creating next sproc
294- CREATE TEMP TABLE IF NOT EXISTS faker_store_location
295- (
296- store_id BIGINT , place_osm_id BIGINT , place_osm_type TEXT , place_name TEXT ,
297- road_osm_id BIGINT , geom GEOMETRY
298- );
299-
300-
301- CREATE PROCEDURE geofaker .points_around_point ()
302- LANGUAGE plpgsql
303- AS $$
304- DECLARE
305- stores_to_process BIGINT ;
306- t_row faker_store_location%rowtype;
307- BEGIN
308-
309- SELECT COUNT (* ) INTO stores_to_process
310- FROM faker_store_location
311- ;
312- RAISE NOTICE ' Generating customers for % stores...' , stores_to_process;
313-
314- DROP TABLE IF EXISTS faker_customer_location;
315- CREATE TEMP TABLE faker_customer_location
316- (
317- id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,
318- store_id BIGINT NOT NULL ,
319- customer_id BIGINT NOT NULL ,
320- geom GEOMETRY(POINT , 3857 ) NOT NULL
321- );
322-
323-
324- FOR t_row IN SELECT * FROM faker_store_location LOOP
325- IF t_row .store_id % 10 = 0 THEN
326- RAISE NOTICE ' Store ID: %' , t_row .store_id ;
327- END IF;
328-
329- DROP TABLE IF EXISTS place_buffer;
330- CREATE TEMP TABLE place_buffer AS
331- SELECT store_id, geom, ST_Buffer(geom, 5000 ) AS geom_buffer
332- FROM faker_store_location
333- WHERE store_id = t_row .store_id
334- ;
335-
336- DROP TABLE IF EXISTS store_potential_customers;
337- CREATE TEMP TABLE store_potential_customers AS
338- SELECT store_id,
339- geofaker .n_points_in_polygon (geom_buffer, 1000 )
340- AS geom
341- FROM place_buffer
342- ;
343- ALTER TABLE store_potential_customers
344- ADD customer_id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY;
345-
346- -- SELECT * FROM store_potential_customers;
347- /*
348- * Using a CTE here with ST_Envelope to bbox join roads.
349- * A simple join (which looks innocent) took 45+ seconds to return 141 rows
350- * while the CTE version takes < 60 ms.
351- */
352- -- EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS)
353- WITH possible_roads AS (
354- SELECT p .store_id , p .customer_id , p .geom AS geom_customer,
355- r .geom AS geom_road,
356- ST_Distance(p .geom , r .geom ) AS distance
357- FROM osm .road_line r
358- INNER JOIN store_potential_customers p
359- ON ST_DWithin(r .geom , p .geom , 300 )
360- WHERE r .route_motor
361- ), ranked AS (
362- SELECT * , ROW_NUMBER() OVER (
363- PARTITION BY store_id, customer_id ORDER BY distance
364- ) AS rnk
365- FROM possible_roads
366- )
367- INSERT INTO faker_customer_location (store_id, customer_id, geom)
368- SELECT store_id, customer_id,
369- ST_Snap(geom_customer, geom_road, 300 ) AS geom_snapped
370- FROM ranked
371- WHERE rnk = 1
372- ;
373- COMMIT ;
374-
375- END LOOP;
376-
377- END;
378- $$;
379-
380-
381- COMMENT ON PROCEDURE geofaker .points_around_point IS ' Creates fake customer locations around a store. Locations are snapped to roads. Locations not scoped to landuse at this time. Requires faker_store_location temp table with fake store data.' ;
382-
383242COMMIT ;
384-
385-
386-
387-
0 commit comments