Regular hexagon construction - how to draw a hexagon. How to build a regular hexagon How to draw a hexagon with a pencil

Is there a pencil near you? Take a look at its cross-section - it is a regular hexagon or, as it is also called, a hexagon. The cross-section of a nut, a field of hexagonal chess, some complex carbon molecules (for example, graphite), a snowflake, a honeycomb and other objects also have this shape. A giant regular hexagon was recently discovered in Doesn't it seem strange that nature so often uses structures of this particular shape for its creations? Let's take a closer look.

A regular hexagon is a polygon with six equal sides and equal angles. From the school course we know that it has the following properties:

  • The length of its sides corresponds to the radius of the circumscribed circle. Of all, only the regular hexagon has this property.
  • The angles are equal to each other, and each measure is 120°.
  • The perimeter of a hexagon can be found using the formula P=6*R, if the radius of the circle described around it is known, or P=4*√(3)*r, if the circle is inscribed in it. R and r are the radii of the circumscribed and inscribed circle.
  • The area occupied by a regular hexagon is determined as follows: S=(3*√(3)*R 2)/2. If the radius is unknown, substitute the length of one of the sides - as is known, it corresponds to the length of the radius of the circumscribed circle.

A regular hexagon has one interesting feature, thanks to which it has become so widespread in nature - it is able to fill any surface of a plane without overlaps or gaps. There is even the so-called Pal lemma, according to which a regular hexagon, the side of which is equal to 1/√(3), is a universal cover, that is, it can cover any set with a diameter of one unit.

Now let's look at constructing a regular hexagon. There are several methods, the simplest of which involves using a compass, pencil and ruler. First, we draw an arbitrary circle with a compass, then we make a point in an arbitrary place on this circle. Without changing the angle of the compass, we place the tip at this point, mark the next notch on the circle, and continue this until we get all 6 points. Now all that remains is to connect them together with straight segments, and you will get the desired figure.

In practice, there are cases when you need to draw a large hexagon. For example, on a two-level plasterboard ceiling, around the mounting location of the central chandelier, you need to install six small lamps on the lower level. Compasses of this size will be very, very difficult to find. What to do in this case? How do you even draw a large circle? Very simple. You need to take a strong thread of the required length and tie one of its ends opposite the pencil. Now all that remains is to find an assistant who would press the second end of the thread to the ceiling at the desired point. Of course, in this case, minor errors are possible, but they are unlikely to be noticeable to an outsider at all.

Content:

A regular hexagon, also called a perfect hexagon, has six equal sides and six equal angles. You can draw a hexagon with a tape measure and a protractor, a rough hexagon with a round object and a ruler, or an even rougher hexagon with just a pencil and a little intuition. If you want to know how to draw a hexagon in different ways, just read on.

Steps

1 Draw a perfect hexagon using a compass

  1. 1 Using a compass, draw a circle. Insert the pencil into the compass. Extend the compass to the desired radius width of your circle. The radius can be from a couple to ten centimeters wide. Next, place a compass and pencil on paper and draw a circle.
    • Sometimes it's easier to draw half a circle first and then the other half.
  2. 2 Move the compass needle to the edge of the circle. Place it on top of the circle. Do not change the angle or position of the compass.
  3. 3 Make a small pencil mark on the edge of the circle. Make it distinct, but not too dark as you will erase it later. Remember to maintain the angle you set for the compass.
  4. 4 Move the compass needle to the mark you just made. Place the needle directly on the mark.
  5. 5 Make another pencil mark on the edge of the circle. This way you will make a second mark at a certain distance from the first mark. Keep moving in one direction.
  6. 6 Use the same method to make four more marks. You must return back to the original mark. If not, then most likely the angle at which you held the compass and made your marks has changed. This may have happened because you squeezed it too tightly or, on the contrary, loosened it a little.
  7. 7 Connect the marks using a ruler. The six places where your marks intersect with the edge of the circle are the six vertices of the hexagon. Using a ruler and pencil, draw straight lines connecting adjacent marks.
  8. 8 Erase the circle, the marks on the edges of the circle, and any other marks you made. Once you have erased all your construction lines, your perfect hexagon should be ready.

