我需要循环一个弧形的圆形阵列,半径很小(就像逐个像素地画一个圆圈),但我试过的所有算法都检查了数组的重复索引(它有几次相同的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步(它获得所有坐标):
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或其他算法跳过步骤(缺少坐标):
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;
}
}
}
答案 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);
}