Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Show Examples in a GUI #264

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/visualize-trajectory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.vscode
.DS_Store
target/
16 changes: 16 additions & 0 deletions examples/visualize-trajectory/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "visualize-trajectory"
version = "0.1.0"
edition = "2021"
authors = ["Philip Linden <[email protected]>"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
eframe = "0.24.1"
egui = "0.24.1"
egui_plot = "0.24.1"
log = "0.4.20"
nyx-space = "1.1.2"
pretty_env_logger = "0.5.0"
serde = { version = "1.0.193", features = ["derive"] }
Binary file added examples/visualize-trajectory/assets/JGM3.cof.gz
Binary file not shown.
38 changes: 38 additions & 0 deletions examples/visualize-trajectory/src/gui/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// This module defines the top-level UI app that will be called at main.rs
use eframe::{App, CreationContext};

use crate::gui::controls::ScenarioPicker;

use super::View;

pub struct NyxGui {
scenario_picker: ScenarioPicker,
}

impl Default for NyxGui {
fn default() -> Self {
Self {
// specify defaults here
scenario_picker: ScenarioPicker::default(),
}
}
}

impl NyxGui {
pub fn new(cc: &CreationContext<'_>) -> Self {
// This is also where you can customize the look and feel of egui using
// `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.

Default::default()
}
}

impl App for NyxGui {
/// By default the app is Reactive: egui is only updated if are input events
/// (like mouse movements) or there are some animations in the GUI.
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
self.scenario_picker.ui(ui);
});
}
}
35 changes: 35 additions & 0 deletions examples/visualize-trajectory/src/gui/controls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::scenario::Scenarios;
pub struct ScenarioPicker {
scenario: Scenarios,
}

impl Default for ScenarioPicker {
fn default() -> Self {
Self {
scenario: Scenarios::LunarTransfer,
}
}
}

impl super::View for ScenarioPicker {
fn ui(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
// change the scenario enum from a dropdown
egui::ComboBox::from_label("Scenario")
.selected_text(self.scenario.to_string())
.show_ui(ui, |ui| {
for scen in &[
Scenarios::LunarTransfer,
Scenarios::OrbitDesign,
] {
ui.selectable_value(&mut self.scenario, *scen, scen.to_string());
}
});

// run the scenario when button is clicked
if ui.button("run").clicked() {
self.scenario.run()
};
});
}
}
9 changes: 9 additions & 0 deletions examples/visualize-trajectory/src/gui/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use egui;
mod app;
mod controls;

pub use app::NyxGui;

pub trait View {
fn ui(&mut self, ui: &mut egui::Ui);
}
24 changes: 24 additions & 0 deletions examples/visualize-trajectory/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use eframe;
use pretty_env_logger;

mod gui;
mod scenario;

use gui::NyxGui;

fn main() -> eframe::Result<()> {
pretty_env_logger::init(); // log events to stdout (export RUST_LOG=info)

// set default options for the UI window when it spawns
let native_options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default(),
..Default::default()
};

// run the app
eframe::run_native(
"Nyx Space",
native_options,
Box::new(|cc| Box::new(NyxGui::new(cc))),
)
}
1 change: 1 addition & 0 deletions examples/visualize-trajectory/src/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod scenario;
142 changes: 142 additions & 0 deletions examples/visualize-trajectory/src/scenario.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use std::fmt;

use log::info;
use nyx_space::{
cosmic::{Bodies, Cosm},
dynamics::{Drag, Harmonics, OrbitalDynamics, PointMasses, SolarPressure, SpacecraftDynamics},
io::gravity::HarmonicsMem,
md::Event,
od::ui::GroundStation,
propagators::Propagator,
time::{Epoch, Unit},
Orbit, Spacecraft,
};

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Scenarios {
LunarTransfer,
OrbitDesign,
}

impl fmt::Display for Scenarios {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
Scenarios::LunarTransfer => write!(f, "Lunar Transfer"),
Scenarios::OrbitDesign => write!(f, "Orbit Design"),
}
}
}

impl Scenarios {
pub fn run(&self) {

info!("running scenario: {:?}", self.to_string());
match self {
Scenarios::LunarTransfer => lunar_transfer(),
Scenarios::OrbitDesign => orbit_design(),
}
info!("done.")
}
}

