SwiftyH3

0.6.0

Uber's H3 Geospatial Indexing System for Swift
pawelmajcher/SwiftyH3

What's New

Release 0.6.0

2026-08-12T14:24:38Z

Major changes:

  • updated vendored H3 library to v4.5.0

Minor updates:

  • fixed multipolygon tests such that they are rotation-invariant

No breaking changes are expected, unless your implementation relied on specific order of points in multipolygon.

Full Changelog: 0.5.0...0.6.0

SwiftyH3 ⬡

The Swifty way to use Uber's H3 geospatial indexing system.

Documentation Swift versions Swift platforms

Quick Start

import SwiftyH3

// Find the containing cell for a given location
let latlng = H3LatLng(latitudeDegs: 37.7955, longitudeDegs: -122.3937)
let cell = try! latlng.cell(at: .res10)
print(cell) // 8a283082a677fff

// Retrieve the center of the cell (as H3LatLng or CLLocationCoordinate2D)
let coordinate: CLLocationCoordinate2D = try! cell.center.coordinates

// Find the bounds of this cell
let bounds: [H3LatLng] = try! cell.boundary

Installation

Swift Package Manager

Add the following line to your package's Package.swift file:

.package(url: "https://github.com/pawelmajcher/SwiftyH3.git", "0.5.0"..<"0.6.0")

Xcode

Go to File > Add Package Dependencies... and enter https://github.com/pawelmajcher/SwiftyH3.git in the upper-right corner.

H3 API support

Indexing functions

H3 C function Example SwiftyH3 code Docs
latLngToCell try H3LatLng(latitudeDegs: 37.7955, longitudeDegs: -122.3937).cell(at: .res8) 📖
cellToLatLng try H3Cell("8a283082a677fff")!.center 📖
cellToBoundary try H3Cell("8a283082a677fff")!.boundary 📖

Index inspection functions

H3 C function Example SwiftyH3 code Docs
getResolution try H3DirectedEdge("115283473fffffff")!.resolution 📖
getBaseCellNumber try H3Vertex("22528340bfffffff")!.baseCellNumber 📖
getIndexDigit try H3Vertex("22528340bfffffff")!.digit(for: .res2) 📖
constructCell try H3Cell(base: 20, [0, 6, 0, 4, 0, 5]) 📖
stringToH3 H3Cell("8a283082a677fff")! 📖
h3ToString try H3Cell(599686042433355775).description 📖
isValidCell cell.isValid 📖
isValidIndex cell.isSomeH3Index 📖
isResClassIII cell.isResClassIII 📖
isPentagon cell.isPentagon 📖
getIcosahedronFaces ⚠️ Not yet available
maxFaceCount This function exists for memory management and is not exposed.

Grid traversal functions

H3 C function Example SwiftyH3 code Docs
gridDistance try originCell.gridDistance(to: destinationCell) 📖
gridRing try cell.gridRing(distance: 1) 📖
gridRingUnsafe Not exposed. Use gridRing.
maxGridRingSize This function exists for memory management and is not exposed.
gridDisk try cell.gridDisk(distance: 2) 📖
maxGridDiskSize This function exists for memory management and is not exposed.
gridDiskDistances Not exposed. Use try 1...3.map { cell.gridRing(distance: $0) }.
gridDiskUnsafe Not exposed. Use gridDisk.
gridDiskDistancesUnsafe Not exposed. Use try 1...3.map { cell.gridRing(distance: $0) }.
gridDiskDistancesSafe Not exposed. Use try 1...3.map { cell.gridRing(distance: $0) }.
gridDisksUnsafe Not exposed. Use try cells.flatMap { cell in 1...3.flatMap { cell.gridRing(distance: $0) } }.
gridPathCells try cell1.path(to: ...) 📖
gridPathCellsSize This function exists for memory management and is not exposed.
cellToLocalIj ⚠️ Not yet available
localIjToCell ⚠️ Not yet available

Hierarchical grid functions

H3 C function Example SwiftyH3 code Docs
cellToParent try cell.parent(at: .res1) 📖
cellToChildren try cell.children(at: .res12) 📖
cellToChildrenSize try cell.children(at: .res12).count 📖
cellToCenterChild try cell.children(at: .res12).center 📖
cellToChildPos try parentCell.children(at: .res12).index(of: childCell) 📖
childPosToCell try cell.children(at: .res12)[23] 📖
compactCells try [cell1, ..., cell50].compacted 📖
uncompactCells try [cell1, cell2, cell3].uncompacted(at: .res8) 📖
uncompactCellsSize This function exists for memory management and is not exposed.

Region functions

H3 C function Example SwiftyH3 code Docs
polygonToCells try H3Polygon([...]).cells(at: .res7) 📖
maxPolygonToCellsSize This function exists for memory management and is not exposed.
polygonToCellsExperimental try H3Polygon([...]).cellsExperimental(at: .res7, containmentType: .overlapping) 📖
maxPolygonToCellsSizeExperimental This function exists for memory management and is not exposed.
cellsToLinkedMultiPolygon try [cell1, cell2, cell3].multiPolygon 📖
destroyLinkedMultiPolygon This function exists for memory management and is not exposed.

Directed edge functions

