三角形/六角形の座標を生成する(xyz)
-
20-09-2019 - |
質問
六角形のグリッドのXYZ座標を生成する反復関数を考え出そうとしています。 Start Hexの位置(簡単に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);
}
}
}
各リングには前のリングよりも6つのポイントが含まれており、各120°ベクトルには、センターからの各ステップに1つの追加ポイントが含まれています。私もそれを知っています 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
解決
別の可能なソリューション、それは走ります O(半径2), とは異なります O(半径4) の Temickのソリューション (多くのスタイルを犠牲にして)これは次のとおりです。
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つのエッジを移動して他の座標を計算できます。
他のヒント
あるだけではありません x + y + z = 0
, 、しかし、x、y、zの絶対値は、リングの半径の2倍に等しくなります。これは、連続する各リングのすべての六角形を識別するのに十分でなければなりません。
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("");
}
これは楽しいパズルでした。
O(半径2) しかし、(できれば)(できれば)少しでもスタイルがあります Ofriの解決策。 私には、座標が方向(移動)ベクトルを使用してリングを「歩いている」かのように生成され、移動ベクトルの周りでゼロをシフトするのと同等であることがわかりました。
このバージョンにも利点があります エリックの解決策 無効な座標に触れることは決してないということです(エリックはそれらを拒否しますが、これは決してテストする必要さえありません)。
# 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つの歓声。
OK、両方のオプションを試した後、Ofriのソリューションは少し速く、初期オフセット値を簡単に提供できるため、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要素をコピーし、タイルあたり約0.5msが実行されますが、これは十分に優れています。 TehmickとOfriに感謝します!
JS