pub mod position;
pub use position::to_topocentric::{to_topocentric_with, to_topocentric_with_ctx};
use crate::astro::eop::EopProvider;
use crate::astro::nutation::NutationModel;
use crate::calculus::ephemeris::Ephemeris;
use crate::coordinates::cartesian::Position;
use crate::coordinates::centers::*;
use crate::coordinates::frames::ReferenceFrame;
use crate::coordinates::transform::context::{AstroContext, TransformContext};
use crate::coordinates::transform::providers::{center_shift_as, CenterShiftProvider};
use crate::qtty::LengthUnit;
use crate::time::JulianDate;
pub trait IntoTransformArgs<Params> {
fn into_params_jd(self) -> (Params, JulianDate);
}
impl IntoTransformArgs<()> for JulianDate {
#[inline]
fn into_params_jd(self) -> ((), JulianDate) {
((), self)
}
}
impl<P: Clone> IntoTransformArgs<P> for (P, JulianDate) {
#[inline]
fn into_params_jd(self) -> (P, JulianDate) {
self
}
}
pub trait TransformCenter<C2: ReferenceCenter, F: ReferenceFrame, U: LengthUnit> {
fn to_center<A: IntoTransformArgs<C2::Params>>(&self, args: A) -> Position<C2, F, U>
where
Self: Sized,
{
let (params, jd) = args.into_params_jd();
let ctx: AstroContext = AstroContext::default();
self.to_center_with(params, jd, &ctx)
}
fn to_center_with<Ctx>(
&self,
params: C2::Params,
jd: JulianDate,
ctx: &Ctx,
) -> Position<C2, F, U>
where
Ctx: TransformContext,
Ctx::Eph: Ephemeris,
Self: Sized,
{
self.to_center_as::<Ctx::Eph, Ctx::Eop, Ctx::Nut>(params, jd, ctx.astro_context())
}
fn to_center_as<Eph: Ephemeris, Eop: EopProvider, Nut: NutationModel>(
&self,
params: C2::Params,
jd: JulianDate,
ctx: &AstroContext<Eph, Eop>,
) -> Position<C2, F, U>;
}
impl<C1, C2, F, U> TransformCenter<C2, F, U> for Position<C1, F, U>
where
C1: ReferenceCenter<Params = ()>,
C2: ReferenceCenter<Params = ()>,
F: ReferenceFrame,
U: LengthUnit,
(): CenterShiftProvider<C1, C2, F>,
{
fn to_center_as<Eph: Ephemeris, Eop: EopProvider, Nut: NutationModel>(
&self,
_params: (),
jd: JulianDate,
ctx: &AstroContext<Eph, Eop>,
) -> Position<C2, F, U> {
let shift = center_shift_as::<C1, C2, F, Nut, Eph, Eop>(jd, ctx);
Position::new(
self.x() + shift[0].to::<U>(),
self.y() + shift[1].to::<U>(),
self.z() + shift[2].to::<U>(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::calculus::ephemeris::Ephemeris;
use crate::coordinates::cartesian;
use crate::coordinates::transform::context::DefaultEphemeris;
use crate::coordinates::transform::Transform;
use crate::macros::assert_cartesian_eq;
use crate::qtty::AstronomicalUnit;
use crate::time::JulianDate;
const EPSILON: f64 = 1e-8;
#[test]
fn test_position_barycentric_to_geocentric() {
let earth_bary = DefaultEphemeris::earth_barycentric(JulianDate::J2000);
let earth_geo: cartesian::position::EclipticMeanJ2000<AstronomicalUnit, Geocentric> =
earth_bary.transform(JulianDate::J2000);
let expected_earth_geo =
cartesian::position::EclipticMeanJ2000::<AstronomicalUnit, Geocentric>::CENTER;
assert_cartesian_eq!(
&earth_geo,
&expected_earth_geo,
EPSILON,
"Earth in Geocentric should be at origin. Current: {:?}",
earth_geo
);
}
#[test]
fn test_position_heliocentric_to_geocentric() {
let earth_helio = DefaultEphemeris::earth_heliocentric(JulianDate::J2000);
let earth_geo: cartesian::position::EclipticMeanJ2000<AstronomicalUnit, Geocentric> =
earth_helio.transform(JulianDate::J2000);
let expected =
cartesian::position::EclipticMeanJ2000::<AstronomicalUnit, Geocentric>::CENTER;
assert_cartesian_eq!(&earth_geo, &expected, EPSILON);
}
}