【问题标题】:How do I compute the linear index of a 3D coordinate and vice versa?如何计算 3D 坐标的线性索引,反之亦然?
【发布时间】:2012-06-09 19:34:28
【问题描述】:

如果我有一个点 (x, y z),我如何找到该点的线性索引 i?我的编号方案是 (0,0,0) is 0, (1, 0, 0) is 1, . . ., (0, 1, 0) 是最大 x 维度, .... 另外,如果我有一个线性坐标 i,我如何找到 (x, y, z)? 我似乎在谷歌上找不到这个,所有的结果都充满了其他不相关的东西。谢谢!

【问题讨论】:

  • 坐标总是由整数组成吗?你可以有负坐标吗?除了 x 轴之外,您是否有任何轴的最大值?
  • 每个坐标的分割数相同还是不同?最后一点用(N,N,N)(N1,N2,N3)表示?

标签: arrays math multidimensional-array matrix coordinate-transformation


【解决方案1】:

如果你的坐标没有上限,你可以从origo和向外编号。一层一层。

(0,0,0) -> 0
(0,0,1) -> 1
(0,1,0) -> 2
(1,0,0) -> 3
(0,0,2) -> 4
   :       :
(a,b,c) -> (a+b+c)·(a+b+c+1)·(a+b+c+2)/6 + (a+b)·(a+b+1)/2 + a

逆向更难,因为您必须求解一个 3 次多项式。

m1 = InverseTetrahedralNumber(n)
m2 = InverseTriangularNumber(n - Tetra(m1))
a = n - Tetra(m1) - Tri(m2)
b = m2 - a
c = m1 - m2

在哪里

InverseTetrahedralNumber(n) = { x ∈ ℕ | Tetra(n) ≤ x < Tetra(n+1) } 
Tetra(n) = n·(n+1)·(n+2)/6 
InverseTriangularNumber(n) = { x ∈ ℕ | Tri(n) ≤ x < Tri(n+1) } 
Tri(n) = n·(n+1)/2

InverseTetrahedralNumber(n) 可以通过large analytic solution 计算得出,也可以使用some numeric method 进行搜索。


这是我对代数解决方案 (javascript) 的尝试。我正在使用替换 p = a+b+cq = a+br = a 来简化方程。

function index(a,b,c) {
    var r = a;
    var q = r + b;
    var p = q + c;
    return (p*(p+1)*(p+2) + 3*q*(q+1) + 6*r)/6;
}

function solve(n) {
    if (n <= 0) {
        return [0,0,0];
    }

    var sqrt = Math.sqrt;
    var cbrt = function (x) { return Math.pow(x,1.0/3); };

    var X = sqrt(729*n*n - 3);
    var Y = cbrt(81*n + 3*X);
    var p = Math.floor((Y*(Y-3)+3)/(Y*3));
    if ((p+1)*(p+2)*(p+3) <= n*6) p++;
    var pp = p*(p+1)*(p+2);

    var Z = sqrt(72*n+9-12*pp);
    var q = Math.floor((Z-3)/6);
    if (pp + (q+1)*(q+2)*3 <= n*6) q++;
    var qq = q*(q+1);

    var r = Math.floor((6*n-pp-3*qq)/6);
    if (pp + qq*3 + r*6 < n*6) r++;

    return [r, q - r, p - q];
}

【讨论】:

    【解决方案2】:

    有几种方法可以将 3d 坐标映射到单个数字。这是一种方法。

    某个函数 f(x,y,z) 给出坐标 (x,y,z) 的线性索引。它有一些我们想要导出的常数 a,b,c,d,这样我们就可以编写一个有用的转换函数。

    f(x,y,z) = a*x + b*y + c*z + d
    

    您已指定 (0,0,0) 映射到 0。所以:

    f(0,0,0) = a*0 + b*0 + c*0 + d = 0
    d = 0
    f(x,y,z) = a*x + b*y + c*z
    

    这就解决了。 您已指定 (1,0,0) 映射到 1。所以:

    f(1,0,0) = a*1 + b*0 + c*0 = 1
    a = 1
    f(x,y,z) = x + b*y + c*z
    

    这就解决了。 让我们任意决定 (MAX_X, 0, 0) 之后的下一个最大数是 (0,1,0)。

    f(MAX_X, 0, 0) = MAX_X
    f(0, 1, 0) = 0 + b*1 + c*0 = MAX_X + 1
    b = MAX_X + 1
    f(x,y,z) = x + (MAX_X + 1)*y + c*z
    

    这就解决了。 让我们任意决定(MAX_X, MAX_Y, 0)之后的下一个最大数是(0,0,1)。

    f(MAX_X, MAX_Y, 0) = MAX_X + MAX_Y * (MAX_X + 1)
    f(0,0,1) = 0 + (MAX_X + 1) * 0  + c*1 = MAX_X + MAX_Y * (MAX_X + 1) + 1
    c = MAX_X + MAX_Y * (MAX_X + 1) + 1
    c = (MAX_X + 1) + MAX_Y * (MAX_X + 1)
    c = (MAX_X + 1) * (MAX_Y + 1)
    

    现在我们知道了 a、b、c 和 d,我们可以编写如下函数:

    function linearIndexFromCoordinate(x,y,z, max_x, max_y){
        a = 1
        b = max_x + 1
        c = (max_x + 1) * (max_y + 1)
        d = 0
        return a*x + b*y + c*z + d
    }
    

    您可以通过类似的逻辑从线性索引中获取坐标。我有一个非常棒的演示,这个页面太小而无法包含。所以我就跳过数学课,只给你最后的方法。

    function coordinateFromLinearIndex(idx, max_x, max_y){
        x =  idx % (max_x+1)
        idx /= (max_x+1)
        y = idx % (max_y+1)
        idx /= (max_y+1)
        z = idx
        return (x,y,z)
    }
    

    【讨论】:

    • 很好的答案!我想我会为你 375 年以上的奇妙证明感到困惑(但现在它是有道理的)。非常感谢。
    • @Kevin 你好!我意识到这个问题已经有将近 2 年的历史了,但我想知道:你可能有你提到的那个数学讲座的链接吗?你的方法看起来非常棒,所以我很好奇这背后的数学原理。
    • 您不应该在接受答案后更改编辑中的代码 - 它应该在评论中完成。
    • @MarkAnderson,如果我没记错的话,数学课只存在于我正在撰写coordinateFromLinearIndex 的时候。我可以编辑答案以显示我是如何得出最终代码块的,但首先我需要记住我是如何做到的 :-)
    • 我可以让您对divmod() function 的优点感兴趣吗?我确信coordinateFromLinearIndex() 可以从其独特的属性中受益。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-30
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    相关资源
    最近更新 更多