DGG Grid System

DGG Grid System

Code
using GlobalGrids, GeoMakie, CairoMakie

grid = ISEA3H()

cells_r0 = [ISEA3HCell(i, Int[]) for i in 0:19]

fig = Figure()
ax = GeoAxis(fig[1,1], dest = "+proj=ortho +lon_0=-50 +lat_0=30")
poly!(ax, cells_r0, color=(:black, .4))

ep = surface!(ax,
    -180..180, -90..90,
    zeros(axes(rotr90(GeoMakie.earth())));
    shading = NoShading, color = rotr90(GeoMakie.earth())
)
translate!(ep, 0, 0, -1)

fig

The DGG (Discrete Global Grid) module provides parametric grid types inspired by DGGRID. Grid configuration is encoded in type parameters, enabling zero-cost dispatch across different projections, apertures, and topologies.

Grid Configuration

A DGG grid is parameterized by three values:

Parameter Options Description
Projection :isea, :fuller Map projection (currently uses Lambert azimuthal equal-area)
Aperture 3, 4, 7, 43 Number of child cells per parent (currently 3 is implemented)
Topology :hex, :tri, :diamond Cell shape (currently :hex is implemented)

This gives 12 preset grid types, each with a corresponding cell type:

Grid Cell Description
ISEA3H ISEA3HCell ISEA aperture-3 hexagonal
ISEA4H ISEA4HCell ISEA aperture-4 hexagonal
ISEA7H ISEA7HCell ISEA aperture-7 hexagonal
ISEA43H ISEA43HCell ISEA mixed 4-3 hexagonal
ISEA4T ISEA4TCell ISEA aperture-4 triangular
ISEA4D ISEA4DCell ISEA aperture-4 diamond
FULLER3H FULLER3HCell Fuller aperture-3 hexagonal
FULLER4H FULLER4HCell Fuller aperture-4 hexagonal
FULLER7H FULLER7HCell Fuller aperture-7 hexagonal
FULLER43H FULLER43HCell Fuller mixed 4-3 hexagonal
FULLER4T FULLER4TCell Fuller aperture-4 triangular
FULLER4D FULLER4DCell Fuller aperture-4 diamond
Note

Currently only aperture-3 hexagonal grids (ISEA3H, FULLER3H) are fully implemented. Other apertures and topologies are defined in the type system but not yet functional.

Cell Index Layout

Each cell wraps a single UInt64 encoding the base face (0-19) and hierarchical digits:

Aperture Bits/digit Max digits Max resolution
3, 4 2 29 29
7, 43 3 19 19

Cell count at resolution \(r\) with aperture \(A\): \(\;20 \cdot A^r\)

At resolution 0, there are 20 base cells corresponding to the 20 faces of the icosahedron. All cells are hexagons (no pentagons in the face-based addressing scheme).

Creating a DGGCell

From Coordinates and Resolution

coord = LonLat(-75.0, 54.0)
cell = ISEA3HCell(coord, 5)
 DGGCell 5 0-00021

From Base Face and Digits

# Base face 0, digits [1, 2, 0]
cell = ISEA3HCell(0, [1, 2, 0])
 DGGCell 3 0-120

From Hex String

