Skip to content

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.

k=0: origin
k=1: + 6 neighbors
k=2: + 12 outer
k=3: + 18 outer

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
ParameterTypeDescription
$originintCenter cell
$kintRadius in grid steps (≥ 0)
$disk = $h3->gridDisk($origin, 2);
echo count($disk);   // up to 19

k 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): array

Returns 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 out

Use 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.

fine cellcoarse parentcellToParent()
coarse cellfine childrencellToChildren()
many cellsfewer mixed-res cellscompactCells()

cellToParent

The ancestor cell at a coarser resolution.

public function cellToParent(int $cell, int $parentRes): int
ParameterTypeDescription
$cellintThe starting cell
$parentResintTarget 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 step

Children 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
ParameterTypeDescription
$cellsarrayA compacted set of cell indices
$resintResolution to expand to (≥ the finest cell present)
$restored = $h3->uncompactCells($compacted, 9);

Worked example — radius search with banded distance

nearby.php
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

H3 PHP — Hexagonal geospatial indexing for PHP. Released under the MIT license.