2 Draw a rough hexagon using a round object and a ruler

  1. 1 Trace the rim of the glass with a pencil. This way you will draw a circle. It is very important to draw with a pencil, since later you will need to erase all the auxiliary lines. You can also trace an upside down glass, jar, or anything else that has a round base.
  2. 2 Draw horizontal lines through the center of your circle. You can use a ruler, a book - anything with a straight edge. If you do have a ruler, you can mark the middle by calculating the vertical length of the circle and dividing it in half.
  3. 3 Draw an "X" over half the circle, dividing it into six equal sections. Since you've already drawn a line through the middle of the circle, the X needs to be wider than it is tall so that the parts are equal. Imagine dividing a pizza into six pieces.
  4. 4 Make triangles out of each section. To do this, use a ruler to draw a straight line underneath the curved part of each section, connecting it to the other two lines to form a triangle. Do this with the remaining five sections. Think of it like making a crust around your pizza slices.
  5. 5 Erase all auxiliary lines. The guide lines include your circle, the three lines that divided your circle into sections, and other marks you made along the way.

3 Draw a rough hexagon using one pencil

  1. 1 Draw a horizontal line. To draw a straight line without a ruler, simply draw the starting and ending point of your horizontal line. Then place the pencil at the starting point and draw the line to the end. The length of this line can be only a couple of centimeters.
  2. 2 Draw two diagonal lines from the ends of the horizontal one. The diagonal line on the left side should point outward in the same way as the diagonal line on the right. You can imagine that these lines form an angle of 120 degrees with respect to the horizontal line.
  3. 3 Draw two more horizontal lines coming from the first horizontal lines drawn inward. This will create a mirror image of the first two diagonal lines. The bottom left line should be a reflection of the top left line, and the bottom right line should be a reflection of the top right line. While the top horizontal lines should look outward, the bottom ones should look inward to the base.
  4. 4 Draw another horizontal line connecting the bottom two diagonal lines. This way you will draw the base for your hexagon. Ideally, this line should be parallel to the top horizontal line. Now you have completed your hexagon.
  • The pencil and compass should be sharp to minimize errors from marks that are too wide.
  • When using the compass method, if you connect each mark instead of all six, you will get an equilateral triangle.

Warnings

  • The compass is a rather sharp object, be very careful with it.

Principle of operation

  • Each method will help you draw a hexagon formed by six equilateral triangles with a radius equal to the length of all sides. The six radii drawn are the same length and all the lines to create the hexagon are also the same length, since the width of the compass did not change. Due to the fact that the six triangles are equilateral, the angles between their vertices are 60 degrees.

What you will need

  • Paper
  • Pencil
  • Ruler
  • Pair of compasses
  • Something that can be placed under the paper to prevent the compass needle from slipping.
  • Eraser

A regular circumscribed triangle is constructed as follows(Figure 38). From the center of a given circle of radius R 1 draw a circle with radius R2 = 2R1 and divide it into three equal parts. Division points A, B, C are the vertices of a regular triangle circumscribed about a circle of radius R 1 .

Figure 38

Regular circumscribed quadrilateral (square) can be constructed using a compass and ruler (Figure 39). In a given circle, two mutually perpendicular diameters are drawn. Taking the points of intersection of the diameters with the circle as centers, the radius of the circle R describe arcs until they intersect each other at points A, B, C, D . Points A , B , C , D and are the vertices of a square circumscribed about a given circle.

Figure 39

To construct a regular circumscribed hexagon it is necessary to first construct the vertices of the described square in the manner indicated above (Figure 40, a). Simultaneously with determining the vertices of the square, a given circle of radius R divided into six equal parts at the points 1, 2, 3, 4, 5, 6 and draw the vertical sides of the square. Drawing a circle through the dividing points 2–5 And 3–6 straight lines until they intersect with the vertical sides of the square (Figure 40, b), we get the vertices A, B, D, E described regular hexagon.

Figure 40

Other peaks C And F determined using an arc of a circle of radius O.A., which is carried out until it intersects with the continuation of the vertical diameter of a given circle.
3 PAIRINGS

Let's learn how to draw a hexagonal prism in different positions.

Study different ways of constructing a regular hexagon, make drawings of hexagons, check the correctness of their construction. Construct hexagonal prisms based on the hexagons.

Consider the hexagonal prism in Fig. 3.52 and its orthogonal projections in Fig. 3.53. At the base of a hexagonal prism (hexagon) are regular hexagons, the side faces are identical rectangles. In order to correctly depict a hexagon in perspective, you must first learn how to correctly depict its base in perspective (Fig. 3.54). In the hexagon in Fig. 3.55 vertices are designated by numbers from one to six. If you connect points 1 and 3, 4 and 6 with vertical straight lines, you will notice that these straight lines, together with the center point of the circle, divide the diameter 5 - 2 into four equal segments (these segments are indicated by arcs). The opposite sides of a hexagon are parallel to each other and to a line passing through its center and connecting two vertices (for example, sides 6 - 1 and 4 - 3 are parallel to line 5 - 2). These observations will help you construct a hexagon in perspective, as well as check the correctness of this construction. There are two ways to construct a regular hexagon from a representation: based on a circumcircle and based on a square.

