Intro to the Problem

Hi there!

I've been trying to seamlessly tile hexagons on an XY plane-- without spaces in between.

I've currently accomplished this, however: My current hexagonal tiling

which as you can tell, isn't seamless or uniform in spacing.

What I'd like answered here is, where in my math have I veered off track, for my result not to match what I desire? Why does the distance between the hexagons vary instead of being constantly zero?

If you can't answer that because I've failed to communicate my process effectively, how would you go about tiling hexagons on an XY plane to achieve the desired result?

The Math Behind the Tiling

In order to tile regular hexagons as in the desired seamless result, I took the approach of stacking hexagons in radial layers.

Starting with a center hexagon (L0), I'd surround it with a layer (L1) of hexagons, then I'd surround L1 with L2 of hexagons, and so on.

My ultimate question regarding said radial stacking approach was: what's the distance and the angle from the center of the starting hexagon (L0) to the center of any other hexagon in the tessellation? Knowing such an angle and distance, I could radially plot each hexagon from the center of the tessellation.

By analyzing the case of circles, finding that the centers of two similar bitangent circles are a distance of twice their radius apart, I figured that the centers of two similar regular hexagons are a distance of twice their radius apart-- only, the radius of a hexagon changes; it isn't constant.

Here's a GeoGebra diagram demonstrating how I found the radius of a hexagon-- or the distance from its center to its perimeter, given an angle: Distance from the center of a hexagon to its perimeter, at angle theta.

Because this radius repeats every PI/3, or TAU/6 radians, the input angle for which to calculate a radius can be modulated by PI/3, such that it becomes (angle MOD PI/3). For a regular polygon with n sides, the input angle with which to find a radius can be modulated by TAU/n radians.

I also graphed my derived equations in Desmos: Desmos graph of n-sided regular polygon. They seem to check out.

Once I'd found the radius of a hexagon at an angle, I postulated that to find the coordinates of the center of another hexagon, say from origin L0 to a hexagon in set L1, I simply had to find the angle between the L0 and the next hexagon, find the radius of that angle as a vector, and multiply that radius vector by the layer index + 1 (layer 1 + 1 = 2). For L0 to L2, I'd multiply said vector by 3, because layer 2 + 1 = 3.

Here's a diagram of said vector multiplication in GeoGebra: Distances between hexagon centers.

Coding the Tessellation

Coding the tessellation of the hexagons in both Python (visualized in Blender) and JavaScript (visualized in P5.js), I achieved these undesirable results: Blender/Python result, P5.js/JavaScript result.

Here's my code in JavaScript:

var m = -sin(TAU/n)/(1 - cos(TAU/n)); //slope between p[0] (1,0) and p[1] (sin(TAU/n), cos(TAU/n)
var n = 6; //number of sides
var spacing = 8; //multiplies radii by an arbitrary constant because this is on a small pixel scale
var numLayers = 1; //number of radial layers to draw

function getRadius(angle) //returns the radius of a polygon at an angle from the x axis
  let x1 = -1/(tan(angle % (TAU/n)) * (1/m) - 1) ;
  let y1 = m * (x1 - 1);
  let r1 = sqrt(x1*x1 + y1*y1);
  return r1;

function drawShapes() //For each layer, 
  for (let layer = 1; layer < numLayers + 1; layer++) //start at L1 because L0 can't be drawn
    let shapes = n*layer; //There are 6 * current-layer # of hexagons per layer
    for(let shape = 0; shape < shapes; shape++)
      let theta = shape * TAU/shapes; //360 degrees are evenly divided into the # of shapes
      let dist = layer * 2*getRadius(theta); //distance from L0 to L[i] is 2r*i
      let x = dist * cos(theta); //get the coordinates of the current shape
      let y = dist * sin(theta);
      polygon(spacing*x, spacing*y, 8, n) //draw a regular polygon (x, y, radius, # of sides)

Where I Think the Issue is

