我有一个六边形网格:
其中模板类型坐标为T。如何计算两个六边形之间的距离?
例如:
dist((3,3), (5,5)) = 3
dist((1,2), (1,4)) = 2
我有一个六边形网格:
其中模板类型坐标为T。如何计算两个六边形之间的距离?
例如:
dist((3,3), (5,5)) = 3
dist((1,2), (1,4)) = 2
首先应用变换 (y, x) |-> (u, v) = (x, y + floor(x / 2))。
现在面部相邻情况如下:
0 1 2 3
0*-*-*-*
|\|\|\|
1*-*-*-*
|\|\|\|
2*-*-*-*
假设点为(u1, v1)和(u2, v2)。令du = u2 - u1,dv = v2 - v1。距离为
if du and dv have the same sign: max(|du|, |dv|), by using the diagonals
if du and dv have different signs: |du| + |dv|, because the diagonals are unproductive
在Python中:
def dist(p1, p2):
y1, x1 = p1
y2, x2 = p2
du = x2 - x1
dv = (y2 + x2 // 2) - (y1 + x1 // 2)
return max(abs(du), abs(dv)) if ((du >= 0 and dv >= 0) or (du < 0 and dv < 0)) else abs(du) + abs(dv)
d = max( abs(x1 - x2), abs(y1 -y2), abs( (-x1 + -y1) - (-x2 + -y2) )
使用您的坐标系统,正确的距离显式公式如下:
d((x1,y1),(x2,y2)) = max( abs(x1 - x2),
abs((y1 + floor(x1/2)) - (y2 + floor(x2/2)))
)
d((0,2), (5,1)) = 4 != 5
。这是因为 d = max(abs(y1 - y2), abs((x1 + floor(y1 / 2))) - (x2 + floor(y2 / 2)))
。当我使用 d = max(abs(x1 - x2), ...)
时,d((1,0), (0,2)) = 1 != 2
。 - zodiac以下是我的做法:
以一个单元格为中心(如果选择0,0
,则更容易理解),距离为dY
的单元格形成一个大六边形(“半径”为dY
)。这个六边形的一个顶点是(dY2,dY)
。如果dX<=dY2
,路径是一条蜿蜒到达大六边形边缘的路径,距离为dY
。否则,路径是从顶点开始的“对角线”,加上从顶点到第二个单元格的垂直路径,需要添加dX-dY2
个单元格。
可能更易理解的描述方式:
dX = abs(x1 - x2);
dY = abs(y1 - y2);
dY2= floor((abs(y1 - y2) + (y1+1)%2 ) / 2);
然后:
d = d((x1,y1),(x2,y2))
= dX < dY2 ? dY : dY + dX-dY2 + y1%2 * dY%2
d((3,2), (0,1)) = 3 != 4
- zodiacd((3,3), (0,0)) = 6 != 4
, 但是 d((0,0), (3,3)) = 4
。为什么你只用了 y1 而没有用 y2? - zodiac首先,您需要将您的坐标转换为“数学”坐标系。每两列,您需要将坐标在y方向上移动1个单位。可以通过以下方式从您的坐标(u,v)计算出“数学”坐标(s,t):
s = u + floor(v/2) t = v
如果你将六边形的一侧称为a,则坐标系的基向量为(0, -sqrt(3)a)和(3a/2,sqrt(3)a/2)。要找到点之间的最小距离,需要在你的坐标系中计算曼哈顿距离,它由|s1-s2|+|t1-t2|给出,其中s和t是你的系统中的坐标。曼哈顿距离仅涵盖沿着基向量方向行走,因此仅涵盖像这样行走:|/,但不涵盖像这样行走:|\。你需要将向量转换为另一个具有基向量(0,-sqrt(3)a)和(3a/2,-sqrt(3)a/2)的坐标系。在该系统中的坐标由s'=s-t和t'=t给出,因此该坐标系中的曼哈顿距离由|s1'-s2'|+|t1'-t2'|给出。您要查找的距离是两个计算得到的曼哈顿距离中的最小值。您的代码应如下所示:struct point
{
int u;
int v;
}
int dist(point const & p, point const & q)
{
int const ps = p.u + (p.v / 2); // integer division!
int const pt = p.v;
int const qs = q.u + (q.v / 2);
int const qt = q.v;
int const dist1 = abs(ps - qs) + abs(pt - qt);
int const dist2 = abs((ps - pt) - (qs - qt)) + abs(pt - qt);
return std::min(dist1, dist2);
}
dist((2,1), (1,2)):dist1 = abs(2 - 1) + abs(1 - 2) = 2,dist2 = abs((2 - 1) - (1 - 2)) + abs(1 - 2) = abs(2) + abs(-1) = 3
,结果是 2 != 1
。 - zodiac(奇数-r)(没有z,只有x,y)
我看到了一些实现上的问题。抱歉,我没有全部检查,但也许我的解决方案对某些人有帮助,也可能是一个不好的、未经优化的解决方案。
主要思路是按对角线和水平方向移动。但为此我们需要注意:
1)例如,我们有0;3(x1=0;y1=3),要到达y2=6,我们可以在每个点上处理6步,即:0-左边界,6-右边界
2)计算一些偏移量
#include <iostream>
#include <cmath>
int main()
{
//while(true){
int x1,y1,x2,y2;
std::cin>>x1>>y1;
std::cin>>x2>>y2;
int diff_y=y2-y1; //only up-> bottom no need abs
int left_x,right_x;
int path;
if( y1>y2 ) { // if Down->Up then swap
int temp_y=y1;
y1=y2;
y2=temp_y;
//
int temp_x=x1;
x1=x2;
x2=temp_x;
} // so now we have Up->Down
// Note that it's odd-r horizontal layout
//OF - Offset Line (y%2==1)
//NOF -Not Offset Line (y%2==0)
if( y1%2==1 && y2%2==0 ){ //OF ->NOF
left_x = x1 - ( (y2 - y1 + 1)/2 -1 ); //UP->DOWN no need abs
right_x = x1 + (y2 - y1 + 1)/2; //UP->DOWN no need abs
}
else if( y1%2==0 && y2%2==1 ){ // OF->NOF
left_x = x1 - (y2 - y1 + 1)/2; //UP->DOWN no need abs
right_x = x1 + ( (y2 - y1 + 1)/2 -1 ); //UP->DOWN no need abs
}
else{
left_x = x1 - (y2 - y1 + 1)/2; //UP->DOWN no need abs
right_x = x1 + (y2 - y1 + 1)/2; //UP->DOWN no need abs
}
/////////////////////////////////////////////////////////////
if( x2>=left_x && x2<=right_x ){
path = y2 - y1;
}
else {
int min_1 = std::abs( left_x - x2 );
int min_2 = std::abs( right_x - x2 );
path = y2 - y1 + std::min(min_1, min_2);
}
std::cout<<"Path: "<<path<<"\n\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n";
//}
return 0;
}
我相信你所寻找的答案是:
d((x1,y1),(x2,y2))=max(abs(x1-x2),abs(y1-y2));
你可以在这里找到关于六边形网格坐标系/距离的良好解释:
http://keekerdc.com/2011/03/hexagon-grids-coordinate-systems-and-distance-calculations/