6

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.

  • OpenJUMP can generate short multilinestrings and triangles but they are probably too simple for you. You could read some OSM data in and select some random features but perhaps that's not random enough. Perhaps you must write WKT frames LINESTRING(...) and POLYGON((...)) and fill in some points inside it. Not totally trivial because you want to avoid self-intersections but perhaps running the sketch through ST_MakeValid could help. – user30184 Jun 18 '14 at 7:32
  • There's a function to return a set of random points within a given multipolygon: trac.osgeo.org/postgis/wiki/UserWikiRandomPoint – Martin F Jun 18 '14 at 18:34
  • @martinf: point generation would be easy anyway, and I know of ways to generate them like the one you linked. Making random polygons means most of the problem. – Pavel V. Jun 19 '14 at 5:20
  • Have you considered generating random line boundaries and feeding them through MakeValid? I bet that would give some pretty complicated shapes. You could probably do something in the vein of a random walk to keep it in the same general area, maybe even a random walk plus some kind of sort if you want something a bit more regular. – jpmc26 Aug 27 '14 at 7:20
  • @jpmc26: no, I haven't considered this. Do you have some special line boundary generation algorithm in mind? For my needs my quasi-centroid algorithm seems ideal (so testing another approach is not a priority now), but you can expand your suggestion to an answer, if it is somehow better than mine, or concerns both lines and polygons. – Pavel V. Aug 27 '14 at 10:47
8

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.

| improve this answer | |
  • If you know some minor optimization, don't be afraid to edit and improve my code (and add a note starting with "EDIT by XYZ:" explaining why and how it is better). For major optimization (or if it is better only under some conditions), post your own answer. I won't accept my own answer until question of complex line generation is properly answered, at least for sake of completeness. – Pavel V. Jun 27 '14 at 11:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.