我正在尝试提出一个迭代函数,为六边形网格生成xyz坐标。使用起始十六进制位置(简单来说就是0,0,0),我想计算每个连续“六边形”环的坐标,如下所示:
到目前为止,我设法想出的就是这个(javascript中的例子):
var radius = 3
var xyz = [0,0,0];
// for each ring
for (var i = 0; i < radius; i++) {
var tpRing = i*6;
var tpVect = tpRing/3;
// for each vector of ring
for (var j = 0; j < 3; j++) {
// for each tile in vector
for(var k = 0; k < tpVect; k++) {
xyz[0] = ???;
xyz[1] = ???;
xyz[2] = ???;
console.log(xyz);
}
}
}
我知道每个环比前一个包含六个点,每个120°向量包含从中心开始的每个步骤的一个附加点。我也知道所有瓷砖x + y + z = 0
。但是,如何生成遵循以下顺序的坐标列表?
0, 0, 0
0,-1, 1
1,-1, 0
1, 0,-1
0, 1,-1
-1, 1, 0
-1, 0, 1
0,-2, 2
1,-2, 1
2,-2, 0
2,-1,-1
2, 0,-2
1, 1,-2
0, 2,-2
-1, 2,-1
-2, 2, 0
-2, 1, 1
-2, 0, 2
-1,-1, 2
答案 0 :(得分:13)
另一种可能的解决方案,在 O(半径 2 )中运行,与 O(半径 4 )不同 > tehMick's solution(以很多风格为代价)是:
radius = 4
for r in range(radius):
print "radius %d" % r
x = 0
y = -r
z = +r
print x,y,z
for i in range(r):
x = x+1
z = z-1
print x,y,z
for i in range(r):
y = y+1
z = z-1
print x,y,z
for i in range(r):
x = x-1
y = y+1
print x,y,z
for i in range(r):
x = x-1
z = z+1
print x,y,z
for i in range(r):
y = y-1
z = z+1
print x,y,z
for i in range(r-1):
x = x+1
y = y-1
print x,y,z
或写得更简洁:
radius = 4
deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]]
for r in range(radius):
print "radius %d" % r
x = 0
y = -r
z = +r
print x,y,z
for j in range(6):
if j==5:
num_of_hexas_in_edge = r-1
else:
num_of_hexas_in_edge = r
for i in range(num_of_hexas_in_edge):
x = x+deltas[j][0]
y = y+deltas[j][1]
z = z+deltas[j][2]
print x,y,z
它的灵感来自于六边形实际上位于六边形的外部,因此您可以找到其中1个点的坐标,然后通过移动其6个边来计算其他坐标。
答案 1 :(得分:12)
不仅是x + y + z = 0
,而且x,y和z的绝对值等于环的半径的两倍。这应该足以识别每个连续环上的每个六边形:
var radius = 4;
for(var i = 0; i < radius; i++)
{
for(var j = -i; j <= i; j++)
for(var k = -i; k <= i; k++)
for(var l = -i; l <= i; l++)
if(Math.abs(j) + Math.abs(k) + Math.abs(l) == i*2 && j + k + l == 0)
console.log(j + "," + k + "," + l);
console.log("");
}
答案 2 :(得分:5)
这是一个有趣的谜题。
O(半径 2 )但是(希望)比Ofri's solution.更多样式我觉得可以生成坐标,就好像你是使用方向(移动)向量在环上“行走”,并且转弯相当于在移动向量周围移动零点。
这个版本还具有优于Eric's solution的优势,因为它永远不会触及无效坐标(Eric拒绝它们,但是这个甚至不必测试它们。)
# enumerate coords in rings 1..n-1; this doesn't work for the origin
for ring in range(1,4):
# start in the upper right corner ...
(x,y,z) = (0,-ring,ring)
# ... moving clockwise (south-east, or +x,-z)
move = [1,0,-1]
# each ring has six more coordinates than the last
for i in range(6*ring):
# print first to get the starting hex for this ring
print "%d/%d: (%d,%d,%d) " % (ring,i,x,y,z)
# then move to the next hex
(x,y,z) = map(sum, zip((x,y,z), move))
# when a coordinate has a zero in it, we're in a corner of
# the ring, so we need to turn right
if 0 in (x,y,z):
# left shift the zero through the move vector for a
# right turn
i = move.index(0)
(move[i-1],move[i]) = (move[i],move[i-1])
print # blank line between rings
为python的序列切片提供三种欢呼。
答案 3 :(得分:1)
好的,在尝试了两种选项之后,我已经确定了Ofri的解决方案,因为它更快一点,并且很容易提供初始偏移值。我的代码现在看起来像这样:
var xyz = [-2,2,0];
var radius = 16;
var deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]];
for(var i = 0; i < radius; i++) {
var x = xyz[0];
var y = xyz[1]-i;
var z = xyz[2]+i;
for(var j = 0; j < 6; j++) {
for(var k = 0; k < i; k++) {
x = x+deltas[j][0]
y = y+deltas[j][1]
z = z+deltas[j][2]
placeTile([x,y,z]);
}
}
}
“placeTile”方法使用cloneNode复制预定义的svg元素,每个tile需要大约0.5ms才能执行,这已经足够了。非常感谢tehMick和Ofri的帮助!
JS
答案 4 :(得分:0)
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.textAlign = "center";
const radius = 20;
const altitude = Math.sqrt(3) * radius;
const total = 3;
for (let x = -total; x <= total; x++) {
let y1 = Math.max(-total, -x-total);
let y2 = Math.min(total, -x+total);
for (let y = y1; y <= y2; y++) {
let xx = x * altitude + Math.cos(1/3*Math.PI) * y * altitude;
let yy = y * radius * 1.5;
xx += canvas.width/2;
yy += canvas.height/2;
drawHex(xx, yy, radius);
ctx.fillText(x+","+y, xx, yy);
}
}
function drawHex(x, y, radius){
ctx.beginPath();
for(let a = 0; a < Math.PI*2; a+=Math.PI/3){
let xx = Math.sin(a) * radius + x;
let yy = Math.cos(a) * radius + y;
if(a == 0) ctx.moveTo(xx, yy);
else ctx.lineTo(xx, yy);
}
ctx.stroke();
}
<canvas id="canvas" width=250 height=250>