1 | | = Random Points in Polygon = |
2 | | This set-returning function generates {{{num_points}}} uniform random points within a polygon geometry {{{geom}}}. See examples below. |
3 | | {{{ |
4 | | #!sql |
5 | | CREATE OR REPLACE FUNCTION RandomPointsInPolygon(geom geometry, num_points integer) |
6 | | RETURNS SETOF geometry AS |
7 | | $BODY$DECLARE |
8 | | target_proportion numeric; |
9 | | n_ret integer := 0; |
10 | | loops integer := 0; |
11 | | x_min float8; |
12 | | y_min float8; |
13 | | x_max float8; |
14 | | y_max float8; |
15 | | srid integer; |
16 | | rpoint geometry; |
17 | | BEGIN |
18 | | -- Get envelope and SRID of source polygon |
19 | | SELECT ST_XMin(geom), ST_YMin(geom), ST_XMax(geom), ST_YMax(geom), ST_SRID(geom) |
20 | | INTO x_min, y_min, x_max, y_max, srid; |
21 | | -- Get the area proportion of envelope size to determine if a |
22 | | -- result can be returned in a reasonable amount of time |
23 | | SELECT ST_Area(geom)/ST_Area(ST_Envelope(geom)) INTO target_proportion; |
24 | | RAISE DEBUG 'geom: SRID %, NumGeometries %, NPoints %, area proportion within envelope %', |
25 | | srid, ST_NumGeometries(geom), ST_NPoints(geom), |
26 | | round(100.0*target_proportion, 2) || '%'; |
27 | | IF target_proportion < 0.0001 THEN |
28 | | RAISE EXCEPTION 'Target area proportion of geometry is too low (%)', |
29 | | 100.0*target_proportion || '%'; |
30 | | END IF; |
31 | | RAISE DEBUG 'bounds: % % % %', x_min, y_min, x_max, y_max; |
32 | | |
33 | | WHILE n_ret < num_points LOOP |
34 | | loops := loops + 1; |
35 | | SELECT ST_SetSRID(ST_MakePoint(random()*(x_max - x_min) + x_min, |
36 | | random()*(y_max - y_min) + y_min), |
37 | | srid) INTO rpoint; |
38 | | IF ST_Contains(geom, rpoint) THEN |
39 | | n_ret := n_ret + 1; |
40 | | RETURN NEXT rpoint; |
41 | | END IF; |
42 | | END LOOP; |
43 | | RAISE DEBUG 'determined in % loops (% efficiency)', loops, round(100.0*num_points/loops, 2) || '%'; |
44 | | END$BODY$ |
45 | | LANGUAGE plpgsql VOLATILE |
46 | | COST 100 |
47 | | ROWS 1000; |
48 | | ALTER FUNCTION RandomPointsInPolygon(geometry, integer) OWNER TO postgres; |
49 | | }}} |
50 | | |
51 | | == Examples == |
52 | | {{{ |
53 | | #!sql |
54 | | -- Return 10 random points/rows |
55 | | SELECT ST_AsText(RandomPointsInPolygon('POLYGON ((10 20, 30 60, 50 20, 10 20))', 10)); |
56 | | |
57 | | -- Or 10 random points as a single MultiPoint |
58 | | SELECT ST_AsText(ST_Union(geom)) |
59 | | FROM RandomPointsInPolygon('POLYGON ((10 20, 30 60, 50 20, 10 20))', 10) AS geom |
60 | | }}} |
61 | | |
62 | | Now for a more complicated and practical example using a geopolitical polygon of the [http://www.aprsworld.net/gisdata/world/uncompressed/ world] table, create 10000 random points in India: |
63 | | {{{ |
64 | | #!sql |
65 | | CREATE TABLE india_random_points |
66 | | ( |
67 | | gid serial NOT NULL, |
68 | | CONSTRAINT india_random_points_pkey PRIMARY KEY (gid) |
69 | | ); |
70 | | SELECT AddGeometryColumn('india_random_points', 'geom', 4326, 'POINT', 2); |
71 | | |
72 | | # Populate table with 10000 random points within India |
73 | | INSERT INTO india_random_points(geom) |
74 | | SELECT RandomPointsInPolygon(geom, 10000) |
75 | | FROM world WHERE name='INDIA'; |
76 | | }}} |
77 | | |
78 | | == See also == |
79 | | * UserWikiRandomPoint : create one random point |
| 1 | UserWikiRandomPoint |