5

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!

3
  • 3
    Is this homework? I am glad I graduated. Jan 26, 2010 at 20:35
  • Nick, thank you for you editing, but it's not a homework :)
    – Coyod
    Jan 26, 2010 at 20:59
  • If you shift every other row to the left on the image (so that all the same x's are in the same column), it might be easier for you to see the pattern. If you have any specific questions, please let us know. Jan 26, 2010 at 21:00

6 Answers 6

8

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

5
  • @Coyod. What kind of optimization? It should be rather efficient already.
    – shura
    Feb 5, 2010 at 21:29
  • @shura: optimization for my requirements :) русский?[x]
    – Coyod
    Feb 8, 2010 at 13:48
  • @Coyod. It is not very easy to suggest a solution for your requirements without knowing them. Вот так.
    – shura
    Feb 9, 2010 at 22:50
  • @shura: loved the approach, though I had some difficulties with it on larger loops - I posted my exact solution below. Nov 16, 2015 at 0:36
  • Added images to visualize this algorithm. Apr 9, 2016 at 9:54
1

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

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.

1
  • imagine that is not a problem, the problem is an algorithm for adding cells(squares) by spiral from the center :)
    – Coyod
    Jan 26, 2010 at 21:20
0

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

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
0

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
    }
1
  • I was able to get it work as @shura described it. I added some images to his answer to help visualize the algorithm. Apr 5, 2016 at 14:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.