The original SwiftGeographicLib
repository. SwiftGeographicLib
is a ready-to-use Swift wrapper for the geodesic routines from the renowned GeographicLib.
Under the hood, it calls the C library, but exposes a Swifty, type-safe API.
Use the Swift Package Manager. In your Package.swift
:
dependencies: [
.package(
url: "https://github.com/sindreoyen/SwiftGeographicLib.git",
.upToNextMinor(from: "1.0.1")
)
]
This library gives you three main APIs to solve geodesic problems on an ellipsoid:
Geodesic
– static direct/inverse callsGeodesicLine
– incremental “walk a geodesic” APIGeodesicPolygon
– accumulate points/edges to get perimeter & area
Tip: All APIs default to the World Geodetic System ellipsoid, WGS-84, unless you supply another
GeodGeodesic
model.
let start = (lat: 40.64, lon: -73.78) // JFK
let dest = Geodesic.direct(
from: start,
distance: 10_000_000, // 10 000 km
azimuth: 45.0 // north-east
)
// dest.latitude, dest.longitude
let (lat2, lon2, azi2,
s12, m12, M12, M21, S12,
a12) = Geodesic.generalDirect(
from: start,
azimuth: 45,
flags: .all, // all outputs
s12_a12: 10e6
)
let a = (lat: 40.64, lon: -73.78)
let b = (lat: 1.36, lon: 103.99)
let (distance, fwd, rev) = Geodesic.inverse(between: a, and: b)
let (a12, s12, azi1, azi2, m12, M12, M21, S12) =
Geodesic.generalInverse(between: a, and: b)
Use this when you want to step along a geodesic:
import SwiftGeographicLib
// 1) Basic init (no endpoint pinned)
let caps: GeodesicMask = [.distanceIn, .longitude]
let line = GeodesicLine(
from: (lat: 40.64, lon: -73.78),
azimuth: 45.0,
caps: caps
)
// 2) Direct init (endpoint fixed)
let line2 = GeodesicLine(
directFrom: (lat: 40.64, lon: -73.78),
azimuth: 45.0,
distance: 10_000_000,
caps: .all
)
// Simple: by distance
let pt1 = line.position(distance: 1_000_000)
// Full: all outputs
let (lat, lon, azi2, s12, m12, M12, M21, S12, a12) =
line.genPosition(flags: .arcMode, s12_a12: 100.0)
line.setDistance(500_000)
line.genSetDistance(flags: .arcMode, s13_a13: 4.5)
Accumulate vertices or edges to get perimeter & area:
let poly = GeodesicPolygon(polyline: false)
poly.addPoint((lat: 0.0, lon: 0.0))
poly.addEdge(azimuth: 90, distance: 111_000)
let (count, area, perimeter) = poly.compute(reverse: false, signed: true)
let coords = [(lat:0, lon:0), (lat:0, lon:1), (lat:1, lon:1), (lat:1, lon:0)]
let (area, peri) = GeodesicPolygon.area(of: coords)
SwiftGeographicLib provides two OptionSet
types to mirror the C bitmasks:
/// geod_mask values
public struct GeodesicMask: OptionSet {
public let rawValue: UInt32
public init(rawValue: UInt32) { self.rawValue = rawValue }
public static let none = GeodesicMask([])
public static let latitude = GeodesicMask(rawValue: 1<<7)
public static let longitude = GeodesicMask(rawValue: (1<<8)|(1<<3))
public static let azimuth = GeodesicMask(rawValue: 1<<9)
public static let distance = GeodesicMask(rawValue: (1<<10)|(1<<0))
public static let distanceIn = GeodesicMask(rawValue: (1<<11)|(1<<0)|(1<<1))
public static let reducedLength = GeodesicMask(rawValue: (1<<12)|(1<<0)|(1<<2))
public static let scale = GeodesicMask(rawValue: (1<<13)|(1<<0)|(1<<2))
public static let area = GeodesicMask(rawValue: (1<<14)|(1<<4))
public static let all: GeodesicMask = [
.latitude, .longitude, .azimuth,
.distance, .distanceIn, .reducedLength,
.scale, .area
]
}
/// geod_flags values
public struct GeodesicFlags: OptionSet {
public let rawValue: UInt32
public init(rawValue: UInt32) { self.rawValue = rawValue }
public static let none = GeodesicFlags([])
public static let arcMode = GeodesicFlags(rawValue: 1<<0)
public static let unrollLong = GeodesicFlags(rawValue: 1<<15)
}
Feel free to open issues, suggest features, or submit pull requests.
All methods live in Sources/SwiftGeographicLib
and tests in Tests/SwiftGeographicLibTests
.
Thank you for your contributions!