extern crate hyperdual;
extern crate nalgebra as na;
extern crate prost;
pub use self::xb::Xb;
use self::xb::{Ephemeris, Epoch as XbEpoch};
pub use crate::cosmic::{Frame, GuidanceMode, Orbit, Spacecraft};
pub use crate::errors::NyxError;
use crate::linalg::allocator::Allocator;
use crate::linalg::{DefaultAllocator, DimName, OMatrix, OVector};
use crate::md::StateParameter;
use crate::time::{Duration, Epoch, Unit, SECONDS_PER_DAY};
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::time::Instant;
pub trait TimeTagged {
fn epoch(&self) -> Epoch;
fn set_epoch(&mut self, epoch: Epoch);
fn shift_by(&mut self, duration: Duration) {
self.set_epoch(self.epoch() + duration);
}
}
pub trait State: Copy + PartialEq + fmt::Display + fmt::LowerExp + Send + Sync
where
Self: Sized,
DefaultAllocator: Allocator<f64, Self::Size>
+ Allocator<f64, Self::Size, Self::Size>
+ Allocator<f64, Self::VecLength>,
{
type Size: DimName;
type VecLength: DimName;
fn zeros() -> Self {
unimplemented!()
}
fn as_vector(&self) -> Result<OVector<f64, Self::VecLength>, NyxError>;
fn stm(&self) -> Result<OMatrix<f64, Self::Size, Self::Size>, NyxError> {
unimplemented!()
}
fn reset_stm(&mut self) {
unimplemented!()
}
fn set(&mut self, epoch: Epoch, vector: &OVector<f64, Self::VecLength>)
-> Result<(), NyxError>;
fn set_with_delta_seconds(self, delta_t_s: f64, vector: &OVector<f64, Self::VecLength>) -> Self
where
DefaultAllocator: Allocator<f64, Self::VecLength>,
{
let mut me = self;
me.set(me.epoch() + delta_t_s, vector).unwrap();
me
}
fn epoch(&self) -> Epoch;
fn set_epoch(&mut self, epoch: Epoch);
fn add(self, _other: OVector<f64, Self::Size>) -> Self {
unimplemented!()
}
fn value(&self, _param: &StateParameter) -> Result<f64, NyxError> {
Err(NyxError::StateParameterUnavailable)
}
fn set_value(&mut self, _param: &StateParameter, _val: f64) -> Result<(), NyxError> {
Err(NyxError::StateParameterUnavailable)
}
}
impl XbEpoch {
pub fn as_raw(&self) -> f64 {
f64::from(self.days) + self.seconds / SECONDS_PER_DAY
}
pub fn to_epoch(&self) -> Epoch {
let epoch_delta = i64::from(self.days) * Unit::Day + self.seconds * Unit::Second;
match self.ts {
0 => {
unimplemented!("TAI")
}
1 => match self.repr {
5 => Epoch::from_jde_et(epoch_delta.in_unit(Unit::Day)),
_ => unimplemented!("ET"),
},
2 => match self.repr {
0 => Epoch::from_tt_seconds(epoch_delta.in_seconds()),
_ => unimplemented!("TT"),
},
3 => {
unimplemented!("UTC")
}
4 => match self.repr {
2 => Epoch::from_tdb_seconds(epoch_delta.in_seconds()),
5 => Epoch::from_jde_tdb(epoch_delta.in_unit(Unit::Day)),
_ => unimplemented!("TDB"),
},
_ => unimplemented!(),
}
}
}
impl Xb {
pub fn from_file(input_filename: &str) -> Result<Self, NyxError> {
let mut input_xb_buf = Vec::new();
match File::open(input_filename) {
Err(e) => return Err(NyxError::LoadingError(format!("{}", e))),
Ok(mut f) => {
if f.read_to_end(&mut input_xb_buf).is_err() {
return Err(NyxError::LoadingError("Could not read buffer".to_string()));
}
}
};
Self::from_buffer(&input_xb_buf)
}
pub fn from_buffer(input_xb_buf: &[u8]) -> Result<Self, NyxError> {
use self::prost::Message;
if input_xb_buf.is_empty() {
return Err(NyxError::LoadingError("XB buffer is empty".to_string()));
}
let decode_start = Instant::now();
match Self::decode(&*input_xb_buf) {
Ok(xb) => {
info!("Loaded XB in {} ms.", decode_start.elapsed().as_millis());
Ok(xb)
}
Err(e) => Err(NyxError::LoadingError(format!(
"Could not decode XB: {}",
e
))),
}
}
pub fn ephemeris_from_path<'a>(&'a self, path: &[usize]) -> Result<&'a Ephemeris, NyxError> {
match &self.ephemeris_root {
None => Err(NyxError::ObjectNotFound("not ephemeris root".to_string())),
Some(root) => {
if path.is_empty() {
return Ok(root);
}
for pos in path {
if root.children.get(*pos).is_none() {
let hpath: String =
path.iter().map(|p| format!("{}", p)).collect::<String>();
return Err(NyxError::ObjectNotFound(hpath));
}
}
match path.len() {
1 => Ok(&self.ephemeris_root.as_ref().unwrap().children[path[0]]),
2 => Ok(
&self.ephemeris_root.as_ref().unwrap().children[path[0]].children[path[1]],
),
3 => Ok(
&self.ephemeris_root.as_ref().unwrap().children[path[0]].children[path[1]]
.children[path[2]],
),
_ => unimplemented!(),
}
}
}
}
fn ephemeris_seek_by_name(
name: &str,
cur_path: &mut Vec<usize>,
e: &Ephemeris,
) -> Result<Vec<usize>, NyxError> {
if e.name == name {
Ok(cur_path.to_vec())
} else if e.children.is_empty() {
Err(NyxError::ObjectNotFound(name.to_string()))
} else {
for (cno, child) in e.children.iter().enumerate() {
let mut this_path = cur_path.clone();
this_path.push(cno);
let child_attempt = Self::ephemeris_seek_by_name(name, &mut this_path, child);
if let Ok(found_path) = child_attempt {
return Ok(found_path);
}
}
Err(NyxError::ObjectNotFound(name.to_string()))
}
}
pub fn ephemeris_find_path(&self, name: String) -> Result<Vec<usize>, NyxError> {
match &self.ephemeris_root {
None => Err(NyxError::ObjectNotFound("No root!".to_string())),
Some(root) => {
if root.name == name {
Ok(Vec::new())
} else {
let mut path = Vec::new();
Self::ephemeris_seek_by_name(&name, &mut path, root)
}
}
}
}
fn ephemeris_names(mut names: &mut Vec<String>, e: &Ephemeris) {
names.push(e.name.clone());
for child in &e.children {
Self::ephemeris_names(&mut names, child);
}
}
pub fn ephemeris_get_names(&self) -> Vec<String> {
let mut names = Vec::new();
if let Some(root) = &self.ephemeris_root {
Self::ephemeris_names(&mut names, root);
}
names
}
}
pub mod orientations {
pub const J2000: i32 = 1;
}
mod bodies;
pub use self::bodies::*;
mod orbit;
pub use self::orbit::*;
mod orbitdual;
pub use self::orbitdual::*;
mod bplane;
pub use self::bplane::*;
mod spacecraft;
pub use self::spacecraft::*;
mod frames;
pub use self::frames::*;
mod rotations;
pub use self::rotations::*;
mod cosm;
mod xb;
pub use self::cosm::*;
pub mod eclipse;
pub const SPEED_OF_LIGHT: f64 = 299_792_458.0;
pub const SPEED_OF_LIGHT_KMS: f64 = SPEED_OF_LIGHT / 1000.0;
pub const AU: f64 = 149_597_870.700;
pub const STD_GRAVITY: f64 = 9.80665;