Based on a circumscribed circle. Look at Fig. 3.56. All vertices of a regular hexagon belong to a circumcircle whose radius is equal to the side of the hexagon.


Horizontal hexagon. Draw a horizontal ellipse of arbitrary opening, i.e., a circumscribed circle in perspective. Now you need to find six points on it, which are the vertices of the hexagon. Draw any diameter of a given circle through its center (Fig. 3.57). The extreme points of the diameter - 5 and 2, lying on the ellipse, are the vertices of the hexagon. To find the remaining vertices, it is necessary to divide this diameter into four equal segments. The diameter has already been divided by the center point of the circle into two radii; all that remains is to divide each radius in half. In a perspective drawing, all four segments contract evenly as they move away from the viewer (Fig. 3.58). Now draw through the midpoints of the radii - points A and B - straight lines perpendicular to straight line 5 - 2. You can find their direction using tangents to the ellipse at points 5 and 2 (Fig. 3.59). These tangents will be perpendicular to the diameter 5 - 2, and the lines drawn through points A and B parallel to these tangents will also be perpendicular to the line 5 - 2. Designate the points obtained at the intersection of these lines with the ellipse as 1, 3, 4, 6 ( Fig. 3.60). Connect all six vertices with straight lines (Fig. 3.61).

Check the correctness of your construction in different ways. If the construction is correct, then the lines connecting the opposite vertices of the hexagon intersect in the center of the circle (Fig. 3.62), and the opposite sides of the hexagon are parallel to the corresponding diameters (Fig. 3.63). Another check method is shown in Fig. 3.64.

Vertical hexagon. In such a hexagon, the straight lines connecting points 7 and 3, b and 4, as well as tangents to the circumscribed circle at points 5 and 2, have a vertical direction and retain it in the perspective drawing. Thus, by drawing two vertical tangents to the ellipse, we find points 5 and 2 (points of tangency). Connect them with a straight line, and then divide the resulting diameter 5 - 2 into 4 equal segments, taking into account their perspective reductions (Fig. 3.65). Draw vertical lines through points A and B, and at their intersection with the ellipse, find points 1,3,6l4. Then connect points 1 - 6 sequentially with straight lines (Fig. 3.66). Check the correctness of the hexagon construction in the same way as the previous example.

The described method of constructing a hexagon allows us to obtain this figure based on a circle, which is easier to depict in perspective than a square of given proportions. Therefore, this method of constructing a hexagon seems to be the most accurate and universal. The square-based construction method makes it easy to depict a hexagon in the case when there is already a cube in the drawing, in other words, when the proportions of the square and the direction of its sides are determined.

Based on a square. Look at Fig. 3.67. A hexagon inscribed in a square is equal to the side of the square in the horizontal direction 5 - 2, and less than its length in the vertical direction.

Vertical hexagon. Draw a vertical square in perspective. Draw a straight line through the intersection of the diagonals parallel to its horizontal sides. Divide the resulting segment 5 - 2 into four equal parts and draw vertical lines through points A and B (Fig. 3.68). The lines delimiting the hexagon at the top and bottom do not coincide with the sides of the square. Draw them at a certain distance (1114 a) from the horizontal sides of the square and parallel to them. By connecting points 1 and 3 found in this way with point 2, and points 6 and 4 with point 5, we obtain a hexagon (Fig. 3.69).

A horizontal hexagon is built in the same sequence (Fig. 3.70 and 3.71).

This construction method is only suitable for hexagons with sufficient opening. If the opening of the hexagon is insignificant, it is better to use the method based on the circumscribed circle. To check a hexagon constructed through a square, you can use methods already known to you.

In addition, there is another way - to describe a circle around the resulting hexagon (in your drawing - an ellipse). All vertices of the hexagon must belong to this ellipse.

Once you have mastered the skills of drawing a hexagon, you will be free to move on to drawing a hexagonal prism. Carefully look at the diagram in Fig. 3.72, as well as diagrams for constructing hexagonal prisms based on a circumscribed circle (Fig. 3.73; 3.74 and 3.75) and based on a square (Fig. 3.76; 3.77 and 3.78). Draw vertical and horizontal hexagons in different ways. In the drawing of a vertical hexagon, the long sides of the side faces will be vertical straight lines parallel to each other, and the hexagon of the base will be more open the further it is from the horizon line. In a drawing of a horizontal hexagon, the long sides of the side faces will converge at the vanishing point on the horizon, and the opening of the base hexagon will be greater the further it is from the viewer. When depicting a hexagon, also make sure that the parallel edges of both bases converge in perspective (Fig. 3.79; 3.80).

