extern crate hyperdual;
extern crate nalgebra as na;
extern crate prost;
use std::convert::TryFrom;
use std::fs::File;
use std::io::Read;
use std::time::Instant;
pub use self::xb::Xb;
use self::xb::{Ephemeris, Epoch as XbEpoch};
pub use crate::errors::NyxError;
use crate::time::{Epoch, TimeUnit, SECONDS_PER_DAY};
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 = self.days * TimeUnit::Day + self.seconds * TimeUnit::Second;
match self.ts {
0 => {
unimplemented!("TAI")
}
1 => match self.repr {
5 => Epoch::from_jde_et(epoch_delta.in_unit_f64(TimeUnit::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_f64(TimeUnit::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;
}
#[derive(Copy, Clone, Debug)]
#[allow(clippy::upper_case_acronyms)]
pub enum Bodies {
SSB,
Sun,
MercuryBarycenter,
Mercury,
VenusBarycenter,
Venus,
EarthBarycenter,
Earth,
Luna,
MarsBarycenter,
JupiterBarycenter,
SaturnBarycenter,
UranusBarycenter,
NeptuneBarycenter,
PlutoBarycenter,
}
impl Bodies {
pub fn ephem_path(&self) -> &'static [usize] {
match *self {
Self::SSB => &[],
Self::Sun => &[0],
Self::MercuryBarycenter => &[1],
Self::Mercury => &[1],
Self::VenusBarycenter => &[2],
Self::Venus => &[2],
Self::EarthBarycenter => &[3],
Self::Earth => &[3, 0],
Self::Luna => &[3, 1],
Self::MarsBarycenter => &[4],
Self::JupiterBarycenter => &[5],
Self::SaturnBarycenter => &[6],
Self::UranusBarycenter => &[7],
Self::NeptuneBarycenter => &[8],
Self::PlutoBarycenter => &[9],
}
}
pub fn name(&self) -> String {
match *self {
Self::SSB => "Solar System Barycenter".to_string(),
Self::Sun => "Sun".to_string(),
Self::MercuryBarycenter => "Mercury".to_string(),
Self::Mercury => "Mercury".to_string(),
Self::VenusBarycenter => "Venus".to_string(),
Self::Venus => "Venus".to_string(),
Self::EarthBarycenter => "Earth Moon Barycenter".to_string(),
Self::Earth => "Earth".to_string(),
Self::Luna => "Moon".to_string(),
Self::MarsBarycenter => "Mars".to_string(),
Self::JupiterBarycenter => "Jupiter Barycenter".to_string(),
Self::SaturnBarycenter => "Saturn Barycenter".to_string(),
Self::UranusBarycenter => "Uranus Barycenter".to_string(),
Self::NeptuneBarycenter => "Neptune Barycenter".to_string(),
Self::PlutoBarycenter => "Pluto Barycenter".to_string(),
}
}
}
impl TryFrom<String> for Bodies {
type Error = NyxError;
fn try_from(name: String) -> Result<Self, Self::Error> {
match name.to_lowercase().as_str() {
"solar system barycenter" | "ssb" => Ok(Self::SSB),
"sun" => Ok(Self::Sun),
"mercury" => Ok(Self::Mercury),
"venus" => Ok(Self::Venus),
"earth moon barycenter" => Ok(Self::EarthBarycenter),
"earth" => Ok(Self::Earth),
"moon" | "luna" => Ok(Self::Luna),
"mars" | "mars barycenter" => Ok(Self::MarsBarycenter),
"jupiter" | "jupiter barycenter" => Ok(Self::JupiterBarycenter),
"saturn" | "saturn barycenter" => Ok(Self::SaturnBarycenter),
"uranus" | "uranus barycenter" => Ok(Self::UranusBarycenter),
"neptune" | "neptune barycenter" => Ok(Self::NeptuneBarycenter),
"pluto" | "pluto barycenter" => Ok(Self::PlutoBarycenter),
_ => Err(NyxError::ObjectNotFound(name)),
}
}
}
impl TryFrom<Vec<usize>> for Bodies {
type Error = NyxError;
fn try_from(ephem_path: Vec<usize>) -> Result<Self, Self::Error> {
match ephem_path.len() {
0 => Ok(Self::SSB),
1 => match ephem_path[0] {
0 => Ok(Self::Sun),
1 => Ok(Self::Mercury),
2 => Ok(Self::Venus),
3 => Ok(Self::EarthBarycenter),
4 => Ok(Self::MarsBarycenter),
5 => Ok(Self::JupiterBarycenter),
6 => Ok(Self::SaturnBarycenter),
7 => Ok(Self::UranusBarycenter),
8 => Ok(Self::NeptuneBarycenter),
9 => Ok(Self::PlutoBarycenter),
_ => Err(NyxError::ObjectNotFound(format!("{:?}", ephem_path))),
},
2 if ephem_path[0] == 3 => match ephem_path[1] {
0 => Ok(Self::Earth),
1 => Ok(Self::Luna),
_ => Err(NyxError::ObjectNotFound(format!("{:?}", ephem_path))),
},
_ => Err(NyxError::ObjectNotFound(format!("{:?}", ephem_path))),
}
}
}
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;