2010-01-12 49 views
24

Tôi đang cố gắng tìm ra một hàm lặp tạo ra tọa độ xyz cho lưới lục giác. Toán học chưa bao giờ dễ dàng đối với tôi (tôi không thông minh lắm!) Và vấn đề này khiến tôi bối rối. Với một vị trí hex bắt đầu (nói 0,0,0 cho simplicty) Tôi muốn để tính toán tọa độ cho mỗi "vòng" liên tiếp của hình lục giác, như minh họa ở đây:Tạo tọa độ tam giác/lục giác (xyz)

Cho đến nay, tất cả tôi đã quản lý để đưa ra là thế này (ví dụ trong 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); 
     } 
    } 
} 

tôi biết mỗi vòng bao gồm sáu điểm nhiều hơn so với trước đó và mỗi 120 ° vector chứa một điểm bổ sung cho mỗi bước từ trung tâm. Tôi cũng biết rằng x + y + z luôn = 0. Nhưng làm thế nào tôi có thể tạo ra một danh sách các tọa độ mà theo trình tự này:

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 

Tôi có lẽ sẽ được xấu hổ bởi sự đơn giản của câu trả lời nhưng xin đừng để điều đó ngăn cản bạn đóng góp! ;) Như tôi đã nói, tôi không thông minh lắm!

Rất cám ơn,

JS

+1

Chỉnh sửa nhỏ.Mỗi vòng chứa ** 6 * k ** điểm, hoặc ** 6 * (k-1) ** điểm nhiều hơn điểm trước, trong đó k là chỉ số vòng được bắt đầu từ số không. –

Trả lời

12

Một giải pháp có thể khác, chạy trong O (bán kính^2), không giống như O (bán kính^4) của giải pháp tehMick (với chi phí rất nhiều kiểu) là:

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 

hay viết ngắn gọn hơn một chút:

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 

của nó lấy cảm hứng từ thực tế, hình lục giác đang thực sự ở bên ngoài của hình lục giác bản thân, vì vậy bạn có thể tìm tọa độ của 1 trong tổng số điểm của mình, và sau đó tính toán những người khác bằng cách di chuyển trên 6 cạnh của nó.

+0

Đây cũng là một giải pháp thú vị, cảm ơn bạn! Tôi đã thực sự thực hiện cả hai phương pháp trong dự án của tôi với khả năng chuyển đổi giữa chúng và hiện đang chạy một số điểm chuẩn để xem đó là nhanh hơn. Một yếu tố khác là sẽ dễ dàng thay đổi vị trí "bắt đầu" từ 0,0,0 đến một điểm khác trên lưới (nói 5, -3, -2) và tạo ra lưới xung quanh điểm đó. Bất kỳ ý tưởng về điều này? –

+0

Rất đơn giản: trong các dòng x = 0, y = -r, z = + r đầu tiên, chỉ cần thêm vị trí bắt đầu, như: x = x0, y = y0-r, z = z0 + r và bạn done :) –

+0

Cuối cùng, đây là câu trả lời được chấp nhận của tôi vì nó là một chút nhỏ hơn và dễ dàng hơn để nuôi một vị trí bắt đầu bù đắp. Xem câu trả lời của tôi dưới đây để thực hiện cuối cùng. Cảm ơn Ofri! –

12

Không chỉ là x + y + z = 0, nhưng giá trị tuyệt đối của x, y, z là tương đương với hai lần bán kính của vòng.Như vậy là đủ để xác định tất cả các hình lục giác trên mỗi vòng liên tiếp:

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) 
       document.body.innerHTML += (j + "," + k + "," + l + "<br />"); 
     document.body.innerHTML += ("<br />"); 
    } 

Output: 0,0,0

-1,0,1 -1,1,0 0, -1 , 1 0,1, -1 1, -1,0 1,0, -1

-2,0,2 -2,1,1 -2,2,0 -1 , -1,2 -1,2, -1 0, -2,2 0,2, -2 1, -2,1 1,1, -2 2, -2,0 2, -1, -1 2,0, -2

-3, 0,3 -3,1,2 -3,2,1 -3,3,0 -2, -1,3 -2,3, -1 -1, -2,3 - 1,3, -2 0, -3,3 0,3, -3 1, -3,2 1,2, -3 2, -3,1 2,1, -3 3 , -3,0 3, -2, -1 3, -1, -2 3,0, -3

+0

Chà, điều đó cực kỳ đơn giản! Tôi đã nhìn chằm chằm vào trình tự cố gắng tìm một mối quan hệ như vậy nhưng không biết nhiều về toán học hình học, nó chỉ khiến tôi đau đầu. Nhờ ví dụ của bạn bây giờ tôi thấy mối quan hệ (nhìn vào bài viết trên Wikipedia về giá trị tuyệt đối hơn nữa đã giúp giảm penny). Tôi sẽ cung cấp cho nó một whirl nhưng nó đã trông giống như một câu trả lời được chấp nhận. Cảm ơn! –

+0

Tôi cho rằng phương pháp này có thể được sử dụng ngay cả khi điểm bắt đầu không phải là 0,0,0? Làm thế nào tôi sẽ ăn trong các tọa độ bắt đầu? - thực sự, đừng bận tâm, nghĩ rằng tôi biết cách làm điều này. Sẽ đăng giải pháp đầy đủ khi hoàn thành. –

+0

Yup, như bạn có thể đoán, chỉ cần bắt đầu tôi ở bán kính của vòng trong cùng bạn muốn xuất. –

1

Ok, sau khi thử cả hai tùy chọn tôi đã giải quyết trên dung dịch của Ofri vì nó nhanh hơn một chút và giúp dễ dàng cung cấp giá trị bù ban đầu. Mã của tôi bây giờ trông như thế này:

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]); 
       } 
     } 
} 

Phương pháp "placeTile" sử dụng cloneNode để sao chép một yếu tố svg được xác định trước và phải mất khoảng 0.5 ms mỗi ngói để thực hiện đó là quá đủ tốt. Cảm ơn tehMick và Ofri đã giúp đỡ bạn!

JS

+0

điều này không làm việc cho bán kính = 1. bạn đang thiếu một 'placeTile ([x, y, z]);' ngay trước vòng lặp thứ hai. – gaitat

5

Đây là một câu đố thú vị.

O (bán kính^2) nhưng với (hy vọng) phong cách hơn một chút so với giải pháp của Ofri. Nó xảy ra với tôi rằng tọa độ có thể được tạo ra như thể bạn đang "đi bộ" quanh vòng bằng cách sử dụng một hướng (di chuyển) vectơ, và rằng một lượt là tương đương với dịch chuyển số không xung quanh vector chuyển động.

Phiên bản này cũng có lợi thế hơn giải pháp của Eric ở chỗ nó không bao giờ chạm vào tọa độ không hợp lệ (Eric từ chối chúng, nhưng điều này thậm chí không bao giờ phải kiểm tra chúng).

# 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 

Ba cổ vũ cho việc cắt chuỗi của python.

Các vấn đề liên quan