Skip to main content

lox_orbits/
orbits.rs

1// SPDX-FileCopyrightText: 2025 Helge Eichhorn <git@helgeeichhorn.de>
2//
3// SPDX-License-Identifier: MPL-2.0
4
5/// Builder patterns for constructing orbits from orbital elements.
6pub mod builders;
7mod cartesian;
8/// Collections of named trajectories.
9pub mod ensemble;
10mod keplerian;
11/// Sun-synchronous orbit construction.
12pub mod sso;
13mod trajectory;
14
15pub use cartesian::StateToDynGroundError;
16pub use ensemble::{DynEnsemble, Ensemble};
17pub use trajectory::{DynTrajectory, Trajectory, TrajectoryError, TrajectoryTransformationError};
18
19use lox_bodies::{DynOrigin, Origin, PointMass, TryPointMass, UndefinedOriginPropertyError};
20use lox_core::{
21    coords::Cartesian,
22    elements::{GravitationalParameter, Keplerian},
23};
24use lox_frames::{DynFrame, ReferenceFrame};
25use lox_time::{
26    Time,
27    time_scales::{DynTimeScale, TimeScale},
28};
29use thiserror::Error;
30
31/// The state representation of an orbit, either Cartesian or Keplerian.
32pub enum OrbitType {
33    /// Cartesian position and velocity state.
34    Cartesian(Cartesian),
35    /// Classical Keplerian orbital elements.
36    Keplerian(Keplerian),
37}
38
39/// An orbital state parameterized by state representation, time scale, origin, and reference frame.
40#[derive(Debug, Clone, Copy, PartialEq)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42pub struct Orbit<S, T: TimeScale, O: Origin, R: ReferenceFrame> {
43    state: S,
44    time: Time<T>,
45    origin: O,
46    frame: R,
47}
48
49/// A dynamically-typed orbit with runtime time scale, origin, and frame.
50pub type DynOrbit = Orbit<OrbitType, DynTimeScale, DynOrigin, DynFrame>;
51
52impl<S, T, O, R> Orbit<S, T, O, R>
53where
54    T: TimeScale,
55    O: Origin,
56    R: ReferenceFrame,
57{
58    /// Constructs an orbit from its state, epoch, origin, and reference frame.
59    #[inline]
60    pub const fn from_state(state: S, time: Time<T>, origin: O, frame: R) -> Self {
61        Self {
62            state,
63            time,
64            origin,
65            frame,
66        }
67    }
68
69    /// Returns the orbital state.
70    #[inline]
71    pub fn state(&self) -> S
72    where
73        S: Copy,
74    {
75        self.state
76    }
77
78    /// Returns the epoch of this orbit.
79    #[inline]
80    pub fn time(&self) -> Time<T>
81    where
82        T: Copy,
83    {
84        self.time
85    }
86
87    /// Returns the central body origin.
88    #[inline]
89    pub fn origin(&self) -> O
90    where
91        O: Copy,
92    {
93        self.origin
94    }
95
96    /// Returns the reference frame.
97    #[inline]
98    pub fn reference_frame(&self) -> R
99    where
100        R: Copy,
101    {
102        self.frame
103    }
104
105    /// Returns the gravitational parameter of the origin, or an error if undefined.
106    pub fn try_gravitational_parameter(
107        &self,
108    ) -> Result<GravitationalParameter, UndefinedOriginPropertyError>
109    where
110        O: TryPointMass,
111    {
112        self.origin.try_gravitational_parameter()
113    }
114
115    /// Returns the gravitational parameter of the origin.
116    pub fn gravitational_parameter(&self) -> GravitationalParameter
117    where
118        O: PointMass,
119    {
120        self.origin.gravitational_parameter()
121    }
122}
123
124impl<S, T, O, R> Orbit<S, T, O, R>
125where
126    T: TimeScale + Copy + Into<DynTimeScale>,
127    O: Origin + Copy + Into<DynOrigin>,
128    R: ReferenceFrame + Copy + Into<DynFrame>,
129{
130    /// Converts this orbit into a dynamically-typed orbit.
131    pub fn into_dyn(self) -> Orbit<S, DynTimeScale, DynOrigin, DynFrame> {
132        Orbit::from_state(
133            self.state,
134            self.time.into_dyn(),
135            self.origin.into(),
136            self.frame.into(),
137        )
138    }
139}
140
141/// An orbit with Cartesian position and velocity state.
142pub type CartesianOrbit<T, O, R> = Orbit<Cartesian, T, O, R>;
143/// A dynamically-typed Cartesian orbit.
144pub type DynCartesianOrbit = Orbit<Cartesian, DynTimeScale, DynOrigin, DynFrame>;
145
146/// An orbit with classical Keplerian elements state.
147pub type KeplerianOrbit<T, O, R> = Orbit<Keplerian, T, O, R>;
148/// A dynamically-typed Keplerian orbit.
149pub type DynKeplerianOrbit = Orbit<Keplerian, DynTimeScale, DynOrigin, DynFrame>;
150
151/// Errors that can occur when constructing a trajectory.
152#[derive(Debug, Clone, PartialEq, Error)]
153pub enum TrajectorError {
154    /// Too few states were provided to construct a trajectory.
155    #[error("at least 2 states are required but only {0} were provided")]
156    InsufficientStates(usize),
157}