甚至在2D中分布随机点

Kez*_*Kez 2 random plot 2d distribution pseudocode

我正在尝试做一个简单的"人群"模型,需要在2D区域内分配随机点.这个半伪代码是我最好的尝试,但是在我运行它之前我就能看到很大的问题,因为对于密集的人群来说,新点太近的可能性会很快变得非常高,这使得效率非常低且容易发生失败,除非价值被微调.可能也会出现签名值,但为了简单起见,我将其留下.

int numPoints = 100;
int x[numPoints];
int y[numPoints];
int testX, testY;

tooCloseRadius = 20;
maxPointChecks = 100;
pointCheckCount = 0;

for (int newPoint = 0; newPoint < numPoints; newPoint++ ){

    //Keep checking random points until one is found with no other points in close proximity, or maxPointChecks reached.
    while (pointCheckCount < maxPointChecks){
        tooClose = false;
        // Make a new random point and check against all previous points
        testX = random(1000);
        testY = random(1000);
        for ( testPoint = 0; testPoint < newPoint; testPoint++ ){
            if  ( (isTooClose (x[testPoint] , y[testPoint], textX, testY, tooCloseRadius) ) {
            tooClose = true;
            break; // (exit for loop)
        }
        if (tooClose == false){
            // Yay found a point with some space!
            x[newPoint] = testX;
            y[newPoint] = testY;
            break; // (exit do loop)
        }
        //Too close to one of the points, start over.
        pointCheckCount++;
    }
    if (tooClose){
        // maxPointChecks reached without finding a point that has some space.
        // FAILURE DEPARTMENT
    } else {
        // SUCCESS
    }
}

// Simple Trig to check if a point lies within a circle.
(bool) isTooClose(centerX, centerY, testX, testY, testRadius){
    return (testX - centreX)^2 + (testY - centreY)^2)  < testRadius ^2
}
Run Code Online (Sandbox Code Playgroud)

在谷歌搜索主题之后,我相信我所做的就是称为拒绝采样(?),自适应拒绝采样可能是一种更好的方法,但数学太复杂了.

是否有任何优雅的方法来实现这一目标,不需要统计学学位?

Sar*_* T. 5

对于这个问题,您提出生成随机样本的最佳方法是使用Poisson Disk Sampling.

https://www.jasondavies.com/poisson-disc

现在,如果您想以简单的方式对矩形中的随机点进行采样.只需从0到最大尺寸的长度每个点采样两个值.

如果表示较小维度的值大于该维度,则抛弃该对并重试.

伪代码:

while (need more points)
begin
   range = max (rect_width, rect_height);

   x = uniform_random(0,range);
   y = uniform_random(0,range);

   if (x > rect_width) or (y > rect_height)
    continue;
   else
     insert point(x,y) into point_list;
end
Run Code Online (Sandbox Code Playgroud)

您采样两个长度中较大者的原因是,当长度不同时,使统一选择标准等效.

例如,假设一侧长度为K而另一侧长度为10K.并假设使用的数字类型的分辨率为K的1/1000,然后对于较短的一侧,只有1000个可能的值,而对于较长的一侧,有10000个可能的值可供选择.1/1000的概率与1/10000不同.简单地说,短边的坐标值比长边的坐标值大10倍 - 这意味着采样不是真正均匀的.


您希望确保生成的点与任何已生成点之间的距离不近的场景的伪代码:

while (need more points)
begin
   range = max (rect_width, rect_height)

   x = uniform_random(0,range);
   y = uniform_random(0,range);

   if (x > rect_width) or (y > rect_height)
    continue;

   new_point = point(x,y);

   too_close = false;

   for (p : all points)
   begin
     if (distance(p, new_point) < minimum_distance)
     begin
       too_close = true;
       break;
     end
   end

   if (too_close)
      continue;

   insert point(x,y) into point_list;
end
Run Code Online (Sandbox Code Playgroud)