use crate::coordinate::CoordinateState;
use crate::thrust::{ThrustArc, ThrustParams};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum PhaseFunction {
HG = 0,
HG1G2 = 1,
HG12 = 2,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Orbit {
pub orbit_id: Option<String>,
pub object_id: Option<String>,
pub state: CoordinateState,
pub a1: f64,
pub a2: f64,
pub a3: f64,
pub ng_alpha: f64,
pub ng_r0: f64,
pub ng_m: f64,
pub ng_n: f64,
pub ng_k: f64,
pub non_grav_dt: Option<f64>,
pub ng_covariance: Option<[[f64; 3]; 3]>,
pub phot_system: Option<PhaseFunction>,
pub h_mag: f64,
pub slope1: f64,
pub slope2: f64,
pub thrust: Option<ThrustParams>,
}
impl Orbit {
pub fn new(state: CoordinateState) -> Self {
Self {
orbit_id: None,
object_id: None,
state,
a1: 0.0,
a2: 0.0,
a3: 0.0,
ng_alpha: 0.0,
ng_r0: 0.0,
ng_m: 0.0,
ng_n: 0.0,
ng_k: 0.0,
non_grav_dt: None,
ng_covariance: None,
phot_system: None,
h_mag: f64::NAN,
slope1: 0.0,
slope2: 0.0,
thrust: None,
}
}
pub fn with_orbit_id(mut self, id: impl Into<String>) -> Self {
self.orbit_id = Some(id.into());
self
}
pub fn with_object_id(mut self, id: impl Into<String>) -> Self {
self.object_id = Some(id.into());
self
}
pub fn with_nongrav(mut self, a1: f64, a2: f64, a3: f64) -> Self {
self.a1 = a1;
self.a2 = a2;
self.a3 = a3;
self
}
pub fn with_g_function(mut self, alpha: f64, r0: f64, m: f64, n: f64, k: f64) -> Self {
self.ng_alpha = alpha;
self.ng_r0 = r0;
self.ng_m = m;
self.ng_n = n;
self.ng_k = k;
self
}
pub fn with_non_grav_dt(mut self, dt: Option<f64>) -> Self {
self.non_grav_dt = dt;
self
}
pub fn with_nongrav_covariance(mut self, covariance: Option<[[f64; 3]; 3]>) -> Self {
self.ng_covariance = covariance;
self
}
pub fn with_photometry(
mut self,
phot_system: PhaseFunction,
h: f64,
slope1: f64,
slope2: f64,
) -> Self {
self.phot_system = Some(phot_system);
self.h_mag = h;
self.slope1 = slope1;
self.slope2 = slope2;
self
}
pub fn with_hg(self, h: f64, g: f64) -> Self {
self.with_photometry(PhaseFunction::HG, h, g, 0.0)
}
pub fn with_thrust(mut self, thrust: Option<ThrustParams>) -> Self {
self.thrust = thrust;
self
}
pub(crate) fn to_ffi_with_keep(
&self,
) -> crate::error::Result<(empyrean_sys::EmpyreanOrbit, OrbitFfiKeep)> {
use std::ffi::CString;
let (phase_int, h, s1, s2) = match self.phot_system {
Some(pf) => (pf as i32, self.h_mag, self.slope1, self.slope2),
None => (-1, f64::NAN, 0.0, 0.0),
};
let orbit_id_cstr =
CString::new(self.orbit_id.as_deref().unwrap_or("")).unwrap_or_default();
let object_id_cstr =
CString::new(self.object_id.as_deref().unwrap_or("")).unwrap_or_default();
let orbit_id_ptr = orbit_id_cstr.as_ptr();
let object_id_ptr = object_id_cstr.as_ptr();
let thrust_arcs: Vec<empyrean_sys::EmpyreanThrustArc> = self
.thrust
.as_ref()
.map(|tp| tp.arcs.iter().map(ThrustArc::to_ffi).collect())
.unwrap_or_default();
let dv_corrections: Vec<[f64; 3]> = self
.thrust
.as_ref()
.map(|tp| tp.dv_corrections.clone())
.unwrap_or_default();
let correction_covariances: Vec<[[f64; 3]; 3]> = self
.thrust
.as_ref()
.map(|tp| tp.correction_covariances.clone())
.unwrap_or_default();
let thrust_arcs_ptr = if thrust_arcs.is_empty() {
std::ptr::null()
} else {
thrust_arcs.as_ptr()
};
let dv_corrections_ptr = if dv_corrections.is_empty() {
std::ptr::null()
} else {
dv_corrections.as_ptr()
};
let correction_covariances_ptr = if correction_covariances.is_empty() {
std::ptr::null()
} else {
correction_covariances.as_ptr()
};
let ffi = empyrean_sys::EmpyreanOrbit {
state: self.state.to_ffi()?,
orbit_id: orbit_id_ptr,
object_id: object_id_ptr,
a1: self.a1,
a2: self.a2,
a3: self.a3,
ng_alpha: self.ng_alpha,
ng_r0: self.ng_r0,
ng_m: self.ng_m,
ng_n: self.ng_n,
ng_k: self.ng_k,
non_grav_dt: self.non_grav_dt.unwrap_or(f64::NAN),
has_non_grav_covariance: u8::from(self.ng_covariance.is_some()),
non_grav_covariance: self.ng_covariance.unwrap_or([[0.0; 3]; 3]),
phot_system: phase_int,
h_mag: h,
slope1: s1,
slope2: s2,
thrust_arcs: thrust_arcs_ptr,
n_thrust_arcs: thrust_arcs.len(),
dv_corrections: dv_corrections_ptr,
n_dv_corrections: dv_corrections.len(),
correction_covariances: correction_covariances_ptr,
n_correction_covariances: correction_covariances.len(),
};
let keep = OrbitFfiKeep {
_orbit_id: orbit_id_cstr,
_object_id: object_id_cstr,
_thrust_arcs: thrust_arcs,
_dv_corrections: dv_corrections,
_correction_covariances: correction_covariances,
};
Ok((ffi, keep))
}
}
pub(crate) struct OrbitFfiKeep {
_orbit_id: std::ffi::CString,
_object_id: std::ffi::CString,
_thrust_arcs: Vec<empyrean_sys::EmpyreanThrustArc>,
_dv_corrections: Vec<[f64; 3]>,
_correction_covariances: Vec<[[f64; 3]; 3]>,
}
pub(crate) fn orbits_to_ffi(
orbits: &[Orbit],
) -> crate::error::Result<(Vec<empyrean_sys::EmpyreanOrbit>, Vec<OrbitFfiKeep>)> {
let mut keep: Vec<OrbitFfiKeep> = Vec::with_capacity(orbits.len());
let ffi = orbits
.iter()
.map(|o| {
let (f, k) = o.to_ffi_with_keep()?;
keep.push(k);
Ok(f)
})
.collect::<crate::error::Result<Vec<_>>>()?;
Ok((ffi, keep))
}