Contents

libardoram/h3swift

A Swift package providing an idiomatic Swift API for [Uber's H3](https://h3geo.org/) hexagonal geospatial indexing system.

Requirements

  • Swift 5.10+
  • iOS 14+ / macOS 14+ / watchOS 7+ / tvOS 14+

Installation

Swift Package Manager

Add the package to your Package.swift dependencies:

dependencies: [
    .package(url: "https://github.com/libardoram/H3Swift.git", from: "1.0.0"),
]

Then add "H3" to your target's dependencies:

.target(
    name: "MyApp",
    dependencies: ["H3"]
)

Xcode

  1. FileAdd Package Dependencies…
  2. Enter the repository URL.
  3. Choose the version rule and click Add Package.

Usage

Convert a coordinate to an H3 index

import H3

let coord = H3Coordinate(lat: 37.7793, lng: -122.4193)
let index = H3Index(coordinate: coord, resolution: 9)

print(index)          // e.g. "8928308280fffff"
print(index.isValid)  // true
print(index.resolution) // 9

Create an index from a hex string

// Failable — returns nil for invalid strings
if let index = H3Index(string: "8928308280fffff") {
    print(index.coordinate) // center of the cell
}

Traverse neighbors (k-ring)

let neighbors = index.kRing(k: 1)  // 7 cells: self + 6 neighbors
let twoRings  = index.kRing(k: 2)  // 19 cells

Navigate the hierarchy

// Coarser resolution
let parent = index.parent(at: 5)
let directParent = index.directParent

// Finer resolution
let children = index.children(at: 10)
let centerChild = index.directCenterChild

Get the cell boundary

let vertices = index.boundary()  // [H3Coordinate] in CCW order

Get the cell edges

let edges = index.edges()  // 6 edges for hexagon, 5 for pentagon

for edge in edges {
    print("Edge: \(edge)")
    print("Origin: \(edge.origin)")
    print("Destination: \(edge.destination)")
    print("Boundary: \(edge.boundary())")
}

// Create edge between two neighboring cells
let neighbor = index.kRing(k: 1).first { $0 != index }!
if let edge = H3Edge(from: index, to: neighbor) {
    print("Created edge: \(edge)")
}

Grid distance between two cells

How many cells apart are two H3 indexes at the same resolution?

import H3

let sf    = H3Index(coordinate: H3Coordinate(lat: 37.7793, lng: -122.4193), resolution: 9)
let oakland = H3Index(coordinate: H3Coordinate(lat: 37.8044, lng: -122.2712), resolution: 9)

let steps = sf.distance(to: oakland)
print(steps)  // e.g. 42  (grid hops, not kilometres)

Check if a cell is a pentagon

The H3 grid contains 12 pentagons per resolution (at icosahedron vertices). Most spatial operations work fine on them, but it's useful to know:

import H3

let coord = H3Coordinate(lat: 37.7793, lng: -122.4193)
let index = H3Index(coordinate: coord, resolution: 5)

if index.isPentagon {
    print("\(index) is a pentagon")
} else {
    print("\(index) is a hexagon")
}

// Get all 12 pentagons at resolution 3
let pentagonIndexes = H3Index.pentagons(resolution: 3)

Average cell area and edge length at a resolution

Useful for understanding the scale of your data:

import H3

for res in 0...5 {
    let areaKm2 = H3Index.hexArea(resolution: res, unit: .km2)
    let edgeKm  = H3Index.edgeLength(resolution: res, unit: .km)
    let count   = H3Index.cellCount(resolution: res)
    print("res \(res): \(areaKm2) km²  edge \(edgeKm) km  total cells \(count)")
}
// res 0:  4357449.4 km²  edge 1107.7 km  total cells 122
// res 1:   609788.4 km²  edge  418.7 km  total cells 842
// res 2:    86745.9 km²  edge  158.2 km  total cells 5882
// ...

Fill a polygon with H3 cells

Convert a geographic polygon into a set of H3 cells at a given resolution:

import H3

let exterior: [H3Coordinate] = [
    H3Coordinate(lat: 37.7749, lng: -122.4194),
    H3Coordinate(lat: 37.8049, lng: -122.4194),
    H3Coordinate(lat: 37.8049, lng: -122.3894),
    H3Coordinate(lat: 37.7749, lng: -122.3894),
]

let polygon = H3GeoPolygon(exterior: exterior)
let cells = polygon.fill(resolution: 9)

print("Filled \(cells.count) cells")

// With holes
let hole: [H3Coordinate] = [
    H3Coordinate(lat: 37.7849, lng: -122.4144),
    H3Coordinate(lat: 37.7949, lng: -122.4144),
    H3Coordinate(lat: 37.7949, lng: -122.4044),
    H3Coordinate(lat: 37.7849, lng: -122.4044),
]
let polygonWithHole = H3GeoPolygon(exterior: exterior, holes: [hole])
let cellsWithHole = polygonWithHole.fill(resolution: 9)

Examples

The repository includes two example scripts demonstrating package functionality:

Running Examples

# Run basic example
swift Examples/BasicExample.swift

# Run advanced example
swift Examples/AdvancedExample.swift

Basic Example (Examples/BasicExample.swift)

Demonstrates core functionality:

  • Convert coordinates to H3 indexes
  • Get cell center and boundary
  • Traverse neighbors (k-ring)
  • Navigate hierarchy (parent/children)
  • Check cell properties (pentagon, base cell, resolution class)
  • Query resolution statistics
  • Get pentagons and resolution-0 cells

Advanced Example (Examples/AdvancedExample.swift)

Demonstrates advanced functionality:

  • Grid distance between locations
  • Grid line between cells
  • Neighbor detection
  • Cell edges (create and query)
  • Polyfill (polygon to H3 cells)
  • Polyfill with holes
  • Compact/uncompact cells
  • kRingDistances
  • HexRing
  • Icosahedron faces

API Reference

H3Coordinate

| Property / Initializer | Description | |---|---| | init(lat:lng:) | Creates a coordinate from degrees | | lat: Double | Latitude in degrees | | lng: Double | Longitude in degrees |

Conforms to Equatable, Hashable, Codable, Sendable.

H3Index

| Initializer | Description | |---|---| | init(_ value: UInt64) | Wrap a raw 64-bit index | | init(coordinate:resolution:) | Convert a coordinate to an H3 cell | | init?(string:) | Parse a hex string; returns nil if invalid |

| Property | Description | |---|---| | rawValue: UInt64 | The underlying 64-bit value | | resolution: Int | Resolution (0–15) | | isValid: Bool | Whether this is a valid H3 index | | coordinate: H3Coordinate | Center coordinate of the cell | | description: String | Lowercase hex string (e.g. "8928308280fffff") | | baseCell: Int | Base cell number (0–121) | | isPentagon: Bool | Whether this cell is one of the 12 pentagons | | isResClassIII: Bool | Whether at a Class III resolution (odd resolutions) | | directParent: H3Index? | Parent one resolution coarser | | directCenterChild: H3Index? | Center child one resolution finer |

| Method | Description | |---|---| | kRing(k:) | All cells within k rings | | kRingDistances(k:) | All cells within k rings with grid distances | | hexRing(k:) | Cells in the hollow ring at exactly distance k | | parent(at:) | Ancestor at the given resolution | | children(at:) | All children at the given resolution | | centerChild(at:) | Center child at the given resolution | | distance(to:) | Grid distance to another cell | | gridLine(to:) | Grid line to another cell | | isNeighbor(of:) | Whether another cell is a direct neighbor | | edges() | All unidirectional edges originating from this cell | | faces() | Icosahedron face numbers this cell intersects | | boundary() | Cell boundary vertices | | compact(:) | Compress cells to most coarse resolution | | uncompact(:resolution:) | Expand compacted cells to target resolution | | hexArea(resolution:unit:) | Average cell area at resolution | | edgeLength(resolution:unit:) | Average edge length at resolution | | cellCount(resolution:) | Total cells at resolution | | res0Cells() | All 122 resolution-0 base cells | | pentagons(resolution:) | All 12 pentagons at resolution |

Conforms to Equatable, Hashable, CustomStringConvertible, Sendable.

H3Edge

Represents a unidirectional edge between two neighboring H3 cells.

| Initializer | Description | |---|---| | init(_ value: UInt64) | Wrap a raw 64-bit edge index | | init?(from:to:) | Create edge between two neighboring cells |

| Property | Description | |---|---| | rawValue: UInt64 | The underlying 64-bit value | | isValid: Bool | Whether this is a valid directed edge | | origin: H3Index | The origin cell | | destination: H3Index | The destination cell | | cells: (origin: H3Index, destination: H3Index) | Both cells |

| Method | Description | |---|---| | boundary() | Edge boundary vertices |

Conforms to Equatable, Hashable, CustomStringConvertible, Sendable.

H3GeoPolygon

A geographic polygon for polyfill operations.

| Initializer | Description | |---|---| | init(exterior:holes:) | Create polygon with exterior and optional holes |

| Property | Description | |---|---| | exterior: [H3Coordinate] | The exterior boundary | | holes: [[H3Coordinate]] | Interior holes |

| Method | Description | |---|---| | fill(resolution:) | Get all H3 cells within the polygon |

Conforms to Sendable.

Supporting Types

| Type | Description | |---|---| | H3Index.AreaUnit | .km2 or .m2 for area queries | | H3Index.LengthUnit | .km or .m for length queries | | H3Index.KRingEntry | Pairs index: H3Index with distance: Int |

License

MIT License. See LICENSE for details.

Package Metadata

Repository: libardoram/h3swift

Default branch: main

README: README.md