H3 C function Example SwiftyH3 code Docs
areNeighborCells try cell1.isNeighbor(of: cell2) 📖
cellsToDirectedEdge try originCell.directedEdge(to: destinationCell) 📖
isValidDirectedEdge directedEdge.isValid 📖
getDirectedEdgeOrigin try directedEdge.origin 📖
getDirectedEdgeDestination try directedEdge.destination 📖
directedEdgeToCells Not exposed. Use try (directedEdge.origin, directedEdge.destination).
originToDirectedEdges try originCell.directedEdges 📖
directedEdgeToBoundary try directedEdge.boundary 📖

Vertex functions

H3 C function Example SwiftyH3 code Docs
cellToVertex try cell.vertex(3) 📖
cellToVertexes try cell.vertices 📖
vertexToLatLng try vertex.latLng 📖
isValidVertex vertex.isValid 📖

Miscellaneous H3 functions

H3 C function Example SwiftyH3 code Docs
degsToRads Not exposed. Use Measurement<UnitAngle>(value: 23, unit: .degrees).converted(to: .radians).value.
radsToDegs Not exposed. Use Measurement<UnitAngle>(value: 1.2, unit: .radians).converted(to: .degrees).value.
getHexagonAreaAvgKm2 H3Cell.Resolution.res8.averageHexagonArea.converted(to: .squareKilometers).value
getHexagonAreaAvgM2 H3Cell.Resolution.res8.averageHexagonArea.value 📖
cellAreaRads2 try cell.areaRads2 📖
cellAreaKm2 try cell.area.converted(to: .squareKilometers).value
cellAreaM2 try cell.area.converted(to: .squareMeters).value 📖
getHexagonEdgeLengthAvgKm H3Cell.Resolution.res8.averageHexagonEdgeLength.converted(to: .kilometers).value
getHexagonEdgeLengthAvgM H3Cell.Resolution.res8.averageHexagonEdgeLength.value 📖
edgeLengthKm try directedEdge.length.converted(to: .kilometers).value
edgeLengthM try directedEdge.length.value 📖
edgeLengthRads try directedEdge.lengthRads.value 📖
getNumCells H3Cell.Resolution.res3.numberOfCells 📖
getRes0Cells H3Cell.res0Cells 📖
res0CellCount This function exists for memory management and is not exposed.
getPentagons H3Cell.Resolution.res3.pentagons 📖
pentagonCount This function exists for memory management and is not exposed.
greatCircleDistanceKm h3LatLng1.distance(to: h3LatLng2).converted(to: .kilometers).value
greatCircleDistanceM h3LatLng1.distance(to: h3LatLng2).value 📖
greatCircleDistanceRads h3LatLng1.distanceRads(to: h3LatLng2).value 📖
describeH3Error do {...} catch { print(error.errorDescription) } 📖

Note

The Measurement<UnitType> types and LocalizedError protocol, including related methods and properties, are part of Foundation. Include import Foundation to use them.

Core Location and MapKit support

CLLocationCoordinate2D

You can convert an H3LatLng value to CLLocationCoordinate2D and vice versa using initializers or computed properties.

// H3LatLng ➡️ CLLocationCoordinate2D
let coordinateFromProperty: CLLocationCoordinate2D = H3LatLng(latitudeDegs: 37.7955, longitudeDegs: -122.3937).coordinates
let coordinateFromInitializer = CLLocationCoordinate2D(H3LatLng(latitudeDegs: 37.7955, longitudeDegs: -122.3937))

// CLLocationCoordinate2D ➡️ H3LatLng
let h3LatLngFromProperty: H3LatLng = CLLocationCoordinate2D(latitude: 37.7955, longitude: -122.3937).h3LatLng
let h3LatLngFromInitializer = H3LatLng(CLLocationCoordinate2D(latitude: 37.7955, longitude: -122.3937))

MKPolygon and MKMultiPolygon

You can create an MKPolygon with an initializer taking [H3LatLng] or H3Polygon values. Analogically, you can initialize MKMultiPolygon with [H3Polygon] array.

// H3 with MapKit for SwiftUI example

import SwiftUI
import MapKit
import SwiftyH3

struct H3CellMapExampleView: View {
    let cellBoundary = try! H3LatLng(latitudeDegs: 37.7955, longitudeDegs: -122.3937).cell(at: .res4).boundary
    
    var body: some View {
        Map {
            MapPolygon(MKPolygon(cellBoundary))
        }
    }
}

MapContent (MapKit for SwiftUI)

H3Cell, H3Polygon, and H3DirectedEdge conform to the MapContent protocol which means that you can use them as map content when using MapKit for SwiftUI.

// H3 with MapKit for SwiftUI example

import SwiftUI
import MapKit
import SwiftyH3

struct H3CellMapExampleView: View {
    var body: some View {
        Map {
            H3Cell("87283082affffff")
            H3DirectedEdge("115283473fffffff").stroke(.blue, lineWidth: 2)
            try? ["8528342ffffffff", "85283093fffffff"].map { H3Cell($0)! }.multiPolygon[0]
        }
    }
}

License

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

  • None
Last updated: Thu Oct 29 2026 23:46:21 GMT-0900 (Hawaii-Aleutian Daylight Time)