use crate::ops::Rotation3;
use crate::DeriveReferenceFrame;
use qtty::angular::Radians;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
const FRAME_BIAS_DALPHA0_ARCSEC: f64 = -0.0146;
const FRAME_BIAS_XI0_ARCSEC: f64 = -0.0166170;
const FRAME_BIAS_ETA0_ARCSEC: f64 = -0.0068192;
const ARCSEC_TO_RAD: f64 = std::f64::consts::PI / 648_000.0;
#[inline]
fn frame_bias_gcrs_to_eme2000() -> Rotation3 {
let xi0 = Radians::new(FRAME_BIAS_XI0_ARCSEC * ARCSEC_TO_RAD);
let eta0 = Radians::new(FRAME_BIAS_ETA0_ARCSEC * ARCSEC_TO_RAD);
let da0 = Radians::new(FRAME_BIAS_DALPHA0_ARCSEC * ARCSEC_TO_RAD);
Rotation3::rx(eta0) * Rotation3::ry(-xi0) * Rotation3::rz(-da0)
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ICRS;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra")]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ICRF;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EquatorialMeanJ2000;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EME2000;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EquatorialMeanOfDate;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EquatorialTrueOfDate;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GCRS;
impl ICRS {
#[inline]
#[must_use]
pub fn direction_rotation_to_icrf() -> Rotation3 {
Rotation3::IDENTITY
}
#[inline]
#[must_use]
pub fn direction_rotation_to_gcrs() -> Rotation3 {
Rotation3::IDENTITY
}
#[inline]
#[must_use]
pub fn frame_bias_to_eme2000() -> Rotation3 {
frame_bias_gcrs_to_eme2000()
}
}
impl ICRF {
#[inline]
#[must_use]
pub fn direction_rotation_to_icrs() -> Rotation3 {
Rotation3::IDENTITY
}
}
impl GCRS {
#[inline]
#[must_use]
pub fn direction_rotation_to_icrs() -> Rotation3 {
Rotation3::IDENTITY
}
#[inline]
#[must_use]
pub fn frame_bias_to_eme2000() -> Rotation3 {
frame_bias_gcrs_to_eme2000()
}
}
impl EME2000 {
#[inline]
#[must_use]
pub fn frame_bias_to_gcrs() -> Rotation3 {
frame_bias_gcrs_to_eme2000().inverse()
}
#[inline]
#[must_use]
pub fn frame_bias_to_icrs() -> Rotation3 {
frame_bias_gcrs_to_eme2000().inverse()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CIRS;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TIRS;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "alt", azimuth = "az", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Horizontal;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EclipticMeanJ2000;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EclipticOfDate;
pub type EclipticMeanOfDate = EclipticOfDate;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EclipticTrueOfDate;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(
polar = "lat",
azimuth = "lon",
distance = "altitude",
inherent,
ellipsoid = "Grs80"
)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ITRF;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(
polar = "lat",
azimuth = "lon",
distance = "altitude",
inherent,
ellipsoid = "Wgs84"
)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ECEF;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "b", azimuth = "l", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Galactic;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FK4B1950;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "dec", azimuth = "ra", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TEME;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MercuryFixed;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct VenusFixed;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MarsFixed;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MoonPrincipalAxes;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct JupiterSystemIII;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SaturnFixed;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct UranusFixed;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NeptuneFixed;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, DeriveReferenceFrame)]
#[frame(polar = "lat", azimuth = "lon", distance = "radius", inherent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PlutoFixed;
#[cfg(test)]
mod tests {
use super::*;
use crate::centers::{AffineCenter, ReferenceCenter};
use crate::frames::{ReferenceFrame, SphericalNaming};
use crate::spherical::{Direction, Position};
#[allow(unused_imports)]
use qtty::angular::{Degrees, Radians};
#[allow(unused_imports)]
use qtty::length::{Kilometers, Meters};
use qtty::units::{Kilometer, Parsec};
use qtty::Quantity;
use qtty::DEG;
#[test]
fn test_frame_names() {
assert_eq!(ICRS::frame_name(), "ICRS");
assert_eq!(ICRF::frame_name(), "ICRF");
assert_eq!(EME2000::frame_name(), "EME2000");
assert_eq!(Horizontal::frame_name(), "Horizontal");
assert_eq!(EclipticMeanJ2000::frame_name(), "EclipticMeanJ2000");
assert_eq!(EclipticOfDate::frame_name(), "EclipticOfDate");
assert_eq!(EclipticTrueOfDate::frame_name(), "EclipticTrueOfDate");
assert_eq!(EclipticMeanOfDate::frame_name(), "EclipticOfDate");
assert_eq!(Galactic::frame_name(), "Galactic");
assert_eq!(ITRF::frame_name(), "ITRF");
assert_eq!(ECEF::frame_name(), "ECEF");
assert_eq!(FK4B1950::frame_name(), "FK4B1950");
assert_eq!(TEME::frame_name(), "TEME");
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 test_spherical_naming() {
assert_eq!(ICRS::polar_name(), "dec");
assert_eq!(ICRS::azimuth_name(), "ra");
assert_eq!(EME2000::polar_name(), "dec");
assert_eq!(EME2000::azimuth_name(), "ra");
assert_eq!(Horizontal::polar_name(), "alt");
assert_eq!(Horizontal::azimuth_name(), "az");
assert_eq!(EclipticMeanJ2000::polar_name(), "lat");
assert_eq!(EclipticMeanJ2000::azimuth_name(), "lon");
assert_eq!(EclipticOfDate::polar_name(), "lat");
assert_eq!(EclipticOfDate::azimuth_name(), "lon");
assert_eq!(EclipticTrueOfDate::polar_name(), "lat");
assert_eq!(EclipticTrueOfDate::azimuth_name(), "lon");
assert_eq!(Galactic::polar_name(), "b");
assert_eq!(Galactic::azimuth_name(), "l");
assert_eq!(ITRF::distance_name(), "altitude");
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");
assert_eq!(MarsFixed::distance_name(), "radius");
}
#[test]
fn test_icrs_direction_new() {
let d = Direction::<ICRS>::new(120.0 * DEG, 45.0 * DEG);
assert_eq!(d.ra(), 120.0 * DEG);
assert_eq!(d.dec(), 45.0 * DEG);
}
#[test]
fn test_horizontal_direction_new() {
let d = Direction::<Horizontal>::new(30.0 * DEG, 180.0 * DEG);
assert_eq!(d.alt(), 30.0 * DEG);
assert_eq!(d.az(), 180.0 * DEG);
}
#[test]
fn test_ecliptic_direction_new() {
let d = Direction::<EclipticMeanJ2000>::new(270.0 * DEG, -10.0 * DEG);
assert_eq!(d.lon(), 270.0 * DEG);
assert_eq!(d.lat(), -10.0 * DEG);
}
#[test]
fn test_galactic_direction_new() {
let d = Direction::<Galactic>::new(45.0 * DEG, 20.0 * DEG);
assert_eq!(d.l(), 45.0 * DEG);
assert_eq!(d.b(), 20.0 * DEG);
}
#[test]
fn test_direction_canonicalization() {
let d = Direction::<ICRS>::new(370.0 * DEG, 45.0 * DEG);
assert!((d.ra().value() - 10.0).abs() < 1e-10);
assert_eq!(d.dec(), 45.0 * DEG);
let d = Direction::<ICRS>::new(0.0 * DEG, 100.0 * DEG);
assert!((d.dec().value() - 80.0).abs() < 1e-10);
}
#[derive(Debug, Copy, Clone)]
struct TestCenter;
impl ReferenceCenter for TestCenter {
type Params = ();
fn center_name() -> &'static str {
"TestCenter"
}
}
impl AffineCenter for TestCenter {}
#[test]
fn test_icrs_position_new() {
let p = Position::<TestCenter, ICRS, Parsec>::new(120.0 * DEG, 45.0 * DEG, 10.0);
assert_eq!(p.ra(), 120.0 * DEG);
assert_eq!(p.dec(), 45.0 * DEG);
}
#[test]
fn test_horizontal_position_new() {
let p = Position::<TestCenter, Horizontal, Kilometer>::new(30.0 * DEG, 180.0 * DEG, 100.0);
assert_eq!(p.alt(), 30.0 * DEG);
assert_eq!(p.az(), 180.0 * DEG);
}
#[test]
fn test_position_accessors_any_center() {
#[derive(Debug, Copy, Clone)]
struct ParamCenter;
impl ReferenceCenter for ParamCenter {
type Params = f64;
fn center_name() -> &'static str {
"ParamCenter"
}
}
let p = Position::<ParamCenter, ICRS, Parsec>::new_unchecked_with_params(
42.0,
45.0 * DEG,
120.0 * DEG,
Quantity::<Parsec>::new(10.0),
);
assert_eq!(p.ra(), 120.0 * DEG);
assert_eq!(p.dec(), 45.0 * DEG);
}
}