循环遍历圆形的数组而不重复索引

时间:2016-11-24 16:10:14

标签: algorithm geometry trigonometry pseudocode

我需要循环一个弧形的圆形阵列,半径很小(就像逐个像素地画一个圆圈),但我试过的所有算法都检查了数组的重复索引(它有几次相同的x和y) )。 我的半径为3,圆形28个元素(未填充),但算法迭代360次。我可以在做某事之前检查x或y是否发生变化,但这很蹩脚。

我的代码现在:

for (int radius = 1; radius < 6; radius++)
{
    for (double i = 0; i < 360; i += 1)
    {
        double angle = i * System.Math.PI / 180;
        int x = (int)(radius * System.Math.Cos(angle)) + centerX;
        int y = (int)(radius * System.Math.Sin(angle)) + centerY;

        // do something
        // if (array[x, y]) ....
    }
}      

PS:我不能使用中点圆,因为我需要从2到6增加半径,而不是每个索引都得到,因为他的圆圈不是真的(根据三角学)

编辑: 我真正需要的是从边缘开始逐边扫描一个完整的圆圈。

360步(它获得所有坐标):

Full scan

for (int radius = 2; radius <= 7; radius++)
{
    for (double i = 0; i <= 360; i += 1)
    {
        double angle = i * System.Math.PI / 180;
        int x = (int)(radius * System.Math.Cos(angle));
        int y = (int)(radius * System.Math.Sin(angle));
        print(x, y, "X");
    }
}

使用Midpoint Circle或其他算法跳过步骤(缺少坐标):

Midpoint Circle Algorithm

for (int radius = 2; radius <= 7; radius++)
{
    int x = radius;
    int y = 0;
    int err = 0;
    while (x >= y)
    {
        print(x, y, "X");
        print(y, x, "X");
        print(-y, x, "X");
        print(-y, x, "X");
        print(-x, y, "X");
        print(-x, -y, "X");
        print(-y, -x, "X");
        print(y, -x, "X");
        print(x, -y, "X");

        y += 1;
        err += 1 + 2 * y;
        if (2 * (err - x) + 1 > 0)
        {
            x -= 1;
            err += 1 - 2 * x;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

这里有两种算法思路:一种是光栅化圆形。 OP代码在这方面提供了几个改进的机会:(a)不需要对整个360度圆采样,意识到圆在两个轴上是对称的。 (x,y)可以在其他三个象限中反映为(-x,y),( - x,-y)和(x,-y)。 (b)环路上的台阶应与曲率有关。一个简单的启发式方法是使用半径作为步骤。所以......

let step = MIN(radius, 90)
for (double i=0; i<90; i += step) {
   add (x,y) to results
   reflect into quadrants 2,3,4 and add to results
}

通过这些改进,您可能不再关心生成的重复样本。如果你仍然这样做,那么独立于圆圈的第二个想法是如何散列一对整数。这里有一篇很好的文章:Mapping two integers to one, in a unique and deterministic way

简而言之,我们从x,y对中计算出一个int,它保证唯一映射,然后检查是否有重复...

cantor(x, y) = 1/2(x + y)(x + y + 1) + y

这仅适用于x,y的正值,这正是您所需要的,因为我们只是在第一象限中计算(然后反映)。对于每一对,检查它们是否是唯一的

let s = an empty set
int step = MIN(radius, 90)
for (double i=0; i<90; i += step) {
    generate (x,y)
    let c = cantor(x,y)
    if (not(s contains c)) {
        add (x,y) to results
        reflect into quadrants 2,3,4 and add to results
        add c to s
    }
}

答案 1 :(得分:0)

知道了!

它不漂亮,但为我工作。

int maxRadius = 7;

for (int radius = 1; radius <= maxRadius; radius++)
{
    x = position.X - radius;
    y = position.Y - radius;
    x2 = position.X + radius;
    y2 = position.Y + radius;
    for (int i = 0; i <= radius * 2; i++)
    {
        if (InCircle(position.X, position.Y, x + i, y, maxRadius)) // Top X
            myArray[position, x + i, y];    // check array

        if (InCircle(position.X, position.Y, x + i, y2, maxRadius)) // Bottom X
            myArray[position, x + i, y2];    // check array

        if (i > 0 && i < radius * 2)
        {
            if (InCircle(position.X, position.Y, x, y + i, maxRadius)) // Left Y
                myArray[position, x, y + i];    // check array  

            if (InCircle(position.X, position.Y, x2, y + i, maxRadius)) // Right Y
                myArray[position, x2, y + i];    // check array   
        }
    }
}


public static bool InCircle(int originX, int originY, int x, int y, int radius)
{
    int dx = Math.Abs(x - originX);
    if (dx > radius) return false;
    int dy = Math.Abs(y - originY);
    if (dy > radius) return false;
    if (dx + dy <= radius) return true;
    return (dx * dx + dy * dy <= radius * radius);
}