Understand error handling in h3o
masterh3o leans toward providing specific error types for individual functions. This allows consumers to use pattern matching to handle specific error cases more effectively when calling API methods.repository·master·Indexed 19 days ago
https://github.com/hydroniumlabs/h3oA 100% Rust implementation of the H3 geospatial indexing system, version 0.11.0. Designed for performance and WASM compatibility without C dependencies, it provides tools for H3 cell indexing via CellIndex, coordinate conversions with LatLng, and grid traversal. Optional geometry features enable conversions between H3 objects and geometric shapes using ToGeo and ToCells traits, as well as path plotting with Plotter and polygon dissolution with Solvent.
h3o leans toward providing specific error types for individual functions. This allows consumers to use pattern matching to handle specific error cases more effectively when calling API methods.The h3o API is primarily centered around the CellIndex type, which serves as the main entry point for most H3 operations. While the library contains various internal modules for grid traversal and coordinate systems, most functionality is exposed directly through CellIndex to provide a streamlined consumer experience.
Key architectural components include:
src/index): Contains the core H3 index types, with CellIndex being the most prominent.src/coord): Acts as a bridge between public types. For example, converting a CellIndex to a LatLng involves the IJK coordinate system internally.src/grid): Handles grid traversal algorithms (finding neighbors, traversing from one cell to another). This module is internal; its capabilities are exposed via the CellIndex API.To install the h3o CLI or binary, ensure you have the Rust toolchain installed, then use cargo install.
cargo install h3oIf you are migrating from the original H3 library, use this mapping to find the equivalent functionality in h3o:
| H3 | h3o |
|---|---|
latLngToCell | LatLng::to_cell |
cellToLatLng | LatLng::from |
cellToBoundary | CellIndex::boundary |
| H3 | h3o |
|---|---|
constructCell | CellIndex::from_raw_parts |
getResolution | CellIndex::resolution |
getBaseCellNumber | CellIndex::base_cell |
getIndexDigit | CellIndex::direction_at |
stringToH3 | str::parse |
h3ToString | ToString::to_string |
isValidCell | CellIndex::try_from |
isValidIndex | is_valid_index |
isResClassIII | Resolution::is_class3 |
isPentagon | CellIndex::is_pentagon |
getIcosahedronFaces | CellIndex::icosahedron_faces |
maxFaceCount | CellIndex::max_face_count |
| H3 | h3o |
|---|---|
gridDisk | CellIndex::grid_disk |
maxGridDiskSize | max_grid_disk_size |
maxGridRingSize | max_grid_ring_size |
gridDiskDistances | CellIndex::grid_disk_distances |
gridDiskUnsafe | CellIndex::grid_disk_fast |
gridDiskDistancesUnsafe | CellIndex::grid_disk_distances_fast |
gridDiskDistancesSafe | CellIndex::grid_disk_distances_safe |
gridDisksUnsafe | CellIndex::grid_disks_fast |
gridRingUnsafe | CellIndex::grid_ring_fast |
gridRing | CellIndex::grid_ring |
gridPathCells | CellIndex::grid_path_cells |
gridPathCellsSize | CellIndex::grid_path_cells_size |
gridDistance | CellIndex::grid_distance |
cellToLocalIj | CellIndex::to_local_ij |
localIjToCell | CellIndex::try_from |
| H3 | h3o |
|---|---|
cellToParent | CellIndex::parent |
cellToChildren | CellIndex::children |
cellToChildrenSize | CellIndex::children_count |
cellToCenterChild | CellIndex::center_child |
cellToChildPos | CellIndex::child_position |
childPosToCell | CellIndex::child_at |
compactCells | CellIndex::compact |
uncompactCells | CellIndex::uncompact |
uncompactCellsSize | CellIndex::uncompact_size |
| H3 | h3o |
|---|---|
polygonToCells | geom::Tiler::into_coverage |
maxPolygonToCellsSize | geom::Tiler::coverage_size_hint |
h3SetToLinkedGeo | geom::Solvent::dissolve |
areNeighborCells | CellIndex::is_neighbor_with |
cellsToDirectedEdge | CellIndex::edge |
isValidDirectedEdge | DirectedEdgeIndex::try_from |
getDirectedEdgeOrigin | DirectedEdgeIndex::origin |
getDirectedEdgeDestination | DirectedEdgeIndex::destination |
directedEdgeToCells | DirectedEdgeIndex::cells |
originToDirectedEdges | CellIndex::edges |
directedEdgeToBoundary | DirectedEdgeIndex::boundary |
| H3 | h3o |
|---|---|
cellToVertex | CellIndex::vertex |
cellToVertexes | CellIndex::vertexes |
vertexToLatLng | LatLng::from |
isValidVertex | VertexIndex::try_from |
degsToRads | f64::to_radians |
radsToDegs | f64::to_degrees |
getHexagonAreaAvgKm2 | Resolution::area_km2 |
getHexagonAreaAvgM2 | Resolution::area_m2 |
cellAreaKm2 | CellIndex::area_km2 |
cellAreaM2 | CellIndex::area_m2 |
cellAreaRads2 | CellIndex::area_rads2 |
getHexagonEdgeLengthAvgKm | Resolution::edge_length_km |
getHexagonEdgeLengthAvgM | Resolution::edge_length_m |
edgeLengthKm | DirectedEdgeIndex::length_km |
edgeLengthM | DirectedEdgeIndex::length_m |
edgeLengthRads | DirectedEdgeIndex::length_rads |
getNumCells | Resolution::cell_count |
getRes0Cells | CellIndex::base_cells |
res0CellCount | BaseCell::count |
getPentagons | Resolution::pentagons |
pentagonCount | Resolution::pentagon_count |
greatCircleDistanceKm | LatLng::distance_km |
greatCircleDistanceM | LatLng::distance_m |
greatCircleDistanceRads | LatLng::distance_rads |
The NEIGHBORS table defines the adjacency relationship between icosahedron faces. For any given face, the table provides 4 FaceOrientIJK entries representing its neighbors in different quadrants:
IJ (index 1): The ij quadrant neighbor.KI (index 2): The ki quadrant neighbor.JK (index 3): The jk quadrant neighbor.Note: The first entry (index 0) in the array for each face is the face itself (the 'central face').
Each FaceOrientIJK contains:
face: The neighbor's Face.translate: A CoordIJK representing the resolution 0 translation relative to the primary face.ccw_rot60: The number of 60-degree counter-clockwise rotations relative to the primary face.// Example of accessing neighbors
let current_face_idx = 0;
let neighbors = h3o::NEIGHBORS[current_face_idx];
// Access the 'ij' quadrant neighbor
let ij_neighbor = neighbors[h3o::IJ];
println!("Neighbor face: {:?}, translation: {:?}", ij_neighbor.face, ij_neighbor.translate);A VertexIndex represents a single topological vertex in the H3 grid system, which is shared by three cells. Unlike a CellIndex, a VertexIndex identifies a specific point in space by encoding both an "owner" cell and a specific vertex number on that cell.
The 64-bit index is laid out as follows:
U (bit 63): Unused, always 0.M (bits 59-62): Index mode (set to 4 for Vertex mode).V (bits 56-58): Vertex number on the owner cell [0, 5].O (bits 0-55): Owner cell index..vertex() to retrieve the Vertex on the owner cell..owner() to retrieve the CellIndex that owns this vertex.VertexIndex into a LatLng to get its geographic coordinates.VertexIndex from a hex string using FromStr or from a u64 using TryFrom.// Create from a hex u64
let index = h3o::VertexIndex::try_from(0x2222597fffffffff)?;
// Access the owner cell
let owner = index.owner();
// Access the specific vertex number
let vertex = index.vertex();
// Get geographic coordinates
let coords: h3o::LatLng = index.into();A DirectedEdgeIndex is encoded as a 64-bit integer with the following layout:
| Bit(s) | Name | Description |
|---|---|---|
| 63 | U | Unused reserved bit (always 0) |
| 62-59 | M | Index mode (always set to 2 for DirectedEdge) |
| 58-56 | E | Edge of the origin cell [1; 6] |
| 55-0 | O | Origin cell index |
References:
The ContainmentMode determines the logic used to decide if an H3 cell is considered part of the input geometry. This affects both the completeness of the coverage and whether cells overlap between adjacent polygons.
| Mode | Behavior |
|---|---|
ContainsCentroid | Fastest. Selects cells whose centroids are inside the polygon. May overshoot boundaries or leave small gaps. Ensures no overlapping cells between adjacent polygons. |
ContainsBoundary | Selects cells whose entire boundaries are within the polygon. Avoids overshooting but may leave more uncovered area than ContainsCentroid. |
IntersectsBoundary | Selects cells that partially or fully intersect the polygon boundary. Guarantees complete coverage but may result in overlapping cells between adjacent polygons. |
Covers | Similar to IntersectsBoundary, but also includes cells that completely cover the geometry without the boundary intersecting. |
The Tiler struct allows you to convert geographic shapes (Polygons) into a set of H3 cells. You can configure the tiler using a TilerBuilder to specify the H3 Resolution and the ContainmentMode (how a cell is determined to be 'inside' a shape).
To use it:
TilerBuilder with a specific Resolution.ContainmentMode.Tiler.Polygon objects using .add() or .add_batch()..into_coverage() to get an iterator of CellIndex or .into_annotated_coverage() to get AnnotatedCell objects which include containment metadata.use geo::{LineString, Polygon};
use h3o::{geom::{ContainmentMode, TilerBuilder}, Resolution};
let polygon = Polygon::new(
LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]),
vec![],
);
let mut tiler = TilerBuilder::new(Resolution::Six)
.containment_mode(ContainmentMode::Covers)
.build();
tiler.add(polygon)?;
// Get just the cell indices
let cells = tiler.into_coverage().collect::<Vec<_>>();
// Or get cells with containment info
let annotated_cells = tiler.into_annotated_coverage().collect::<Vec<_>>();To use h3o in your Rust project, import the necessary types like LatLng and Resolution. You can create a coordinate and convert it into an H3 cell at a specific resolution.
Note that LatLng::new returns a Result, so you must handle potential errors (e.g., invalid latitude/longitude values) using .expect() or proper error handling.
use h3o::{LatLng, Resolution};
let coord = LatLng::new(37.769377, -122.388903).expect("valid coord");
let cell = coord.to_cell(Resolution::Nine);Use max_grid_disk_size(k) and max_grid_ring_size(k) to determine the upper bounds of cells produced by grid traversal algorithms for a given radius k.
max_grid_disk_size(k): Returns the maximum number of indices produced by the grid disk algorithm. For very large k (>= 13,780,510), it returns the total cell count for resolution 15.max_grid_ring_size(k): Returns the maximum number of cells that result from the gridRing algorithm.let count = h3o::max_grid_disk_size(3);
let ring_count = h3o::max_grid_ring_size(3);If you enable the geom feature, you can use the Geometry API to convert between H3 objects and geometric shapes. This is achieved through two primary traits:
ToGeo: Converts H3 objects into geometries (e.g., converting a set of CellIndex values into a multi-polygon).ToCells: Converts geometries into H3 objects (e.g., finding the set of CellIndex values that cover a specific polygon).The API also provides wrapper types around RustGeo types to ensure H3-specific constraints are met and includes From/Into implementations for seamless GeoJSON interoperability.