Traversal & Hierarchy
Once a location is a cell, two kinds of movement matter: moving sideways across the grid to neighbors, and moving up and down the resolution hierarchy to parents and children. This page covers both.
use Foysal50x\H3\H3;
$h3 = new H3();
$origin = $h3->latLngToCell(37.7749, -122.4194, 9);Understanding k-rings
Distance on the H3 grid is measured in steps between cells, written as k. The cells exactly k
steps away form a hollow ring; the cells up to k steps away form a filled disk.
A disk at k contains the disk at k − 1 plus one more ring. Each ring k adds 6 * k cells (on a
clean hexagon), so a full disk grows as 1, 7, 19, 37, 61, …
Traversal functions
gridDisk
Every cell within k steps of an origin — a filled disk, including the origin.
public function gridDisk(int $origin, int $k): array| Parameter | Type | Description |
|---|---|---|
$origin | int | Center cell |
$k | int | Radius in grid steps (≥ 0) |
$disk = $h3->gridDisk($origin, 2);
echo count($disk); // up to 19k is bounded for safety
To prevent memory exhaustion, k is capped (default 500, which is ~751,501 cells). A larger k
throws an H3Exception. Raise the limit deliberately with
H3::setMaxGridK() if your use case needs it.
gridDiskDistances
Like gridDisk, but each result carries its step distance from the origin.
public function gridDiskDistances(int $origin, int $k): arrayReturns a list of array{cell: int, distance: int}.
$results = $h3->gridDiskDistances($origin, 2);
foreach ($results as $r) {
printf("%s is %d step(s) away\n", $h3->h3ToString($r['cell']), $r['distance']);
}This is ideal for distance-banded pricing or weighting — closer cells cost less, farther cells cost more.
gridRing
Only the cells at exactly k steps — a hollow ring, not a filled disk.
public function gridRing(int $origin, int $k): array$ring = $h3->gridRing($origin, 3); // just the cells 3 steps outUse a ring when you want a boundary or perimeter rather than the whole area inside it.
gridDistance
The number of grid steps between two cells.
public function gridDistance(int $origin, int $destination): int$steps = $h3->gridDistance($cellA, $cellB);Both cells must be at the same resolution and reasonably close; far-apart cells or pentagon distortion can cause this to throw.
gridPathCells
The line of cells forming a path from one cell to another, inclusive of both ends.
public function gridPathCells(int $start, int $end): array$path = $h3->gridPathCells($start, $end);
echo 'Path length: ' . count($path) . ' cells' . PHP_EOL;Useful for drawing routes or sampling cells along a straight line between two points.
Hierarchy functions
The grid is hierarchical: every cell has a coarser parent and a set of finer children. These functions move between resolutions.
cellToParent
The ancestor cell at a coarser resolution.
public function cellToParent(int $cell, int $parentRes): int| Parameter | Type | Description |
|---|---|---|
$cell | int | The starting cell |
$parentRes | int | Target resolution, coarser than the cell's own |
$cell = $h3->latLngToCell(37.7749, -122.4194, 10);
$parent = $h3->cellToParent($cell, 8);Throws if $parentRes is not coarser than the cell's resolution. Great for privacy
(coarsen a precise location) and roll-up aggregation.
cellToChildren
Every descendant cell at a finer resolution.
public function cellToChildren(int $cell, int $childRes): array$children = $h3->cellToChildren($cell, 11);
echo count($children); // ~7 per resolution stepChildren multiply fast
Each resolution step finer multiplies the child count by ~7. Going two steps finer is ~49 cells;
five steps is ~16,807. Pick a small enough jump, and throws if $childRes is not finer than the
cell's resolution.
cellToCenterChild
The single central child at a finer resolution — a stable representative of the cell as you zoom in.
public function cellToCenterChild(int $cell, int $childRes): int$centerChild = $h3->cellToCenterChild($cell, 11);compactCells
Replace a dense set of same-resolution cells with the smallest mixed-resolution set covering the same area. Whenever all 7 children of a parent are present, they collapse into the parent.
public function compactCells(array $cells): array$area = $h3->gridDisk($origin, 5); // many res-9 cells
$compacted = $h3->compactCells($area); // far fewer mixed-res cells
printf("%d cells compacted to %d\n", count($area), count($compacted));Compaction commonly cuts storage by 50–90% for contiguous areas — ideal for persisting coverage zones and geofences.
uncompactCells
The inverse — expand a compacted (mixed-resolution) set back to a single resolution.
public function uncompactCells(array $cells, int $res): array| Parameter | Type | Description |
|---|---|---|
$cells | array | A compacted set of cell indices |
$res | int | Resolution to expand to (≥ the finest cell present) |
$restored = $h3->uncompactCells($compacted, 9);Worked example — radius search with banded distance
use Foysal50x\H3\H3;
$h3 = H3::getInstance();
// Items already indexed by their res-9 cell
$itemsByCell = [/* cellIndex => [...items] */];
$user = $h3->latLngToCell(37.7749, -122.4194, 9);
$within = $h3->gridDiskDistances($user, 3);
$hits = [];
foreach ($within as $r) {
foreach ($itemsByCell[$r['cell']] ?? [] as $item) {
$hits[] = ['item' => $item, 'rings' => $r['distance']];
}
}
// Closer rings first
usort($hits, fn ($a, $b) => $a['rings'] <=> $b['rings']);Next steps
- Work with the connections between cells in Edges & Vertices.
- Measure the areas and distances you've traversed in Measurements & Utilities.