0

我正在寻找一种方法来生成以下数字序列(这是一个像素的 8 个邻居的相对坐标,从西北像素开始,以西结束)。第一个数字是 y 坐标,第二个数字是 x 坐标:

 y,  x
 _____

 1, -1   // N-W
 1,  0   // N
 1,  1   // N-E
 0,  1   // E
-1,  1   // S-E
-1,  0   // S
-1, -1   // S-W
 0, -1   // W

我可以想出几种丑陋的方法来实现这一点,例如将坐标放入数组中,但我想知道是否有一种我没有想到的干净有效的方法。

编辑:由于我试图实现的算法的设计方式,像素必须按特定顺序(NW 到 W)迭代。

4

2 回答 2

3

仅考虑以下生成 Y 坐标的方法。

从 NW 开始,我们要实现 {1, 1, 1, 0, -1, -1, -1, 0}。这是循环给出的重复模式:

for( int i = 0; i < 8; i++ )
{
    // You can combine into one ternary if you are adventurous
    int y = (i % 4 == 3) ? 0 : 1;
    y *= (i > 3) ? -1 : 1;
}

因此,这将为 y 值生成所需的序列。

现在考虑从 NE 开始的 x 值序列:{1, 1, 1, 0, -1, -1, -1, 0 }。你可以看到它是相同的序列。

因此,我们可以从 NW 开始生成所需的序列,使用前一个循环的 2 偏移量并修改最后一个三元组以适应序列末尾的换行:

for (int i = 2; i < 10; i++ )
{
    int x = (i % 4 == 3) ? 0 : 1;
    x *= (i % 8 > 3) ? 1 : -1;   
}

现在将两者组合成一个循环是微不足道的:

for (int i = 0; i < 8; i++)
{
    int y = (i % 4 == 3) ? 0 : 1;
    y *= (i > 3) ? -1 : 1;

    int x = ( (i+2) % 4 == 3) ? 0 : 1;
    x *= ( (i+2) % 8 > 3) ? 1 : -1;
}
于 2012-11-23T23:38:15.907 回答
1

另一种可读的替代方法是显式枚举边,如下所示:

int x = -1;
int y = 1;
for (int side = 0; side < 4; side++)
{
    for (int steps = 0; steps < 2; steps++)
    {
        // use coordinates here
        printf("%d, %d\n", y, x);

        if (side == 0) { x++; }
        else if (side == 1) { y--; }
        else if (side == 2) { x--; }
        else /* if side == 3) */ { y++; }
    }
}

/*
result:
1, -1
1, 0
1, 1
0, 1
-1, 1
-1, 0
-1, -1
0, -1
*/

这具有额外的好处,即可以通过更改起始角和沿边的步数来遍历任何大小的邻域。

@louism:“我可以想出几种丑陋的方法来实现这一点,例如将坐标放入数组中”-实际上,我认为这是最好的方法。它清晰易读(与上面@ose 描述的模数算术方法不同),并且可能是最快的。

@louism:您能否对三种不同的方法(数组查找、枚举边、模运算)进行基准测试并发布结果?我会对此很感兴趣,因为它是我现在正在编写的代码中使用的东西。

于 2012-11-24T05:04:49.130 回答