Math 确定以0,0为中心的栅格坐标的索引,并沿围绕原点的螺旋线递增

Math 确定以0,0为中心的栅格坐标的索引,并沿围绕原点的螺旋线递增,math,Math,这是一个与以下相反的问题: 这两种方式是: 索引->坐标(完成,见上面的问题) 坐标->索引(我的问题) 我一直坚持的部分是从原始坐标中获取扇区,而没有大量丑陋的逻辑分支 有没有简单的算术方法来确定扇区?如何反转此函数以获取坐标对并返回索引?考虑在不改变方向的情况下所采取的步骤数。你会发现顺序是1,1,2,2,3,3,4,4,5,5,…模式应该很明显。现在,在四条这样的直边之后,你差不多回到了同一个角落。因此,您可以找到连接这些角点的线的索引: c0: 0, 1+1+2+2, …+

这是一个与以下相反的问题:

这两种方式是: 索引->坐标(完成,见上面的问题) 坐标->索引(我的问题)

我一直坚持的部分是从原始坐标中获取扇区,而没有大量丑陋的逻辑分支


有没有简单的算术方法来确定扇区?如何反转此函数以获取坐标对并返回索引?

考虑在不改变方向的情况下所采取的步骤数。你会发现顺序是1,1,2,2,3,3,4,4,5,5,…模式应该很明显。现在,在四条这样的直边之后,你差不多回到了同一个角落。因此,您可以找到连接这些角点的线的索引:

c0: 0,       1+1+2+2, …+3+3+4+4, …+5+5+6+6, …+7+7+8+8, …
c1: 1,     …+1+2+2+3, …+3+4+4+5, …
c2: 1+1,   …
c3: 1+1+2, …
对于每一个,你都可以写一个公式。第一种是这样的:

c0[i] = sum((2*i - 1) + (2*i - 1) + (2*i) + (2*i)) = sum(8*i - 2)
现在。它会告诉你

c0[i] = 4i² + 2i
所以,如果有人给你一个索引n,你可以通过,取正解,然后四舍五入到整数,来求解你最后一次访问那条边线。您可以对其他边缘线执行相同的操作,也可以接受在最坏的情况下绕中心旋转一整圈。如果一整圈意味着四个星光区段,你不想一场接一场地走

Wolfram Alpha还打印序列的前几个元素:6,20,42,72110。您可以使用它来查看,并找到其中一条注释的内容

写入0,1,2,。。。顺时针螺旋;序列在4条对角线中的一条上给出数字

但我可以向你保证,它同样适用于逆时针螺旋线…

这是一个例子,如果你在螺旋线上画素数的位置,它有一些有趣的性质

25|26|27|28|29|30
24| 9|10|11|12|31
23| 8| 1| 2|13|32
22| 7| 0| 3|14|33
21| 6| 5| 4|15|34
20|19|18|17|16|35
 ........     |36
首先要注意的是平方数的位置。这些位于对角线上,左上对角线为奇数正方形,右下对角线为偶数正方形

25|  |  |  |  |  
  | 9|  |  |  |
  |  | 1|  |  |
  |  | 0|  |  |
  |  |  | 4|  |
  |  |  |  |16|
 ........     |36
让我们看看这些有坐标(x,y)的对角线

首先注意对角线,如果y>=0和x=1-y,我们位于左上角的对角线上,值为
(2 y-1)^2
(1-2x)^2

如果y=0且x>=1-y,则xpos=x+y-1。该值将为
(2 y-1)^2+pos

底部的水平行有y=y,x=0&&(x>=1-y&&x=y&&x0){ pos=-x-y; squ=4*x*x; //左侧垂直行 }否则{ squ=(1-2*x)*(1-2*x); pos=x+y-1; } 返回squ+pos; } 我在上有一个javascript实现。这会使数字上升到99

一个稍微简单的函数是

spiral = function(x,y) {
    var res;
    var u = x+y;
    var v = x-y;
    if(u>0) {
        if(v>=0) {
            x <<= 1;
            res = x*(x-1) + v;
        } else {
            y <<= 1;
            res = y*(y-1) + v;
        }
    } else {
        if(v<0) {
            x <<= 1;
            res = -x*(1-x) - v;
        } else {
            y <<= 1;
            res = -y*(1-y) - v;
        }
    }
    return res;
}
spiral=函数(x,y){
var-res;
var u=x+y;
var v=x-y;
如果(u>0){
如果(v>=0){

x这将是一个非常晚的答案,但我无论如何都要回答,因为我自己也有这个问题,而且从来没有真正找到解决其他答案问题的可靠方法。这里是对所有其他答案的补充答案,因为为什么不:

以下是我找到的解决方案的一些伪代码:

// n is the number in the spiral at (x, y)
// m is an intermediate step towards calculating n
m = 2 * max(abs(x), abs(y)) - (x > -y) // this relies on booleans being evaluated as 0 or 1
n = m^2 + abs(x + (-1)^m * floor((m + 1) / 2)) + abs(y - (-1)^m * floor(m / 2))
Python 3中:(最新测试版本为3.7.0)

在JavaScript中:

function number_in_spiral(x, y)
{
    var m = 2 * Math.max(Math.abs(x), Math.abs(y)) - (x > -y);
    return m * m + Math.abs(x + Math.pow(-1, m) * Math.floor((m + 1) / 2)) + 
                   Math.abs(y - Math.pow(-1, m) * Math.floor(m / 2));
}
请记住,这个公式中的y向上增加,这在很多情况下都不理想。在这种情况下,要么将输入y乘以-1,要么在公式中的每个实例中用-y替换y


我希望这对某些人有用。如果没有,至少在我4年后不可避免地回到这个问题上时,它对我有用。

谢谢你的回答。除了初始方向(1索引位置)是向上而不是向左(如OP中的链接)外,它是有效的.我试过搞乱这个函数,但还没有完全解决这个问题。
// n is the number in the spiral at (x, y)
// m is an intermediate step towards calculating n
m = 2 * max(abs(x), abs(y)) - (x > -y) // this relies on booleans being evaluated as 0 or 1
n = m^2 + abs(x + (-1)^m * floor((m + 1) / 2)) + abs(y - (-1)^m * floor(m / 2))
import math

def number_in_spiral(x, y):
    m = 2 * max(abs(x), abs(y)) - (x > -y)
    return m * m + abs(x + pow(-1, m) * math.floor((m + 1) / 2)) + \
                   abs(y - pow(-1, m) * math.floor(m / 2))
function number_in_spiral(x, y)
{
    var m = 2 * Math.max(Math.abs(x), Math.abs(y)) - (x > -y);
    return m * m + Math.abs(x + Math.pow(-1, m) * Math.floor((m + 1) / 2)) + 
                   Math.abs(y - Math.pow(-1, m) * Math.floor(m / 2));
}