在矩形的周长上生成随机点,均匀分布

时间:2012-01-25 15:57:02

标签: algorithm math graphics

给定任何特定的矩形(x1,y1) - (x2,y2),如何在其周边生成随机点?

我已经提出了一些方法,但似乎应该采用一种非常规范的方法来实现它。

首先,我以为我会在矩形内生成一个随机点并将其夹到最近的一侧,但分布看起来并不均匀(点几乎从不落在短边上)。其次,我随机选了一个侧面然后在那边选择了一个随机点。代码有点笨拙而且也不统一 - 但是恰恰相反(短边有相同的机会获得积分作为长边)。最后,我一直在考虑将矩形“展开”成一行并在线上选择一个随机点。我认为这会产生统一的分布,但我想在走上这条道路之前我会问这里。

8 个答案:

答案 0 :(得分:14)

你的最后一种方法就是我在阅读你的标题时所建议的。去吧。如果您选择一个概率与边长成比例的一侧,那么您的第二种方法(随机选择一侧)将起作用。

答案 1 :(得分: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;
}

答案 2 :(得分:3)

如果通过'周边的随机点'你实际上意味着'从周长的均匀随机分布中选择的点',那么是的,你的'展开'方法是正确的。

但是应该提到的是,你以前的两种方法都限定是一个“周边的随机点”,只是非均匀分布。

答案 3 :(得分:2)

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

将周长视为[长度为2*a + 2*b]的单个长行,在其中生成一个随机数,计算该点在矩形上的位置[假设它从某个任意点开始,它不会这个问题。

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

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

答案 4 :(得分: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);
 }

答案 5 :(得分:1)

这是我的均匀分布实现(假设x1&lt; x2和y1&lt; 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)...

    }
}

答案 6 :(得分:0)

这是我在Javascript中的实现

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

答案 7 :(得分:0)

想象一下,我会尝试在没有分支的情况下做到这一点,将X和Y坐标表示为行走“展开”矩形的随机数的函数。

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))]
}