Hexagon grids (hexagonal grids) are used in some games, but they are not as simple or common as rectangle grids. I've been collecting resources on hex meshes for almost 20 years, and I wrote this guide to the most elegant approaches, implemented in the simplest code. This article makes extensive use of the guides of Charles Fu and Clark Verbrugge. I will describe the different ways to create hexagon meshes, their relationships, and the most common algorithms. Many parts of this article are interactive: selecting a grid type changes the corresponding diagrams, code, and texts. (Note per.: this applies only to the original, I advise you to study it. In the translation, all the information of the original is preserved, but without interactivity.).

The code examples in the article are written in pseudocode, so they are easier to read and understand in order to write your own implementation.

Geometry

Hexagons are six-sided polygons. Regular hexagons have all sides (edges) of the same length. We will only work with regular hexagons. Typically, hexagon meshes use horizontal (pointy top) and vertical (flat top) orientations.


Hexagons with flat (left) and sharp (right) tops

Hexagons have 6 faces. Each face is common to two hexagons. Hexagons have 6 corner points. Each corner point is common to three hexagons. You can read more about centers, edges, and corner points in my article on mesh parts (squares, hexagons, and triangles).

Angles

In a regular hexagon, the internal angles are 120°. There are six "wedges", each of which is an equilateral triangle with internal angles of 60°. Corner point i is located at a distance of (60° * i) + 30°, size units from the center center. In the code:

Function hex_corner(center, size, i): var angle_deg = 60 * i + 30 var angle_rad = PI / 180 * angle_deg return Point(center.x + size * cos(angle_rad), center.y + size * sin(angle_rad) )
To fill a hexagon, you need to get the vertices of the polygon from hex_corner(…, 0) to hex_corner(…, 5) . To draw the outline of the hexagon, you need to use these vertices and then draw the line again in hex_corner(..., 0) .

The difference between the two orientations is that x and y are swapped, resulting in a change in angles: flat-top hexagons have angles of 0°, 60°, 120°, 180°, 240°, 300°, and pointed-top hexagons have angles of 30 °, 90°, 150°, 210°, 270°, 330°.


Corners of hexagons with flat and sharp tops

Size and location

Now we want to place several hexagons together. In horizontal orientation, the height of the hexagon is height = size * 2 . The vertical distance between adjacent hexagons is vert = height * 3/4 ​​.

Hexagon width width = sqrt(3)/2 * height . The horizontal distance between adjacent hexagons is horiz = width .

Some games use pixel art for hexagons, which does not exactly match the regular hexagons. The angle and placement formulas described in this section will not match the dimensions of such hexagons. The rest of the article describing hex mesh algorithms applies even if the hexagons are slightly stretched or squashed.



Coordinate systems

Let's start assembling the hexagons into a grid. In the case of grids of squares, there is only one obvious way to assemble. For hexagons, there are many approaches. I recommend using cubic coordinates as your primary representation. Axial coordinates or offset coordinates should be used to store maps and display coordinates to the user.

Offset coordinates

The most common approach is to offset each subsequent column or row. Columns are designated col or q. Rows are denoted by row or r . You can offset odd or even columns/rows, so horizontal and vertical hexagons each have two options.


Horizontal arrangement "odd-r"


Horizontal arrangement “even-r”


Vertical "odd-q" arrangement


Vertical arrangement “even-q”

Cubic coordinates

Another way to look at hexagon grids is to see them as three main axes, not two, as in grids of squares. They display elegant symmetry.

Let's take a grid of cubes and let's cut it out diagonal plane at x + y + z = 0. This is a strange idea, but it will help us simplify the hexagon mesh algorithms. In particular, we will be able to use standard operations from Cartesian coordinates: summing and subtracting coordinates, multiplying and dividing by a scalar quantity, as well as distances.

Notice the three main axes on the grid of cubes and their relationship to the six diagonal directions of the hexagon grid. The diagonal axes of the grid correspond to the main direction of the hexagon grid.


Hexagons


cubes

Since we already have algorithms for square and cube meshes, using cubic coordinates allows us to adapt these algorithms to hexagon meshes. I will use this system for most of the article's algorithms. To use the algorithms with a different coordinate system, I convert the cubic coordinates, run the algorithm, and then convert them back.

Learn how cubic coordinates work for a hexagon mesh. When you select hexagons, cubic coordinates corresponding to the three axes are highlighted.

  1. Each direction of the cube grid corresponds to lines on a grid of hexagons. Try selecting a hexagon with z equal to 0, 1, 2, 3 to see the connection. The line is marked in blue. Try the same for x (green) and y (purple).
  2. Each direction of the hexagon grid is a combination of two directions of the cube grid. For example, the "north" of a hexagon grid lies between +y and -z , so each step by "north" increases y by 1 and decreases z by 1.
