【问题标题】:Manhattan Distance between tiles in a hexagonal grid曼哈顿六边形网格中瓷砖之间的距离
【发布时间】:2011-07-02 08:54:53
【问题描述】:

对于方形网格,图块 A 和 B 之间的欧式距离为:

distance = sqrt(sqr(x1-x2)) + sqr(y1-y2))

对于被限制在方形网格中移动的演员,曼哈顿距离是我们必须行进的实际距离的更好衡量标准:

manhattanDistance = abs(x1-x2) + abs(y1-y2))

如何获得六边形网格中两块瓷砖之间的曼哈顿距离,如下面的红线和蓝线所示?

【问题讨论】:

  • 我不确定你的问题是否有意义。你的意思是,你如何测量红线或蓝线的长度?
  • 这个问题看起来不太合理,因为它描述了方格上的欧几里得距离,但似乎要求的是六边形格上的曼哈顿距离。
  • 对不起,我的意思是通过最短路径之一从 A 移动到 B 的次数。

标签: algorithm path distance hexagonal-tiles


【解决方案1】:

我曾经在游戏中设置了一个六边形坐标系,使 y 轴与 x 轴成 60 度角。这避免了奇偶行的区别。


(来源:althenia.net

这个坐标系中的距离是:

dx = x1 - x0
dy = y1 - y0

if sign(dx) == sign(dy)
    abs(dx + dy)
else
    max(abs(dx), abs(dy))

您可以将 (x', y) 从您的坐标系转换为 (x, y)在这个使用:

x = x' - floor(y/2)

所以dx 变成:

dx = x1' - x0' - floor(y1/2) + floor(y0/2)

使用整数除法实现此操作时要小心舍入。在 C 中,int y floor(y/2)(y%2 ? y-1 : y)/2

【讨论】:

  • 我只是在撰写类似的答案,所以 +1。但是,“整数除法”对于坐标变换是不正确的。 y/2 必须是 floor (y / 2),其中 / 产生有理数,floor 向负无穷大舍入。
  • @Svante - 谢谢。这是我想做的伪代码,当然是四舍五入:)
  • 谢谢你,阿兹。这正是我所需要的。
  • 如果翻转y轴,则需要将“abs(dx + dy)”改为“abs(dx) + abs(dy)”。 (如果 y 轴保持不变,这也有效,因此它也是一种更通用的算法。)
  • @SorenJohnson 改变 abs(dx + dy) 是不够的,你还需要将 if 语句更改为 sign(dx) != sign(dy) (这只是咬我,就是这样我知道...)另外,如果有人想知道,sign() 是一个函数,如果数字为负数,则返回 -1,如果为零,则返回零,如果为正数,则返回 1。
【解决方案2】:

我假设您想要在图中确定的两个图块的中心之间的平面中的欧几里得距离。我想这可以从图中得出。对于任何 x 和 y,从瓦片中心 (x, y) 到瓦片中心 (x + dx, y) 的向量是 (dx, 0)。从瓦片中心 (x, y) 和 (x, y + dy) 的向量是 (-dy / 2, dy*sqrt(3) / 2)。一个简单的向量加法给出了一个在 (x, y) 和 (x + dx, y + dy) 之间的 (dx - (dy / 2), dy * sqrt(3) / 2) 的向量,对于任何 x, y, dx,和dy。那么总距离就是向量的范数:sqrt((dx - (dy / 2)) ^ 2 + 3 * dy * dy / 4)

【讨论】:

    【解决方案3】:

    如果要直线距离:

    double dy = y2 - y1;
    double dx = x2 - x1;
    // if the height is odd
    if ((int)dy & 1){
        // whether the upper x coord is displaced left or right
        // depends on whether the y1 coordinate is odd
        dx += ((y1 & 1) ? -0.5 : 0.5);
    }
    double dis = sqrt(dx*dx + dy*dy);
    

    我想说的是,如果dy 是偶数,它只是一个矩形空间。如果dy 为奇数,则右上角的位置为向左或向右1/2 个单位。

    【讨论】:

    • 浮点数为“偶数”有意义吗? bit-and 是检查浮点数均匀性的有效方法吗?
    • @Svante:好点子。我放了一个演员表。我输入double的唯一原因是因为1/2可以进入图片。
    • 浮点数通常不能很好地替代有理数。您确定 (int)1.0 在您打算使用的任何编译器中都是 1 吗?如果是(int)0.999999(int)1.00000001 怎么办?如果您绝对必须使用浮点数,请尽可能晚地生成它们。
    • @Svante:又是好点。您可以假设浮点对于整数是精确的,但依赖它可能仍然不是一个好主意。在这种情况下,使用半整数会更加谨慎。我只是不想让代码更加混乱。
    • 感谢您的考虑。我的想法是在伪代码中没有任何实现细节,即没有类型、没有强制转换、没有位摆弄、没有不精确的函数,= 表示相等,而不是赋值。
    【解决方案4】:

    无法直接回答这个问题。这个问题的答案与你如何组织内存中的磁贴非常相关。我使用奇数-q 垂直布局,并使用以下 matlab 代码始终给我正确的答案。

    function f = offset_distance(x1,y1,x2,y2)
        ac = offset_to_cube(x1,y1);
        bc = offset_to_cube(x2,y2);
        f = cube_distance(ac, bc);
    end
    
    function f = offset_to_cube(row,col)
        %x = col - (row - (row&1)) / 2;
        x = col - (row - mod(row,2)) / 2;
        z = row;
        y = -x-z;
        f = [x,z,y];
    end
    
    function f= cube_distance(p1,p2)
        a = abs( p1(1,1) - p2(1,1));
        b = abs( p1(1,2) - p2(1,2));
        c = abs( p1(1,3) - p2(1,3));
        f =  max([a,b,c]);
    end
    

    这是一个matlab测试代码

    sx = 6;
    sy = 1;
    for i = 0:7
        for j = 0:5
            k = offset_distance(sx,sy,i,j);
            disp(['(',num2str(sx),',',num2str(sy),')->(',num2str(i),',',num2str(j),')=',num2str(k)])
        end
    end
    

    有关此解决方案的数学详细信息,请访问:http://www.redblobgames.com/grids/hexagons/。您可以在以下位置获得完整的 hextile 库:http://www.redblobgames.com/grids/hexagons/implementation.html

    【讨论】:

      【解决方案5】:

      这听起来像是Bresenham line algorithm 的工作。您可以使用它来计算从 A 到 B 的段数,这将告诉您路径距离。

      【讨论】:

        【解决方案6】:

        如果将不同的六边形定义为图,则可以得到从节点 A 到节点 B 的最短路径。由于到六边形中心的距离是恒定的,因此将其设置为边权重。

        不过,这对于大型字段可能效率低下。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-19
          • 1970-01-01
          相关资源
          最近更新 更多