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