在六边形场上通过螺旋创建单元的算法

时间:2010-01-26 20:34:10

标签: php algorithm hexagonal-tiles

帮助找到在六边形场上通过螺旋线创建单元格的算法。

看图片:

alt text http://img685.imageshack.us/img685/927/fieldr.png

让我们想象一个无量纲的二维数组。 X轴是蓝线,Y是水平,螺旋是红色。

我需要通过螺旋

将细胞从中心点x0y0添加到N点

请告诉我解决问题的方法。 谢谢!

6 个答案:

答案 0 :(得分:6)

我建议稍微更改细胞编号,以便当你向下和向右(或向上和向左)时X保持不变。 那么像下面这样的简单算法应该可以工作:

  int x=0, y=0;   
  add(x, y); // add the first cell
  int N=1 
  for( int N=1; <some condition>; ++N ) {
    for(int i=0; i<N; ++i) add(++x, y);  // move right
    for(int i=0; i<N-1; ++i) add(x, ++y); // move down right. Note N-1
    for(int i=0; i<N; ++i) add(--x, ++y); // move down left
    for(int i=0; i<N; ++i) add(--x, y); // move left
    for(int i=0; i<N; ++i) add(x, --y); // move up left
    for(int i=0; i<N; ++i) add(++x, --y); // move up right
  }

这会产生如下点:

Plot of generated points

转化后我们得到:

Transformation of the generated points into a hex grid

答案 1 :(得分:1)

enter image description here (圆圈的直径为1)

这是获取位置i的函数:

  void getHexPosition( int i, ref double x, ref double y )
  {
     if ( i == 0 ) { x = y = 0; return; }

     int layer = (int) Math.Round( Math.Sqrt( i/3.0 ) );

     int firstIdxInLayer = 3*layer*(layer-1) + 1;
     int side = (i - firstIdxInLayer) / layer; // note: this is integer division
     int idx  = (i - firstIdxInLayer) % layer;                  
     x =  layer * Math.Cos( (side - 1) * Math.PI/3 ) + (idx + 1) * Math.Cos( (side + 1) * Math.PI/3 );
     y = -layer * Math.Sin( (side - 1) * Math.PI/3 ) - (idx + 1) * Math.Sin( (side + 1) * Math.PI/3 );
  }

Math.Sqrt(.75)缩放结果

enter image description here

如果您对shura的答案中的倾斜坐标感兴趣:

  int[] h = { 1, 1, 0, -1, -1, 0, 1, 1, 0 };
  void getHexSkewedPosition( int i, ref int hx, ref int hy )
  {
     if ( i == 0 ) { hx = hy = 0; return; }

     int layer = (int) Math.Round( Math.Sqrt( i/3.0 ) );

     int firstIdxInLayer = 3*layer*(layer-1) + 1;
     int side = (i - firstIdxInLayer) / layer;
     int idx  = (i - firstIdxInLayer) % layer;

     hx = layer*h[side+0] + (idx+1) * h[side+2];
     hy = layer*h[side+1] + (idx+1) * h[side+3];
  }

  void getHexPosition( int i, ref double hx, ref double hy )
  {
     int x = 0, y = 0;
     getHexSkewedPosition( i, ref x, ref y );
     hx = x - y * .5;
     hy = y * Math.Sqrt( .75 );
  }

答案 2 :(得分:0)

想象一下你有一个正方形的网格,而不是六边形,使用该网格创建螺旋,然后通过移动说,每个奇数y向左移动m个像素来绘制它,这将给你带来这种效果。

答案 3 :(得分:0)

您可以使用适当的分数功能一次选择一个六边形,以选择六个尚未选择的相邻六边形中最好的六个选定上一轮选择的十六进制。我认为有效的得分函数是选择最接近(0,0)(强制一次选择一个“壳”中的六角形),通过选择最接近(1,0)来强制关系(强制一致的螺旋方向)在新的shell)。可以使用以下函数计算十六进制网格中的距离:

double grid_distance(int dx, int dy) {
  double real_dx = dx + y/2.0;
  double real_dy = dy * sqrt(3)/2.0;
  return sqrt(real_dx * real_dx + real_dy * real_dy);
}

答案 4 :(得分:0)

你可以通过模拟方向来做到这一点。如果您的指示是“0点向上”,那么随着时间顺序递增1,以下情况应该如下:

Pick a centre cell.
Pick the second cell (ideally in direction 0).
Set direction to 2.

While you have more cells to mark:
  if the cell in (direction+1)%6 is free:
    set direction = (direction+1)%6
  mark current cell as used
  go to cell in direction

答案 5 :(得分:0)

我喜欢@ shura解决问题的方法,但无法使用那种精确的算法。另外,我使用的是2x1六边形间距(其中x个单元格间隔2个,其他x个项目都是隐藏的)。

这是我的工作(虽然在JavaScript中):

    //Hexagon spiral algorithm, modified from 
    for(var n=1; n<=rings; ++n) {
        x+=2; add(x, y);
        for(var i=0; i<n-1; ++i) add(++x,++y); // move down right. Note N-1
        for(var i=0; i<n; ++i) add(--x,++y); // move down left
        for(var i=0; i<n; ++i) { x-=2; add(x, y); } // move left
        for(var i=0; i<n; ++i) add(--x,--y); // move up left
        for(var i=0; i<n; ++i) add(++x, --y); // move up right
        for(var i=0; i<n; ++i) { x+=2; add(x, y); }  // move right
    }