137 lines
4.1 KiB
Rust
137 lines
4.1 KiB
Rust
//! Reference frames: where a state's origin is and how its axes are oriented.
|
|
//!
|
|
//! This module carries the frame *type*. Transformations between orientations —
|
|
//! J2000 to ITRF, topocentric, geodetic site coordinates — are a separate piece of
|
|
//! work and will land here on top of ANISE.
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::body::Body;
|
|
|
|
/// How a frame's axes are oriented.
|
|
///
|
|
/// Provisional and deliberately coarse. The distinctions that matter for
|
|
/// sub-arcsecond work — ICRF against EME2000, ITRF against a body-fixed IAU frame
|
|
/// — arrive with the transformations, which is the point at which getting them
|
|
/// wrong would show up. Marked `#[non_exhaustive]` so refining it is not a
|
|
/// breaking change.
|
|
#[non_exhaustive]
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum Orientation {
|
|
/// Inertial, aligned with the J2000 mean equator and equinox.
|
|
J2000,
|
|
/// Rotating with the central body.
|
|
BodyFixed,
|
|
}
|
|
|
|
/// A reference frame: a central body and an orientation.
|
|
///
|
|
/// Held by every [`Cartesian`](crate::cartesian::Cartesian) and every element set,
|
|
/// which is what lets conversions read `mu` from the state rather than take it as
|
|
/// an argument.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
|
pub struct Frame {
|
|
/// The body at the origin.
|
|
pub center: Body,
|
|
/// How the axes are oriented.
|
|
pub orientation: Orientation,
|
|
}
|
|
|
|
impl Frame {
|
|
/// Earth-centered, J2000-oriented.
|
|
pub const EARTH_J2000: Self = Self {
|
|
center: Body::EARTH,
|
|
orientation: Orientation::J2000,
|
|
};
|
|
|
|
/// Earth-centered, rotating with the Earth.
|
|
pub const EARTH_FIXED: Self = Self {
|
|
center: Body::EARTH,
|
|
orientation: Orientation::BodyFixed,
|
|
};
|
|
|
|
/// Moon-centered, J2000-oriented.
|
|
pub const MOON_J2000: Self = Self {
|
|
center: Body::MOON,
|
|
orientation: Orientation::J2000,
|
|
};
|
|
|
|
/// A J2000-oriented frame centered on `center`.
|
|
pub const fn inertial(center: Body) -> Self {
|
|
Self {
|
|
center,
|
|
orientation: Orientation::J2000,
|
|
}
|
|
}
|
|
|
|
/// A frame rotating with `center`.
|
|
pub const fn body_fixed(center: Body) -> Self {
|
|
Self {
|
|
center,
|
|
orientation: Orientation::BodyFixed,
|
|
}
|
|
}
|
|
|
|
/// The central body's gravitational parameter, m^3/s^2.
|
|
pub fn mu(&self) -> f64 {
|
|
self.center.mu
|
|
}
|
|
|
|
/// Whether orbital motion in this frame is unaccelerated by the frame itself.
|
|
///
|
|
/// Element conversions and the two-body relations are only meaningful in an
|
|
/// inertial frame; in a rotating one the velocity is not the inertial velocity.
|
|
pub fn is_inertial(&self) -> bool {
|
|
matches!(self.orientation, Orientation::J2000)
|
|
}
|
|
|
|
/// The same frame with a different orientation.
|
|
pub fn with_orientation(&self, orientation: Orientation) -> Self {
|
|
Self {
|
|
orientation,
|
|
..*self
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Frame {
|
|
fn default() -> Self {
|
|
Self::EARTH_J2000
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_frame_carries_the_central_bodys_mu() {
|
|
assert_eq!(Frame::EARTH_J2000.mu(), Body::EARTH.mu);
|
|
assert_eq!(Frame::MOON_J2000.mu(), Body::MOON.mu);
|
|
}
|
|
|
|
#[test]
|
|
fn test_only_inertial_frames_report_inertial() {
|
|
assert!(Frame::EARTH_J2000.is_inertial());
|
|
assert!(!Frame::EARTH_FIXED.is_inertial());
|
|
assert!(Frame::inertial(Body::SUN).is_inertial());
|
|
assert!(!Frame::body_fixed(Body::SUN).is_inertial());
|
|
}
|
|
|
|
#[test]
|
|
fn test_orientation_can_be_swapped_keeping_the_center() {
|
|
let fixed = Frame::EARTH_J2000.with_orientation(Orientation::BodyFixed);
|
|
assert_eq!(fixed, Frame::EARTH_FIXED);
|
|
assert_eq!(fixed.center, Body::EARTH);
|
|
}
|
|
|
|
#[test]
|
|
fn test_frame_round_trips_through_json() {
|
|
let json = serde_json::to_string(&Frame::MOON_J2000).unwrap();
|
|
assert_eq!(
|
|
serde_json::from_str::<Frame>(&json).unwrap(),
|
|
Frame::MOON_J2000
|
|
);
|
|
}
|
|
}
|