[GIS] ny random data generator supporting geometry in PostGIS

postgispostgis-2.0random

I found few random data generators for PostgreSQL (such as this one), but none supporting PostGIS geometry type, other than point. Making points would be quite easy, but for lines with multiple nodes and for polygons (I need more complex polygons than simple rectangles) it would be hell to write the function myself. I would prefer using others' tools (free and opensource, if possible) instead of making them myself.

EDIT: there are algorithms generating random points within a polygon. For polygons, I would prefer a different approach: to generate quasi-centroids first and then make polygons around them. I have some idea how to do it (random starting direction or random angle from previous node + random distance from quasi-centroid). Although if I found a tool generating polygons from scratch, making a centroid or a random point within would be easy. If no one points to any such a tool in a few days, I'll make it myself and post the code as an answer.

I don't need complex line generator so much now, so I'll either make it later, or wait for some other answers. Working complex line generators will get at least +1 from me even if I found I won't really need them, and if combined by some good complex polygon generation they should merit acceptation.

Best Answer

I made and tested the functions I need. For point generation I used a simplified version of the functions in trac.osgeo.org/postgis/wiki/UserWikiRandomPoint:

CREATE OR REPLACE FUNCTION random_point( x_min integer DEFAULT 13, y_min integer DEFAULT 49, 
    x_max integer DEFAULT 16, y_max integer DEFAULT 51, srid integer DEFAULT 4326 )
RETURNS geometry AS
$func$
BEGIN
  RETURN ( 
    SELECT ST_SetSRID(
      ST_MakePoint(
        random()*(x_max - x_min) + x_min,
        random()*(y_max - y_min) + y_min
      ), srid
    ) 
  );
END
$func$ LANGUAGE plpgsql VOLATILE;

I don't need the position to be extra accurate, so I use approximate coordinates for Czech Republic.

I don't need to generate lines now. For the polygon I started from scratch, using the algorithm I described in the question (building the polygon around a quasicentroid):

--max_dist default is for WGS84 (EPSG4326) - slightly less than 200 meters
CREATE OR REPLACE FUNCTION random_polygon( qcen geometry, max_dist float DEFAULT 0.0002 )
RETURNS geometry AS
$func$
DECLARE
  i INTEGER;
  nodes geometry[];
  angle FLOAT;
  angle_start FLOAT;
  dist FLOAT;   --for polar areas, we would have too make separately lat and lon distance - lon distance would be too short otherwise
BEGIN
  -- we can skip this step if we are sure we can get only points
  -- it could handle multipoint too, but the results wouldn't be nice
  IF ST_geometryType( qcen ) != 'ST_Point' THEN
    RETURN NULL;
  END IF;

  -- PI/3 and 2/3 PI means that 
  angle_start := ( random()*1/3*PI() )::INTEGER;
  angle := angle_start;
  FOR i IN 1..20 LOOP   -- we rarely reach 20 nodes, but now we are safe from endless loop
    dist := random() * max_dist;
    SELECT array_append( nodes, ST_Translate( qcen, sin(angle)*dist, cos(angle)*dist ) ) INTO nodes;
    angle := angle + random()*2/3*PI();
    IF angle > 2*PI() THEN EXIT; END IF; 
  END LOOP;
  SELECT array_append( nodes, nodes[1] ) INTo nodes; -- assuming 1 is the lower bound
  RETURN ST_MakePolygon( ST_MakeLine( nodes ) );
END
$func$ LANGUAGE plpgsql VOLATILE;

I picked few of the resulting geometries for the following image:

resulting geometries

I don't mind when geometries intersect each other; otherwise there would be a check for this too.

Related Question