2013-02-22 23 views
1

我想有一個函數,我可以輸入一個半徑值,並說功能吐出該區域的大小圓圈。捕捉是我希望它只爲基於整數的座標。使用歐幾里德距離在網格上查找圓的區域?

有人告訴我在別處看看高斯圓問題,這看起來是正是我感興趣的,但我實在不明白它背後的數學(假設它實際上是在計算準確的我我想要)。

作爲一個方面說明,我目前使用一個修改後的圓形繪製算法,它的確產生了我期望的結果,但它看起來效率非常低(算法和我用它來獲得區)。

所以,對我來說可能的答案是這樣一個函數的實際代碼或僞代碼,如果這樣的事情存在或像高斯的圓周問題的徹底解釋和爲什麼它是/我不是在尋找什麼對於。

我希望該函數將產生結果:

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

回答

1

這是一個老問題,但我最近對同一件事的工作。你所要做的是如你所說,高斯的圈子的問題,這是有點描述here

雖然我也有困難understaning這一切的背後嚴重的數學,它或多或少地平底鍋出來的時候不使用奇怪的到外星人的符號是這樣的:

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; 

我不知道爲什麼或如何工作的,老實說我是個有點鬱悶我必須使用循環弄清楚這一點,而不是一條線,因爲它意味着表演nce是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; 

什麼這個代碼是從中心環出沿着正交線的邊緣,並且在每個點處從管線添加的距離在一個perpendicualr方向到邊緣。最後它將在四分位數中得到點數,所以它將結果翻兩番,並增加一個,因爲也有中心點。我覺得wolfram方程做了類似的事情,因爲它也乘以4並加1,但是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

我也曾經有過近日來解決這個問題,我最初的做法是,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. 將橙色點乘以8。這會給你黃色的 。
  4. 方塊粉紅點。這會給你深藍色的。然後 乘四,這會讓你綠色的。
  5. 添加軸上的點和中心的點。這給你 淺藍色和紅色。

My Gauss Circle Problem algorithm illustrated