Swift package that wraps the VSOP87 analytical planetary theory to deliver fast, deterministic positions, brightness estimates, and distances for major Solar System bodies. All public APIs revolve around the SolarSystemBody enum so you can query the Sun, planets, Moon, and the Earth-Moon barycenter with a single entry point.
- Retrieve heliocentric ecliptic rectangular coordinates (in astronomical units) using VSOP87a.
- Convert heliocentric positions to Earth-centered inertial (ECI) coordinates aligned with the J2000 mean equator.
- Estimate apparent visual magnitudes for the Sun, Moon, and planets with built-in phase angle corrections.
- Compute body-to-body distances directly from VSOP positions.
- Swift 6.1 or newer (Swift Package manifest version).
- iOS 18 / macOS 13 (per
Package.swiftdeployment targets).
Add SolarSystem to your package dependencies:
// Package.swift
dependencies: [
.package(url: "https://github.com/sihaolu/SolarSystem.git", from: "1.0.0")
],
targets: [
.target(
name: "MyApp",
dependencies: [
.product(name: "SolarSystem", package: "SolarSystem")
]
)
]When using Xcode, you can add the Git repository URL through File ▸ Add Package… and select the desired version rule.
All APIs expect a Julian Day expressed as a Double. The library leaves date conversion to callers so you can integrate your preferred time system. The following helper mirrors the one used in the unit tests:
import Foundation
private let appleZero: TimeInterval = 2451910.5 // 2001-01-01 00:00:00 UTC (CFAbsoluteTime zero)
private let secondsPerDay = 86_400.0
extension Date {
var julianDay: Double {
appleZero + timeIntervalSinceReferenceDate / secondsPerDay
}
}import Foundation
import simd
import SolarSystem
let now = Date()
let jd = now.julianDay
let marsHeliocentric = SolarSystemBody.mars.heliocentricEclipticCoordinate(julianDay: jd)
// -> SIMD3<Double> in astronomical units (AU)The heliocentric coordinates follow the VSOP87 convention: ecliptic reference plane, rectangular components (x, y, z), and astronomical units. The origin is at the Sun.
let moonECI = SolarSystemBody.moon.eci(julianDay: jd)
// ECI frame centered on Earth, expressed in AUSolarSystemBody.earth.eci(julianDay:) always returns (0, 0, 0) because the frame is Earth-centered.
if let magnitude = SolarSystemBody.venus.apparentMagnitude(julianDay: jd) {
print("Venus is magnitude \(magnitude)")
}Magnitudes incorporate distance and phase-angle corrections when documented for each body. The function returns nil for earthMoonBarycenter, and a fixed value of -26.74 for the Sun.
let earthToSaturnAU = SolarSystemBody.earth.distance(to: .saturn, julianDate: jd)The result is the Euclidean separation between two heliocentric positions in astronomical units.
- All positions are taken from the VSOP87a XSmall series published by Celestial Programming, providing arcminute-level accuracy across several millennia. You can replace it with more accurate models at an expense of larger size.
- ECI conversion uses a mean obliquity model based on the J2000 epoch and the IAU 2006 precession series.
- Magnitude models use polynomial fits from published photometric phase curves; ring inclination and other secondary effects are approximated where required.
Clone the repository and use Swift Package Manager:
swift testThe bundled tests validate magnitude ranges and confirm positional outputs for Earth against known values.