使用欧氏距离在网格上找到圆的区域?

时间:2013-02-22 15:24:43

标签: distance geometry area

我想要一个函数,我可以输入一个半径值并让所述函数吐出该大小圆圈的区域。问题是我希望它只对基于整数的坐标这样做。

我被其他地方告知要查看高斯的圆圈问题,这看起来正是我感兴趣的,但我并不真正理解它背后的数学(假设它实际上是准确的)在计算我想要的东西。)

作为旁注,我目前使用的是一种改进的圆绘制算法,它确实可以产生我想要的结果,但它看起来非常低效(算法和我使用它来获得该区域的方式) )。

所以,对我来说可能的答案是这样的函数的实际代码或伪代码,如果这样的东西存在或类似于对高斯圆问题的彻底解释以及为什么它不是我正在寻找的东西

我希望该函数产生的结果:

Input: Output
0: 1
1: 5
2: 13
3: 29
4: 49
5: 81
6: 113
7: 149
8: 197
9: 253

2 个答案:

答案 0 :(得分:1)

这是一个老问题,但我最近在研究同样的事情。你要做的就像你说的那样,高斯的圆圈问题,有点描述here

虽然我也很难理解这背后的严肃数学,但是当不使用奇怪的外星符号时,它或多或少地突出了这个:

1 + 4 * sum(i=0, r^2/4, r^2/(4*i+1) - r^2/(4*i+3))

在java中至少是:

int sum = 0;
for(int i = 0; i <= (radius*radius)/4; i++)
  sum += (radius*radius)/(4*i+1) - (radius*radius)/(4*i+3);
sum = sum * 4 + 1;

我不知道为什么或如何工作,说实话我有点笨拙我必须使用一个循环才能得到它而不是一行,因为它意味着性能是O(r ^ 2/4)而不是O(1)。

由于数学向导似乎不能比循环更好,我决定看看是否可以将其降低到O(r + 1)性能,我做了。所以不要使用上面的,使用下面的。 O(r ^ 2/4)是可怕的,即使我使用平方根也会变慢。

int sum = 0;
for(int x = 0; x <= radius; x++)
  sum += Math.sqrt(radius * radius - x * x);
sum = sum * 4 + 1;

这段代码的作用是沿着正交线从中心向外循环到边缘,并且在每个点处在垂直方向上添加从线到边缘的距离。最后它将具有一个quater中的点数,因此它将结果增加四倍并添加一个因为还有中心点。我觉得wolfram方程做了类似的事情,因为它也乘以4并加一,但IDK为什么它循环r ^ 2/4。

老实说,这些并不是很好的解决方案,但它似乎是最好的解决方案。如果你正在调用一个定期执行此操作的函数,那么当新的半径出现时,将结果保存在查找表中,而不是每次都进行完整的计算。


它不是你问题的一部分,但它可能与某人有关,所以无论如何我都会添加它。我个人正在努力寻找一个圆圈内的所有点,其中的单元格定义为:

(centreX - cellX)^2 + (centreY - cellY)^2 <= radius^2 + radius

这使整个事情摆脱了重击,因为额外+半径使得这不完全是毕达哥拉斯定理。这个额外的位使得圆圈在网格上看起来更具视觉吸引力,因为它们在正交边缘上没有那些小疙瘩。事实证明,是的,我的形状仍然是一个圆圈,但它使用sqrt(r ^ 2 + r)作为半径而不是r,这显然有效,但不要问我怎么做。无论如何,这意味着对我来说,我的代码略有不同,看起来更像是这样:

int sum = 0;
int compactR = ((radius * radius) + radius) //Small performance boost I suppose
for(int j = 0; j <= compactR  / 4; j++)
  sum += compactR / (4 * j + 1) - compactR / (4 * j + 3);
sum = sum * 4 + 1;

答案 1 :(得分:1)

我最近也不得不解决这个问题,我的初始方法是Numeron的问题 - 从中​​心向外迭代x轴并计算右上角的点数,然后将它们翻两番。

然后我将算法改进了3.4倍左右。 我现在所做的只是计算该圆内的一个内切正方形内有多少个点,以及该正方形与圆的边缘之间的距离(实际上是相反的顺序)。 这样,我实际上计算了圆的边缘,x轴和正方形的右边缘之间的八分之一点。 这是代码:

public static int gaussCircleProblem(int radius) {
    int allPoints=0; //holds the sum of points
    double y=0; //will hold the precise y coordinate of a point on the circle edge for a given x coordinate.
    long inscribedSquare=(long) Math.sqrt(radius*radius/2); //the length of the side of an inscribed square in the upper right quarter of the circle
    int x=(int)inscribedSquare; //will hold x coordinate - starts on the edge of the inscribed square
    while(x<=radius){
        allPoints+=(long) y; //returns floor of y, which is initially 0
        x++; //because we need to start behind the inscribed square and move outwards from there
        y=Math.sqrt(radius*radius-x*x); // Pythagorean equation - returns how many points there are vertically between the X axis and the edge of the circle for given x
    }
    allPoints*=8; //because we were counting points in the right half of the upper right corner of that circle, so we had just one-eightth
    allPoints+=(4*inscribedSquare*inscribedSquare); //how many points there are in the inscribed square
    allPoints+=(4*radius+1); //the loop and the inscribed square calculations did not touch the points on the axis and in the center
    return allPoints;
}

这是一张图片来说明:

My Gauss Circle Problem algorithm illustrated

  1. 在圆圈的右上角四舍五入一个刻有正方形(粉红色)的边长。
  2. 转到内接方格后面的下一个x坐标,开始计算橙色点,直到到达边缘。
  3. 将橙色点乘以8。这会给你黄色 的。
  4. 粉红点。这会给你深蓝色的。然后 乘以4,这将得到绿色的。
  5. 在轴上添加点,在中心添加点。这给了你 淡蓝色和红色的。