Math for fun.
(2011-07-10: Fixed a few spelling errors and a maths error: of course the short edge is half the hypotenuse, not half the long edge)
Given that the subjects of this post are usually in English, it is time again for an English blog post. This time it’s about math and Role-Playing Games.
I recently acquired the Core Rulebook of Traveller, specifically the new Mongoose edition, because I am still looking for an entertaining SF system. Traveller looks like it might fit the bill, so I’m familiarising myself with the rules and starting to do some design work for a one-shot adventure to run, to see if it works out OK in actual play.
The nice thing about Traveller is that it gives you a lot of tools to create your own setting. The starting point is the sub-sector map, where you draw out your worlds and their features and relations.
Now, this is a hex map, and I had been looking for some time for Linux tools to create hex maps. Unfortunately, they are rather thin on the ground. So why not do it myself? Using the Traveller rules, I could create a sub-sector with worlds, bases, starports and trade routes fully automatically, and with a bit more effort I could even draw up the map automatically, since the Traveller map symbols are standardised.
So here’s the first snag: I haven’t done any trigonometry since my school days, which is a long way in the past, and I wasn’t good in the subject to begin with. So, the first step is to find out how to calculate the size and position of a regular hexagon in a Cartesian space.
Turns out this is rather simple. See the diagram for illustrations: for a hexagon with edges of length a, the distance from the origin (the centre of the hexagon) to a vertex is a. The distance from the intersection with the edge and the nearest vertex is, of course, b=a/2 (the segments to the vertex and to the edge form a right triangle with angle 60∘, therefore the short edge is 1/2 the hypotenuse), and the distance from the origin to the centre of an edge is c=a*sin(60∘). Knowing that, we can calculate the x/y coordinates of every vertex (code example).
After that, the Cairo toolkit gives us the tools to draw a hexagon. First we use the move_to method to move to the first vertex, and then we just iterate over the list of vertices and do a line-to to the next vertex, ending with a close-path call to draw the line from the last vertex back to the first one. Of course, we have to do a bit of translation to transform the normal Cartesian coordinates into a page-oriented axis system with the origin at the top left and the positive direction of the y-axis downwards.
All that remains is to calculate how big the hexes are going to be on the page. Since the odd hex-columns are 2a wide and the even columns are offset and only 1a wide, the total width will be (1.5*(number of columns)+1)*a, and the total height will be (2*(number of rows)+1)*c. If we don’t mind the last column to be cut into half-hexes, we can drop the +1. Solve for a, and you have the optimum edge length.
Now it’s only a matter of iterating over the row and column numbers, calculating the origin for every hex based on the row/column coordinate, calculating the vertices as above, and then drawing the hexagon. Voila: 1 empty map to go.
I hope this was clear.