Purpose
H3 is built by projecting a hexagonal grid onto an icosahedron and wrapping that onto the sphere. An icosahedron has 12 vertices, and a hexagonal grid cannot tile a surface with vertex curvature without a defect at each vertex — so every H3 resolution has exactly 12 pentagon cells, one at each icosahedron vertex, for every resolution from 0 to 15. This page documents what breaks when code written for "an H3 cell" implicitly means "an H3 hexagon," and states the explicit handling required.
What breaks
- Six-neighbour assumption
- A hexagon has exactly 6 edge-adjacent neighbours; a pentagon has exactly 5. Any code that allocates a fixed-size array of 6 for gridDisk/neighbour results, or assumes symmetric opposite-neighbour pairs, will index incorrectly or silently drop a neighbour at a pentagon.
- Regular-shape assumption
- A hexagon cell at a given resolution has a roughly consistent inscribed:circumscribed radius ratio across the globe; a pentagon does not share that ratio, and is not a regular pentagon in the geometric sense — its five sides and angles are not equal, because it is a projected, distorted shape, not a construction primitive.
- Inscribed/circumscribed ratio
- A regular hexagon's inscribed-to-circumscribed radius ratio is cos(30 degrees), approximately 0.866. A pentagon's ratio is lower and is NOT a fixed constant across pentagons — it must be computed per cell from the true boundary, never assumed from the hexagon constant.
- Area consistency
- H3's aperture-7 hierarchy and icosahedron projection already vary cell area by roughly a factor of two across the globe for ordinary hexagons; pentagon cells add a further, distinct area distortion at each of the 12 vertex locations, independent of the general face-projection variance.
Any function that computes a circle, a neighbour ring, or a shape-regularity
metric from an H3 index must check isPentagon(cell) before applying a
hexagon-derived constant. Code that hardcodes cos(30°) as the
inscribed:circumscribed ratio, or that assumes gridDisk(cell, 1) always
returns 7 cells (self plus 6), will produce silently wrong results at
exactly 12 locations per resolution — rare enough in ad hoc testing to pass
review, common enough in global-coverage production data to appear in every
large campaign.
Detection
isPentagon(cell) (h3-js v4) returns whether a given cell index is one of
the 12 pentagons at its resolution. getPentagons(resolution) returns the
full list of the 12 pentagon cell indexes at that resolution directly,
useful for pre-flagging a dataset before any per-cell shape computation runs
rather than checking every cell individually.
import { isPentagon, getPentagons } from "h3-js";
const pentagonsAtRes8 = getPentagons(8); // exactly 12 cell indexes
const flagged = cellSet.map((cell) => ({
cell,
isPentagon: isPentagon(cell),
}));
The same enumeration with the Python bindings (h3-py v4):
import h3
pentagons_at_res8 = h3.get_pentagons(8) # exactly 12 cell ids
flagged = [(c, h3.is_pentagon(c)) for c in cell_set]
Where the 12 pentagons fall — land vs water
The icosahedron underlying H3 is deliberately oriented so its 12 vertices — and
therefore all 12 pentagons — sit in the ocean. This is not folklore: locating
getPentagons(res) for every resolution and testing each cell center against
Natural Earth 110m land shows all 12 pentagon centers are over water at every
resolution 0 through 15 (zero land centers). The choice keeps the pentagon
distortion off inhabited, high-inventory geography.
The nuance is footprint, not center. A resolution-0 pentagon spans thousands of kilometres, so even with its center in open water its boundary can clip a coastline. Flagging whether each pentagon's boundary intersects land (still Natural Earth 110m) shows the effect shrinking as cells shrink:
- Centers over land (all resolutions)
- 0 of 12 — the design guarantee.
- Boundary clips land · R0
- 8 of 12 — the base pentagons are enormous.
- Boundary clips land · R1 / R2
- 5 / 4 of 12.
- Boundary clips land · R3 / R4
- 2 / 2 of 12.
- Boundary clips land · R5 and finer
- 0 of 12 — small enough to sit entirely in open water.
So from roughly R5 onward the 12 pentagons are fully offshore; only at very
coarse resolutions (R0–R4) does a pentagon footprint touch land at all (at R2,
the four that clip a coast fall on Norway, the Bohai/Yellow Sea coast, western
Australia, and the Argentine shelf). The full per-resolution table with every
cell id, center, and both flags is generated to public/fixtures/pentagons.json
by scripts/gen-pentagons.ts.
// How the flags are produced (see scripts/gen-pentagons.ts):
import { getPentagons, cellToLatLng } from "h3-js";
import * as turf from "@turf/turf";
const rows = getPentagons(res).map((cell) => {
const [lat, lng] = cellToLatLng(cell);
const onLand = land.features.some((f) =>
turf.booleanPointInPolygon(turf.point([lng, lat]), f),
);
return { cell, lat, lng, centerOnLand: onLand };
});
# Equivalent with h3-py v4 + shapely (land = a shapely prepared land geometry):
import h3
from shapely.geometry import Point
def pentagons_land_flags(res, land):
rows = []
for cell in h3.get_pentagons(res):
lat, lng = h3.cell_to_latlng(cell)
rows.append({"cell": cell, "lat": lat, "lng": lng,
"center_on_land": land.contains(Point(lng, lat))})
return rows
Classification uses Natural Earth 1:110m land, which omits small islands, so
"water" means "not on a 110m landmass," not "provably open ocean." A pentagon
center near a small island could read as water. For land-sensitive work re-run
gen-pentagons.ts against a finer land polygon.
Effects on downstream conversions
- Circle approximation (h3-to-inscribed-circle,
h3-to-circumscribed-circle): both
inscribedCircleandcircumscribedCirclecompute radius from the true, great-circle-densified boundary — min geodesic distance for inscribed, max for circumscribed — rather than from a nominal edge length, which is the only reason they remain correct on pentagons at all. Any circle function that instead derives radius from edge length times a hexagon constant will under- or over-state the inscribed/circumscribed radius for the 12 pentagon cells at each resolution. - Polyfill:
polygonToH3infullorintersectmode treats a pentagon cell like any other cell for containment testing — the boundary ring is simply five vertices instead of six — so polyfill correctness is unaffected. What is affected is any post-polyfill shape-regularity assumption applied uniformly across the result set. - Neighbour operations:
gridDisk,gridRingUnsafe, and compaction logic that assumes a fixed ring size per k-distance will return fewer cells at a k-ring centered on or adjacent to a pentagon, because a pentagon has 5 immediate neighbours, not 6, and the standard ring-size formula (3k² + 3k + 1for a hexagon-only disk) does not hold once a pentagon is inside the disk radius.
Face-crossing cells (a related, distinct distortion)
Pentagon cells sit at icosahedron vertices; a second, related distortion —
face-crossing-cells — affects ordinary
hexagon cells whose area happens to straddle two icosahedron faces. These
cells are not pentagons and pass isPentagon as false, but their edges are
asymmetric and their inscribed:circumscribed ratio deviates from the
resolution norm for the same underlying reason: local projection distortion
near a geometric singularity of the icosahedron. Detection for this case is
not a boolean flag but a comparison of the cell's actual inscribed and
circumscribed radii against the resolution's typical hexagon values — a
ratio significantly below the hexagon norm indicates a face-crossing or
otherwise distorted cell even when isPentagon returns false.
Guidance
Handle pentagons explicitly rather than filtering them out: they are valid, permanent members of every resolution's cell set (12 per resolution, not an error condition), and any campaign with sufficient geographic scope will include one eventually. Their centers all fall over water (see the land/water section above), and from resolution 5 onward their footprints are fully offshore, so pentagons rarely coincide with dense land inventory — but vertex placement is fixed by the icosahedron construction, so a Pacific, polar, or coastal cell set can still contain one. Report per-cell shape regularity (the computed inscribed:circumscribed ratio) alongside any circle or area conversion rather than assuming a resolution-level constant, and never hardcode the hexagon ratio of cos(30 degrees) in a function that will also receive pentagon input.
Assumptions and limitations
This page assumes h3-js v4 semantics for isPentagon and getPentagons.
