pub mod position;
pub use position::to_topocentric::to_topocentric_with_ctx;
use crate::coordinates::cartesian::Position;
use crate::coordinates::centers::*;
use crate::coordinates::frames::ReferenceFrame;
use crate::coordinates::transform::context::AstroContext;
use crate::coordinates::transform::providers::CenterShiftProvider;
use crate::time::JulianDate;
use qtty::LengthUnit;
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> {
let (params, jd) = args.into_params_jd();
self.to_center_with(params, jd, &AstroContext::default())
}
fn to_center_with(
&self,
params: C2::Params,
jd: JulianDate,
ctx: &AstroContext,
) -> 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_with(
&self,
_params: (),
jd: JulianDate,
ctx: &AstroContext,
) -> Position<C2, F, U> {
let shift = <() as CenterShiftProvider<C1, C2, F>>::shift(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::time::JulianDate;
use qtty::AstronomicalUnit;
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);
}
}