cell = ISEA3HCell(coord, 5)
str = encode(cell)
@info str
ISEA3HCell(str)
[ Info: 9ffffffffffff
 DGGCell 5 0-00021

Using the Convenience Wrapper

# dggcells defaults to ISEA3H
dggcells(LonLat(0.0, 0.0), 5)
1-element Vector{ISEA3HCell}:
  DGGCell 5 2-02111

Inspecting Cells

Code
cell = ISEA3HCell(LonLat(-75.0, 54.0), 5)

@show resolution(cell)
@show is_pentagon(cell)
@show GlobalGrids.digits(cell)
@show base_cell(cell)
@show decode(cell)
@show encode(cell)
nothing
resolution(cell) = 5
is_pentagon(cell) = false
GlobalGrids.digits(cell) = [0, 0, 0, 2, 1]
base_cell(cell) = 0
decode(cell) = "0-00021"
encode(cell) = "9ffffffffffff"

GeoInterface

Code
import GeoInterface as GI

cell = ISEA3HCell(LonLat(-75.0, 54.0), 5)

@show GI.centroid(cell)
@show GI.coordinates(cell)
@show GI.area(cell)  # meters²
nothing
GI.centroid(cell) = LonLat{Float64} (-74.80647024233285, 53.05197910471103)
GI.coordinates(cell) = GlobalGrids.LonLat{Float64}[LonLat{Float64} (-76.91521522049418, 51.774045987604815), LonLat{Float64} (-74.11520152663938, 51.29823891022437), LonLat{Float64} (-71.9503424158508, 52.5233039946571), LonLat{Float64} (-72.57483691601311, 54.28987114368925), LonLat{Float64} (-75.56583819628354, 54.79924651143595), LonLat{Float64} (-77.73282091186331, 53.506402242296794), LonLat{Float64} (-76.91521522049418, 51.774045987604815)]
GI.area(cell) = 1.049517740173022e11

Grid Hierarchy

  • parent, siblings, and children
Code
cell = ISEA3HCell(LonLat(0.0, 0.0), 5)

fig = Figure()
ax = Axis(fig[1,1], title="Cell:Black, Parent:Blue, Siblings:Orange, Children:Green")
lines!(ax, GlobalGrids.parent(cell), color = :blue)
poly!(ax, cell, color = :black)
lines!(ax, siblings(cell), color = :orange)
lines!(ax, children(cell), color = :green)
fig

Quantizing Geometries

Point

Code
ll = LonLat(-54.0, -12.0)

fig = Figure()
ax = Axis(fig[1,1], title="Cells Containing Point at Resolutions 0-5")
for res in 0:5
    lines!(ax, dggcells(ll, res))
end
scatter!(ax, ll)

fig

MultiPoint

Code
coords = [LonLat(360rand() - 180, 180rand() - 90) for _ in 1:100]

x = ISEA3HCell.(coords, 0)

f, a, p = lines(x, axis=(;type=GeoAxis, dest = "+proj=ortho +lon_0=-50 +lat_0=30"))
scatter!(a, coords, color=:black)
f

Line

  • Containment options for lines: :center and :shortest_path.
Code
line = GI.Line([LonLat(0, 0), LonLat(1,1)])

fig = Figure(size=(700, 300))

for (i, containment) in enumerate((:center, :shortest_path))
    ax = Axis(fig[1, i], aspect=DataAspect(), title="containment = :$containment")
    x = dggcells(line, 6; containment)
    lines!(ax, x)
    lines!(ax, GI.coordinates(line), linewidth=3, color = :black)
end

fig

Polygon

  • Containment modes for polygons:
    • :center: Include cell if its center is inside the polygon.
    • :overlap: Include cell if any part intersects the polygon.
Code
boundary = [(-20.0, -20.0), (-20.0, 20.0), (20.0, 20.0), (20.0, -20.0), (-20.0, -20.0)]
poly = GI.Polygon([boundary])

fig = Figure(size=(700, 300))

for (i, containment) in enumerate((:center, :overlap))
    ax = Axis(fig[1, i], aspect=DataAspect(), title="containment = :$containment")
    x = dggcells(poly, 4; containment)
    lines!(ax, x)
    lines!(ax, GI.LineString(boundary), linewidth=2, color=:black)
end

fig

Comparison with IGEO7

Both DGG (aperture-3) and IGEO7 (aperture-7) use Lambert azimuthal equal-area projection on the icosahedron. Key differences:

ISEA3H IGEO7
Base cells 20 faces 12 vertices
Aperture 3 7
Children per cell 3 7 (hex) / 6 (pentagon)
Pentagons None 12 at each resolution
Digits 0-2 0-6
Rotation per level 30° 19.1°
Max resolution 29 20
Cells at res 5 4,860 168,072