【问题标题】:Find area of circle on a grid using euclidean distance?使用欧几里德距离在网格上查找圆的区域?
【发布时间】:2013-02-08 06:20:08
【问题描述】:

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

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

作为旁注,我目前使用一种修改过的圆形绘图算法,它确实产生了我想要的结果,但它似乎非常低效(算法和我使用它来获取区域的方式)。

因此,对我而言,可能的答案是此类函数的实际代码或伪代码(如果存在这样的事情)或类似高斯圆问题的彻底解释以及为什么它是/不是我正在寻找的东西.

我希望函数产生的结果:

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

【问题讨论】:

    标签: distance geometry area


    【解决方案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;
    

    这段代码的作用是从中心向外沿一条正交线循环到边缘,并在每个点添加垂直方向上从线到边缘的距离。最后它会有一个四分之一的点数,所以它将结果翻了两番并加了一个,因为还有中心点。我觉得 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;
    

    【讨论】:

      【解决方案2】:

      我最近也不得不解决这个问题,我最初的方法是 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;
      }
      

      这里有一张图片来说明:

      1. 在圆的右上四分之一处向下取整内切正方形(粉红色)的边长。
      2. 转到内接正方形后面的下一个 x 坐标,开始计算橙色点,直到到达边缘。
      3. 将橙色点乘以八。这会给你黄色 那些。
      4. 将粉红色的点平方​​。这会给你深蓝色的。然后 乘以四,这会让你得到绿色的。
      5. 添加轴上的点和中心的点。这给你 浅蓝色的和红色的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-03
        • 2013-12-08
        • 2013-03-02
        相关资源
        最近更新 更多