Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Time #56

Merged
merged 14 commits into from
Feb 11, 2024
84 changes: 53 additions & 31 deletions crates/lox_core/src/coords/states.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,34 @@ use float_eq::float_eq;
use glam::{DMat3, DVec3};

use crate::math::{mod_two_pi, normalize_two_pi};
use crate::time::continuous::Time;
use crate::time::continuous::{Time, TimeScale};

pub trait TwoBodyState {
fn time(&self) -> Time;
fn to_cartesian_state(&self, grav_param: f64) -> CartesianState;
fn to_keplerian_state(&self, grav_param: f64) -> KeplerianState;
pub trait TwoBodyState<T: TimeScale> {
AngusGMorrison marked this conversation as resolved.
Show resolved Hide resolved
fn time(&self) -> Time<T>;
fn to_cartesian_state(&self, grav_param: f64) -> CartesianState<T>;
fn to_keplerian_state(&self, grav_param: f64) -> KeplerianState<T>;
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CartesianState {
time: Time,
#[derive(Debug, PartialEq)]
pub struct CartesianState<T: TimeScale> {
time: Time<T>,
position: DVec3,
velocity: DVec3,
}

impl CartesianState {
pub fn new(time: Time, position: DVec3, velocity: DVec3) -> Self {
// Must be manually implemented, since derive macros always bound the generic parameters by the given trait, not the
// tightest possible bound. I.e., `TimeScale` is not inherently `Copy`, but `Time<TimeScale>` is.
// See https://github.com/rust-lang/rust/issues/108894#issuecomment-1459943821
impl<T: TimeScale> Clone for CartesianState<T> {
fn clone(&self) -> Self {
*self
}
}

impl<T: TimeScale> Copy for CartesianState<T> {}

impl<T: TimeScale> CartesianState<T> {
pub fn new(time: Time<T>, position: DVec3, velocity: DVec3) -> Self {
Self {
time,
position,
Expand All @@ -43,16 +54,16 @@ impl CartesianState {
}
}

impl TwoBodyState for CartesianState {
fn time(&self) -> Time {
impl<T: TimeScale> TwoBodyState<T> for CartesianState<T> {
fn time(&self) -> Time<T> {
self.time
}

fn to_cartesian_state(&self, _grav_param: f64) -> CartesianState {
fn to_cartesian_state(&self, _grav_param: f64) -> CartesianState<T> {
*self
}

fn to_keplerian_state(&self, grav_param: f64) -> KeplerianState {
fn to_keplerian_state(&self, grav_param: f64) -> KeplerianState<T> {
let r = self.position.length();
let v = self.velocity.length();
let h = self.position.cross(self.velocity);
Expand Down Expand Up @@ -118,9 +129,9 @@ impl TwoBodyState for CartesianState {
}
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct KeplerianState {
time: Time,
#[derive(Debug, PartialEq)]
pub struct KeplerianState<T: TimeScale> {
time: Time<T>,
semi_major: f64,
eccentricity: f64,
inclination: f64,
Expand All @@ -129,9 +140,20 @@ pub struct KeplerianState {
true_anomaly: f64,
}

impl KeplerianState {
// Must be manually implemented, since derive macros always bound the generic parameters by the given trait, not the
// tightest possible bound. I.e., `TimeScale` is not inherently `Copy`, but `Time<TimeScale>` is.
// See https://github.com/rust-lang/rust/issues/108894#issuecomment-1459943821
impl<T: TimeScale> Clone for KeplerianState<T> {
fn clone(&self) -> Self {
*self
}
}

impl<T: TimeScale> Copy for KeplerianState<T> {}

impl<T: TimeScale> KeplerianState<T> {
pub fn new(
time: Time,
time: Time<T>,
semi_major: f64,
eccentricity: f64,
inclination: f64,
Expand Down Expand Up @@ -195,20 +217,20 @@ impl KeplerianState {
}
}

impl TwoBodyState for KeplerianState {
fn time(&self) -> Time {
impl<T: TimeScale> TwoBodyState<T> for KeplerianState<T> {
fn time(&self) -> Time<T> {
self.time
}

fn to_cartesian_state(&self, grav_param: f64) -> CartesianState {
fn to_cartesian_state(&self, grav_param: f64) -> CartesianState<T> {
let (pos, vel) = self.to_perifocal(grav_param);
let rot = DMat3::from_rotation_z(self.ascending_node)
* DMat3::from_rotation_x(self.inclination)
* DMat3::from_rotation_z(self.periapsis_argument);
CartesianState::new(self.time, rot * pos, rot * vel)
}

fn to_keplerian_state(&self, _grav_param: f64) -> KeplerianState {
fn to_keplerian_state(&self, _grav_param: f64) -> KeplerianState<T> {
*self
}
}
Expand All @@ -235,13 +257,13 @@ mod tests {
use glam::DVec3;

use crate::bodies::{Earth, PointMass};
use crate::time::continuous::TimeScale;
use crate::time::continuous::TDB;

use super::*;

#[test]
fn test_elliptic() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let grav_param = 3.9860047e14;
let semi_major = 24464560.0;
let eccentricity = 0.7311;
Expand Down Expand Up @@ -297,7 +319,7 @@ mod tests {

#[test]
fn test_circular() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let grav_param = 3.986004418e14;
let semi_major = 6778136.6;
let eccentricity = 0.0;
Expand Down Expand Up @@ -338,7 +360,7 @@ mod tests {

#[test]
fn test_circular_orekit() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let grav_param = 3.9860047e14;
let semi_major = 24464560.0;
let eccentricity = 0.0;
Expand Down Expand Up @@ -370,7 +392,7 @@ mod tests {

#[test]
fn test_hyperbolic_orekit() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let grav_param = 3.9860047e14;
let semi_major = -24464560.0;
let eccentricity = 1.7311;
Expand Down Expand Up @@ -402,7 +424,7 @@ mod tests {

#[test]
fn test_equatorial() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let grav_param = 3.9860047e14;
let semi_major = 24464560.0;
let eccentricity = 0.7311;
Expand Down Expand Up @@ -434,7 +456,7 @@ mod tests {

#[test]
fn test_circular_equatorial() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let grav_param = 3.9860047e14;
let semi_major = 24464560.0;
let eccentricity = 0.0;
Expand Down Expand Up @@ -466,7 +488,7 @@ mod tests {

#[test]
fn test_iss() {
let time = Time::j2000(TimeScale::TDB);
let time = Time::<TDB>::j2000();
let position = DVec3::new(6068.27927, -1692.84394, -2516.61918);
let velocity = DVec3::new(-0.660415582, 5.495938726, -5.303093233);
let grav_param = Earth.gravitational_parameter();
Expand Down
Loading
Loading