diff --git a/anise-gui/icon-128.png b/anise-gui/icon-128.png deleted file mode 100644 index 0bee42f2..00000000 Binary files a/anise-gui/icon-128.png and /dev/null differ diff --git a/anise-gui/icon-256.png b/anise-gui/icon-256.png new file mode 100644 index 00000000..6e294cd1 Binary files /dev/null and b/anise-gui/icon-256.png differ diff --git a/anise-gui/src/epa.rs b/anise-gui/src/epa.rs new file mode 100644 index 00000000..3f71fc4d --- /dev/null +++ b/anise-gui/src/epa.rs @@ -0,0 +1,100 @@ +use anise::prelude::Almanac; +use egui_extras::{Column, TableBuilder}; + +pub fn epa_ui(ui: &mut egui::Ui, almanac: &Almanac) { + TableBuilder::new(ui) + .column(Column::auto().at_least(100.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::remainder()) + .header(20.0, |mut header| { + header.col(|ui| { + ui.heading("Name"); + }); + header.col(|ui| { + ui.heading("ID"); + }); + header.col(|ui| { + ui.heading("Quat w"); + }); + + header.col(|ui| { + ui.heading("Quat x"); + }); + header.col(|ui| { + ui.heading("Quat y"); + }); + header.col(|ui| { + ui.heading("Quat z"); + }); + + header.col(|ui| { + ui.heading("From ID"); + }); + header.col(|ui| { + ui.heading("To ID"); + }); + }) + .body(|mut body| { + let epa = &almanac.euler_param_data; + + let binding = epa.lut.entries(); + let mut values = binding.values().collect::>().to_vec(); + values.sort_by_key(|(opt_id, _)| match opt_id { + Some(id) => *id, + None => 0, + }); + + for (opt_id, opt_name) in values { + let data = if let Some(id) = opt_id { + epa.get_by_id(*id).unwrap() + } else { + epa.get_by_name(&opt_name.clone().unwrap()).unwrap() + }; + + body.row(30.0, |mut row| { + row.col(|ui| { + ui.label(match opt_name { + Some(name) => format!("{name}"), + None => "Unset".to_string(), + }); + }); + + row.col(|ui| { + ui.label(match opt_id { + Some(id) => format!("{id}"), + None => "Unset".to_string(), + }); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.w)); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.x)); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.y)); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.z)); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.from)); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.to)); + }); + }) + } + }); +} diff --git a/anise-gui/src/main.rs b/anise-gui/src/main.rs index 8fdeb06f..0f0b852c 100644 --- a/anise-gui/src/main.rs +++ b/anise-gui/src/main.rs @@ -6,6 +6,8 @@ mod ui; use ui::UiApp; mod bpc; +mod epa; +mod pca; mod spk; #[cfg(not(target_arch = "wasm32"))] @@ -25,7 +27,7 @@ fn main() { viewport: egui::ViewportBuilder::default() .with_inner_size([1024.0, 640.0]) .with_icon( - eframe::icon_data::from_png_bytes(&include_bytes!("../icon-128.png")[..]).unwrap(), + eframe::icon_data::from_png_bytes(&include_bytes!("../icon-256.png")[..]).unwrap(), ), ..Default::default() }; diff --git a/anise-gui/src/pca.rs b/anise-gui/src/pca.rs new file mode 100644 index 00000000..9a9e1869 --- /dev/null +++ b/anise-gui/src/pca.rs @@ -0,0 +1,143 @@ +use anise::prelude::Almanac; +use egui_extras::{Column, TableBuilder}; + +pub fn pca_ui(ui: &mut egui::Ui, almanac: &Almanac) { + TableBuilder::new(ui) + .column(Column::auto().at_least(100.0).resizable(true)) + .column(Column::auto().at_least(50.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(75.0).resizable(true)) + .column(Column::auto().at_least(125.0).resizable(true)) + .column(Column::auto().at_least(125.0).resizable(true)) + .column(Column::auto().at_least(125.0).resizable(true)) + .column(Column::remainder()) + .header(20.0, |mut header| { + header.col(|ui| { + ui.heading("Name"); + }); + header.col(|ui| { + ui.heading("ID"); + }); + header.col(|ui| { + ui.heading("Gravity param (km^3/s^2)"); + }); + + header.col(|ui| { + ui.heading("Major axis (km)"); + }); + header.col(|ui| { + ui.heading("Minor axis (km)"); + }); + header.col(|ui| { + ui.heading("Polar axis (km)"); + }); + + header.col(|ui| { + ui.heading("Pole right asc."); + }); + header.col(|ui| { + ui.heading("Pole declination"); + }); + header.col(|ui| { + ui.heading("Prime meridian"); + }); + }) + .body(|mut body| { + let pck = &almanac.planetary_data; + + let binding = pck.lut.entries(); + let mut values = binding.values().collect::>().to_vec(); + values.sort_by_key(|(opt_id, _)| match opt_id { + Some(id) => *id, + None => 0, + }); + + for (opt_id, opt_name) in values { + let data = if let Some(id) = opt_id { + pck.get_by_id(*id).unwrap() + } else { + pck.get_by_name(&opt_name.clone().unwrap()).unwrap() + }; + + body.row(30.0, |mut row| { + row.col(|ui| { + ui.label(match opt_name { + Some(name) => format!("{name}"), + None => "Unset".to_string(), + }); + }); + + row.col(|ui| { + ui.label(match opt_id { + Some(id) => format!("{id}"), + None => "Unset".to_string(), + }); + }); + + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", data.mu_km3_s2)); + }); + + match data.shape { + None => { + // Three empty columns + row.col(|ui| { + ui.label("Unset"); + }); + row.col(|ui| { + ui.label("Unset"); + }); + row.col(|ui| { + ui.label("Unset"); + }); + } + Some(shape) => { + row.col(|ui| { + ui.text_edit_singleline(&mut format!( + "{}", + shape.semi_major_equatorial_radius_km + )); + }); + row.col(|ui| { + ui.text_edit_singleline(&mut format!( + "{}", + shape.semi_minor_equatorial_radius_km + )); + }); + row.col(|ui| { + ui.text_edit_singleline(&mut format!("{}", shape.polar_radius_km)); + }); + } + } + + match data.pole_right_ascension { + None => row.col(|ui| { + ui.label("Unset"); + }), + Some(pole_ra) => row.col(|ui| { + ui.label(format!("{pole_ra}")); + }), + }; + + match data.pole_declination { + None => row.col(|ui| { + ui.label("Unset"); + }), + Some(pole_dec) => row.col(|ui| { + ui.label(format!("{pole_dec}")); + }), + }; + + match data.prime_meridian { + None => row.col(|ui| { + ui.label("Unset"); + }), + Some(pm) => row.col(|ui| { + ui.label(format!("{pm}")); + }), + }; + }); + } + }); +} diff --git a/anise-gui/src/ui.rs b/anise-gui/src/ui.rs index 71c95645..b8b9d945 100644 --- a/anise-gui/src/ui.rs +++ b/anise-gui/src/ui.rs @@ -1,14 +1,13 @@ use anise::{almanac::Almanac, errors::AlmanacError}; use eframe::egui; use egui::Theme; -use egui_extras::{Column, TableBuilder}; use hifitime::TimeScale; use log::error; #[cfg(target_arch = "wasm32")] use poll_promise::Promise; -use crate::{bpc::bpc_ui, spk::spk_ui}; +use crate::{bpc::bpc_ui, epa::epa_ui, pca::pca_ui, spk::spk_ui}; #[cfg(target_arch = "wasm32")] type AlmanacFile = Option<(String, Vec)>; @@ -128,7 +127,8 @@ impl eframe::App for UiApp { match &self.path { None => { let mut trigger_file_load = false; - trigger_file_load |= ui.button("Select file to inspect...").clicked(); + trigger_file_load |= + ui.button("Select file to inspect...").clicked(); // If we are in the browser, we need to also check if the file // is ready to be loaded instead of just checking if the button @@ -140,18 +140,17 @@ impl eframe::App for UiApp { // Show the open file dialog if trigger_file_load { - // Try to load this file - match self.load_almanac() { - FileLoadResult::NoFileSelectedYet => { - } - FileLoadResult::Ok((path, almanac)) => { - self.almanac = almanac; - self.path = Some(path); - } - FileLoadResult::Error(e) => { - error!("{e}"); - } + // Try to load this file + match self.load_almanac() { + FileLoadResult::NoFileSelectedYet => {} + FileLoadResult::Ok((path, almanac)) => { + self.almanac = almanac; + self.path = Some(path); } + FileLoadResult::Error(e) => { + error!("{e}"); + } + } } } Some(path) => { @@ -178,7 +177,7 @@ impl eframe::App for UiApp { let mut unload_file = false; ui.vertical(|ui| { - ui.horizontal(|ui|{ + ui.horizontal(|ui| { ui.label(format!("Inspecting {path}")); if ui.button("Close").clicked() { unload_file = true; @@ -192,11 +191,21 @@ impl eframe::App for UiApp { ui.text_edit_singleline(&mut format!("{crc}")); if label.ends_with("SPK") { - let num_summaries = self.almanac.spk_data[0].as_ref().unwrap().daf_summary().unwrap().num_summaries(); + let num_summaries = self.almanac.spk_data[0] + .as_ref() + .unwrap() + .daf_summary() + .unwrap() + .num_summaries(); ui.label("Number of summaries"); ui.label(format!("{num_summaries}")); } else if label.ends_with("PCK") { - let num_summaries = self.almanac.bpc_data[0].as_ref().unwrap().daf_summary().unwrap().num_summaries(); + let num_summaries = self.almanac.bpc_data[0] + .as_ref() + .unwrap() + .daf_summary() + .unwrap() + .num_summaries(); ui.label("Number of summaries"); ui.label(format!("{num_summaries}")); } @@ -226,176 +235,29 @@ impl eframe::App for UiApp { } }); - ui.checkbox( - &mut self.show_unix, - "UNIX timestamps", - ); + ui.checkbox(&mut self.show_unix, "UNIX timestamps"); }); } // Now display the data if label == "DAF/PCK" { - bpc_ui(ui, &self.almanac, self.show_unix, self.selected_time_scale); + bpc_ui( + ui, + &self.almanac, + self.show_unix, + self.selected_time_scale, + ); } else if label == "DAF/SPK" { - spk_ui(ui, &self.almanac, self.show_unix, self.selected_time_scale) + spk_ui( + ui, + &self.almanac, + self.show_unix, + self.selected_time_scale, + ); } else if label == "ANISE/PCA" { - TableBuilder::new(ui) - .column(Column::auto().at_least(100.0).resizable(true)) - .column(Column::auto().at_least(50.0).resizable(true)) - .column(Column::auto().at_least(75.0).resizable(true)) - .column(Column::auto().at_least(75.0).resizable(true)) - .column(Column::auto().at_least(75.0).resizable(true)) - .column(Column::auto().at_least(125.0).resizable(true)) - .column(Column::auto().at_least(125.0).resizable(true)) - .column(Column::auto().at_least(125.0).resizable(true)) - .column(Column::remainder()) - .header(20.0, |mut header| { - header.col(|ui| { - ui.heading("Name"); - }); - header.col(|ui| { - ui.heading("ID"); - }); - header.col(|ui| { - ui.heading("Gravity param (km^3/s^2)"); - }); - - header.col(|ui| { - ui.heading("Major axis (km)"); - }); - header.col(|ui| { - ui.heading("Minor axis (km)"); - }); - header.col(|ui| { - ui.heading("Polar axis (km)"); - }); - - header.col(|ui| { - ui.heading("Pole right asc."); - }); - header.col(|ui| { - ui.heading("Pole declination"); - }); - header.col(|ui| { - ui.heading("Prime meridian"); - }); - }) - .body(|mut body| { - let pck = &self.almanac.planetary_data; - - let binding = pck.lut.entries(); - let mut values = binding.values().collect::>().to_vec(); - values.sort_by_key(|(opt_id, _)| match opt_id { - Some(id) => *id, - None => 0 - }); - - for (opt_id, opt_name) in values - { - let data = if let Some(id) = opt_id { - pck.get_by_id(*id).unwrap() - } else { - pck.get_by_name(&opt_name.clone().unwrap()).unwrap() - }; - - body.row(30.0, |mut row| { - row.col(|ui| { - ui.label(match opt_name { - Some(name) => format!("{name}"), - None => "Unset".to_string(), - }); - }); - - row.col(|ui| { - ui.label(match opt_id { - Some(id) => format!("{id}"), - None => "Unset".to_string(), - }); - }); - - row.col(|ui| { - ui.text_edit_singleline(&mut format!( - "{}", - data.mu_km3_s2 - )); - }); - - match data.shape { - None => { - // Three empty columns - row.col(|ui| { - ui.label("Unset"); - }); - row.col(|ui| { - ui.label("Unset"); - }); - row.col(|ui| { - ui.label("Unset"); - }); - } - Some(shape) => { - row.col(|ui| { - ui.text_edit_singleline( - &mut format!( - "{}", - shape.semi_major_equatorial_radius_km - ), - ); - }); - row.col(|ui| { - ui.text_edit_singleline( - &mut format!( - "{}", - shape.semi_minor_equatorial_radius_km - ), - ); - }); - row.col(|ui| { - ui.text_edit_singleline( - &mut format!( - "{}", - shape.polar_radius_km - ), - ); - }); - } - } - - match data.pole_right_ascension { - None => row.col(|ui| { - ui.label("Unset"); - }), - Some(pole_ra) => { - row.col(|ui| { - ui.label(format!("{pole_ra}")); - }) - } - }; - - match data.pole_declination { - None => row.col(|ui| { - ui.label("Unset"); - }), - Some(pole_dec) => { - row.col(|ui| { - ui.label(format!("{pole_dec}")); - }) - } - }; - - match data.prime_meridian { - None => row.col(|ui| { - ui.label("Unset"); - }), - Some(pm) => { - row.col(|ui| { - ui.label(format!("{pm}")); - }) - } - }; - }); - } - }); + pca_ui(ui, &self.almanac); + } else if label == "ANISE/EPA" { + epa_ui(ui, &self.almanac); } }); diff --git a/anise/src/almanac/metaload/mod.rs b/anise/src/almanac/metaload/mod.rs index d3e583a5..720485ec 100644 --- a/anise/src/almanac/metaload/mod.rs +++ b/anise/src/almanac/metaload/mod.rs @@ -107,7 +107,7 @@ mod meta_test { let almanac = meta._process(true).unwrap(); // Shows everything in this Almanac - almanac.describe(None, None, None, None, None); + almanac.describe(None, None, None, None, None, None); // Process again to confirm that the CRC check works assert!(meta._process(true).is_ok()); diff --git a/anise/src/almanac/mod.rs b/anise/src/almanac/mod.rs index 7bf65d5d..227d7d4a 100644 --- a/anise/src/almanac/mod.rs +++ b/anise/src/almanac/mod.rs @@ -252,6 +252,7 @@ impl Almanac { spk: Option, bpc: Option, planetary: Option, + eulerparams: Option, time_scale: Option, round_time: Option, ) { @@ -292,5 +293,12 @@ impl Almanac { if planetary.unwrap_or(!print_any) { println!("=== PLANETARY DATA ==\n{}", self.planetary_data.describe()); } + + if eulerparams.unwrap_or(!print_any) { + println!( + "=== EULER PARAMETER DATA ==\n{}", + self.euler_param_data.describe() + ); + } } } diff --git a/anise/src/structure/dataset/mod.rs b/anise/src/structure/dataset/mod.rs index a5aa7758..793dc795 100644 --- a/anise/src/structure/dataset/mod.rs +++ b/anise/src/structure/dataset/mod.rs @@ -41,6 +41,7 @@ io_imports!(); mod datatype; mod error; +mod pretty_print; pub use datatype::DataSetType; pub use error::DataSetError; diff --git a/anise/src/structure/dataset/pretty_print.rs b/anise/src/structure/dataset/pretty_print.rs new file mode 100644 index 00000000..340dfde7 --- /dev/null +++ b/anise/src/structure/dataset/pretty_print.rs @@ -0,0 +1,70 @@ +use tabled::{settings::Style, Table, Tabled}; + +use crate::structure::EulerParameterDataSet; + +use super::NaifId; + +#[derive(Tabled, Default)] +struct EulerParamRow { + #[tabled(rename = "Name")] + name: String, + #[tabled(rename = "ID")] + id: String, + #[tabled(rename = "Quat w")] + qw: f64, + #[tabled(rename = "Quat x")] + qx: f64, + #[tabled(rename = "Quat y")] + qy: f64, + #[tabled(rename = "Quat z")] + qz: f64, + #[tabled(rename = "To ID")] + to: NaifId, + #[tabled(rename = "From ID")] + from: NaifId, +} + +impl EulerParameterDataSet { + /// Returns a table describing this planetary data set + pub fn describe(&self) -> String { + let binding = self.lut.entries(); + let mut values = binding.values().collect::>().to_vec(); + values.sort_by_key(|(opt_id, _)| match opt_id { + Some(id) => *id, + None => 0, + }); + + let mut rows = Vec::new(); + + for (opt_id, opt_name) in values { + let data = if let Some(id) = opt_id { + self.get_by_id(*id).unwrap() + } else { + self.get_by_name(&opt_name.clone().unwrap()).unwrap() + }; + + let row = EulerParamRow { + name: match opt_name { + Some(name) => format!("{name}"), + None => "Unset".to_string(), + }, + id: match opt_id { + Some(id) => format!("{id}"), + None => "Unset".to_string(), + }, + qw: data.w, + qx: data.x, + qy: data.y, + qz: data.z, + to: data.to, + from: data.from, + }; + + rows.push(row); + } + + let mut tbl = Table::new(rows); + tbl.with(Style::modern()); + format!("{tbl}") + } +}