A module to create (almost) hexagonal grids of variable size on a sphere, fully implemented in python.
The grid is built by subdividing a base polyhedron into hexagon tiles. The base polyhedron is an icosahedron, which comprises:
- 20 faces (equilateral triangles)
- 12 vertices
- 30 edges
At the vertices of the icosahedron, instead of an hexagon, a pentagon is constructed.
For a given grid resolution n, each edge of the icosahedron goes through exactly n hexagon centers (not counting the polygons found at the ends). The inside of faces is then filled with tile-centers by following a triangular pattern.
This allows to cover the icosahedron. Its surface is then mapped to the sphere using a projection.
There are two available projections in projection module:
-
GnomonicProj: a simple projection, which produces hexagonal tiles about 60% larger (in area) at the corners of a face than at its center. -
SnyderEAProj: a more complex projection, slower to compute (roughly 3x slower than Gnomonic projection), but which preserves areas. The implementation is based on Brenton R S Recht's blog. See there for more details.
A tile identifier has the following pattern: ?XXXXX-YYYYY-ZZZZZ
?is one of the 20 lettersA ... T, each letter corresponding to one face of the icosahedronXXXXX,YYYYY,ZZZZZare the integer coordinates of the tile in the triangular mesh covering face?. An useful property holds:
XXXXX + YYYYY + ZZZZZ = 2 * (n + 1)
- Install the package with pip
$ pip install hexasphere
- Import the library in python
from hexasphere import hexgrid, projection
- Create a
HexGridobject:
my_grid = hexgrid.HexGrid()
- Instantiate a projection system
Projectionassociated with this grid:
my_projection = projection.MyProjection(my_grid)
- Provide the projection system to the grid:
my_grid.projection = my_projection
- Compute closest grid resolution
nfor any desired hex dimension (in kilometers):
n = my_grid.compute_n_for_radius(0.25)
n = my_grid.compute_n_for_height(0.25)
n = my_grid.compute_n_for_side(0.25)
- Retrieve average hex dimension (in kilometers) for any given resolution
n:
my_grid.compute_radius_for_n(n)
my_grid.compute_height_for_n(n)
my_grid.compute_side_for_n(n)
- To find the string identifier of the hexagon to which a geographic point
(lat, lon)belongs, call:
hex_identifier = my_grid.latlon_to_hex(lat, lon, n, out_str=True)[0]
- To find the
(lat, lon)coordinates of the center of an hex, call:
my_grid.hex_to_latlon(hex_identifier, in_str=True)
my_grid.hex_to_latlon(hex_identifier, n, in_str=True) # n is here not required
grid.latlon_to_hex also supports overlapping grids:
value = 12 # Overlap distance (in km)
my_grid.set_overlap(value)
The method grid.latlon_to_hex returns the list of distinct hexes a point of coordinates (lat, lon) belongs to:
hexes_identifier = my_grid.latlon_to_hex(lat, lon, n, out_str=True)
One can also deal with an Hexagon object instead of an hexagon string identifier:
hex_object = my_grid.latlon_to_hex(lat, lon, n)[0]
hex_object = hexgrid.Hexagon(my_grid, str_id=hexagon_identifier)
The coordinates of the vertices of the corresponding shape can then be retrieved:
shape_coordinates = hex_object.retrieve_polygon(out_latlon=True)
To retrieve a neighboring hex:
hex_neighbor = hex_object.compute_neighbor(dP=(0, 1, -1))
To retrieve the list of hexes in the k-ring centered on the hex object:
hexes = hex_object.k_ring(k, out_str=True)