use super::{Planet, Satellite, Star};
use crate::astro::orbit::Orbit;
use crate::astro::{HasIauRotation, IauRotationParams};
use crate::coordinates::spherical::position::{EclipticMeanJ2000, EquatorialMeanJ2000};
use crate::targets::CoordinateWithPM;
use crate::time::JulianDate;
use qtty::length::nominal::RSUN;
use qtty::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Sun;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Mercury;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Venus;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Earth;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Moon;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Mars;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Jupiter;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Saturn;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Uranus;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Neptune;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Pluto;
macro_rules! define_body_rotations {
(
$(
$rotation_const:ident => $body:ty {
alpha0_deg: $alpha0_deg:expr,
alpha0_rate: $alpha0_rate:expr,
delta0_deg: $delta0_deg:expr,
delta0_rate: $delta0_rate:expr,
w0_deg: $w0_deg:expr,
w_rate: $w_rate:expr $(,)?
}
),+ $(,)?
) => {
$(
pub const $rotation_const: IauRotationParams = IauRotationParams {
alpha0_deg: $alpha0_deg,
alpha0_rate: $alpha0_rate,
delta0_deg: $delta0_deg,
delta0_rate: $delta0_rate,
w0_deg: $w0_deg,
w_rate: $w_rate,
};
impl HasIauRotation for $body {
const ROTATION: IauRotationParams = $rotation_const;
}
impl $body {
pub const ROTATION: IauRotationParams = $rotation_const;
}
)+
};
}
define_body_rotations!(
MERCURY_ROTATION => Mercury {
alpha0_deg: Degrees::new(281.0103),
alpha0_rate: Degrees::new(-0.0328),
delta0_deg: Degrees::new(61.4155),
delta0_rate: Degrees::new(-0.0049),
w0_deg: Degrees::new(329.5988),
w_rate: Degrees::new(6.1385108),
},
VENUS_ROTATION => Venus {
alpha0_deg: Degrees::new(272.76),
alpha0_rate: Degrees::new(0.0),
delta0_deg: Degrees::new(67.16),
delta0_rate: Degrees::new(0.0),
w0_deg: Degrees::new(160.20),
w_rate: Degrees::new(-1.4813688),
},
MARS_ROTATION => Mars {
alpha0_deg: Degrees::new(317.269),
alpha0_rate: Degrees::new(-0.10927),
delta0_deg: Degrees::new(54.432),
delta0_rate: Degrees::new(-0.05827),
w0_deg: Degrees::new(176.049),
w_rate: Degrees::new(350.891982443),
},
MOON_ROTATION => Moon {
alpha0_deg: Degrees::new(269.9949),
alpha0_rate: Degrees::new(0.0031),
delta0_deg: Degrees::new(66.5392),
delta0_rate: Degrees::new(0.0130),
w0_deg: Degrees::new(38.3213),
w_rate: Degrees::new(13.17635815),
},
JUPITER_ROTATION => Jupiter {
alpha0_deg: Degrees::new(268.057),
alpha0_rate: Degrees::new(-0.006),
delta0_deg: Degrees::new(64.495),
delta0_rate: Degrees::new(0.002),
w0_deg: Degrees::new(284.95),
w_rate: Degrees::new(870.5360000),
},
SATURN_ROTATION => Saturn {
alpha0_deg: Degrees::new(40.589),
alpha0_rate: Degrees::new(-0.036),
delta0_deg: Degrees::new(83.537),
delta0_rate: Degrees::new(-0.004),
w0_deg: Degrees::new(38.90),
w_rate: Degrees::new(810.7939024),
},
URANUS_ROTATION => Uranus {
alpha0_deg: Degrees::new(257.311),
alpha0_rate: Degrees::new(0.0),
delta0_deg: Degrees::new(-15.175),
delta0_rate: Degrees::new(0.0),
w0_deg: Degrees::new(203.81),
w_rate: Degrees::new(-501.1600928),
},
NEPTUNE_ROTATION => Neptune {
alpha0_deg: Degrees::new(299.36),
alpha0_rate: Degrees::new(0.0), delta0_deg: Degrees::new(43.46),
delta0_rate: Degrees::new(0.0), w0_deg: Degrees::new(249.978),
w_rate: Degrees::new(541.1397757),
},
PLUTO_ROTATION => Pluto {
alpha0_deg: Degrees::new(132.993),
alpha0_rate: Degrees::new(0.0),
delta0_deg: Degrees::new(-6.163),
delta0_rate: Degrees::new(0.0),
w0_deg: Degrees::new(302.695),
w_rate: Degrees::new(56.3625225),
},
);
pub const SUN: super::Star<'static> = super::Star::new_const(
"Sun",
LightYears::new(1.58125e-5), SolarMasses::new(1.0),
RSUN,
L_SUN,
CoordinateWithPM::<EquatorialMeanJ2000<LightYear>>::new_static(
EquatorialMeanJ2000::<LightYear>::new_raw(
HourAngles::from_hms(-23, 0, 0.0).to_const::<Degree>(), HourAngles::from_hms(18, 44, 48.0).to_const::<Degree>(), LightYears::new(1.58125e-5), ),
JulianDate::J2000,
),
);
pub const MERCURY: super::Planet = super::Planet {
mass: Kilograms::new(3.3011e23),
radius: Kilometers::new(2439.7),
orbit: Orbit::new(
AstronomicalUnits::new(0.38709893),
0.20563069,
Degrees::new(7.00487),
Degrees::new(48.33167),
Degrees::new(29.12478),
Degrees::new(174.79439),
JulianDate::J2000,
),
};
pub const VENUS: super::Planet = super::Planet {
mass: Kilograms::new(4.8675e24),
radius: Kilometers::new(6051.8),
orbit: Orbit::new(
AstronomicalUnits::new(0.72333199),
0.00677323,
Degrees::new(3.39471),
Degrees::new(76.68069),
Degrees::new(54.85229),
Degrees::new(50.44675),
JulianDate::J2000,
),
};
pub const EARTH: super::Planet = super::Planet {
mass: Kilograms::new(5.97237e24),
radius: Kilometers::new(6371.0),
orbit: Orbit::new(
AstronomicalUnits::new(1.00000011),
0.01671022,
Degrees::new(0.00005),
Degrees::new(-11.26064),
Degrees::new(114.20783),
Degrees::new(357.51716),
JulianDate::J2000,
),
};
pub const MOON: super::Satellite = super::Satellite::new_const(
"Moon",
Kilograms::new(7.346e22),
Kilometers::new(1_737.4),
Orbit {
semi_major_axis: AstronomicalUnits::new(2.566881e-6),
eccentricity: 0.054_9,
inclination: Degrees::new(5.145),
longitude_of_ascending_node: Degrees::new(125.08),
argument_of_perihelion: Degrees::new(318.15),
mean_anomaly_at_epoch: Degrees::new(135.27),
epoch: JulianDate::J2000,
},
);
pub const MARS: super::Planet = super::Planet {
mass: Kilograms::new(6.4171e23),
radius: Kilometers::new(3389.5),
orbit: Orbit::new(
AstronomicalUnits::new(1.52366231),
0.09341233,
Degrees::new(1.85061),
Degrees::new(49.57854),
Degrees::new(286.46230),
Degrees::new(19.41248),
JulianDate::J2000,
),
};
pub const JUPITER: super::Planet = super::Planet {
mass: Kilograms::new(1.8982e27),
radius: Kilometers::new(69911.0),
orbit: Orbit::new(
AstronomicalUnits::new(5.20336301),
0.04839266,
Degrees::new(1.30530),
Degrees::new(100.55615),
Degrees::new(274.19770),
Degrees::new(19.65053),
JulianDate::J2000,
),
};
pub const SATURN: super::Planet = super::Planet {
mass: Kilograms::new(5.6834e26),
radius: Kilometers::new(58232.0),
orbit: Orbit::new(
AstronomicalUnits::new(9.53707032),
0.05415060,
Degrees::new(2.48446),
Degrees::new(113.71504),
Degrees::new(338.71690),
Degrees::new(317.51238),
JulianDate::J2000,
),
};
pub const URANUS: super::Planet = super::Planet {
mass: Kilograms::new(8.6810e25),
radius: Kilometers::new(25362.0),
orbit: Orbit::new(
AstronomicalUnits::new(19.19126393),
0.04716771,
Degrees::new(0.76986),
Degrees::new(74.22988),
Degrees::new(96.73436),
Degrees::new(142.26794),
JulianDate::J2000,
),
};
pub const NEPTUNE: super::Planet = super::Planet {
mass: Kilograms::new(1.02409e26),
radius: Kilometers::new(24622.0),
orbit: Orbit::new(
AstronomicalUnits::new(30.06896348),
0.00858587,
Degrees::new(1.76917),
Degrees::new(131.72169),
Degrees::new(273.24966),
Degrees::new(259.90868),
JulianDate::J2000,
),
};
pub const PLUTO: super::Planet = super::Planet {
mass: Kilograms::new(1.303e22),
radius: Kilometers::new(1188.3),
orbit: Orbit::new(
AstronomicalUnits::new(39.48168677),
0.24880766,
Degrees::new(17.14175),
Degrees::new(110.30347),
Degrees::new(113.76329),
Degrees::new(14.86205),
JulianDate::J2000,
),
};
pub const CERES: Planet = Planet {
mass: Kilograms::new(9.393e20),
radius: Kilometers::new(473.0),
orbit: Orbit::new(
AstronomicalUnits::new(2.7675),
0.0758,
Degrees::new(10.5941),
Degrees::new(80.3055),
Degrees::new(73.5977),
Degrees::new(95.9892),
JulianDate::J2000,
),
};
pub const HAUMEA: Planet = Planet {
mass: Kilograms::new(4.006e21),
radius: Kilometers::new(620.0),
orbit: Orbit::new(
AstronomicalUnits::new(43.218),
0.195,
Degrees::new(28.19),
Degrees::new(121.9),
Degrees::new(239.1),
Degrees::new(205.7),
JulianDate::J2000,
),
};
pub const MAKEMAKE: Planet = Planet {
mass: Kilograms::new(3.1e21),
radius: Kilometers::new(715.0),
orbit: Orbit::new(
AstronomicalUnits::new(45.791),
0.159,
Degrees::new(29.01),
Degrees::new(79.3),
Degrees::new(286.1),
Degrees::new(159.8),
JulianDate::J2000,
),
};
pub const ERIS: Planet = Planet {
mass: Kilograms::new(1.66e22),
radius: Kilometers::new(1163.0),
orbit: Orbit::new(
AstronomicalUnits::new(67.864),
0.44177,
Degrees::new(44.04),
Degrees::new(35.95),
Degrees::new(151.231),
Degrees::new(204.17),
JulianDate::J2000,
),
};
pub const DWARF_PLANETS: &[&Planet] = &[&super::PLUTO, &CERES, &HAUMEA, &MAKEMAKE, &ERIS];
pub const IO: Satellite = Satellite::new_const(
"Io",
Kilograms::new(8.9319e22),
Kilometers::new(1821.6),
Orbit {
semi_major_axis: AstronomicalUnits::new(0.002823),
eccentricity: 0.0041,
inclination: Degrees::new(0.036),
longitude_of_ascending_node: Degrees::new(43.977),
argument_of_perihelion: Degrees::new(84.129),
mean_anomaly_at_epoch: Degrees::new(171.016),
epoch: JulianDate::J2000,
},
);
pub const EUROPA: Satellite = Satellite::new_const(
"Europa",
Kilograms::new(4.7998e22),
Kilometers::new(1560.8),
Orbit {
semi_major_axis: AstronomicalUnits::new(0.004485),
eccentricity: 0.009,
inclination: Degrees::new(0.465),
longitude_of_ascending_node: Degrees::new(219.106),
argument_of_perihelion: Degrees::new(88.970),
mean_anomaly_at_epoch: Degrees::new(324.528),
epoch: JulianDate::J2000,
},
);
pub const GANYMEDE: Satellite = Satellite::new_const(
"Ganymede",
Kilograms::new(1.4819e23),
Kilometers::new(2634.1),
Orbit {
semi_major_axis: AstronomicalUnits::new(0.007155),
eccentricity: 0.0013,
inclination: Degrees::new(0.177),
longitude_of_ascending_node: Degrees::new(63.552),
argument_of_perihelion: Degrees::new(192.417),
mean_anomaly_at_epoch: Degrees::new(317.654),
epoch: JulianDate::J2000,
},
);
pub const CALLISTO: Satellite = Satellite::new_const(
"Callisto",
Kilograms::new(1.0759e23),
Kilometers::new(2410.3),
Orbit {
semi_major_axis: AstronomicalUnits::new(0.012585),
eccentricity: 0.0074,
inclination: Degrees::new(0.192),
longitude_of_ascending_node: Degrees::new(298.848),
argument_of_perihelion: Degrees::new(52.643),
mean_anomaly_at_epoch: Degrees::new(51.483),
epoch: JulianDate::J2000,
},
);
pub const TITAN: Satellite = Satellite::new_const(
"Titan",
Kilograms::new(1.3452e23),
Kilometers::new(2574.73),
Orbit {
semi_major_axis: AstronomicalUnits::new(0.008167),
eccentricity: 0.0288,
inclination: Degrees::new(0.34854),
longitude_of_ascending_node: Degrees::new(168.650),
argument_of_perihelion: Degrees::new(186.585),
mean_anomaly_at_epoch: Degrees::new(30.744),
epoch: JulianDate::J2000,
},
);
pub const TRITON: Satellite = Satellite::new_const(
"Triton",
Kilograms::new(2.14e22),
Kilometers::new(1353.4),
Orbit {
semi_major_axis: AstronomicalUnits::new(0.002371),
eccentricity: 0.000016,
inclination: Degrees::new(156.865), longitude_of_ascending_node: Degrees::new(216.732),
argument_of_perihelion: Degrees::new(185.965),
mean_anomaly_at_epoch: Degrees::new(144.960),
epoch: JulianDate::J2000,
},
);
pub const MAJOR_MOONS: &[&Satellite] = &[
&super::MOON,
&IO,
&EUROPA,
&GANYMEDE,
&CALLISTO,
&TITAN,
&TRITON,
];
#[derive(Debug, Clone)]
pub struct LagrangePoint {
pub name: &'static str,
pub parent_system: &'static str,
pub position: EclipticMeanJ2000<AstronomicalUnit>,
}
const SUN_EARTH_L1: LagrangePoint = LagrangePoint {
name: "Sun–Earth L1",
parent_system: "Sun–Earth",
position: EclipticMeanJ2000::<AstronomicalUnit>::new_raw(
Degrees::new(0.0), Degrees::new(0.0), AstronomicalUnits::new(0.99),
),
};
const SUN_EARTH_L2: LagrangePoint = LagrangePoint {
name: "Sun–Earth L2",
parent_system: "Sun–Earth",
position: EclipticMeanJ2000::<AstronomicalUnit>::new_raw(
Degrees::new(0.0), Degrees::new(180.0), AstronomicalUnits::new(1.01),
),
};
pub const LAGRANGE_POINTS: &[&LagrangePoint] = &[&SUN_EARTH_L1, &SUN_EARTH_L2];
#[derive(Debug)]
pub struct SolarSystem<'a> {
pub sun: &'a Star<'a>,
pub planets: &'a [&'a Planet],
pub dwarf_planets: &'a [&'a Planet],
pub moons: &'a [&'a Satellite<'a>],
pub lagrange_points: &'a [&'a LagrangePoint],
}
pub const PLANETS: &[&Planet] = &[
&super::MERCURY,
&super::VENUS,
&super::EARTH,
&super::MARS,
&super::JUPITER,
&super::SATURN,
&super::URANUS,
&super::NEPTUNE,
];
pub const SOLAR_SYSTEM: SolarSystem<'static> = SolarSystem {
sun: &super::SUN,
planets: PLANETS,
dwarf_planets: DWARF_PLANETS,
moons: MAJOR_MOONS,
lagrange_points: LAGRANGE_POINTS,
};
#[cfg(test)]
mod tests {
use super::*;
use affn::frames::{
JupiterSystemIII, MarsFixed, MercuryFixed, MoonPrincipalAxes, NeptuneFixed, PlutoFixed,
ReferenceFrame, SaturnFixed, SphericalNaming, UranusFixed, VenusFixed,
};
#[test]
fn planetary_frame_names() {
assert_eq!(MercuryFixed::frame_name(), "MercuryFixed");
assert_eq!(VenusFixed::frame_name(), "VenusFixed");
assert_eq!(MarsFixed::frame_name(), "MarsFixed");
assert_eq!(MoonPrincipalAxes::frame_name(), "MoonPrincipalAxes");
assert_eq!(JupiterSystemIII::frame_name(), "JupiterSystemIII");
assert_eq!(SaturnFixed::frame_name(), "SaturnFixed");
assert_eq!(UranusFixed::frame_name(), "UranusFixed");
assert_eq!(NeptuneFixed::frame_name(), "NeptuneFixed");
assert_eq!(PlutoFixed::frame_name(), "PlutoFixed");
}
#[test]
fn spherical_naming_is_planetocentric() {
assert_eq!(MercuryFixed::polar_name(), "lat");
assert_eq!(MercuryFixed::azimuth_name(), "lon");
assert_eq!(MercuryFixed::distance_name(), "radius");
assert_eq!(MarsFixed::polar_name(), "lat");
assert_eq!(MarsFixed::azimuth_name(), "lon");
}
#[test]
fn rotation_params_at_j2000() {
let p = &MARS_ROTATION;
assert!((p.alpha0(JulianDate::J2000).value() - 317.269).abs() < 1e-10);
assert!((p.delta0(JulianDate::J2000).value() - 54.432).abs() < 1e-10);
assert!((p.w(JulianDate::J2000).value() - 176.049).abs() < 1e-10);
}
#[test]
fn rotation_params_rate() {
let p = &MARS_ROTATION;
let alpha = p.alpha0(JulianDate::J2000 + JulianDate::JULIAN_CENTURY);
assert!((alpha.value() - (317.269 - 0.10927)).abs() < 1e-10);
let w = p.w(JulianDate::J2000 + qtty::Days::new(1.0));
assert!((w.value() - (176.049 + 350.891982443)).abs() < 1e-8);
}
#[test]
fn body_associated_rotation_constants_match_catalog() {
assert_eq!(Mars::ROTATION.alpha0_deg, MARS_ROTATION.alpha0_deg);
assert_eq!(Jupiter::ROTATION.w_rate, JUPITER_ROTATION.w_rate);
assert_eq!(Moon::ROTATION.delta0_deg, MOON_ROTATION.delta0_deg);
}
}