fn lunar_transfer() {
// Initialize the cosm which stores the ephemeris
let cosm = Cosm::de438();
// Grab the frames we'll use
let eme2k = cosm.frame("EME2000");
let iau_earth = cosm.frame("IAU Earth");
// Define the epoch
let epoch = Epoch::from_gregorian_utc(2014, 7, 22, 11, 29, 10, 811_000);
// Define the initial orbit
let orbit = Orbit::cartesian(
-137380.1984338506,
75679.87867537055,
21487.63875187856,
-0.2324532014235503,
-0.4462753967758019,
0.08561205662877103,
epoch,
eme2k,
);

// Define the spacecraft
let sat = Spacecraft::new(orbit, 1000.0, 0.0, 1.0, 15.0, 1.7, 2.2);

info!("loading assets");
// Set up the harmonics first because we need to pass them to the overarching orbital dynamics
// Load the harmonics from the JGM3 file (GMAT uses the JGM2 in this case).
// It's gunzipped (hence `true` as the last parameter)
let stor = match HarmonicsMem::from_cof("assets/JGM3.cof.gz", 20, 20, true) {
Ok(stor) => stor,
Err(error) => panic!("Problem reading harmonics file: {:?}", error),
};
// Set up the orbital dynamics: we need to specify the models one by one here
// because the usual functions wrap the dynamics so that they can be used in a Monte Carlo
// setup.
let orbital_dyn = OrbitalDynamics::new(vec![
// Note that we are only accounting for Sun, Moon and Jupiter, in addition to the integration frame's GM
PointMasses::new(
&[Bodies::Sun, Bodies::Luna, Bodies::JupiterBarycenter],
cosm.clone(),
),
// Specify that these harmonics are valid only in the IAU Earth frame. We're using the
Harmonics::from_stor(iau_earth, stor, cosm.clone()),
]);

// Set up SRP and Drag second, because we need to pass them to the overarching spacecraft dynamics
let srp = SolarPressure::default(eme2k, cosm.clone());
let drag = Drag::std_atm1976(cosm.clone());
// Set up the spacecraft dynamics
let sc_dyn = SpacecraftDynamics::from_models(orbital_dyn, vec![srp, drag]);

// Propagate until periapse
let prop = Propagator::default(sc_dyn);

info!("propagating");
let (out, traj) = prop
.with(sat)
.until_event(30. * Unit::Day, &Event::periapsis())
.unwrap();
}

fn orbit_design() {
// Load the NASA NAIF DE438 planetary ephemeris.
let cosm = Cosm::de438();
// Grab the Earth Mean Equator J2000 frame
let eme2k = cosm.frame("EME2000");
// Set the initial start time of the scenario
let epoch = Epoch::from_gregorian_tai_at_noon(2021, 2, 25);
// Nearly circular orbit (ecc of 0.01), inclination of 49 degrees and TA at 30.0
let orbit = Orbit::keplerian_altitude(500.0, 0.01, 49.0, 0.0, 0.0, 30.0, epoch, eme2k);

// Define the landmark by specifying a name, a latitude, a longitude,
// an altitude (in km) and a frame. Note that we're also "cloning"
// the Cosm: don't worry, it's a shared object, so we're just cloning the
// the reference to it in memory, and never loading it more than once.
let landmark = GroundStation::from_point(
"Eiffel Tower".to_string(),
36.0544,
112.1402,
0.0,
cosm.frame("IAU Earth"),
cosm.clone(),
);

// Let's print this landmark to make sure we've created it correctly.
info!("target: {:}", landmark);

// Let's specify the force model to be two body dynamics
// And use the default propagator setup: a variable step Runge-Kutta 8-9
let setup = Propagator::default(OrbitalDynamics::two_body());

// Use the setup to seed a propagator with the initial state we defined above.
let mut prop = setup.with(orbit);
// Now let's propagate and generate the trajectory so we can analyse it.
let (final_state, traj) = match prop.for_duration_with_traj(1 * Unit::Day) {
Ok(state) => state,
Err(error) => panic!("Error during propagation: {:?}", error)
};

// Printing the state with `:o` will print its Keplerian elements
info!("{:?}", final_state);
}
Loading