Repository navigation
Release 4.5.0
Aligns the port with upstream H3 4.5.0 and modernizes the supported .NET targets.
Breaking Changes 📣
- retargets the library to
net10.0,net8.0,netstandard2.1andnetstandard2.0; EOLnet6.0/net7.0targets have been dropped (netstandard2.0remains for Unity and .NET Framework consumers) #98, #140 EdgeLengthRadians/EdgeLengthKilometers/EdgeLengthMetersandGetDirectedEdgeBoundaryVerticesnow throwArgumentExceptionwhen the index is not a valid directed edge instead of silently returning 0 / an empty enumerable, matching upstream'sE_DIR_EDGE_INVALID#109GridRingis now pentagon safe, matching upstream 4.3.0+gridRing: it no longer throws on pentagonal distortion, transparently falling back to a slower-but-correct traversal. The previous throwing behaviour is available asGridRingUnsafe(= upstreamgridRingUnsafe), which the obsoleteGetHexRingnow aliases.GridRingalso now validates its inputsCellAreaInRadiansSquared(and the Km²/m² variants) use upstream 4.5.0's Cagnoli formula with compensated summation; areas differ very slightly from previous releases (cell areas at a given resolution now sum to the area of the sphere to within 1e-14)H3Index,CoordIJK,FaceIJKandLatLngare now structs (completingCoordIJ,Vec2d,Vec3d,FaceOrientIJKfrom earlier work), eliminating per-index/per-vertex heap allocations throughout:FromLatLng/FromPointandToLatLng/ToPointare measured allocation-free (previously 131 and 96 B/op), grid disk allocations drop ~2.3x and children iteration ~17x #93. Value semantics apply:nullis no longer a valid index (useH3Index.Invalid;default(H3Index)==Invalid), mutations affect only the local copy, and scratch-buffer/reuse parameters have been removed (LocalCoordIJK.ToH3Index,CoordIJK.FromVec2d/CubeRound,ToFaceIJK,ToCoordinate,GetCellBoundaryVertices,Coordinate.ToH3Index,FaceIJK.FromLatLng,Vec3d.FromLonLat);H3Index.ToFaceWithInitializedFijktakes theFaceIJKbyref- the obsolete
GeoCoordtype is removed (structs cannot be subclassed) along with the obsolete members producing it (H3Index.ToGeoCoord/FromGeoCoord,VertexToGeoCoord,GetUnidirectionalEdgeBoundaryVertices— the latter two threwInvalidCastExceptionat runtime anyway);FaceIJK/Vec2d/Vec3dmembers named*GeoCoord*are renamed to*LatLng* - the
netstandard2.0/netstandard2.1targets no longer depend onSystem.Text.Json, making the assembly consumable from Unity without the STJ dependency chain (this is what existing Unity-focused forks patch out) #140.H3IndexJsonConverter(and the[JsonConverter]attribute onH3Index) are now only available onnet8.0+, where STJ is part of the framework. If you consume the netstandard targets from .NET Framework and rely on JSON serialization, copy the previous converter class into your project and register it viaJsonSerializerOptions.Converters. The (accidentallypublic)IsExternalInitshim is also no longer part of the netstandard assemblies (replaced by the internal, source-only Polyfill equivalent) - internal lookup tables are now compile-time generated (single source of truth in the
H3.Datasource generator) and flattened, substantially reducing static initialization cost and steady-state heap usage. This slims some (implementation-oriented) public surface:BaseCellsis now astaticclass; the per-instanceBaseCell.NeighbouringCells/NeighbourRotationsarrays andNeighbourDirectionsdictionary are replaced by shared flattened tables (see the newBaseCells.IsPentagonCellNumber(int)helper);LookupTables.NewDirectionClass2/NewDirectionClass3/NewAdjustmentClass2/NewAdjustmentClass3and theDirectionToUnitVector/UnitVectorToDirectiondictionaries are removed (the traversal data lives in generated packed tables; unit vectors remain available viaLookupTables.UnitVectors);LookupTables.PentagonIndexesPerResolutionis now a generatedH3Index[][]instead ofDictionary<int, H3Index[]>(indexing by resolution is source compatible); andLookupTables.FaceIjkBaseCellsis now a lazily-built property (the library itself uses the flat generated tables) CompactCellsnow produces deterministically ordered output (sorted by index value within each resolution, coarsest resolutions last) instead of hash-set ordering; as before, the only guarantee is that the result is a minimal covering set
Fixes 🔧
- fixes
IsValidCellrejecting valid cells at resolutions >= 11 (and accepting some invalid low-resolution indexes) due to 32-bit shift wraparound in its bit masks; validation is now a port of upstream's fasterisValidCell#111 - fixes
Vec2d.Intersectto usedoubleinstead offloat, improving the precision of geographic coordinate output (upstream #652) #86 - fixes possible overflows in
GetDirectNeighbourrotations,LocalIjToCell/LocalIjkToCellcoordinate conversions andIsNeighbourdigit lookups (upstream #706, #707, #677, #684) GridPathCellsis now bidirectional per upstream 4.5.0: paths that cross pentagon distortion relative to the origin's local coordinate chart are retried anchored at the destination (upstream #1111)- fixes a pattern-matching precedence bug in
GetDirectNeighbour's polar pentagon handling (is not 118 or 8dropped the base cell 8 check) - updates the average hexagon edge-length/area lookup tables from stale 3.x values to the upstream 4.x recomputed values
GetCellBoundariesnow passes the caller'sGeometryFactorythrough to the individual cell boundary polygons instead of only to the outer MultiPolygon- fixes an off-by-one in the base cell range used to build
LookupTables.PentagonIndexesPerResolution
Enhancements 🎉
- new hierarchy extensions
CellToChildPos,ChildPosToCellandCellToChildrenSize(upstream 4.1.0) #102 - new
H3Index.IsValidIndexproperty validating any index mode (upstream 4.4.0'sisValidIndex) - new directed edge extensions
ReverseDirectedEdge(upstream 4.4.0) andDestinationToDirectedEdges - new
CellsToMultiPolygonset extension producing the dissolved outline(s) of a cell set, with upstream 4.5.0 validation semantics (=cellsToMultiPolygon) - new grid statistics on
H3Index:GetNumberOfCells,GetRes0Cells,GetPentagons,GetHexagonAreaAverageInKmSquared/InMSquaredandGetHexagonEdgeLengthAverageInKm/InM - new
LatLng.GetLoopAreaInRadiansSquaredspherical loop area helper - polyfill improvements #53:
Fillnow supportsPoint,LineString,MultiPoint,MultiLineStringand (nested)GeometryCollectioninputs; polygonal fills seed from every component, fixing fills ofMultiPolygons with disjoint components; and a newFill(geometry, resolution, Func<H3Index, bool>)overload flood fills with a caller-provided containment predicate (e.g. for containment checks in a non-WGS84 CRS) - canonical cell set operations #61:
CanonicalizeCells,IsCanonicalCellsandCanonicalCellsContain(binary-search point-in-coverage against possibly-compacted sets, without uncompacting) - new component-based
H3Index.Create(resolution, baseCellNumber, digits)with full validation (upstream 4.5.0constructCell) - performance: allocation-free
CoordIJK->Directionconversion (~10x faster; benefitsFromLatLng/FromPoint), allocation-freeIsNeighbourshared-parent fast path (~2.7x faster), presized traversal materialization, fasterIsValidCell, and faster bitwise index rotations - performance: static initialization allocates ~6x less (130 KB -> 22 KB; ~half the steady-state heap) via compile-time generated, flattened lookup tables; pentagon checks use a bitmask instead of object lookups;
GridDistance/CellToLocalIjare ~2x faster andGridPathCells~1.6x faster (flat base cell neighbour tables replace per-cell dictionaries);CompactCellsis ~2x faster with ~2x fewer allocations (sorted sibling-run scan replaces nested dictionaries/sets);GridDiskDistancesSafeallocates ~2x less and is ~20% faster (array-based BFS with an open-addressed dedup table);CellToVertexesis ~1.4x faster (vertex rotations computed once per cell); polyfill flood fills allocate ~20% less andLineHexEstimatecaches the per-resolution pentagon radius (large constant win forTraceCoordinates/LineStringfills); plus smaller wins inGetParentForResolution,GetCellBoundaryand direction rotations NetTopologySuite2.6.0; source-only Polyfill for netstandard backfills. The netstandard targets now depend only onNetTopologySuite(plusMicrosoft.Bcl.HashCodeonnetstandard2.0)- XML documentation is now generated (and correctly named) for all targets
- pure struct members are annotated
readonly(C# 8; no runtime/netstandard impact) - new standalone
test/H3.CompareBenchmarkssuite comparing the published 4.0.0 package against the current tree (see its README; the two versions are not ABI compatible, so each is compiled separately)
Notes relative to upstream 4.5.0: getIndexDigit is covered by the existing GetDirectionForResolution; describeH3Error is not applicable (exceptions carry failure detail); buffer-sizing functions (maxGridDiskSize et al.) are unnecessary with lazy enumerables.