diff --git a/.idea/lox-space.iml b/.idea/lox-space.iml
index 7e2df88b..5407fa9f 100644
--- a/.idea/lox-space.iml
+++ b/.idea/lox-space.iml
@@ -12,6 +12,7 @@
+
diff --git a/crates/lox_core/Cargo.toml b/crates/lox_core/Cargo.toml
index b80050b8..53949e3c 100644
--- a/crates/lox_core/Cargo.toml
+++ b/crates/lox_core/Cargo.toml
@@ -17,4 +17,4 @@ divan = "0.1.2"
[[bench]]
name = "iau_frames"
-harness = false
\ No newline at end of file
+harness = false
diff --git a/crates/lox_core/src/bin/lox.rs b/crates/lox_core/src/bin/lox.rs
index d4f12ac1..e2437fca 100644
--- a/crates/lox_core/src/bin/lox.rs
+++ b/crates/lox_core/src/bin/lox.rs
@@ -6,9 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-use lox_core::bodies::{MercuryBarycenter, NaifId};
+use lox_core::bodies::{Body, MercuryBarycenter};
fn main() {
println!("Hello LOX");
- println!("{}", MercuryBarycenter::ID)
+ println!("{}", MercuryBarycenter.id())
}
diff --git a/crates/lox_core/src/bodies.rs b/crates/lox_core/src/bodies.rs
index 83d85832..21aeeb14 100644
--- a/crates/lox_core/src/bodies.rs
+++ b/crates/lox_core/src/bodies.rs
@@ -7,6 +7,7 @@
*/
use std::f64::consts::PI;
+use std::fmt::{Display, Formatter};
use crate::time::constants::f64::{SECONDS_PER_DAY, SECONDS_PER_JULIAN_CENTURY};
@@ -16,9 +17,19 @@ pub mod planets;
pub mod satellites;
pub mod sun;
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct NaifId(pub i32);
+
+impl Display for NaifId {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
/// NaifId is implemented for all bodies.
-pub trait NaifId: Copy {
- const ID: i32;
+pub trait Body {
+ fn id(&self) -> NaifId;
+ fn name(&self) -> &'static str;
}
/// Expands to derivations of the fundamental traits every body must implement.
@@ -27,8 +38,28 @@ macro_rules! body {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct $i;
- impl NaifId for $i {
- const ID: i32 = $naif_id;
+ impl Body for $i {
+ fn id(&self) -> NaifId {
+ NaifId($naif_id)
+ }
+
+ fn name(&self) -> &'static str {
+ stringify!($ident)
+ }
+ }
+ };
+ ($i:ident, $name:literal, $naif_id:literal) => {
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct $i;
+
+ impl Body for $i {
+ fn id(&self) -> NaifId {
+ NaifId($naif_id)
+ }
+
+ fn name(&self) -> &'static str {
+ $name
+ }
}
};
}
@@ -48,16 +79,16 @@ body! { Neptune, 899 }
body! { Pluto, 999 }
// Barycenters.
-body! { SolarSystemBarycenter, 0 }
-body! { MercuryBarycenter, 1 }
-body! { VenusBarycenter, 2 }
-body! { EarthBarycenter, 3 }
-body! { MarsBarycenter, 4 }
-body! { JupiterBarycenter, 5 }
-body! { SaturnBarycenter, 6 }
-body! { UranusBarycenter, 7 }
-body! { NeptuneBarycenter, 8 }
-body! { PlutoBarycenter, 9 }
+body! { SolarSystemBarycenter, "Solar System Barycenter", 0 }
+body! { MercuryBarycenter, "Mercury Barycenter", 1 }
+body! { VenusBarycenter, "Venus Barycenter", 2 }
+body! { EarthBarycenter, "Earth Barycenter", 3 }
+body! { MarsBarycenter, "Mars Barycenter", 4 }
+body! { JupiterBarycenter, "Jupiter Barycenter", 5 }
+body! { SaturnBarycenter, "Saturn Barycenter", 6 }
+body! { UranusBarycenter, "Uranus Barycenter", 7 }
+body! { NeptuneBarycenter, "Neptune Barycenter", 8 }
+body! { PlutoBarycenter, "Pluto Barycenter", 9 }
// Satellites.
body! { Moon, 301 }
@@ -228,12 +259,226 @@ body! {Davida, 2000511 }
body! {Mathilde, 2000253 }
body! {Steins, 2002867 }
body! {Braille, 2009969 }
-body! {WilsonHarrington, 2004015 }
+body! {WilsonHarrington, "Wilson-Harrington", 2004015 }
body! {Toutatis, 2004179 }
body! {Itokawa, 2025143 }
body! {Bennu, 2101955 }
-pub trait Ellipsoid: NaifId {
+impl NaifId {
+ pub fn body(&self) -> Option> {
+ match self.0 {
+ 10 => Some(Box::new(Sun)),
+
+ // Planets.
+ 199 => Some(Box::new(Mercury)),
+ 299 => Some(Box::new(Venus)),
+ 399 => Some(Box::new(Earth)),
+ 499 => Some(Box::new(Mars)),
+ 599 => Some(Box::new(Jupiter)),
+ 699 => Some(Box::new(Saturn)),
+ 799 => Some(Box::new(Uranus)),
+ 899 => Some(Box::new(Neptune)),
+ 999 => Some(Box::new(Pluto)),
+
+ // Barycenters.
+ 0 => Some(Box::new(SolarSystemBarycenter)),
+ 1 => Some(Box::new(MercuryBarycenter)),
+ 2 => Some(Box::new(VenusBarycenter)),
+ 3 => Some(Box::new(EarthBarycenter)),
+ 4 => Some(Box::new(MarsBarycenter)),
+ 5 => Some(Box::new(JupiterBarycenter)),
+ 6 => Some(Box::new(SaturnBarycenter)),
+ 7 => Some(Box::new(UranusBarycenter)),
+ 8 => Some(Box::new(NeptuneBarycenter)),
+ 9 => Some(Box::new(PlutoBarycenter)),
+
+ // Satellites.
+ 301 => Some(Box::new(Moon)),
+ 401 => Some(Box::new(Phobos)),
+ 402 => Some(Box::new(Deimos)),
+ 501 => Some(Box::new(Io)),
+ 502 => Some(Box::new(Europa)),
+ 503 => Some(Box::new(Ganymede)),
+ 504 => Some(Box::new(Callisto)),
+ 505 => Some(Box::new(Amalthea)),
+ 506 => Some(Box::new(Himalia)),
+ 507 => Some(Box::new(Elara)),
+ 508 => Some(Box::new(Pasiphae)),
+ 509 => Some(Box::new(Sinope)),
+ 510 => Some(Box::new(Lysithea)),
+ 511 => Some(Box::new(Carme)),
+ 512 => Some(Box::new(Ananke)),
+ 513 => Some(Box::new(Leda)),
+ 514 => Some(Box::new(Thebe)),
+ 515 => Some(Box::new(Adrastea)),
+ 516 => Some(Box::new(Metis)),
+ 517 => Some(Box::new(Callirrhoe)),
+ 518 => Some(Box::new(Themisto)),
+ 519 => Some(Box::new(Magaclite)),
+ 520 => Some(Box::new(Taygete)),
+ 521 => Some(Box::new(Chaldene)),
+ 522 => Some(Box::new(Harpalyke)),
+ 523 => Some(Box::new(Kalyke)),
+ 524 => Some(Box::new(Iocaste)),
+ 525 => Some(Box::new(Erinome)),
+ 526 => Some(Box::new(Isonoe)),
+ 527 => Some(Box::new(Praxidike)),
+ 528 => Some(Box::new(Autonoe)),
+ 529 => Some(Box::new(Thyone)),
+ 530 => Some(Box::new(Hermippe)),
+ 531 => Some(Box::new(Aitne)),
+ 532 => Some(Box::new(Eurydome)),
+ 533 => Some(Box::new(Euanthe)),
+ 534 => Some(Box::new(Euporie)),
+ 535 => Some(Box::new(Orthosie)),
+ 536 => Some(Box::new(Sponde)),
+ 537 => Some(Box::new(Kale)),
+ 538 => Some(Box::new(Pasithee)),
+ 539 => Some(Box::new(Hegemone)),
+ 540 => Some(Box::new(Mneme)),
+ 541 => Some(Box::new(Aoede)),
+ 542 => Some(Box::new(Thelxinoe)),
+ 543 => Some(Box::new(Arche)),
+ 544 => Some(Box::new(Kallichore)),
+ 545 => Some(Box::new(Helike)),
+ 546 => Some(Box::new(Carpo)),
+ 547 => Some(Box::new(Eukelade)),
+ 548 => Some(Box::new(Cyllene)),
+ 549 => Some(Box::new(Kore)),
+ 550 => Some(Box::new(Herse)),
+ 553 => Some(Box::new(Dia)),
+ 601 => Some(Box::new(Mimas)),
+ 602 => Some(Box::new(Enceladus)),
+ 603 => Some(Box::new(Tethys)),
+ 604 => Some(Box::new(Dione)),
+ 605 => Some(Box::new(Rhea)),
+ 606 => Some(Box::new(Titan)),
+ 607 => Some(Box::new(Hyperion)),
+ 608 => Some(Box::new(Iapetus)),
+ 609 => Some(Box::new(Phoebe)),
+ 610 => Some(Box::new(Janus)),
+ 611 => Some(Box::new(Epimetheus)),
+ 612 => Some(Box::new(Helene)),
+ 613 => Some(Box::new(Telesto)),
+ 614 => Some(Box::new(Calypso)),
+ 615 => Some(Box::new(Atlas)),
+ 616 => Some(Box::new(Prometheus)),
+ 617 => Some(Box::new(Pandora)),
+ 618 => Some(Box::new(Pan)),
+ 619 => Some(Box::new(Ymir)),
+ 620 => Some(Box::new(Paaliaq)),
+ 621 => Some(Box::new(Tarvos)),
+ 622 => Some(Box::new(Ijiraq)),
+ 623 => Some(Box::new(Suttungr)),
+ 624 => Some(Box::new(Kiviuq)),
+ 625 => Some(Box::new(Mundilfari)),
+ 626 => Some(Box::new(Albiorix)),
+ 627 => Some(Box::new(Skathi)),
+ 628 => Some(Box::new(Erriapus)),
+ 629 => Some(Box::new(Siarnaq)),
+ 630 => Some(Box::new(Thrymr)),
+ 631 => Some(Box::new(Narvi)),
+ 632 => Some(Box::new(Methone)),
+ 633 => Some(Box::new(Pallene)),
+ 634 => Some(Box::new(Polydeuces)),
+ 635 => Some(Box::new(Daphnis)),
+ 636 => Some(Box::new(Aegir)),
+ 637 => Some(Box::new(Bebhionn)),
+ 638 => Some(Box::new(Bergelmir)),
+ 639 => Some(Box::new(Bestla)),
+ 640 => Some(Box::new(Farbauti)),
+ 641 => Some(Box::new(Fenrir)),
+ 642 => Some(Box::new(Fornjot)),
+ 643 => Some(Box::new(Hati)),
+ 644 => Some(Box::new(Hyrrokkin)),
+ 645 => Some(Box::new(Kari)),
+ 646 => Some(Box::new(Loge)),
+ 647 => Some(Box::new(Skoll)),
+ 648 => Some(Box::new(Surtur)),
+ 649 => Some(Box::new(Anthe)),
+ 650 => Some(Box::new(Jarnsaxa)),
+ 651 => Some(Box::new(Greip)),
+ 652 => Some(Box::new(Tarqeq)),
+ 653 => Some(Box::new(Aegaeon)),
+ 701 => Some(Box::new(Ariel)),
+ 702 => Some(Box::new(Umbriel)),
+ 703 => Some(Box::new(Titania)),
+ 704 => Some(Box::new(Oberon)),
+ 705 => Some(Box::new(Miranda)),
+ 706 => Some(Box::new(Cordelia)),
+ 707 => Some(Box::new(Ophelia)),
+ 708 => Some(Box::new(Bianca)),
+ 709 => Some(Box::new(Cressida)),
+ 710 => Some(Box::new(Desdemona)),
+ 711 => Some(Box::new(Juliet)),
+ 712 => Some(Box::new(Portia)),
+ 713 => Some(Box::new(Rosalind)),
+ 714 => Some(Box::new(Belinda)),
+ 715 => Some(Box::new(Puck)),
+ 716 => Some(Box::new(Caliban)),
+ 717 => Some(Box::new(Sycorax)),
+ 718 => Some(Box::new(Prospero)),
+ 719 => Some(Box::new(Setebos)),
+ 720 => Some(Box::new(Stephano)),
+ 721 => Some(Box::new(Trinculo)),
+ 722 => Some(Box::new(Francisco)),
+ 723 => Some(Box::new(Margaret)),
+ 724 => Some(Box::new(Ferdinand)),
+ 725 => Some(Box::new(Perdita)),
+ 726 => Some(Box::new(Mab)),
+ 727 => Some(Box::new(Cupid)),
+ 801 => Some(Box::new(Triton)),
+ 802 => Some(Box::new(Nereid)),
+ 803 => Some(Box::new(Naiad)),
+ 804 => Some(Box::new(Thalassa)),
+ 805 => Some(Box::new(Despina)),
+ 806 => Some(Box::new(Galatea)),
+ 807 => Some(Box::new(Larissa)),
+ 808 => Some(Box::new(Proteus)),
+ 809 => Some(Box::new(Halimede)),
+ 810 => Some(Box::new(Psamathe)),
+ 811 => Some(Box::new(Sao)),
+ 812 => Some(Box::new(Laomedeia)),
+ 813 => Some(Box::new(Neso)),
+ 901 => Some(Box::new(Charon)),
+ 902 => Some(Box::new(Nix)),
+ 903 => Some(Box::new(Hydra)),
+ 904 => Some(Box::new(Kerberos)),
+ 905 => Some(Box::new(Styx)),
+
+ // Minor bodies.
+ 9511010 => Some(Box::new(Gaspra)),
+ 2431010 => Some(Box::new(Ida)),
+ 2431011 => Some(Box::new(Dactyl)),
+ 2000001 => Some(Box::new(Ceres)),
+ 2000002 => Some(Box::new(Pallas)),
+ 2000004 => Some(Box::new(Vesta)),
+ 2000016 => Some(Box::new(Psyche)),
+ 2000021 => Some(Box::new(Lutetia)),
+ 2000216 => Some(Box::new(Kleopatra)),
+ 2000433 => Some(Box::new(Eros)),
+ 2000511 => Some(Box::new(Davida)),
+ 2000253 => Some(Box::new(Mathilde)),
+ 2002867 => Some(Box::new(Steins)),
+ 2009969 => Some(Box::new(Braille)),
+ 2004015 => Some(Box::new(WilsonHarrington)),
+ 2004179 => Some(Box::new(Toutatis)),
+ 2025143 => Some(Box::new(Itokawa)),
+ 2101955 => Some(Box::new(Bennu)),
+ _ => None,
+ }
+ }
+
+ pub fn name(&self) -> String {
+ if let Some(body) = self.body() {
+ body.name().to_string()
+ } else {
+ format!("Body {}", self.0)
+ }
+ }
+}
+
+pub trait Ellipsoid: Body {
fn polar_radius() -> f64;
fn mean_radius() -> f64;
@@ -269,7 +514,7 @@ pub fn along_orbit_radius(_: T) -> f64 {
::along_orbit_radius()
}
-pub trait PointMass: NaifId {
+pub trait PointMass: Body {
fn gravitational_parameter() -> f64;
}
@@ -283,7 +528,7 @@ pub type NutationPrecessionCoefficients = (&'static [f64], &'static [f64]);
type Elements = (f64, f64, f64);
-pub trait RotationalElements: NaifId {
+pub trait RotationalElements: Body {
const NUTATION_PRECESSION_COEFFICIENTS: NutationPrecessionCoefficients;
const RIGHT_ASCENSION_COEFFICIENTS: PolynomialCoefficients;
const DECLINATION_COEFFICIENTS: PolynomialCoefficients;
@@ -413,14 +658,20 @@ mod tests {
use super::*;
- // Jupiter is manually redefined here using known data. This avoids a dependecy on the
+ // Jupiter is manually redefined here using known data. This avoids a dependency on the
// correctness of the PCK parser to test RotationalElements, and prevents compiler errors
// when generated files are malformed or deleted in preparation for regeneration.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Jupiter;
- impl NaifId for Jupiter {
- const ID: i32 = 599;
+ impl Body for Jupiter {
+ fn id(&self) -> NaifId {
+ NaifId(599)
+ }
+
+ fn name(&self) -> &'static str {
+ "Jupiter"
+ }
}
impl PointMass for Jupiter {
@@ -428,6 +679,7 @@ mod tests {
126686531.9003704f64
}
}
+
impl Ellipsoid for Jupiter {
fn polar_radius() -> f64 {
66854f64
@@ -436,6 +688,7 @@ mod tests {
69946f64
}
}
+
impl Spheroid for Jupiter {
fn equatorial_radius() -> f64 {
71492f64
@@ -537,6 +790,17 @@ mod tests {
);
}
+ #[test]
+ fn test_naif_id() {
+ let id = NaifId(0);
+ let name = id.name();
+ assert_eq!(name, "Solar System Barycenter");
+
+ let id = NaifId(-42);
+ let name = id.name();
+ assert_eq!(name, "Body -42");
+ }
+
#[test]
fn test_grav_param() {
assert_eq!(
diff --git a/crates/lox_core/src/frames.rs b/crates/lox_core/src/frames.rs
index acbc99c9..517c92bb 100644
--- a/crates/lox_core/src/frames.rs
+++ b/crates/lox_core/src/frames.rs
@@ -15,7 +15,7 @@ pub mod iau;
// TODO: Replace with proper `Epoch` type
type Epoch = f64;
-pub trait ReferenceFrame: Copy {
+pub trait ReferenceFrame {
fn is_inertial(&self) -> bool;
fn is_rotating(&self) -> bool {
diff --git a/crates/lox_core/src/two_body.rs b/crates/lox_core/src/two_body.rs
index 537ef8a0..8f732121 100644
--- a/crates/lox_core/src/two_body.rs
+++ b/crates/lox_core/src/two_body.rs
@@ -33,14 +33,14 @@ pub trait TwoBody {
}
#[derive(Debug, Clone)]
-pub struct Cartesian {
+pub struct Cartesian {
epoch: Epoch,
center: T,
position: DVec3,
velocity: DVec3,
}
-impl Cartesian {
+impl Cartesian {
pub fn new(epoch: Epoch, center: T, position: DVec3, velocity: DVec3) -> Self {
Self {
epoch,
@@ -51,7 +51,7 @@ impl Cartesian {
}
}
-impl TwoBody for Cartesian {
+impl TwoBody for Cartesian {
type Center = T;
fn epoch(&self) -> Epoch {
@@ -104,7 +104,10 @@ impl TwoBody for Cartesian {
}
}
-impl From> for Cartesian {
+impl From> for Cartesian
+where
+ T: Copy,
+{
fn from(value: Keplerian) -> Self {
let epoch = value.epoch;
let center = value.center;
@@ -114,7 +117,7 @@ impl From> for Cartesian {
}
#[derive(Debug, Clone)]
-pub struct Keplerian {
+pub struct Keplerian {
epoch: Epoch,
center: T,
semi_major: f64,
@@ -125,7 +128,7 @@ pub struct Keplerian {
true_anomaly: f64,
}
-impl Keplerian {
+impl Keplerian {
pub fn new(epoch: Epoch, center: T, elements: Elements) -> Self {
let (semi_major, eccentricity, inclination, ascending_node, periapsis_arg, true_anomaly) =
elements;
@@ -142,7 +145,7 @@ impl Keplerian {
}
}
-impl TwoBody for Keplerian {
+impl TwoBody for Keplerian {
type Center = T;
fn epoch(&self) -> Epoch {
@@ -210,7 +213,7 @@ impl TwoBody for Keplerian {
}
}
-impl From> for Keplerian {
+impl From> for Keplerian {
fn from(value: Cartesian) -> Self {
let epoch = value.epoch;
let center = value.center;