Skip to content

Geodetic::Coordinate::H3

H3 Hexagonal Hierarchical Index

H3 is Uber's hierarchical geospatial indexing system that divides the globe into hexagonal cells (and 12 pentagons per resolution level) using an icosahedron projection. Each cell is identified by a 64-bit integer, typically displayed as a 15-character hex string like 872a1072bffffff.

H3 requires the libh3 C library installed on your system. Without it, all other coordinate systems work normally; H3 operations raise a clear error message with installation instructions.

Prerequisites

# macOS (Homebrew)
brew install h3

# Linux (build from source)
git clone https://github.com/uber/h3.git
cd h3
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build
sudo cmake --install build

You can also set the LIBH3_PATH environment variable to specify a custom library path:

export LIBH3_PATH=/path/to/libh3.dylib

Geodetic searches these paths automatically: - /opt/homebrew/lib/libh3.dylib (macOS ARM Homebrew) - /usr/local/lib/libh3.dylib (macOS Intel Homebrew) - /usr/lib/libh3.so (Linux system) - /usr/local/lib/libh3.so (Linux local install)

Key Differences from Other Spatial Hashes

Feature GH/OLC/GARS/GEOREF/HAM H3
Cell shape BoundingBox Hexagon (6 vertices)
to_area returns Areas::BoundingBox Areas::Polygon
neighbors returns Hash with 8 cardinal keys Array of 6 cells
Code format String 64-bit integer (hex string)
Dependency None (pure Ruby) libh3 (C library via fiddle)

H3 is a 2D coordinate system (no altitude). Conversions to/from other systems go through LLA as the intermediary. Each hex string represents a hexagonal cell; the coordinate's point value is the cell's centroid.

Constructor

# From a hex string
coord = Geodetic::Coordinate::H3.new("872a1072bffffff")

# From a hex string with 0x prefix
coord = Geodetic::Coordinate::H3.new("0x872a1072bffffff")

# From a 64-bit integer
coord = Geodetic::Coordinate::H3.new(0x872a1072bffffff)

# From any coordinate (converts via LLA)
coord = Geodetic::Coordinate::H3.new(lla_coord)
coord = Geodetic::Coordinate::H3.new(utm_coord, precision: 9)
Parameter Type Default Description
source String, Integer, or Coord -- An H3 hex string, integer, or coordinate
precision Integer 7 H3 resolution level (0-15)

Raises ArgumentError if the source string is empty, contains invalid hex characters, or does not represent a valid H3 cell index. String input is case-insensitive (normalized to lowercase). The 0x prefix is stripped automatically.

Attributes

Attribute Type Access Description
code String read-only The hex string representation
h3_index Integer read-only The 64-bit H3 cell index

H3 is immutable -- there are no setter methods.

Resolution

H3 uses "resolution" (0-15) instead of string-length precision. Higher resolution means smaller cells.

Resolution Approximate Cell Area Approximate Edge Length
0 4,357,449 km^2 1,108 km
1 609,788 km^2 419 km
2 86,801 km^2 158 km
3 12,393 km^2 60 km
4 1,770 km^2 23 km
5 252 km^2 8.5 km
6 36 km^2 3.2 km
7 5.2 km^2 (default) 1.2 km
8 0.74 km^2 461 m
9 0.105 km^2 174 m
10 0.015 km^2 66 m
11 0.002 km^2 25 m
12 307 m^2 9.4 m
13 43 m^2 3.6 m
14 6.2 m^2 1.3 m
15 0.9 m^2 0.5 m
coord.resolution             # => 7 (alias: coord.precision)
coord.cell_area              # => 5182586.98 (square meters)
coord.precision_in_meters    # => { lat: ~2276, lng: ~2276, area_m2: ~5182586 }

Checking Availability

Geodetic::Coordinate::H3.available?   # => true if libh3 is found

Conversions

All conversions chain through LLA. The datum parameter defaults to Geodetic::WGS84.

Instance Methods

coord.to_lla                    # => LLA (centroid of the cell)
coord.to_ecef
coord.to_utm
coord.to_enu(reference_lla)
coord.to_ned(reference_lla)
coord.to_mgrs
coord.to_usng
coord.to_web_mercator
coord.to_ups
coord.to_state_plane(zone_code)
coord.to_bng
coord.to_gh36
coord.to_gh
coord.to_ham
coord.to_olc
coord.to_georef
coord.to_gars

Class Methods

H3.from_lla(lla_coord)
H3.from_ecef(ecef_coord)
H3.from_utm(utm_coord)
H3.from_web_mercator(wm_coord)
H3.from_gh(gh_coord)
H3.from_georef(georef_coord)
H3.from_gars(gars_coord)
# ... and all other coordinate systems