Cubic coordinates are a reasonable choice for a hexagon grid coordinate system. The condition is x + y + z = 0, so it must be preserved in the algorithms. The condition also ensures that there will always be a canonical coordinate for each hexagon.

There are many different coordinate systems for cubes and hexagons. In some of them the condition is different from x + y + z = 0. I showed only one of many systems. You can also create cubic coordinates with x-y , y-z , z-x , which have their own set of interesting properties, but I won't go into them here.

But you could argue that you don't want to store 3 numbers for the coordinates because you don't know how to store the map that way.

Axial coordinates

An axial coordinate system, sometimes called a "trapezoidal" coordinate system, is constructed from two or three coordinates from a cubic coordinate system. Since we have the condition x + y + z = 0, the third coordinate is not needed. Axial coordinates are useful for storing maps and displaying coordinates to the user. As with cubic coordinates, you can use the standard operations of adding, subtracting, multiplying, and dividing Cartesian coordinates.

There are many cubic coordinate systems and many axial ones. I won't cover every combination in this guide. I'll select two variables, q (column) and r (row). In the diagrams in this article, q corresponds to x and r corresponds to z, but this correspondence is arbitrary because you can rotate and rotate the diagrams to obtain different correspondences.

The advantage of this system over displacement grids is that the algorithms are more understandable. The downside to the system is that storing a rectangular card is a bit weird; see the section on saving maps. Some algorithms are even clearer in cubic coordinates, but since we have the condition x + y + z = 0, we can calculate the third implied coordinate and use it in these algorithms. In my projects I call the axes q, r, s, so the condition looks like q + r + s = 0, and I can calculate s = -q - r when needed.

Axles

Offset coordinates are the first thing most people think of because they are the same as the standard Cartesian coordinates used for grids of squares. Unfortunately, one of the two axes must run against the grain, and this ends up complicating things. Cube and axis systems go the distance and have simpler algorithms, but card storage is a little more complex. There is another system called “alternating” or “dual”, but we will not consider it here; some find it easier to work with than cubic or axial.


Offset coordinates, cubic and axial

Axis is the direction in which the corresponding coordinate is increasing. Perpendicular to an axis is the line on which the coordinate remains constant. The grid diagrams above show perpendicular lines.

Coordinate transformation

It's likely that you'll use axial or offset coordinates in your design, but many algorithms are more easily expressed in cubic coordinates. Therefore, we need to be able to convert coordinates between systems.

Axial coordinates are closely related to cubic coordinates, so the conversion is simple:

# convert cubic to axial coordinates q = x r = z # convert axial to cubic coordinates x = q z = r y = -x-z
In code, these two functions can be written as follows:

Function cube_to_hex(h): # axial var q = h.x var r = h.z return Hex(q, r) function hex_to_cube(h): # cubic var x = h.q var z = h.r var y = -x-z return Cube(x, y , z)
Offset coordinates are quite a bit more complicated:

Adjacent hexagons

Given one hexagon, what six hexagons is it next to? As you might expect, the answer is easiest in cubic coordinates, quite easy in axial coordinates, and a little more difficult in displacement coordinates. You may also need to calculate six "diagonal" hexagons.

Cubic coordinates

Moving one space in hex coordinates causes one of the three cubic coordinates to change to +1 and the other to -1 (the sum must remain 0). At +1, three possible coordinates can change, and at -1, the remaining two. This gives us six possible changes. Each corresponds to one of the directions of the hexagon. The simplest and fastest way is to precompute the changes and put them into a cubic coordinate table Cube(dx, dy, dz) at compile time:

Var directions = [ Cube(+1, -1, 0), Cube(+1, 0, -1), Cube(0, +1, -1), Cube(-1, +1, 0), Cube( -1, 0, +1), Cube(0, -1, +1) ] function cube_direction(direction): return directions function cube_neighbor(hex, direction): return cube_add(hex, cube_direction(direction))

Axial coordinates

As before, we use the cubic system to begin with. Let's take the Cube(dx, dy, dz) table and transform it into the Hex(dq, dr) table:

Var directions = [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, 0), Hex(-1, +1), Hex(0, +1) ] function hex_direction(direction): return directions function hex_neighbor(hex, direction): var dir = hex_direction(direction) return Hex(hex.q + dir.q, hex.r + dir.r)

Offset coordinates

