Skip to content

mattsta/h3

Repository files navigation

H3 Logo (mattsta fork)

H3: A Hexagonal Hierarchical Geospatial Indexing System

test-linux test-macos test-simd test-perf-flags License

About this repository. H3 was originally created at Uber Technologies, Inc. (github.com/uber/h3). As of April 26, 2026, this repository (mattsta/h3) is the new primary maintained version, focused on production-grade performance, SIMD acceleration, and bulk-API throughput.

The licensing changed at the fork. Pre-fork code remains Apache-2.0 (Uber, 2017–2021). Post-fork work — every new file, every modification — is Copyright © 2026 Matt Stancliff and is licensed under the Sovereign Individual's Covenant License v1.0, which grants rights to natural-person Individuals only and disallows use by corporate entities. Read LICENSE, LICENSE-mattsta, and NOTICE before using or redistributing. If you are a corporation, the post-fork material is unavailable to you under any open- source theory; the original Uber-era code remains available to you upstream at github.com/uber/h3 under Apache-2.0.

H3 is a geospatial indexing system using a hexagonal grid that can be (approximately) subdivided into finer and finer hexagonal grids, combining the benefits of a hexagonal grid with S2's hierarchical subdivisions.

This fork is about performance. Hand-tuned SIMD kernels (NEON / AVX2 / AVX-512), a precision-bounded approximate-libm fast path, batched bulk public APIs, and the audit harness that proves correctness across every flavor of build.

Performance — the headline numbers

Cumulative speedups vs. the upstream Uber 4.4.1 baseline, measured on Apple Silicon (NEON 2-wide path) with a 9-trial interleaved A/B harness. Intel hosts with AVX-512 see additional gains on top of these numbers. Every number here is reproducible from a clean clone in ~10 minutes via python3 scripts/h3_audit.py full (see "Verifying the claims" below).

Single-cell hot path

API upstream → optimized speedup
cellToBoundary 0.50 µs → 0.23 µs ~2.13×
cellToLatLng 0.12 µs → 0.08 µs ~1.55×
cellToVertexes (full ring) 19.5 µs → 15.1 µs ~1.29×
polygonToCellsExperimental (Full) varies ~1.65–1.76×
polygonToCellsExperimental (Overlapping) varies ~1.32–1.49×
polygonToCellsExperimental (Center) varies ~1.39–1.46×
polygonToCells (legacy polyfill) varies ~1.13–1.18×
gridDisk (k=10–40) varies ~1.17–1.22×
gridDisk pentagon paths (k=10–40) varies ~1.51–1.84×
Bulk cellToChildren (allCellsAtRes) varies ~1.84–2.15×

New bulk APIs (cellsToLatLngs, on top of single-cell wins)

For applications converting millions of cells (visualization, map rendering, analytics pipelines), the new SIMD-batched bulk APIs deliver another ~2× throughput multiplier over a per-cell loop:

batch size N per-cell loop batched speedup
16 1.48 µs 0.73 µs 2.03×
256 23.86 µs 11.45 µs 2.08×
1024 94.96 µs 45.22 µs 2.10×
8192 767.52 µs 388.09 µs 1.98×

Stacked end-to-end vs. upstream, the fastest paths reach ~2.18× cellToBoundary, ~1.80× polygonToCellsExperimental, and ~1.98× bulk cellToChildren on a single Apple Silicon core. Add H3_ENABLE_OPENMP=ON and the bulk APIs scale further across cores at batches above ~1024.

Precision contract

The fast path trades ≤180 nm absolute drift vs libm for these speedups — that's ~5 orders of magnitude inside res 15's 25 cm cell inradius and ~7 orders of magnitude inside the project's 0.5 m semantic budget. The cross-build divergence audit (scripts/h3_audit.py divergence) asserts this on 15,000+ cells per run; max observed cell-center divergence is 0.0 m (bit-identical) and max boundary-vertex divergence is ~76 nm at the time of writing.