LLA Convenience Methods

lla = Geodetic::Coordinate::LLA.new(lat: 40.689167, lng: -74.044444)
h3 = lla.to_h3                    # default resolution 7
h3 = lla.to_h3(precision: 9)      # resolution 9

lla = Geodetic::Coordinate::LLA.from_h3(h3)

Serialization

to_s(format = nil)

Returns the hex string. Pass :integer to get the 64-bit integer value.

coord = H3.new("872a1072bffffff")
coord.to_s             # => "872a1072bffffff"
coord.to_s(:integer)   # => 608693941536498687
coord.h3_index         # => 608693941536498687

to_a

Returns [lat, lng] of the cell centroid.

coord.to_a    # => [40.685..., -74.030...]

from_string / from_array

H3.from_string("872a1072bffffff")           # from hex string
H3.from_array([40.689167, -74.044444])       # from [lat, lng]

Neighbors

Returns all adjacent cells as an Array of H3 instances. Hexagons have 6 neighbors; pentagons have 5.

Note: unlike the rectangular spatial hashes which return a directional Hash (:N, :S, etc.), H3 returns a flat Array because hexagonal cells do not have cardinal directions.

coord = H3.new("872a1072bffffff")
neighbors = coord.neighbors
# => [H3, H3, H3, H3, H3, H3]

neighbors.length    # => 6

Grid Disk

The grid_disk(k) method returns all cells within k steps. This is a generalization of neighbors (which is grid_disk(1) minus self).

coord.grid_disk(0)     # => [self] (1 cell)
coord.grid_disk(1)     # => [self + 6 neighbors] (7 cells)
coord.grid_disk(2)     # => 19 cells

Parent and Children

Navigate the H3 hierarchy by moving to coarser or finer resolution levels.

coord = H3.new("872a1072bffffff")    # resolution 7
parent = coord.parent(5)              # => H3 at resolution 5
parent.resolution                     # => 5

children = coord.children(8)          # => Array of 7 H3 cells at resolution 8
children.length                       # => 7
children.first.resolution             # => 8

parent raises ArgumentError if the target resolution is not coarser (lower number). children raises ArgumentError if the target resolution is not finer (higher number).

Area

The to_area method returns the hexagonal cell boundary as an Areas::Polygon with 6 vertices (5 for pentagons).

area = coord.to_area
# => Geodetic::Areas::Polygon

area.includes?(coord.to_lla)    # => true (centroid is inside the cell)
area.boundary.length             # => 7 (6 vertices + closing point)

Pentagon Detection

12 cells at each resolution level are pentagons (artifacts of the icosahedral projection). These have 5 neighbors and 5 boundary vertices instead of 6.

coord.pentagon?    # => false (most cells are hexagons)

Cell Area

coord.cell_area    # => 5182586.98 (square meters)

Equality

Two H3 instances are equal if their hex strings match exactly.

H3.new("872a1072bffffff") == H3.new("872a1072bffffff")       # => true
H3.new("872a1072bffffff") == H3.new(0x872a1072bffffff)       # => true (integer)
H3.new("872a1072bffffff") == H3.new("87195da49ffffff")       # => false

valid?

Returns true if the H3 cell index is valid according to the H3 library.

coord.valid?    # => true

Universal Distance and Bearing Methods

H3 supports all universal distance and bearing methods via the DistanceMethods and BearingMethods mixins:

a = H3.new("872a1072bffffff")     # Statue of Liberty area
b = H3.new("87195da49ffffff")     # London area

a.distance_to(b)                # => Distance (~5,570 km)
a.straight_line_distance_to(b)  # => Distance
a.bearing_to(b)                 # => Bearing
a.elevation_to(b)               # => Float (degrees)

Well-Known H3 Cells

Location H3 Index (res 7) Resolution
Statue of Liberty 872a1072bffffff 7
London 87195da49ffffff 7
Null Island (0, 0) 87754e64dffffff 7

Implementation Notes

Geodetic uses Ruby's fiddle (part of the standard library) to call the H3 v4 C API directly. No gem dependency beyond fiddle is required. The H3 C library must be installed separately.

The library search order is: 1. LIBH3_PATH environment variable 2. /opt/homebrew/lib/libh3.dylib (macOS ARM) 3. /usr/local/lib/libh3.dylib (macOS Intel) 4. /usr/lib/libh3.so (Linux) 5. /usr/local/lib/libh3.so (Linux local) 6. Architecture-specific Linux paths