我们处于二维空间的任何给定位置。该空间分为二次单元格。我想按照它们与我们的距离顺序遍历给定距离内的所有单元格。例如,这可能发生在尺寸增大的环中。距离几乎相等的细胞顺序无关紧要。
如何以距离到给定位置的顺序循环这些单元格?
答案 0 :(得分:2)
如果对整数网格坐标的简化是正确的(正如你在“几乎相等的距离”上所说的那样),你可以通过下面的代码逐渐增加距离逐个细胞。如果您的起点不同于(0,0),则只需将其添加到每个生成的点。关键的想法是:
(d,0)
开始,我们以d
的逆时针方向迭代地寻找具有“相似”距离(整数部分= (0,0)
)的相邻点,直到我们到达起点以下是代码:
#include <cmath>
#include <vector>
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
int dist(double dx, double dy)
{
return (int)sqrt(dx*dx + dy*dy);
}
typedef std::pair<int,int> TPoint;
typedef std::vector<TPoint> TPoints;
void generateNeighbourRing(int d, TPoints& ring)
{
int dx = d;
int dy = 0;
do
{
ring.push_back(TPoint(dx,dy));
int nx = -sgn(dy);
int ny = sgn(dx);
if (nx != 0 && dist(dx+nx, dy) == d)
dx += nx;
else if (ny != 0 && dist(dx, dy+ny) == d)
dy += ny;
else
{
dx += nx;
dy += ny;
}
} while (dx != d || dy != 0);
}
int main()
{
TPoints points;
const int d_max = 4;
for (int d = 0; d <= d_max; ++d)
generateNeighbourRing(d, points);
printf("spiral for dmax=%d (%d points):\n", d_max, points.size());
for (unsigned int i=0; i<points.size(); ++i)
printf(" (%d,%d),", points[i].first, points[i].second);
printf("\n");
}
让我们首先看一下图像,其中与中心单元格距离相等的单元格具有相同的颜色(一旦距离被截断,一旦距离被舍入):
- - - - - -
使用(dx,dy)
,我们以相等的距离迭代环的单元格; (nx,ny)
是一种法向量,沿每个半轴和每个象限内是常数:
每个区域的黑色箭头显示(nx,ny)
;蓝色箭头表示首先搜索具有相等距离的(直接)邻居的方向。
接下来,我们需要考虑具有相等距离的邻居的哪些配置是可能的。由于象限是旋转对称的,因此足以观察第一象限。两个直接邻居之间到中心小区的距离可以相差至多1;对角线朝向或远离中心,距离相差1或2:
。 。 。
(这源于直接的不等式。)重要的结论是不能发生相等距离的2x2块;最多4个邻居可以有相同的距离形成“之字形”:
。 。 。
另一个重要结论是每个细胞至少有2个具有相等距离的邻居,同样仅在某些配置中。由此可以推断,如果沿着蓝色箭头的邻居具有不同的距离,则沿着黑色箭头的邻居具有相同的距离。因此,放入变量ring
的所有点都具有距离d
。 (请注意,在第二个else
- 分支中,不会检查距离。)
接下来我们将终止do ... while
- 循环。注意,对于每次迭代,线(0,0) - (dx,dy)与正x轴之间的角度增加。由于距离保持不变,我们最终将离开当前象限并进入下一个象限。因为沿着半轴,每一个距离都会出现,一旦我们最终到达起点(d,0)。
由此可以得出两点都没有得到两点:在generateNeighbourRing
的一次调用中,再次开始do ... while
循环的迭代,同样的点再次导致无限循环,因此与终止。在generateNeighbourRing
的几次调用中,由于到中心单元的距离不同,所有点都不同。
查看具有相同距离的邻居的可能配置,还可以显示将收集给定距离d
的所有点。