See website/docs/core-library/performance.md for the full table including platform-specific numbers and methodology.

The original H3 documentation site at https://h3geo.org/ covers the conceptual model and the legacy API surface — it is hosted by Uber and reflects upstream. The deltas this fork adds (new bulk APIs, build options, performance numbers) are documented in this README and under dev-docs/ and website/docs/.

  • Post bug reports or feature requests to the GitHub Issues page
  • Ask questions by opening a discussion or by posting to the H3 tag on StackOverflow — the broader H3 community there covers the upstream model and most concepts apply identically here

Installing

We recommend using prebuilt bindings if they are available for your programming language. Bindings published by Uber for the upstream H3 API surface — Java, JavaScript, Python, and others — work against this fork for the entire pre-fork API. They do not yet expose the new bulk APIs added here (latLngsToCells, cellsToLatLngs, cellsToBoundaries); for those you currently call the C library directly or write your own binding.

On macOS, you can install H3 using brew:

brew install h3

Otherwise, to build H3 from source, please see the following instructions.

Building from source

Still here? To build the H3 C library, you'll need a C compiler (tested with gcc and clang), CMake, and Make. If you intend to contribute to H3, you must have clang-format installed and we recommend installing ccmake and LCOV to configure the cmake arguments to build and run the tests and generate the code coverage report. We also recommend using gcc for the code coverage as some versions of clang generate annotations that aren't compatible with lcov. Doxygen is needed to build the API documentation.

Install build-time dependencies

  • Alpine
# Installing the bare build requirements
apk add cmake make gcc libtool musl-dev
  • Debian/Ubuntu
# Installing the bare build requirements
sudo apt install cmake make gcc libtool
# Installing useful tools for development
sudo apt install clang-format cmake-curses-gui lcov doxygen
  • macOS (using brew)

First make sure you have the developer tools installed and then

# Installing the bare build requirements
brew install cmake
# Installing useful tools for development
brew install clang-format lcov doxygen
  • FreeBSD
# Installing the build requirements
sudo pkg install bash cmake gmake doxygen lcov

Compilation

When checking out the H3 Git repository, by default you will check out the latest development version of H3. When using H3 in an application, you will want to check out the most recently released version:

git checkout v$(<VERSION)

From the repository root, you can compile H3 with:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make

All subsequent make commands should be run from within the build directory.

Note: There are several ways to build H3 with CMake; the method above is just one example that restricts all build artifacts to the build directory.

Build options

H3 exposes a small set of CMake options for tuning performance and portability. The defaults are conservative and produce a portable shared library suitable for distribution. Opt in to the rest based on what kind of build you're producing.

