DJBen/SolarSystem

Positions, brightness estimates for major Solar System bodies in Swift 6

★ 1Forks 0SwiftGitHub ↗Compare

README

SolarSystem

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.

Highlights

  • 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.

Requirements

  • Swift 6.1 or newer (Swift Package manifest version).
  • iOS 18 / macOS 13 (per Package.swift deployment targets).

Installation (Swift Package Manager)

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.

Usage

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
    }
}

Heliocentric positions

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.

Earth-centered inertial coordinates

let moonECI = SolarSystemBody.moon.eci(julianDay: jd)
// ECI frame centered on Earth, expressed in AU

SolarSystemBody.earth.eci(julianDay:) always returns (0, 0, 0) because the frame is Earth-centered.

Apparent magnitude

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.

Inter-body distances

let earthToSaturnAU = SolarSystemBody.earth.distance(to: .saturn, julianDate: jd)

The result is the Euclidean separation between two heliocentric positions in astronomical units.

Accuracy notes

  • 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.

Running tests

Clone the repository and use Swift Package Manager:

swift test

The bundled tests validate magnitude ranges and confirm positional outputs for Earth against known values.

Contributors

DJBen

Issues