In axial coordinates, we make changes depending on where we are on the grid. If we are in an offset column/row, then the rule is different from the case of a column/row without an offset.

As before, we create a table of numbers that need to be added to col and row . However, this time we will have two arrays, one for the odd columns/rows and the other for the even ones. Look at (1,1) in the grid map image above and notice how col and row change as you move in each of the six directions. Now let's repeat the process for (2,2) . The tables and code will be different for each of the four types of displacement grids; here is the corresponding code for each grid type.

Odd-r
var directions = [ [ Hex(+1, 0), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex(-1, +1), Hex(0 , +1) ], [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, 0), Hex(0, +1), Hex( +1, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.row & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Even-r
var directions = [ [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, 0), Hex(0, +1), Hex(+1 , +1) ], [ Hex(+1, 0), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex(-1, +1), Hex (0, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.row & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Grid for even (EVEN) and odd (ODD) rows

Odd-q
var directions = [ [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex(0 , +1) ], [ Hex(+1, +1), Hex(+1, 0), Hex(0, -1), Hex(-1, 0), Hex(-1, +1), Hex (0, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.col & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Even-q
var directions = [ [ Hex(+1, +1), Hex(+1, 0), Hex(0, -1), Hex(-1, 0), Hex(-1, +1), Hex(0 , +1) ], [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex (0, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.col & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Grid for even (EVEN) and odd (ODD) columns

Diagonals

Moving in "diagonal" space in hex coordinates changes one of the three cubic coordinates by ±2 and the other two by ∓1 (the sum must remain 0).

Var diagonals = [ Cube(+2, -1, -1), Cube(+1, +1, -2), Cube(-1, +2, -1), Cube(-2, +1, +1 ), Cube(-1, -1, +2), Cube(+1, -2, +1) ] function cube_diagonal_neighbor(hex, direction): return cube_add(hex, diagonals)
As before, we can convert these coordinates to axial coordinates by dropping one of the three coordinates, or convert them to offset coordinates by first calculating the results.


Distances

Cubic coordinates

In the cubic coordinate system, each hexagon is a cube in three-dimensional space. Adjacent hexagons are spaced 1 apart in the hex grid, but spaced 2 apart in the cube grid. This makes calculating distances simple. In a grid of squares, the Manhattan distances are abs(dx) + abs(dy) . In a grid of cubes, the Manhattan distances are abs(dx) + abs(dy) + abs(dz) . The distance in the hexagon grid is equal to half of them:

Function cube_distance(a, b): return (abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z)) / 2
The equivalent of this notation would be to say that one of the three coordinates must be the sum of the other two, and then take that as the distance. You can choose the halving form or the maximum value form below, but they give the same result:

Function cube_distance(a, b): return max(abs(a.x - b.x), abs(a.y - b.y), abs(a.z - b.z))
In the figure, the maximum values ​​are highlighted in color. Note also that each color represents one of the six "diagonal" directions.

GIF


Axial coordinates

In the axial system, the third coordinate is expressed implicitly. Let's convert from axial to cubic to calculate distance:

Function hex_distance(a, b): var ac = hex_to_cube(a) var bc = hex_to_cube(b) return cube_distance(ac, bc)
If the compiler inline (inline) hex_to_cube and cube_distance in your case, then it will generate code like this:

Function hex_distance(a, b): return (abs(a.q - b.q) + abs(a.q + a.r - b.q - b.r) + abs(a.r - b.r)) / 2
There are many different ways to write the distances between hexagons in axial coordinates, but regardless of the writing method the distance between hexagons in the axial system is extracted from the Manhattan distance in the cubic system. For example, the described "difference of differences" is obtained by writing a.q + a.r - b.q - b.r as a.q - b.q + a.r - b.r and using the maximum value form instead of the bisection form cube_distance . They are all similar if you see the connection with cubic coordinates.

Offset coordinates

As with axial coordinates, we convert the offset coordinates to cubic coordinates and then use the cubic distance.

Function offset_distance(a, b): var ac = offset_to_cube(a) var bc = offset_to_cube(b) return cube_distance(ac, bc)
We'll use the same pattern for many of the algorithms: convert from hexagons to cubes, run the cubic version of the algorithm, and convert the cubic results to hexagon coordinates (axial or offset coordinates).

Drawing lines

How to draw a line from one hexagon to another? I'm using linear interpolation to draw lines. The line is uniformly sampled at N+1 points and it is calculated which hexagons these samples are in.

GIF


  1. First we calculate N, which will be the distance in hexagons between the endpoints.
  2. We then evenly sample N+1 points between points A and B. Using linear interpolation, we determine that for values ​​of i from 0 to N including them, each point will be A + (B - A) * 1.0/N * i . In the figure, these control points are shown in blue. The result is floating point coordinates.
  3. Let's convert each control point (float) back to hexagons (int). The algorithm is called cube_round (see below).
Put everything together to draw a line from A to B:

Function lerp(a, b, t): // for float return a + (b - a) * t function cube_lerp(a, b, t): // for hexagons return Cube(lerp(a.x, b.x, t), lerp(a.y, b.y, t), lerp(a.z, b.z, t)) function cube_linedraw(a, b): var N = cube_distance(a, b) var results = for each 0 ≤ i ≤ N: results.append( cube_round(cube_lerp(a, b, 1.0/N * i))) return results
Notes:

  • There are cases where cube_lerp returns a point that is exactly on the edge between two hexagons. Then cube_round moves it in one direction or another. Lines look better if they are moved in one direction. This can be done by adding an "epsilon"-hexagonal Cube(1e-6, 1e-6, -2e-6) to one or both endpoints before starting the loop. This will "nudge" the line in one direction so it doesn't hit the edges.
  • The DDA line algorithm in square grids equates N to the maximum distance along each of the axes. We do the same thing in cubic space, which is similar to distance in a hexagon grid.
  • The cube_lerp function should return a cube with float coordinates. If you're programming in a statically typed language, you won't be able to use the Cube type. You can define a FloatCube type instead, or inline a function in your line drawing code if you don't want to define another type.
  • You can optimize the code by inline cube_lerp and then calculate B.x-A.x , B.x-A.y and 1.0/N outside the loop. Multiplication can be converted to repeated summation. The result will be something like a DDA line algorithm.
  • I use axial or cubic coordinates to draw lines, but if you want to work with offset coordinates, check out .
  • There are many options for drawing lines. Sometimes "overcoating" is required. I was sent code for drawing super-covered lines in hexagons, but I haven't looked into it yet.

Moving range

Coordinate range

Given a hexagon center and a range N, which hexagons are within N steps of it?

We can do the inverse from the distance formula between hexagons distance = max(abs(dx), abs(dy), abs(dz)) . To find all hexagons within N we need max(abs(dx), abs(dy), abs(dz)) ≤ N . This means that all three values ​​are needed: abs(dx) ≤ N and abs(dy) ≤ N and abs(dz) ≤ N . Removing the absolute value, we get -N ≤ dx ≤ N and -N ≤ dy ≤ N and -N ≤ dz ≤ N . In code this will be a nested loop:

Var results = for each -N ≤ dx ≤ N: for each -N ≤ dy ≤ N: for each -N ≤ dz ≤ N: if dx + dy + dz = 0: results.append(cube_add(center, Cube(dx , dy, dz)))
This cycle will work, but it will be quite ineffective. Of all the dz values ​​that we loop through, only one actually satisfies the cube condition dx + dy + dz = 0. Instead, we will directly calculate the value of dz satisfying the condition:

Var results = for each -N ≤ dx ≤ N: for each max(-N, -dx-N) ≤ dy ≤ min(N, -dx+N): var dz = -dx-dy results.append(cube_add( center, Cube(dx, dy, dz)))
This cycle passes only along the required coordinates. In the figure, each range is a pair of lines. Each line is an inequality. We take all hexagons that satisfy the six inequalities.

GIF


Overlapping Ranges

If you need to find hexagons that are in multiple ranges, you can intersect the ranges before generating a list of hexagons.

You can approach this problem from the point of view of algebra or geometry. Algebraically, each domain is expressed as inequality conditions of the form -N ≤ dx ≤ N , and we need to find the intersection of these conditions. Geometrically, each region is a cube in 3D space, and we will intersect two cubes in 3D space to obtain a cuboid in 3D space. We then project it back onto the x + y + z = 0 plane to get hexagons. I will solve this problem algebraically.

First, we rewrite the condition -N ≤ dx ≤ N in the more general form x min ≤ x ≤ x max , and take x min = center.x - N and x max = center.x + N . Let's do the same for y and z, resulting in the general form of the code from the previous section:

Var results = for each xmin ≤ x ≤ xmax: for each max(ymin, -x-zmax) ≤ y ≤ min(ymax, -x-zmin): var z = -x-y results.append(Cube(x, y, z))
The intersection of two ranges a ≤ x ≤ b and c ≤ x ≤ d is max(a, c) ≤ x ≤ min(b, d) . Since the area of ​​hexagons is expressed as ranges over x, y, z, we can intersect each of the ranges x, y, z separately and then use a nested loop to generate a list of hexagons in the intersection. For one area of ​​hexagons we take x min = H.x - N and x max = H.x + N , similarly for y and z . For the intersection of two hexagon regions, we take x min = max(H1.x - N, H2.x - N) and x max = min(H1.x + N, H2.x + N), similarly for y and z . The same pattern works for the intersection of three or more areas.

GIF


Obstacles

If there are obstacles, the easiest way is to fill with a distance limitation (width-first search). In the figure below we limit ourselves to four moves. In the code, fringes[k] is an array of all hexagons that can be reached in k steps. Each time we pass through the main loop, we expand level k-1 by level k.

Function cube_reachable(start, movement): var visited = set() add start to visited var fringes = fringes.append() for each 1< k ≤ movement: fringes.append() for each cube in fringes: for each 0 ≤ dir < 6: var neighbor = cube_neighbor(cube, dir) if neighbor not in visited, not blocked: add neighbor to visited fringes[k].append(neighbor) return visited

Turns

Given a hexagon vector (the difference between two hexagons), we may need to rotate it so that it points to the other hexagon. This is easy to do with cubic coordinates if you stick to a 1/6 circle rotation.

A 60° rotation to the right moves each coordinate one position to the right:

[ x, y, z] to [-z, -x, -y]
A 60° rotation to the left moves each coordinate one position to the left:

[ x, y, z] to [-y, -z, -x]



“Having played” [in the original article] with the diagram, you can see that each rotation is 60° changes signs and physically “rotates” the coordinates. After a 120° rotation, the signs become the same again. A 180° rotation changes signs, but the coordinates return to their original position.

Here is the complete sequence of rotation of position P around the central position C, resulting in a new position R:

  1. Convert P and C positions to cubic coordinates.
  2. Calculating a vector by subtracting the center: P_from_C = P - C = Cube(P.x - C.x, P.y - C.y, P.z - C.z) .
  3. Rotate the vector P_from_C as described above and assign the final vector the designation R_from_C .
  4. Converting the vector back to position by adding the center: R = R_from_C + C = Cube(R_from_C.x + C.x, R_from_C.y + C.y, R_from_C.z + C.z) .
  5. Converts the cubic position R back to the desired coordinate system.
There are several stages of transformation, but each of them is quite simple. It's possible to shorten some of these steps by defining the rotation directly in axial coordinates, but hex vectors don't work with offset coordinates, and I don't know how to shorten the steps for offset coordinates. See also the discussion on stackexchange for other ways to calculate rotation.

Rings

Simple ring

To find out whether a given hexagon belongs to a ring of a given radius radius, you need to calculate the distance from this hexagon to the center, and find out whether it is equal to radius. To get a list of all such hexagons, you need to take radius steps from the center, and then follow the rotated vectors along the path along the ring.

Function cube_ring(center, radius): var results = # this code doesn't work for radius == 0; do you understand why? var cube = cube_add(center, cube_scale(cube_direction(4), radius)) for each 0 ≤ i< 6: for each 0 ≤ j < radius: results.append(cube) cube = cube_neighbor(cube, i) return results
In this code, the cube starts on a ring, shown with a large arrow from the center to the corner of the diagram. I chose angle 4 to start with because it matches the path my direction numbers are moving. You may need a different starting angle. At each stage of the inner loop, the cube moves one hexagon around the ring. After 6 * radius steps he ends up where he started.


Spiral rings

By going through the rings in a spiral pattern, we can fill in the inner parts of the rings:

Function cube_spiral(center, radius): var results = for each 1 ≤ k ≤ radius: results = results + cube_ring(center, k) return results



The area of ​​a large hexagon is the sum of all the circles plus 1 for the center. Use this formula to calculate area.

Traversing hexagons in this way can also be used to calculate the range of movement (see above).

Area of ​​visibility

What is visible from a given position at a given distance, and is not blocked by obstacles? The simplest way to determine this is to draw a line to each hexagon in a given range. If the line does not meet the walls, then you see a hexagon. Move your mouse over the hexagons [on the diagram in the original article] to see how lines are drawn to these hexagons and the walls that the lines meet.

This algorithm can be slow over large areas, but it is easy to implement, so I recommend starting with it.

GIF



There are many different definitions of visibility. Do you want to see the center of another hexagon from the center of the original one? Do you want to see any part of another hexagon from the center of the original one? Maybe any part of another hexagon from any point of the initial one? Obstacles that obstruct your view are smaller than a full hexagon? Scope is a trickier and more varied concept than it seems at first glance. Let's start with the simplest algorithm, but expect that it will definitely correctly calculate the answer in your project. There are even cases when a simple algorithm produces illogical results.

I want to expand this guide in the future. I have