siderust 0.18.0

High-precision astronomy and satellite mechanics in Rust.
Documentation
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Vallés Puig, Ramon

//! VSOP87 / ELP2000-82B ephemeris backend.
//!
//! This is the default (always-available) backend. It delegates to the
//! existing `Planet::vsop87*` inherent methods and `Moon::get_geo_position`.

use super::{AuPerDay, Ephemeris, PlanetState};
use crate::bodies::solar_system::{
    Earth, Jupiter, Mars, Mercury, Moon, Neptune, Saturn, Sun, Uranus, Venus,
};
use crate::coordinates::{
    cartesian::{Position, Velocity},
    centers::{Barycentric, Geocentric, Heliocentric},
    frames::EclipticMeanJ2000,
};
use crate::qtty::{AstronomicalUnit, Kilometer};
use crate::time::JulianDate;

/// VSOP87 / ELP2000-82B ephemeris backend (always available).
///
/// Zero-sized marker type. Coefficient tables originate from
/// [`siderust-archive`](https://crates.io/crates/siderust-archive); this crate
/// only consumes the archive-backed static coefficient snapshots. No local
/// build-time generation occurs in Siderust.
#[derive(Debug, Clone, Copy, Default)]
pub struct Vsop87Ephemeris;

impl Ephemeris for Vsop87Ephemeris {
    fn try_planet_barycentric(
        planet: super::MajorPlanet,
        jd: JulianDate,
    ) -> Result<
        Position<Barycentric, EclipticMeanJ2000, AstronomicalUnit>,
        super::PlanetEphemerisError,
    > {
        use super::MajorPlanet::*;
        Ok(match planet {
            Mercury => crate::bodies::solar_system::Mercury::vsop87e(jd),
            Venus => crate::bodies::solar_system::Venus::vsop87e(jd),
            Mars => crate::bodies::solar_system::Mars::vsop87e(jd),
            Jupiter => crate::bodies::solar_system::Jupiter::vsop87e(jd),
            Saturn => crate::bodies::solar_system::Saturn::vsop87e(jd),
            Uranus => crate::bodies::solar_system::Uranus::vsop87e(jd),
            Neptune => crate::bodies::solar_system::Neptune::vsop87e(jd),
        })
    }

    fn try_pluto_barycentric(
        jd: JulianDate,
    ) -> Result<
        Position<Barycentric, EclipticMeanJ2000, AstronomicalUnit>,
        super::PlanetEphemerisError,
    > {
        // Preserve the default backend's existing coarse catalogue model.
        let helio = crate::bodies::solar_system::PLUTO.orbit.kepler_position(jd);
        let sun = <Self as Ephemeris>::try_sun_barycentric(jd)?;
        Ok(Position::new(
            helio.x() + sun.x(),
            helio.y() + sun.y(),
            helio.z() + sun.z(),
        ))
    }

    #[inline]
    fn sun_barycentric(
        jd: JulianDate,
    ) -> Position<Barycentric, EclipticMeanJ2000, AstronomicalUnit> {
        Sun::vsop87e(jd)
    }

    #[inline]
    fn earth_barycentric(
        jd: JulianDate,
    ) -> Position<Barycentric, EclipticMeanJ2000, AstronomicalUnit> {
        Earth::vsop87e(jd)
    }

    #[inline]
    fn earth_heliocentric(
        jd: JulianDate,
    ) -> Position<Heliocentric, EclipticMeanJ2000, AstronomicalUnit> {
        Earth::vsop87a(jd)
    }

    #[inline]
    fn earth_barycentric_velocity(jd: JulianDate) -> Velocity<EclipticMeanJ2000, AuPerDay> {
        Earth::vsop87e_vel(jd)
    }

    #[inline]
    fn moon_geocentric(jd: JulianDate) -> Position<Geocentric, EclipticMeanJ2000, Kilometer> {
        Moon::get_geo_position(jd)
    }
}

macro_rules! impl_vsop87_planet_state {
    ($($body:ident),+ $(,)?) => {
        $(
            impl PlanetState<$body> for Vsop87Ephemeris {
                #[inline]
                fn heliocentric(
                    jd: JulianDate,
                ) -> Position<Heliocentric, EclipticMeanJ2000, AstronomicalUnit> {
                    $body::vsop87a(jd)
                }
            }
        )+
    };
}

impl_vsop87_planet_state!(Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune);