pawelmajcher/swiftyh3
**The Swifty way to use [Uber's H3 geospatial indexing system](https://h3geo.org/).**
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.boundaryInstallation
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`](https://h3geo.org/docs/api/indexing#latlngtocell) | `try H3LatLng(latitudeDegs: 37.7955, longitudeDegs: -122.3937).cell(at: .res8)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3latlng/cell(at:)) |
| [`cellToLatLng`](https://h3geo.org/docs/api/indexing#celltolatlng) | `try H3Cell("8a283082a677fff")!.center` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/center) |
| [`cellToBoundary`](https://h3geo.org/docs/api/indexing#celltoboundary) | `try H3Cell("8a283082a677fff")!.boundary` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/boundary) |
### Index inspection functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`getResolution`](https://h3geo.org/docs/api/inspection#getresolution) | `try H3DirectedEdge("115283473fffffff")!.resolution` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3indexable/resolution) |
| [`getBaseCellNumber`](https://h3geo.org/docs/api/inspection#getbasecellnumber) | `try H3Vertex("22528340bfffffff")!.baseCellNumber` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3indexable/basecellnumber) |
| [`getIndexDigit`](https://h3geo.org/docs/api/inspection#getindexdigit) | `try H3Vertex("22528340bfffffff")!.digit(for: .res2)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3indexable/digit(for:)) |
| [`constructCell`](https://h3geo.org/docs/api/inspection/#constructcell) | `try H3Cell(base: 20, [0, 6, 0, 4, 0, 5])` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/init(base:_:)) |
| [`stringToH3`](https://h3geo.org/docs/api/inspection#stringtoh3) | `H3Cell("8a283082a677fff")!` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3indexable/init(_:)-8n6gi) |
| [`h3ToString`](https://h3geo.org/docs/api/inspection#h3tostring) | `try H3Cell(599686042433355775).description` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3indexable/description) |
| [`isValidCell`](https://h3geo.org/docs/api/inspection#isvalidcell) | `cell.isValid` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/isvalid) |
| [`isValidIndex`](https://h3geo.org/docs/api/inspection/#isvalidindex) | `cell.isSomeH3Index` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3indexable/issomeh3index) |
| [`isResClassIII`](https://h3geo.org/docs/api/inspection#isresclassiii) | `cell.isResClassIII` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/isresclassiii) |
| [`isPentagon`](https://h3geo.org/docs/api/inspection#ispentagon) | `cell.isPentagon` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/ispentagon) |
| [`getIcosahedronFaces`](https://h3geo.org/docs/api/inspection#geticosahedronfaces) | β οΈ Not yet available |
| [`maxFaceCount`](https://h3geo.org/docs/api/inspection#maxfacecount) | *This function exists for memory management and is not exposed.* |
### Grid traversal functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`gridDistance`](https://h3geo.org/docs/api/traversal#griddistance) | `try originCell.gridDistance(to: destinationCell)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/griddistance(to:)) |
| [`gridRing`](https://h3geo.org/docs/api/traversal#gridring) | `try cell.gridRing(distance: 1)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/gridring(distance:)) |
| [`gridRingUnsafe`](https://h3geo.org/docs/api/traversal#gridringunsafe) | Not exposed. Use `gridRing`. |
| [`maxGridRingSize`](https://h3geo.org/docs/api/traversal#maxgridringsize) | *This function exists for memory management and is not exposed.* |
| [`gridDisk`](https://h3geo.org/docs/api/traversal#griddisk) | `try cell.gridDisk(distance: 2)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/griddisk(distance:)) |
| [`maxGridDiskSize`](https://h3geo.org/docs/api/traversal#maxgriddisksize) | *This function exists for memory management and is not exposed.* |
| [`gridDiskDistances`](https://h3geo.org/docs/api/traversal#griddiskdistances) | Not exposed. Use `try 1...3.map { cell.gridRing(distance: $0) }`. |
| [`gridDiskUnsafe`](https://h3geo.org/docs/api/traversal#griddiskunsafe) | Not exposed. Use `gridDisk`. |
| [`gridDiskDistancesUnsafe`](https://h3geo.org/docs/api/traversal#griddiskdistancesunsafe) | Not exposed. Use `try 1...3.map { cell.gridRing(distance: $0) }`. |
| [`gridDiskDistancesSafe`](https://h3geo.org/docs/api/traversal#griddiskdistancessafe) | Not exposed. Use `try 1...3.map { cell.gridRing(distance: $0) }`. |
| [`gridDisksUnsafe`](https://h3geo.org/docs/api/traversal#griddisksunsafe) | Not exposed. Use `try cells.flatMap { cell in 1...3.flatMap { cell.gridRing(distance: $0) } }`. |
| [`gridPathCells`](https://h3geo.org/docs/api/traversal#gridpathcells) | `try cell1.path(to: ...)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/path(to:)) |
| [`gridPathCellsSize`](https://h3geo.org/docs/api/traversal#gridpathcellssize) | *This function exists for memory management and is not exposed.* |
| [`cellToLocalIj`](https://h3geo.org/docs/api/traversal#celltolocalij) | β οΈ Not yet available |
| [`localIjToCell`](https://h3geo.org/docs/api/traversal#localijtocell) | β οΈ Not yet available |
### Hierarchical grid functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`cellToParent`](https://h3geo.org/docs/api/hierarchy#celltoparent) | `try cell.parent(at: .res1)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/parent(at:)) |
| [`cellToChildren`](https://h3geo.org/docs/api/hierarchy#celltochildren) | `try cell.children(at: .res12)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/children(at:)) |
| [`cellToChildrenSize`](https://h3geo.org/docs/api/hierarchy#celltochildrensize) | `try cell.children(at: .res12).count` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/childrencollection/count) |
| [`cellToCenterChild`](https://h3geo.org/docs/api/hierarchy#celltocenterchild) | `try cell.children(at: .res12).center` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/childrencollection/center) |
| [`cellToChildPos`](https://h3geo.org/docs/api/hierarchy#celltochildpos) | `try parentCell.children(at: .res12).index(of: childCell)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/childrencollection/index(of:)) |
| [`childPosToCell`](https://h3geo.org/docs/api/hierarchy#childpostocell) | `try cell.children(at: .res12)[23]` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/childrencollection/subscript(_:)) |
| [`compactCells`](https://h3geo.org/docs/api/hierarchy#compactcells) | `try [cell1, ..., cell50].compacted` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/swift/sequence/compacted) |
| [`uncompactCells`](https://h3geo.org/docs/api/hierarchy#uncompactcells) | `try [cell1, cell2, cell3].uncompacted(at: .res8)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/swift/sequence/uncompacted(at:)) |
| [`uncompactCellsSize`](https://h3geo.org/docs/api/hierarchy#uncompactcellssize) | *This function exists for memory management and is not exposed.* |
### Region functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`polygonToCells`](https://h3geo.org/docs/api/regions#polygontocells) | `try H3Polygon([...]).cells(at: .res7)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3polygon/cells(at:)) |
| [`maxPolygonToCellsSize`](https://h3geo.org/docs/api/regions#maxpolygontocellssize) | *This function exists for memory management and is not exposed.* |
| [`polygonToCellsExperimental`](https://h3geo.org/docs/api/regions#polygontocellsexperimental) | `try H3Polygon([...]).cellsExperimental(at: .res7, containmentType: .overlapping)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3polygon/cellsexperimental(at:containmenttype:)) |
| [`maxPolygonToCellsSizeExperimental`](https://h3geo.org/docs/api/regions#maxpolygontocellssizeexperimental) | *This function exists for memory management and is not exposed.* |
| [`cellsToLinkedMultiPolygon`](https://h3geo.org/docs/api/regions/#cellstolinkedmultipolygon--cellstomultipolygon) | `try [cell1, cell2, cell3].multiPolygon` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/swift/sequence/multipolygon) |
| [`destroyLinkedMultiPolygon`](https://h3geo.org/docs/api/regions#destroylinkedmultipolygon) | *This function exists for memory management and is not exposed.* |
### Directed edge functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`areNeighborCells`](https://h3geo.org/docs/api/uniedge#areneighborcells) | `try cell1.isNeighbor(of: cell2)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/isneighbor(of:)) |
| [`cellsToDirectedEdge`](https://h3geo.org/docs/api/uniedge#cellstodirectededge) | `try originCell.directedEdge(to: destinationCell)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/directededge(to:)) |
| [`isValidDirectedEdge`](https://h3geo.org/docs/api/uniedge#isvaliddirectededge) | `directedEdge.isValid` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3directededge/isvalid) |
| [`getDirectedEdgeOrigin`](https://h3geo.org/docs/api/uniedge#getdirectededgeorigin) | `try directedEdge.origin` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3directededge/origin) |
| [`getDirectedEdgeDestination`](https://h3geo.org/docs/api/uniedge#getdirectededgedestination) | `try directedEdge.destination` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3directededge/destination) |
| [`directedEdgeToCells`](https://h3geo.org/docs/api/uniedge#directededgetocells) | Not exposed. Use `try (directedEdge.origin, directedEdge.destination)`. |
| [`originToDirectedEdges`](https://h3geo.org/docs/api/uniedge#origintodirectededges) | `try originCell.directedEdges` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/directededges) |
| [`directedEdgeToBoundary`](https://h3geo.org/docs/api/uniedge#directededgetoboundary) | `try directedEdge.boundary` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3directededge/boundary) |
### Vertex functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`cellToVertex`](https://h3geo.org/docs/api/vertex#celltovertex) | `try cell.vertex(3)` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/vertex(_:)) |
| [`cellToVertexes`](https://h3geo.org/docs/api/vertex#celltovertexes) | `try cell.vertices` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/vertices) |
| [`vertexToLatLng`](https://h3geo.org/docs/api/vertex#vertextolatlng) | `try vertex.latLng` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3vertex/latlng) |
| [`isValidVertex`](https://h3geo.org/docs/api/vertex#isvalidvertex) | `vertex.isValid` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3vertex/isvalid) |
### Miscellaneous H3 functions
| H3 C function | Example SwiftyH3 code | Docs |
| :---: | :--- | :---: |
| [`degsToRads`](https://h3geo.org/docs/api/misc#degstorads) | Not exposed. Use `Measurement<UnitAngle>(value: 23, unit: .degrees).converted(to: .radians).value`. |
| [`radsToDegs`](https://h3geo.org/docs/api/misc#radstodegs) | Not exposed. Use `Measurement<UnitAngle>(value: 1.2, unit: .radians).converted(to: .degrees).value`. |
| [`getHexagonAreaAvgKm2`](https://h3geo.org/docs/api/misc#gethexagonareaavgkm2) | `H3Cell.Resolution.res8.averageHexagonArea.converted(to: .squareKilometers).value` |
| [`getHexagonAreaAvgM2`](https://h3geo.org/docs/api/misc#gethexagonareaavgm2) | `H3Cell.Resolution.res8.averageHexagonArea.value` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/resolution/averagehexagonarea) |
| [`cellAreaRads2`](https://h3geo.org/docs/api/misc#cellarearads2) | `try cell.areaRads2` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/arearads2) |
| [`cellAreaKm2`](https://h3geo.org/docs/api/misc#cellareakm2) | `try cell.area.converted(to: .squareKilometers).value` |
| [`cellAreaM2`](https://h3geo.org/docs/api/misc#cellaream2) | `try cell.area.converted(to: .squareMeters).value` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/area) |
| [`getHexagonEdgeLengthAvgKm`](https://h3geo.org/docs/api/misc#gethexagonedgelengthavgkm) | `H3Cell.Resolution.res8.averageHexagonEdgeLength.converted(to: .kilometers).value` |
| [`getHexagonEdgeLengthAvgM`](https://h3geo.org/docs/api/misc#gethexagonedgelengthavgm) | `H3Cell.Resolution.res8.averageHexagonEdgeLength.value` | [π]() |
| [`edgeLengthKm`](https://h3geo.org/docs/api/misc#edgelengthkm) | `try directedEdge.length.converted(to: .kilometers).value` |
| [`edgeLengthM`](https://h3geo.org/docs/api/misc#edgelengthm) | `try directedEdge.length.value` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3directededge/length) |
| [`edgeLengthRads`](https://h3geo.org/docs/api/misc#edgelengthrads) | `try directedEdge.lengthRads.value` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3directededge/lengthrads) |
| [`getNumCells`](https://h3geo.org/docs/api/misc#getnumcells) | `H3Cell.Resolution.res3.numberOfCells` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/resolution/numberofcells) |
| [`getRes0Cells`](https://h3geo.org/docs/api/misc#getres0cells) | `H3Cell.res0Cells` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/res0cells) |
| [`res0CellCount`](https://h3geo.org/docs/api/misc#res0cellcount) | *This function exists for memory management and is not exposed.* |
| [`getPentagons`](https://h3geo.org/docs/api/misc#getpentagons) | `H3Cell.Resolution.res3.pentagons` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3cell/resolution/pentagons) |
| [`pentagonCount`](https://h3geo.org/docs/api/misc#pentagoncount) | *This function exists for memory management and is not exposed.* |
| [`greatCircleDistanceKm`](https://h3geo.org/docs/api/misc#greatcircledistancekm) | `h3LatLng1.distance(to: h3LatLng2).converted(to: .kilometers).value` |
| [`greatCircleDistanceM`](https://h3geo.org/docs/api/misc#greatcircledistancem) | `h3LatLng1.distance(to: h3LatLng2).value` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3latlng/distance(to:)) |
| [`greatCircleDistanceRads`](https://h3geo.org/docs/api/misc#greatcircledistancerads) | `h3LatLng1.distanceRads(to: h3LatLng2).value` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3latlng/distancerads(to:)) |
| [`describeH3Error`](https://h3geo.org/docs/api/misc#describeh3error) | `do {...} catch { print(error.errorDescription) }` | [π](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/swiftyh3error/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]](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3loop) or H3Polygon values. Analogically, you can initialize MKMultiPolygon with [[H3Polygon]](https://swiftpackageindex.com/pawelmajcher/swiftyh3/0.5.0/documentation/swiftyh3/h3multipolygon) 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
- SwiftyH3 (this repository) is licensed under the Apache 2.0 license.
- Uber's H3 library is licensed under the Apache 2.0 license.
Package Metadata
Repository: pawelmajcher/swiftyh3
Default branch: main
README: README.md