H3-Boundary API Reference¶
Complete API documentation for H3-Boundary.
Table of Contents¶
Core Functions¶
These functions have both Python and C++ implementations. The C++ version is used automatically when available.
trace_cell_to_ancestor_faces¶
trace_cell_to_ancestor_faces(
h: str,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6},
res_parent: int = None
) -> Set[int]
Traces which boundary faces of an ancestor cell the given cell lies on.
Parameters:
- h: H3 cell index (string)
- input_faces: Set of face numbers {1-6} to trace
- res_parent: Resolution of ancestor. If None, uses immediate parent
Returns: Set of face numbers at the ancestor's boundary
Example:
from h3_boundary import trace_cell_to_ancestor_faces
cell = '8928308280fffff' # Resolution 9
faces = trace_cell_to_ancestor_faces(cell, {1, 2, 3, 4, 5, 6}, res_parent=6)
print(faces) # e.g., {2, 5}
trace_cell_to_parent_faces¶
trace_cell_to_parent_faces(
h: str,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6}
) -> Set[int]
Convenience function that traces to the immediate parent (res - 1).
children_on_boundary_faces¶
children_on_boundary_faces(
parent: str,
target_res: int,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6}
) -> List[str]
Returns all children at target_res that lie on the parent's specified boundary faces.
Parameters:
- parent: Parent H3 cell index
- target_res: Resolution to descend to (parent resolution ≤ target_res ≤ 15; equal resolution returns [parent])
- input_faces: Set of face numbers {1-6} to filter by
Returns: List of child H3 cell indices
Raises: ValueError if target_res is below the parent's resolution or above 15.
Example:
from h3_boundary import children_on_boundary_faces
children = children_on_boundary_faces('86283082fffffff', 10)
print(f"Found {len(children)} boundary children") # ~240 cells
Performance: - Python: ~0.14ms - C++: ~0.02ms (7x faster)
cell_to_coarsest_ancestor_on_faces¶
cell_to_coarsest_ancestor_on_faces(
h: str,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6}
) -> str
Finds the coarsest ancestor (lowest resolution) where the cell still lies on at least one of the specified boundary faces.
Returns: H3 cell index of the coarsest ancestor
boundary_cell_ids¶
boundary_cell_ids(
parent: str,
target_res: int,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6},
sort: bool = False
) -> numpy.ndarray # dtype uint64
Every boundary child as a NumPy array of 64-bit H3 indexes — the fast way to produce a whole boundary. Cells are grouped by boundary state and a level is expanded at a time with array arithmetic, instead of one call per cell, and no per-cell hex strings are built.
sort=False (default) returns them unordered (grouped by state). sort=True returns traversal order — the same sequence as children_on_boundary_faces, since traversal order is exactly ascending index order — for the cost of one numpy.sort.
| Boundary size | children_on_boundary_faces (Python) |
(C++) | boundary_cell_ids(sort=True) |
boundary_cell_ids() |
|---|---|---|---|---|
| 6,558 | 4.6 ms | 0.56 ms | 0.09 ms | 0.02 ms |
| 59,046 | 42 ms | 5.8 ms | 0.65 ms | 0.11 ms |
| 531,438 | 382 ms | 57 ms | 8.2 ms | 1.4 ms |
ids = boundary_cell_ids(parent, 13) # unordered, fastest
ids = boundary_cell_ids(parent, 13, sort=True) # traversal order
h3i.cell_to_latlng(int(ids[0])) # feed h3.api.basic_int directly
hexes = [format(v, 'x') for v in ids] # …or convert to strings
Uses the C++ extension when built, NumPy otherwise; the sort is always NumPy's radix sort, which beats std::sort on uint64 by ~3.5×. Note boundary_rank is defined against traversal order, so only sort=True output lines up with it. For a slice rather than the whole boundary see boundary_range, or _h3_boundary_cpp.boundary_range_ids (extension only). Requires NumPy, which Shapely already pulls in.
boundary_cell_at¶
boundary_cell_at(
parent: str,
target_res: int,
n: int,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6}
) -> str
Returns the n-th boundary child directly, in O(depth) arithmetic — equivalent to children_on_boundary_faces(parent, target_res)[n] without enumerating the others. The boundary children form a positional numeral system (their index digits are the paths of a face-state automaton), which makes random access, sampling, and sharding possible on boundaries far too large to materialize. The boundary size is 3**(depth+1) - 3 for hexagon parents and 5 * (3**depth - 1) // 2 for pentagons.
parent = h3.latlng_to_cell(37.77, -122.42, 2)
cell = boundary_cell_at(parent, 13, 265_717) # one of 531,438 — no enumeration
Raises: ValueError for an out-of-range target_res, IndexError for n outside the boundary count.
boundary_rank¶
boundary_rank(parent: str, cell: str, input_faces: Set[int] = {1, 2, 3, 4, 5, 6}) -> int
Inverse of boundary_cell_at: the position of cell in the parent's boundary sequence (depth-first traversal order), in O(depth). Doubles as a membership test — raises ValueError if cell is not a descendant of parent or not on the traced boundary.
boundary_range¶
boundary_range(
parent: str,
target_res: int,
start: int = 0,
stop: int | None = None,
input_faces: Set[int] = {1, 2, 3, 4, 5, 6}
) -> Iterator[str]
Yields boundary children [start, stop) in traversal order: seeks to start in O(depth), then streams forward at traversal speed (O(1) amortized per cell, O(depth) memory). This is the bulk counterpart of the indexing functions — use it to shard a boundary across workers with no coordination, or to stream a boundary too large to hold in memory.
# Worker k of n generates only its own slice
for cell in boundary_range(parent, 13, bounds[k], bounds[k + 1]):
process(cell)
Concatenating the slices reproduces children_on_boundary_faces exactly. Repeatedly calling boundary_cell_at instead would re-descend the tree per cell (~9x slower for bulk work).
boundary_cell_at and boundary_rank are pure Python. boundary_range uses the C++ extension when it is available (fetching cells in blocks, so it stays a lazy generator with bounded memory) and falls back to the pure-Python generator otherwise — roughly 14x apart on bulk work.
See Boundary Algorithms for how these relate to the traversal and the boundary walk, with benchmarks.
Geometry Functions¶
Pure Python Functions¶
These use Shapely for geometry operations.
cell_boundary_to_geojson¶
cell_boundary_to_geojson(h: str) -> Dict[str, Any]
Returns a GeoJSON Feature representing the cell boundary.
cell_boundary_from_children¶
cell_boundary_from_children(parent: str, target_res: int) -> Dict[str, Any]
Returns the merged boundary polygon of all boundary children at target_res.
Returns: GeoJSON Feature with properties:
- h3_index: Parent cell index
- child_resolution: Target resolution used
- num_boundary_cells: Number of boundary children
get_buffered_h3_polygon¶
get_buffered_h3_polygon(cell: str, buffer_meters: float = None) -> Dict[str, Any]
Returns a buffered polygon of the cell's native boundary — a cheap approximation of where the cell is.
Not a container: it buffers the nominal hexagon, which the cell's descendants straddle, so a few percent of them fall outside (measured: 896 of 16,807 at res+5). Use get_buffered_boundary_polygon when containment matters. See Buffered Polygons.
Parameters:
- cell: H3 cell index
- buffer_meters: Buffer distance. If None, auto-calculates as 100% of edge length
Returns: GeoJSON Feature with properties:
- h3_index: Cell index
- buffer_meters: Buffer distance used
- method: "buffered_python"
get_buffered_boundary_polygon¶
get_buffered_boundary_polygon(
cell: str,
intermediate_res: int = 10,
buffer_meters: float = None
) -> Dict[str, Any]
Hybrid approach: computes boundary at intermediate resolution, then buffers.
Returns: GeoJSON Feature with properties:
- h3_index: Cell index
- intermediate_res: Resolution used for boundary
- buffer_meters: Buffer distance used
- num_boundary_cells: Number of cells in boundary computation
- method: "buffered_boundary"
C++ Accelerated Functions¶
These use Boost.Geometry and provide significant speedups. All return GeoJSON-compatible output.
cell_boundary_to_geojson_cpp¶
cell_boundary_to_geojson_cpp(cell: str) -> Dict[str, Any]
C++ version of cell boundary to GeoJSON.
cell_boundary_from_children_cpp¶
cell_boundary_from_children_cpp(parent: str, target_res: int) -> Dict[str, Any]
C++ version using Boost.Geometry union operations (pairwise merge tree).
Performance: ~2.5ms at res 6 → 10. The pure-Python version is comparable (~1.3ms) because it delegates to H3's native cells_to_h3shape.
get_buffered_h3_polygon_cpp¶
get_buffered_h3_polygon_cpp(cell: str, buffer_meters: float = None) -> Dict[str, Any]
C++ version of simple buffered polygon.
Performance: ~0.06ms (vs ~0.13ms Python, 2x faster)
get_buffered_boundary_polygon_cpp¶
get_buffered_boundary_polygon_cpp(
cell: str,
intermediate_res: int = 10,
buffer_meters: float = None,
use_convex_hull: bool = False
) -> Dict[str, Any]
C++ buffered polygon with configurable accuracy.
Parameters:
- cell: H3 cell index
- intermediate_res: Resolution for boundary computation (default: 10)
- buffer_meters: Buffer distance. If None, auto-calculates as 100% of edge length
- use_convex_hull:
- True: Fast convex hull approximation (~0.4ms)
- False (default): Accurate union of all cells (~7ms)
Returns: GeoJSON Feature with properties:
- h3_index: Cell index
- intermediate_res: Resolution used
- buffer_meters: Buffer distance used
- method: "buffered_boundary_cpp" or "buffered_boundary_cpp_hull"
Example:
from h3_boundary import get_buffered_boundary_polygon_cpp
# Accurate mode (default)
result = get_buffered_boundary_polygon_cpp(
'86283082fffffff',
intermediate_res=10,
use_convex_hull=False
)
print(result['properties']['method']) # 'buffered_boundary_cpp'
# Fast mode
result = get_buffered_boundary_polygon_cpp(
'86283082fffffff',
intermediate_res=10,
use_convex_hull=True
)
print(result['properties']['method']) # 'buffered_boundary_cpp_hull'
Utility Functions¶
get_backend¶
get_backend() -> str
Returns the current backend: 'cpp' or 'python'.
cpp_geom_available¶
cpp_geom_available() -> bool
Returns True if C++ geometry functions (Boost.Geometry) are available.
C++ API¶
For direct C++ usage, include h3_toolkit.hpp:
#include "h3_toolkit.hpp"
// Trace faces
std::set<int> faces = h3_toolkit::trace_cell_to_ancestor_faces(
cell, input_faces, res_parent
);
// Get boundary children
std::vector<H3Index> children = h3_toolkit::children_on_boundary_faces(
parent, target_res
);
// Get buffered polygon (returns vector of (lon, lat) pairs)
std::vector<std::pair<double, double>> polygon =
h3_toolkit::get_buffered_boundary_polygon(
cell,
intermediate_res,
buffer_meters,
use_convex_hull
);
Function Signatures¶
namespace h3_toolkit {
std::set<int> trace_cell_to_ancestor_faces(
H3Index h,
const std::set<int>& input_faces,
int res_parent
);
std::set<int> trace_cell_to_parent_faces(
H3Index h,
const std::set<int>& input_faces
);
std::vector<H3Index> children_on_boundary_faces(
H3Index parent,
int target_res,
const std::set<int>& input_faces = {1,2,3,4,5,6}
);
H3Index cell_to_coarsest_ancestor_on_faces(
H3Index h,
const std::set<int>& input_faces = {1,2,3,4,5,6}
);
std::vector<std::pair<double, double>> cell_boundary(H3Index cell);
std::vector<std::pair<double, double>> cell_boundary_from_children(
H3Index parent,
int target_res
);
std::vector<std::pair<double, double>> get_buffered_h3_polygon(
H3Index cell,
double buffer_meters = -1.0
);
std::vector<std::pair<double, double>> get_buffered_boundary_polygon(
H3Index cell,
int intermediate_res = 10,
double buffer_meters = -1.0,
bool use_convex_hull = false
);
} // namespace h3_toolkit
Performance Summary¶
| Function | Python | C++ |
|---|---|---|
children_on_boundary_faces |
0.14ms | 0.02ms |
cell_boundary_from_children |
1.3ms | 2.5ms |
get_buffered_boundary_polygon (accurate) |
5.9ms | 7.0ms |
get_buffered_boundary_polygon (fast hull) |
N/A | 0.4ms |
get_buffered_h3_polygon |
0.13ms | 0.06ms |
Benchmarks on a resolution 6 cell with intermediate resolution 10 (Linux, Python 3.14). The C++ backend is fastest for face tracing and hull mode; Python polygon merging is comparable because it uses H3's native cells_to_h3shape.