Random points inside a parallelogram

前端 未结 11 600
失恋的感觉
失恋的感觉 2020-12-02 07:43

I have a 4 side convex Polygon defined by 4 points in 2D, and I want to be able to generate random points inside it.

If it really simplifies the problem, I can limit

相关标签:
11条回答
  • 2020-12-02 08:37

    For PostGIS, this is what I am using (you might want a ward for possible infinite loops). You might export the algorithm to your programming language:

    CREATE or replace FUNCTION random_point(geometry)
    RETURNS geometry
    AS $$
    DECLARE 
        env geometry;
        corner1 geometry;
        corner2 geometry;
        minx real;
        miny real;
        maxx real;
        maxy real;
        x real;
        y real;
        ret geometry;
    begin
    
    select ST_Envelope($1) into env;
    select ST_PointN(ST_ExteriorRing(env),1) into corner1;
    select ST_PointN(ST_ExteriorRing(env),3) into corner2;
    select st_x(corner1) into minx;
    select st_x(corner2) into maxx;
    select st_y(corner1) into miny;
    select st_y(corner2) into maxy;
    loop
        select minx+random()*(maxx-minx) into x;
        select miny+random()*(maxy-miny) into y;
        select ST_SetSRID(st_point(x,y), st_srid($1)) into ret;
        if ST_Contains($1,ret) then
            return ret ;
        end if;
    end loop;
    end;
    $$
    LANGUAGE plpgsql
    volatile
    RETURNS NULL ON NULL INPUT;
    
    0 讨论(0)
  • 2020-12-02 08:40

    Your polygon is two triangles, so why not randomly select one of those, then find a random point in the triangle.

    Probably not the best solution, but it'd work.

    0 讨论(0)
  • 2020-12-02 08:40

    What kind of distribution do you want the points to have? If you don't care, the above methods will work fine. If you want a uniform distribution, the following procedure will work: Divide the polygon into two triangles, a and b. Let A(a) and A(b) be their areas. Sample a point p from the uniform distribution on the interval between 0 and A(a)+A(b). If p < A(a), choose triangle a. Otherwise, choose triangle b. Choose a vertex v of the chosen triangle, and let c and d be the vectors corresponding to the sides of the triangle. Sample two numbers x and y from the exponential distribution with unit average. Then the point (xc+yd)/(x+y) is a sample from the uniform distribution on the polygon.

    0 讨论(0)
  • 2020-12-02 08:41

    A somewhat less "naïve" approach would be to use a polygon fill algorithm, and then select points from the fill lines randomly.

    C Code Sample

    //  public-domain code by Darel Rex Finley, 2007
    
    int  nodes, nodeX[MAX_POLY_CORNERS], pixelX, pixelY, i, j, swap ;
    
    //  Loop through the rows of the image.
    for (pixelY=IMAGE_TOP; pixelY<IMAGE_BOT; pixelY++) {
    
      //  Build a list of nodes.
      nodes=0; j=polyCorners-1;
      for (i=0; i<polyCorners; i++) {
        if (polyY[i]<(double) pixelY && polyY[j]>=(double) pixelY
        ||  polyY[j]<(double) pixelY && polyY[i]>=(double) pixelY) {
          nodeX[nodes++]=(int) (polyX[i]+(pixelY-polyY[i])/(polyY[j]-polyY[i])
          *(polyX[j]-polyX[i])); }
        j=i; }
    
      //  Sort the nodes, via a simple “Bubble” sort.
      i=0;
      while (i<nodes-1) {
        if (nodeX[i]>nodeX[i+1]) {
          swap=nodeX[i]; nodeX[i]=nodeX[i+1]; nodeX[i+1]=swap; if (i) i--; }
        else {
          i++; }}
    
      //  Fill the pixels between node pairs.
      //  Code modified by SoloBold 27 Oct 2008
      //  The flagPixel method below will flag a pixel as a possible choice.
      for (i=0; i<nodes; i+=2) {
        if   (nodeX[i  ]>=IMAGE_RIGHT) break;
        if   (nodeX[i+1]> IMAGE_LEFT ) {
          if (nodeX[i  ]< IMAGE_LEFT ) nodeX[i  ]=IMAGE_LEFT ;
          if (nodeX[i+1]> IMAGE_RIGHT) nodeX[i+1]=IMAGE_RIGHT;
          for (j=nodeX[i]; j<nodeX[i+1]; j++) flagPixel(j,pixelY); }}}
    
       // TODO pick a flagged pixel randomly and fill it, then remove it from the list.
       // Repeat until no flagged pixels remain.
    
    0 讨论(0)
  • 2020-12-02 08:43

    By "general" do you mean all non-parallelogram 4-side polygons in general or all possible polygons?

    How about drawing a random line connecting the 4 sides e.g. If you have this:

    .BBBB.
    A    C
    A    C
    .DDDD.
    

    Then generate a random point on a unit square, then mark the point on the line B and D at the percentage of distance on the X axis. Do the same on line A and C using value from the Y axis.

    Then connect the point on line A to line C and line B to line D, the intersection point is then used as the random point.

    It's not uniform because rounding errors will aid certain points but it should be close if you are working with floating points values.

    Implementation should be rather easy, too, since you are already working with polygons. You should already have code that does those simple tasks.

    Here's a quick pseudocode:

    void GetRandomPoint(Polygon p, ref float x, ref float y) {
    
        float xrand = random();
        float yrand = random();
    
        float h0 = p.Vertices[0] + xrand * p.Vertices[1];
        float h1 = p.Vertices[2] + yrand * p.Vertices[3];
    
        float v0 = p.Vertices[0] + xrand * p.Vertices[2];
        float v1 = p.Vertices[1] + yrand * p.Vertices[3];
    
        GetLineIntersection(h0, h1, v0, v1, x, y);
    
    }
    
    0 讨论(0)
提交回复
热议问题