Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reliably generate hexagonal grid over a world map

Goal

I'm attempting to build an application whereby the whole world map is split into a large number of hexagons. These hexagons, once generated would always cover the same area on the map. Then, given certain geographical coordinates, a hexagon would be rendered on the map if these coordinates would be located within its boundaries. These hexagons need to be very small, each side being approx. 50m - which poses the main issue.

First attempt

My first idea was to pre-generate the hexagonal grid where each hex would be invisible and after figuring out whether a coordinate is within bounds simply change the style of a hexagon. This works if hexagon side length is really large (hundreds of kilometers). In my case however, the application will run out of memory when attempting to draw very small hexagons, even for a smaller portion of the map.

// Attempting to cover the whole map in small hexagons
turf.hexGrid([-179.99, -89.99, 179.99, 89.99], 0.2);

First attempt, but with a twist

My second idea was to use a mask option of hexGrid(), so that I would still generate a hex grid with unchanging hexagon coordinates, but would only attempt to render hexagons within a small map area (e.g. the area visible on a map). This doesn't seem to be possible either, since even generating such grid (and not rendering it on the map) proves too consume too many resources.

// Attempting to cover the whole map in small hexagons only within a given area (mask)
turf.hexGrid([-179.99, -89.90, 178.99, 88.90], 30, {
  mask: polygon([[[20, 60], [21, 60], [22, 62], [22, 63], [20, 60]]]),
});

This will however produce very skewed hexagons, which leads me to believe attempting to generate hex grid for the whole world is generally a bad idea.

skewed hexagons when spread over large area

Optimistic calculations

My last attempt was to generate a single hexagon in top left corner of the map and use its coordinates to calculate how many hexagon would fit between that first hexagon, and any given coordinates.

These calculations almost works but due to rounding up or perhaps a mistake in how I'm calculating the distances (manually) the positioning is off by increasingly large number the further away the coordinates are from the first hexagon.

Real life example The closest example to what I want to achieve is in the running game called "Run an Empire". The hex grid there seems to be loaded on-demand and only surrounding the area one is located in. From the looks of it, that grid does not have any gaps which would prevent the hexagons to connect perfectly.

As an added point of interest, drawing hexagons on a world map will skew them the further north we go. This doesn't seem to happen in the above mentioned game (screenshot below). Would that mean the hexagon sizes are hard-coded, perhaps they are draw on a different map projection in which the skewed doesn't happen?

Main question

Given geographical coordinates like GPS location, how can one reliably generate a hexagonal grid, so that when another hexagonal grid is generated based on another set of coordinates, these two grids would overlap perfectly? I'm open to solving this any tools, not necessarily Turf or Mapbox.


Run an Empire game screenshot

like image 792
Maciej Gurban Avatar asked Apr 22 '19 17:04

Maciej Gurban


1 Answers

I suggest to generate a vector layer with all the hexagons, and load them dynamically performing a geoquery using a geodatabase. The intersection of the point where the pin was placed, will return the hexagon under it, and if you use a buffer, you can also add more hexagons around it.

The boundaries for WGS84 are -180.0000, -90.0000, 180.0000, 90.0000 (I know it is obvious) source: https://spatialreference.org/ref/epsg/wgs-84/ This means that you need to start from there, do an estimation of the number of hexagons you need/want to create. According to https://planetcalc.com/7721/, the hearth radius in meters is 6378137. Assuming you want a hexagon made of 6 equilateral triangles this means that in order to get a hexagon with the side of around 50 meters it will be 100m wide (assuming the flat sides are oriented horizontally).

Now we can say that we need circa 63781 hexagons at the equator, let's simplify to 63800, 360/63800 = 0.00564... so I suggest to start with an offset of the points at the equator of 0.0055 degrees.

One thing to underline, is that WGS84 is a geoid and not spherical (like our planet) so the final representation could be stretched a bit.

UPDATE: To generate the grid automatically, it looks like you can use Quantum GIS as well thanks to Grass

Edit:

https://github.com/rldhont/Quantum-GIS/blob/master/python/plugins/processing/algs/grass7/description/v.mkgrid.txt https://grass.osgeo.org/grass76/manuals/v.mkgrid.html

For a later version: https://github.com/OSGeo/grass/blob/releasebranch_8_0/vector/v.mkgrid/v.mkgrid.html

like image 114
Norcino Avatar answered Nov 30 '22 23:11

Norcino