How to reliably generate hexagonal grid over a world map
Asked Answered
U

1

8

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

Urial answered 22/4, 2019 at 17:15 Comment(6)
What kind of Coordinate system do you use? Can the hexagonal layer be a vectorial layer, dynamically loaded as needed (for example using GeoJSON)? In the past I used GeoServer, OpenLayer and other tools including offline desktop application such ESRI and QMAP. For your purpose, you can try geoserver, save your vector data in a geodb or file and then mesh up the background map with the vector on request based on the point you selected.Dwain
Another option is to get the coordinates you have selected, send an ajax request to a geo database, do a spatial query and return the exagon intersecting your point (or area), and using a buffer, you can even add 100m range for example and get all exagons in that area. For best precision the coordinate system should be the same between the background map, normally WGS84 (EPSG:4326), and the pre-generated grid. This because meshing 2 layers with 2 different coordinate systems always introduces a margin of error, and given your 5m size, it would be easy to notice the mismatch.Dwain
@Dwain AFAIK both Mapbox (drawing the map) and Turf (drawing hexes) use WGS84. The hexes are vectors and would be drawn only when within visible map area. They could be loaded async. I'll definitely check GeoServer although I was really hoping it would be possible to achieve this by calculating the coordinates. Would you recommend any resources to read up on for setting up geoserver the way you described?Urial
The GeoServer documentation is very good (docs.geoserver.org/latest/en/user/gettingstarted/…), I was about to point you to OpenGeo Suite but has been renamed and maybe changed, it is a shame all links seems to be broken, check this: github.com/boundlessgeo/suite and this opengeo-suite.software.informer.com/download. Use the installer in a VM or sandbox, I don't know that website.Dwain
If you decide to create the vector layer take a look at qgis.org/en/site, Quantum GIS is an incredible software and the community behind it is very active.Dwain
Thanks! Do you want to submit an answer so that I can accept it? Otherwise the bounty ends in 15 mins and is going to go to wasteUrial
D
1

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

Dwain answered 2/5, 2019 at 18:23 Comment(1)
last github link is 404Brachium

© 2022 - 2024 — McMap. All rights reserved.