Because the hexagons in my current hexagonal tiling are especially distant around every 60 degrees, I suspect that the modulus of PI/3, which I utilize to evaluate X1 (the x coordinate of a point along a hexagon's perimeter) in my Desmos project is closely linked to my issue of non-uniform spacing.

That's all the information I have to give-- I once again ask, why does the distance between the hexagons vary instead of being constantly zero?

What would you do differently to achieve a seamless or uniformly spaced hexagonal tesselation?

  • 7
    $\begingroup$ I haven't fully read through your code and found the error, but another approach to this would be to consider the vectors $u = (1,0)$ and $v = (1/2,\sqrt{3}/2)$ and set the hexagon centers to be $iu + jv$ for $i,j$ integers. $\endgroup$ Apr 4 at 20:37
  • 1
    $\begingroup$ It was a mistake, but it's quite a pretty mistake. $\endgroup$
    – David K
    Apr 4 at 20:50
  • 1
    $\begingroup$ Your vector suggestions are also great ones— a little more consideration and I would’ve ditched the radial approach for that; but as usual, early laziness caused a later demand for excess effort. $\endgroup$ Apr 4 at 21:00
  • 2
    $\begingroup$ Regarding the first two comments, one can tile a "circular" region without involving lengths of vectors. Besides the vectors $u = (1,0)$ and $v = (1/2,\sqrt{3}/2)$, use also the vector $w=(-1/2,\sqrt{3}/2)$. The centers of the $k^{th}$ "circle" of hexagons will be $ku$, $ku+w$, $ku+2w$, ..., $ku+kw=k(u+w)=kv$ which finishes up one side, followed by $kv-u$, $kv-2u$, ...., $kv-ku=kw$ which finishes up a second side, followed by $kw-v$, ..., $kw-kv=-ku$ which finishes up a third side and thus gets you halfway around the circle of hexagons. The other half of the hexagon continues similarly. $\endgroup$
    – Lee Mosher
    Apr 5 at 12:39
  • 1
    $\begingroup$ One might also consider doing exact arithmetic in $\mathbb Q(\sqrt{2})$ until the last moment, converting to floating point when needed for plotting. $\endgroup$
    – Lee Mosher
    Apr 5 at 12:39

3 Answers 3


I obviously haven't figured out everything you've done, but I'll offer the suggestion that your decision to work radially is hurting you. From your tiling image it looks like the centers are at evenly distributed angles, which is what's causing the bunching and spreading. It'd be the right thing to do if you were laying them down along a circle, but you're not.

How about laying them down in horizontal strips? There's a constant horizontal offset between the centers of each hexagon in a strip. And when you move down to the next strip, the next set of centers is half way between the previous ones horizontally, and all you have to calculate is the single, common vertical displacement.

If you want that same "big hexagon" appearance you'll have to do a bit of work figuring out how many to draw in each strip, and where to start. But that sounds pretty doable to me, and instead of being off by a little bit here and there, you'll see entire hexagons that you need to add or remove. Me, I'd start at 9 o'clock, draw the center strip,and then draw row 1 above, row 1 below, row 2 above, row 2 below, etc.

  • $\begingroup$ That horizontal suggestion is a great one— thank you! I’ll try to implement that instead. Now all that’s left is my curiosity as to what would make the radial approach work. $\endgroup$ Apr 4 at 20:51
  • 1
    $\begingroup$ The best i could suggest for your approach is that you would find the vertices of the successively larger hexagons, and then lay out the smallest hexagons along the sides of that big hexagon, equally spaced. I think you keep seeing circles, which are almost kinda sorta there, but they're actually figures whose sides are straight line segments, and ya gotta respect the straightness. $\endgroup$
    – JonathanZ
    Apr 4 at 21:09
  • 1
    $\begingroup$ I wrote a comment to the OP about laying out small hexagons along the sides of the big one. $\endgroup$
    – Lee Mosher
    Apr 5 at 12:41
  • $\begingroup$ @LeeMosher - That honestly feels more like what the OP was looking for, (along with an explanation of why their calculations didn't work). $\endgroup$
    – JonathanZ
    Apr 5 at 16:49

If you want the radial approach to work, you'll need to modify the theta values from their current equal spacing. Here's one approach: Each layer of hexagons is distinguished by six 'vertex' hexagons occurring at $\theta=0^\circ,60^\circ, 120^\circ$ and so on. As you iterate over each value of shape, define vshape to be the shape value for the prior vertex hexagon. Compute vtheta belonging to this vshape (which are properly calculated by your formula), and measure an angle increment $\alpha$ from this vtheta. By my calculation, if the current hexagon is $\Delta$ steps from the prior vertex hexagon, then the angle increment $\alpha$ to its center is given by $$\tan(\alpha) = \frac{\Delta\frac{\sqrt 3}2}{L-\frac\Delta 2}=\frac{\Delta\sqrt 3}{2L-\Delta}$$ where $L$ is the current layer number.

In code, you want to replace the line

let theta = shape * TAU/shapes; //360 degrees are evenly divided into the # of shape

with the lines:

let vshape = layer * floor(shape / layer); // shape number of prior vertex hexagon
let vtheta = vshape * TAU/shapes;  // theta of prior vertex hexagon
let delta = shape - vshape;        // number of steps away from prior vertex hexagon
let alpha = atan2(delta * sqrt(3), 2 * layer - delta); // angle increment from vtheta
let theta = vtheta + alpha;

(I haven't tested the code, so you might need to modify it if it's not implemented correctly.)

EDIT: Fixed errors in implementation


For layer X, you are positioning the hexagons evenly along a circle. Then you project that circle onto the hexagon of the correct radius.

This is incorrect. This causes the elements of the layer closer to the center to be bunched together, and those further away to be spaced further apart.

The proper distance should be uniformly spaced along the hexagon, not angular uniform spacing.

The easiest solution is horizontal stripes, but if you do want to do it in layers a good option is to find the corners, and divide the steps between them.

Iterate over the 6 vertexes. Find the hexagon locations for each pair, then in layer N add (N-1) side hexagons. Their positions are A + (B-A)*K/(N+1), where K goes from 1 to N-1 inclusive, A and B are the positions of the start and end points, and N is the layer number.

The 6 vertexes are also mathematically simple in location, located at angles V * pi/3 where V varies from 0 to 5 inclusive. These are (+/-1, 0), (+/- 1/3, +/- sqrt(3)/2)


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .