삼각/육각형 좌표 생성 (XYZ)
-
20-09-2019 - |
문제
나는 육각형 그리드에 대한 XYZ 좌표를 생성하는 반복적 인 함수를 생각해 내려고 노력하고 있습니다. 시작 16 진 위치 (단순성을 위해 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 ° 벡터는 중앙에서 각 단계마다 하나의 추가 지점을 포함합니다. 나는 또한 그것을 알고있다 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) 의 Tehmick의 해결책 (많은 스타일을 희생하면) 이것은 다음과 같습니다.
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의 절대 값은 링의 반경의 두 배에 해당합니다. 이것은 각 연속 링에서 모든 육각형을 식별하기에 충분해야합니다.
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의 해결책. 방향 (이동) 벡터를 사용하여 링 주위를 "걷는"것처럼 좌표가 생성 될 수 있으며, 회전은 이동 벡터 주위에서 0을 이동하는 것과 동일합니다.
이 버전은 또한 이점이 있습니다 에릭의 해결책 그것은 잘못된 좌표를 결코 다루지 않는다는 점에서 (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의 시퀀스 슬라이싱에 대한 세 가지 건배.
좋아, 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