option default who uses it
H3_ENABLE_SIMD ON Most consumers. Enables compile-time SIMD dispatch (NEON on AArch64, AVX2 on x86_64, AVX-512 where available). Built without runtime CPU detection — the compiled library expects the host ISA it was built for. Set OFF for a pure-scalar build.
H3_PORTABLE_TUNE ON Wheel / package builders. Pins SIMD translation units to -mtune=generic so the resulting binary runs on any CPU of the target ISA. Turn OFF for a build that exploits the host CPU (-mcpu=native -mtune=native).
H3_ENABLE_LTO OFF Production builds. Enables link-time optimization via CMake's INTERPROCEDURAL_OPTIMIZATION. Adds a few minutes to link time and yields ~5–10% extra throughput on hot paths.
H3_ENABLE_OPENMP OFF Bulk-API consumers. Enables #pragma omp parallel for on the bulk encode/decode paths. Requires find_package(OpenMP) to succeed (libomp / libgomp installed). When enabled, batches above ~1024 elements parallelize automatically.
H3_PGO_GENERATE OFF First stage of a profile-guided optimization build. Produces an instrumented binary that emits .profraw files when run. Use the test/benchmark suite as the training workload. Clang only.
H3_PGO_USE (empty) Second stage of PGO. Pass the path to a merged .profdata (produced from stage 1's .profraw files via llvm-profdata merge — see scripts/dev/pgo-merge.sh). The compiler uses the profile to lay out hot code paths.

Common configurations:

# Wheel / distribution build (default; portable across the target ISA)
cmake -DCMAKE_BUILD_TYPE=Release -DH3_PORTABLE_TUNE=ON ..

# Production build for known host hardware (~5–10% over default)
cmake -DCMAKE_BUILD_TYPE=Release \
      -DH3_PORTABLE_TUNE=OFF -DH3_ENABLE_LTO=ON \
      -DCMAKE_C_FLAGS_RELEASE="-O3 -DNDEBUG -mcpu=native -mtune=native" ..

# Production build with bulk-API parallelism
cmake -DCMAKE_BUILD_TYPE=Release -DH3_ENABLE_OPENMP=ON ..

# Two-stage PGO build (clang only; see scripts/dev/pgo-merge.sh)
# stage 1
cmake -B build_inst -DCMAKE_BUILD_TYPE=Release \
      -DH3_PGO_GENERATE=ON -DCMAKE_C_COMPILER=clang ..
cmake --build build_inst -j
# (run training workload — e.g. `cd build_inst && ctest`)
scripts/dev/pgo-merge.sh build_inst/profraw h3.profdata
# stage 2
cmake -B build_opt -DCMAKE_BUILD_TYPE=Release \
      -DH3_PGO_USE=$PWD/h3.profdata -DCMAKE_C_COMPILER=clang ..
cmake --build build_opt -j

Developer-machine builds with native tune + LTO are wrapped by scripts/dev/configure.sh and scripts/dev/cycle-full.sh for one-command iteration; see scripts/dev/README.md.

You can install system-wide with:

sudo make install

If using the method above, from the repository root, you can clean all build artifacts with:

rm -rf build

Testing

After making the project, you can test with make test. You can run a faster test suite that excludes the most expensive tests with make test-fast.

Coverage

You can generate a code coverage report if lcov is installed, and if the project was built with the CMAKE_BUILD_TYPE=Debug and ENABLE_COVERAGE=ON options. For example, from a clean repository, you could run:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON ..
make
make coverage

You can then view a detailed HTML coverage report by opening coverage/index.html in your browser.

Benchmarks

You can run timing benchmarks by building with the CMAKE_BUILD_TYPE=Release, and running make benchmarks:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
make benchmarks

Documentation

You can build developer documentation with make docs if Doxygen was installed when CMake was run. Index of the documentation will be dev-docs/_build/html/index.html.

After making the project, you can build KML files to visualize the hexagon grid with make kml. The files will be placed in KML.

To build the documentation website, see the website/ directory.

Usage

From the command line

To get the H3 index for some location:

./bin/latLngToCell --resolution 10 --latitude 40.689167 --longitude -74.044444

10 is the H3 resolution, between 0 (coarsest) and 15 (finest). The coordinates entered are the latitude and longitude, in degrees, you want the index for (these coordinates are the Statue of Liberty). You should get an H3 index as output, like 8a2a1072b59ffff.

You can then take this index and get some information about it, for example:

./bin/cellToBoundary --index 8a2a1072b59ffff

This will produce the vertices of the hexagon at this location:

8a2a1072b59ffff
{
   40.690058601 -74.044151762
   40.689907695 -74.045061792
   40.689270936 -74.045341418
   40.688785091 -74.044711031
   40.688935993 -74.043801021
   40.689572744 -74.043521377
}

You can get the center coordinate of the hexagon like so:

./bin/cellToLatLng --index 8a2a1072b59ffff

This will produce some coordinate:

40.6894218437 -74.0444313999

From C

The above features of H3 can also be used from C. For example, you can compile and run examples/index.c like so:

cc -lh3 examples/index.c -o example
./example

You should get output like:

The index is: 8a2a1072b59ffff
Boundary vertex #0: 40.690059, -74.044152
Boundary vertex #1: 40.689908, -74.045062
Boundary vertex #2: 40.689271, -74.045341
Boundary vertex #3: 40.688785, -74.044711
Boundary vertex #4: 40.688936, -74.043801
Boundary vertex #5: 40.689573, -74.043521
Center coordinates: 40.689422, -74.044431

Bulk APIs (encode / decode many cells at once)

For applications converting millions of cells (visualization, map rendering, analytics pipelines), use the batched APIs. They run the same precision-bounded math as the per-cell calls, but amortize the SIMD/trig setup cost across the batch — typically ~2× throughput on top of the single-cell speedups.

#include <h3/h3api.h>
#include <stdlib.h>

void decode_many(const H3Index *cells, int64_t n) {
    LatLng *centers = malloc(n * sizeof *centers);
    CellBoundary *boundaries = malloc(n * sizeof *boundaries);

    /* Bulk decode: N cells → N centers, in one SIMD-batched call. */
    cellsToLatLngs(cells, n, centers);

    /* Bulk decode: N cells → N boundaries (5 or 6 vertices each). */
    cellsToBoundaries(cells, n, boundaries);

    free(centers);
    free(boundaries);
}

void encode_many(const LatLng *coords, int64_t n, int res) {
    H3Index *cells = malloc(n * sizeof *cells);

    /* Bulk encode: N (lat,lng) pairs → N cells at the given resolution. */
    latLngsToCells(coords, n, res, cells);

    free(cells);
}

Each bulk call returns E_SUCCESS or the first per-element error encountered. Inputs are processed independently so the SIMD batching is invisible to correctness — output is bit-identical to the equivalent per-element loop.

When the library is built with -DH3_ENABLE_OPENMP=ON and OpenMP is available, batches above ~1024 elements parallelize automatically across cores.

Verifying performance & correctness claims

The performance numbers in the intro are reproducible. From a clean clone:

# Build, validate, and produce an A/B verdict in one command.
python3 scripts/h3_audit.py full

scripts/h3_audit.py full runs (1) the build matrix Release/Debug × SIMD ON/OFF, (2) the full ctest suite in each cell, (3) cross-build numeric divergence asserts (cellToLatLng meters, cellToBoundary per-vertex meters, cellArea relative — each gated against the project precision budget), (4) same-binary determinism (byte-identical output across runs), (5) per-build round-trip exhaustive (cellToLatLng → latLngToCell == input? across every base cell × resolution), and (6) interleaved A/B benchmarks. All correctness gates must pass for the run to exit zero. See scripts/dev/README.md for the underlying single-purpose scripts the audit composes.

Contributing

Pull requests and GitHub issues are welcome. Please see CONTRIBUTING.md for more information.

By submitting a pull request to a post-fork file (or a post-fork modification to a pre-fork file), you agree that your contribution is licensed under the Sovereign Individual's Covenant License v1.0 on the same terms as the rest of the post-fork codebase, and that you are contributing voluntarily and without commercial expectation. There is no separate CLA — the upstream Uber CLA applies only to contributions sent to uber/h3, not to this fork.

Legal and Licensing

This repository is dual-licensed by authorship date:

See LICENSE for the dual-license map and NOTICE for the human-readable attribution chain. The Sovereign Individual's Covenant License grants rights to natural-person Individuals only and prohibits use by essentially every form of corporate entity (see Article the Fourth of LICENSE-mattsta). It is materially more restrictive than Apache-2.0; do not assume otherwise.

DGGRID Copyright (c) 2015 Southern Oregon University

About

H3 — A Hexagonal Hierarchical Geospatial Indexing System (mattsta fork; SIMD-accelerated, post-2026-04-26)

Resources

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE-mattsta

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors