在六边形域上通过螺旋创建细胞的算法

发布于 2024-08-19 10:10:31 字数 287 浏览 4 评论 0原文

帮助找到一种在六边形域上通过螺旋创建细胞的算法。

看图片:

替代文字

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

我需要从中心点x0y0到点N通过螺旋添加单元格

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

Help to find an algorithm for creating cells by spiral on the hexagonal field.

Look at the image:

alt text

Let's imagine an dimensionless 2d array.
The X axis is the blue line, Y is horizontal, spiral is red.

I need to add cells from the central point x0y0 to point N by spiral

Tell me the way to solve the problem, please.
Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦情居士 2024-08-26 10:10:31

我建议稍微更改单元格编号,以便当您向下和向右(或向上和向左)移动时 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
  }

这会生成如下点:

生成点的图

转换后我们得到:

将生成的点转换为六角网格

I'd suggest changing the cells numbering sligtly, so that X remains the same when you go down and right (or up and left).
Then simple algorithm like the following should work:

  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
  }

This generates the points as follows:

Plot of generated points

After a transformation we get:

Transformation of the generated points into a hex grid

拥有 2024-08-26 10:10:31

输入图片此处描述
(圆的直径为 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) 缩放结果得到

在此处输入图像描述

如果您对像 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 );
  }

enter image description here
(the circles have a diameter of 1)

Here's a function to get position 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 );
  }

Scaling the result by Math.Sqrt(.75) gives

enter image description here

If you're interested in the skewed coordinates like in shura's answer:

  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 );
  }
还在原地等你 2024-08-26 10:10:31

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

Imagine you had a normal grid with squares instead of hexagons, create the spiral using that grid, then draw it by shifting say, every odd y to the left by m pixels, that'll give you that effect.

酒浓于脸红 2024-08-26 10:10:31

您可以使用适当的得分函数一次选择一个六角形,以选择与上一轮选择的六角形相邻的六个尚未选择的六角形中最好的一个。我认为有效的评分函数是选择最接近 (0,0) 的值(强制一次选择一个“壳”中的六角形),通过选择最接近 (1,0) 的值来打破平局(强制一致的螺旋方向)在新的外壳中)。六角网格中的距离可以使用以下函数计算:

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

You can pick hexes one at a time by using an appropriate score function to select the best of the six not-yet-selected adjacent hexes to the hex selected the previous round. I think a score function that works is to pick the closest to (0,0) (forces selecting hexes in one "shell" at a time), breaking ties by choosing the closest to (1,0) (forces a consistent spiral direction in the new shell). Distance in the hex grid can be computed using the following function:

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);
}
哎呦我呸! 2024-08-26 10:10:31

您可以通过模拟方向来做到这一点。如果您的方向是“向上 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

YOu could do it by simulating directions. If your directions are "0 points up", then increment by 1 as you go clock-wise, the following should do:

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
浮生未歇 2024-08-26 10:10:31

我喜欢 @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
    }

I loved @shura's way of approaching the problem, but couldn't get that exact algorithm to work. Also, I'm using a 2x1 hexagon spacing (where x cells are spaced 2 apart, and every other x item is hidden).

Here's what I got working (though in 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
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文