2012-01-25 68 views
10

给定任何特定的矩形(x1,y1) - (x2,y2),如何在其边界上生成一个随机点?在均匀分布的矩形边界上生成一个随机点

我想出了一些方法,但它似乎应该有一个非常规范的方式来做到这一点。首先,我认为我会在矩形内生成一个随机点并将其夹到最近的一侧,但分布看起来并不均匀(点几乎从不落在短边上)。其次,我随机选择一边,然后在那边选择一个随机点。代码有点笨重,也不统一 - 但是正好相反(短边有长边获得积分的机会)。最后,我一直在考虑将矩形“展开”成一条线,然后在线上选取一个随机点。我认为这会产生一个统一的分布,但我想我会在走上这条路之前问这里。

+1

我倒是觉得,在概念上,不管你实际上如何实现它的 “展开” 的做法将是最好的。 – Lazarus

+2

你最后的想法听起来不错。这就是我要做的。 – yurib

+0

我认为这属于http://math.stackexchange.com/;但你的第三种方法感觉很扎实。 – ANeves

回答

14

你最后的做法是我只会从阅读你的标题建议。去那。如果你选择了一边的概率与边长成正比,你的第二种方法(随机选择一边)会起作用。

+0

好主意re:选择边的概率。 –

2

你最后的建议对我来说似乎最好。

将周长视为一条长度为[长度为2*a + 2*b]的长线,在其中生成一个随机数,计算该点在矩形上的位置[假设它从某个任意点开始,哪个并不重要] 。

它只需要一个随机,因此相对便宜[随机有时是昂贵的操作]。

这也是一致的,并且证明它微不足道,偶然的机会会让你到达每个点[假设随机函数是统一的,当然]。

3

如果按照“周长上的随机点”,实际上意味着“从整周范围内的均匀随机分布中选择的点”,那么是的,您的“展开”方法是正确的。

但应该提到的是,您以前的做法有资格是“周边的随机点”,只是分布不均匀。

+0

+1指出“随机”与“均匀分布”之间的区别。 –

1

例如:

static Random random = new Random(); 

/** returns a point (x,y) uniformly distributed 
    * in the border of the rectangle 0<=x<=a, 0<=y<=b 
    */ 
public static Point2D.Double randomRect(double a, double b) { 
    double x = random.nextDouble() * (2 * a + 2 * b); 
    if (x < a) 
     return new Point2D.Double(x, 0); 
    x -= a; 
    if (x < b) 
     return new Point2D.Double(a, x); 
    x -= b; 
    if (x < a) 
     return new Point2D.Double(x, b); 
    else 
     return new Point2D.Double(0, x-a); 
} 
4

这里是Objective-C中展开的想法,似乎是工作的,不是吗:)

//randomness macro 
#define frandom (float)arc4random()/UINT64_C(0x100000000) 
#define frandom_range(low,high) ((high-low)*frandom)+low 

//this will pick a random point on the rect edge 
- (CGPoint)pickPointOnRectEdge:(CGRect)edge { 
    CGPoint pick = CGPointMake(edge.origin.x, edge.origin.y); 
    CGFloat a = edge.size.height; 
    CGFloat b = edge.size.width; 
    CGFloat edgeLength = 2*a + 2*b; 

    float randomEdgeLength = frandom_range(0.0f, (float)edgeLength); 

    //going from bottom left counter-clockwise 
    if (randomEdgeLength<a) { 
    //left side a1 
    pick = CGPointMake(edge.origin.x, edge.origin.y + a); 
    } else if (randomEdgeLength < a+b) { 
    //top side b1 
    pick = CGPointMake(edge.origin.x + randomEdgeLength - a, edge.origin.y + edge.size.height); 
    } else if (randomEdgeLength < (a + b) + a) { 
    //right side a2 
    pick = CGPointMake(edge.origin.x + edge.size.width, edge.origin.y + randomEdgeLength - (a+b)); 
    } else { 
    //bottom side b2 
    pick = CGPointMake(edge.origin.x + randomEdgeLength - (a + b + a), edge.origin.y); 
    } 
    return pick; 
} 
1

这里是我的均匀分布实施(假设X1 < X2和Y1 < Y2):

void randomPointsOnPerimeter(int x1, int y1, int x2, int y2) { 
    int width = abs(x2 - x1); 
    int height = abs(y2 - y1); 
    int perimeter = (width * 2) + (height * 2); 

    // number of points proportional to perimeter 
    int n = (int)(perimeter/8.0f); 

    for (int i = 0; i < n; i++) { 
     int x, y; 
     int dist = rand() % perimeter; 

     if (dist <= width) { 
      x = (rand() % width) + x1; 
      y = y1; 
     } else if (dist <= width + height) { 
      x = x2; 
      y = (rand() % height) + y1; 
     } else if (dist <= (width * 2) + height) { 
      x = (rand() % width) + x1; 
      y = y2; 
     } else { 
      x = x1; 
      y = (rand() % height) + y1; 
     } 

     // do something with (x, y)... 

    } 
} 
0

这是我在Javascri实施PT

 function pickPointOnRectEdge(width,height){ 
      var randomPoint = Math.random() * (width * 2 + height * 2); 
      if (randomPoint > 0 && randomPoint < height){ 
       return { 
        x: 0, 
        y: height - randomPoint 
       } 
      } 
      else if (randomPoint > height && randomPoint < (height + width)){ 
       return { 
        x: randomPoint - height, 
        y: 0 
       } 
      } 
      else if (randomPoint > (height + width) && randomPoint < (height * 2 + width)){ 
       return { 
        x: width, 
        y: randomPoint - (width + height) 
       } 
      } 
      else { 
       return { 
        x: width - (randomPoint - (height * 2 + width)), 
        y: height 
       } 
      } 
     } 
0

想我会尝试这样做没有分支,表达X和Y COORDS为走“展开的”矩形随机数的函数。

X = Blue, Y = Red

JS:

function randomOnRect() { 
    let r = Math.random(); 
    return [Math.min(1, Math.max(0, Math.abs((r * 4 - .5) % 4 - 2) - .5)), 
      Math.min(1, Math.max(0, Math.abs((r * 4 + .5) % 4 - 2) - .5))] 
}