Skip to content

Commit

Permalink
add integrator options, add verlet integration, load spice files in p…
Browse files Browse the repository at this point in the history
…arallel
  • Loading branch information
jan-tennert committed Oct 12, 2024
1 parent 6592244 commit e4bf557
Show file tree
Hide file tree
Showing 23 changed files with 554 additions and 333 deletions.
2 changes: 1 addition & 1 deletion scenarios/solar_system.sim

Large diffs are not rendered by default.

103 changes: 59 additions & 44 deletions src/simulation/components/anise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@ use crate::simulation::ui::toast::{error_toast, success_toast, ToastContainer};
use crate::simulation::{SimState, SimStateType};
use anise::constants::frames::SSB_J2000;
use anise::constants::orientations::J2000;
use anise::errors::AlmanacError;
use anise::math::Vector3;
use anise::prelude::{Almanac, Epoch, Frame};
use anise::naif::daf::DAF;
use anise::naif::spk::summary::SPKSummaryRecord;
use anise::prelude::{Almanac, Epoch, Frame, SPK};
use anise::structure::PlanetaryDataSet;
use bevy::app::Plugin;
use bevy::math::DVec3;
use bevy::prelude::{in_state, IntoSystemConfigs, Local, Name, Query, Res, ResMut, Resource, Update};
use bevy_async_task::{AsyncTaskRunner, AsyncTaskStatus};
use bevy::prelude::{in_state, IntoSystemConfigs, Name, Query, Res, ResMut, Resource, Update};
use bevy_async_task::{AsyncTaskPool, AsyncTaskStatus};
use std::fs;

enum AlmanacType {
SPK(DAF<SPKSummaryRecord>),
PCA(PlanetaryDataSet)
}

struct Error(String);

pub struct AnisePlugin;

Expand Down Expand Up @@ -97,52 +107,68 @@ fn spk_file_loading(
mut toasts: ResMut<ToastContainer>,
mut scenario_data: ResMut<ScenarioData>,
mut loading_state: ResMut<LoadingState>,
mut task_executor: AsyncTaskRunner<Result<Almanac, AlmanacError>>,
mut to_load: Local<Option<Vec<String>>>,
mut task_pool: AsyncTaskPool<Result<AlmanacType, Error>>,
sim_type: Res<SimStateType>
) {
if loading_state.loaded_spice_files || !loading_state.spawned_bodies {
return;
}
if *sim_type != SimStateType::Editor {
if *sim_type != SimStateType::Editor || scenario_data.spice_files.is_empty() || (loading_state.spice_loaded > 0 && loading_state.spice_loaded == loading_state.spice_total) {
loading_state.loaded_spice_files = true;
return;
}
if to_load.is_none() {
*to_load = Some(scenario_data.spice_files.clone());
loading_state.spice_total = to_load.as_ref().unwrap().len() as i32;
}
let to_load_v = to_load.as_mut().unwrap();
match task_executor.poll() {
AsyncTaskStatus::Idle => {
if !to_load_v.is_empty() {
println!("Loading SPICE file: {}", to_load_v.last().unwrap());
let path = to_load_v.pop().unwrap();
task_executor.start(load_spice_file(path, almanac.0.clone()));
if task_pool.is_idle() && loading_state.spice_total == 0 {
loading_state.spice_total = scenario_data.spice_files.iter().count() as i32;
for path in &scenario_data.spice_files {
if path.ends_with(".bsp") {
task_pool.spawn(load_spk(path.clone()));
} else if path.ends_with(".pca") {
task_pool.spawn(load_pca(path.clone()));
} else {
loading_state.loaded_spice_files = true;
*to_load = None;
toasts.0.add(error_toast(format!("Unsupported SPICE file type: {}", path).as_str()));
}
}
AsyncTaskStatus::Pending => {
// <Insert loading screen>
}
AsyncTaskStatus::Finished(r) => {
if let Ok(v) = r {
almanac.0 = v;
} else if let Err(e) = r {
toasts.0.add(error_toast(format!("Couldn't load SPICE file: {}", e).as_str()));
}
for status in task_pool.iter_poll() {
if let AsyncTaskStatus::Finished(t) = status {
match t {
Ok(AlmanacType::SPK(daf)) => {
let spk = almanac.0.with_spk(daf);
if let Ok(s) = spk {
almanac.0 = s;
loading_state.spice_loaded += 1;
} else if let Err(e) = spk {
toasts.0.add(error_toast(format!("Couldn't load SPICE file: {:?}", e).as_str()));
}
}
Ok(AlmanacType::PCA(set)) => {
almanac.0 = almanac.0.with_planetary_data(set);
loading_state.spice_loaded += 1;
}
Err(e) => {
toasts.0.add(error_toast(format!("Couldn't load SPICE file: {:?}", e.0).as_str()));
}
}
loading_state.spice_loaded += 1;
}
}
}

async fn load_spice_file(
async fn load_spk(
path: String,
almanac: Almanac
) -> Result<Almanac, AlmanacError> {
almanac.load(format!("data/{}", path).as_str())
) -> Result<AlmanacType, Error> {
let spk = SPK::load(format!("data/{}", path).as_str()).map_err(|e| Error(format!("{:?}", e)))?;
Ok(AlmanacType::SPK(spk))
}

async fn load_pca(
path: String
) -> Result<AlmanacType, Error> {
let path = format!("data/{}", path);
let data = fs::read(path).map_err(|e| Error(format!("{:?}", e)))?;
let bytes: &[u8] = data.as_slice();
let set = PlanetaryDataSet::from_bytes(bytes);
Ok(AlmanacType::PCA(set))
}

pub fn load_spice_files(
Expand All @@ -161,15 +187,4 @@ pub fn load_spice_files(
if !missing_paths.is_empty() {
toasts.0.add(error_toast(format!("Couldn't load the following SPICE files: {}", missing_paths.join(", ")).as_str()));
}
}

/*fn get_target_frames(
almanac: &Almanac
) -> Vec<Frame> {
let mut frames = almanac.spk_data.iter().filter(|s| s.is_some()).map(|s| s.as_ref().unwrap()).map(|s| {
s.data_summaries().unwrap().iter().map(|d| d.target_frame())
}).flatten().collect::<Vec<Frame>>();
frames.dedup_by_key(|f| f.ephemeris_id);
println!("{:?}", frames);
Vec::new()
}*/
}
18 changes: 9 additions & 9 deletions src/simulation/components/apsis.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::simulation::components::body::{BodyChildren, BodyParent, Moon, Planet, SimPosition, Star, Velocity};
use crate::simulation::components::horizons::AniseMetadata;
use crate::simulation::components::physics::apply_physics;
use crate::simulation::integration::{paused, SimulationStep};
use crate::simulation::scenario::setup::ScenarioData;
use crate::simulation::ui::SimTime;
use crate::simulation::SimState;
use crate::utils::sim_state_type_simulation;
use bevy::prelude::{Transform, Vec3};
use bevy::prelude::{not, Transform, Vec3};
use bevy::{math::DVec3, prelude::{in_state, App, Component, Entity, IntoSystemConfigs, Plugin, Query, Reflect, Res, Update, With, Without}};
use std::collections::HashMap;

Expand All @@ -16,7 +16,7 @@ impl Plugin for ApsisPlugin {
fn build(&self, app: &mut App) {
app
.register_type::<Apsis>()
.add_systems(Update, (update_apsis.after(apply_physics)).run_if(sim_state_type_simulation));
.add_systems(Update, (update_apsis.after(SimulationStep)).run_if(sim_state_type_simulation).run_if(not(paused)));
}

}
Expand Down Expand Up @@ -57,15 +57,15 @@ fn update_apsis(
}
}
if let Some(p_pos) = parent {
let new_distance = p_pos.0.distance(position.0) as f32;
let new_distance = p_pos.current.distance(position.current) as f32;
//perihelion
if apsis.perihelion.distance > new_distance || apsis.perihelion.distance == 0.0 {
apsis.perihelion.distance = new_distance;
apsis.perihelion.position = position.0;
apsis.perihelion.position = position.current;
}
if apsis.aphelion.distance < new_distance || apsis.perihelion.distance == 0.0 {
apsis.aphelion.distance = new_distance;
apsis.aphelion.position = position.0;
apsis.aphelion.position = position.current;
}
}
}
Expand All @@ -78,15 +78,15 @@ fn update_apsis(
}
}
if let Some(p_pos) = parent {
let new_distance = p_pos.0.distance(position.0) as f32;
let new_distance = p_pos.current.distance(position.current) as f32;
//perihelion
if apsis.perihelion.distance > new_distance || apsis.perihelion.distance == 0.0 {
apsis.perihelion.distance = new_distance;
apsis.perihelion.position = position.0;
apsis.perihelion.position = position.current;
}
if apsis.aphelion.distance < new_distance || apsis.perihelion.distance == 0.0 {
apsis.aphelion.distance = new_distance;
apsis.aphelion.position = position.0;
apsis.aphelion.position = position.current;
}
}
}
Expand Down
19 changes: 16 additions & 3 deletions src/simulation/components/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,20 @@ impl Default for OrbitSettings {
}

#[derive(Component, Clone, Default)]
pub struct SimPosition(pub DVec3);
pub struct SimPosition {

pub current: DVec3,
pub previous: Option<DVec3>,

}

impl SimPosition {

pub fn new(value: DVec3) -> Self {
SimPosition { current: value, previous: None }
}

}

#[derive(Component, Clone)]
pub struct BodyShape {
Expand Down Expand Up @@ -202,7 +215,7 @@ impl From<SerializedBody> for BodyBundle {
fn from(value: SerializedBody) -> Self {
BodyBundle {
mass: Mass(value.data.mass),
sim_position: SimPosition(DVec3::from(value.data.starting_position) * 1000.0),
sim_position: SimPosition::new(DVec3::from(value.data.starting_position) * 1000.0),
vel: Velocity(DVec3::from(value.data.starting_velocity) * 1000.0),
name: Name::new(value.data.name),
model_path: ModelPath(format!("models/{}#Scene0", value.data.model_path)),
Expand Down Expand Up @@ -232,7 +245,7 @@ impl BodyBundle {
pub fn empty(index: i32) -> Self {
BodyBundle {
mass: Mass(0.0),
sim_position: SimPosition(DVec3::ZERO),
sim_position: SimPosition::new(DVec3::ZERO),
vel: Velocity(DVec3::ZERO),
name: Name::new(format!("New body {}", index)),
model_path: ModelPath("models/earth.glb#Scene0".to_string()),
Expand Down
4 changes: 2 additions & 2 deletions src/simulation/components/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,12 @@ pub fn update_body_positions(
} else {
let (_, position, mut transform) = bodies.get_mut(entity).unwrap();
transform.translation = Vec3::ZERO;
scale.m_to_unit_dvec(position.0).as_vec3()
scale.m_to_unit_dvec(position.current).as_vec3()
}
} else {
Vec3::ZERO
};
for (_, position, mut transform) in bodies.iter_mut() {
transform.translation = scale.m_to_unit_dvec(position.0).as_vec3() - offset;
transform.translation = scale.m_to_unit_dvec(position.current).as_vec3() - offset;
}
}
5 changes: 2 additions & 3 deletions src/simulation/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use crate::simulation::components::direction::DirectionPlugin;
use crate::simulation::components::horizons::HorizonsPlugin;
use crate::simulation::components::lock_on::LockOnPlugin;
use crate::simulation::components::motion_line::MotionLinePlugin;
use crate::simulation::components::physics::PhysicsPlugin;
use crate::simulation::components::reset::ResetPlugin;
use crate::simulation::components::rotation::RotationPlugin;
use crate::simulation::components::scale::ScalePlugin;
use crate::simulation::components::selection::SelectionPlugin;
use crate::simulation::components::shape::DiameterPlugin;
use crate::simulation::components::speed::SpeedPlugin;
use crate::simulation::integration::IntegrationPlugin;
use bevy::app::Plugin;

pub mod apsis;
Expand All @@ -20,7 +20,6 @@ pub mod camera;
pub mod shape;
pub mod direction;
pub mod lock_on;
pub mod physics;
pub mod body;
pub mod motion_line;
pub mod rotation;
Expand All @@ -43,10 +42,10 @@ impl Plugin for SimComponentPlugin {
// .add_plugins(PanOrbitCameraPlugin)
.add_plugins(DiameterPlugin)
.add_plugins(DirectionPlugin)
.add_plugins(IntegrationPlugin)
.add_plugins(LockOnPlugin)
.add_plugins(ScalePlugin)
.add_plugins(MotionLinePlugin)
.add_plugins(PhysicsPlugin)
.add_plugins(ResetPlugin)
.add_plugins(RotationPlugin)
.add_plugins(SelectionPlugin)
Expand Down
15 changes: 8 additions & 7 deletions src/simulation/components/motion_line.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::simulation::components::body::{BillboardVisible, BodyChildren, BodyShape, Moon, OrbitSettings, Planet, SimPosition, Star};
use crate::simulation::components::physics::{apply_physics, Pause, SubSteps};
use crate::simulation::components::scale::SimulationScale;
use crate::simulation::components::speed::Speed;
use crate::simulation::integration::{paused, Pause, SimulationStep, SubSteps};
use crate::utils::sim_state_type_simulation;
use bevy::prelude::not;
use bevy::{prelude::{App, Camera, Entity, Gizmos, IntoSystemConfigs, Plugin, PreUpdate, Query, Res, Resource, Transform, Vec3, With, Without}, time::Time};
use bevy_panorbit_camera::PanOrbitCamera;

Expand All @@ -12,7 +13,7 @@ impl Plugin for MotionLinePlugin {
fn build(&self, app: &mut App) {
app
.init_resource::<OrbitOffset>()
.add_systems(PreUpdate, (update_lines.after(apply_physics), (draw_orbit_line).after(update_lines)).run_if(sim_state_type_simulation));
.add_systems(PreUpdate, (update_lines.after(SimulationStep), (draw_orbit_line).after(update_lines)).run_if(sim_state_type_simulation).run_if(not(paused)));
}
}

Expand Down Expand Up @@ -57,8 +58,8 @@ fn update_lines(
let speed = speed.0 as f32 * (substeps.0 as f32);
let max_step = (orbit.period as f32 / speed) * MULTIPLIER;
if orbit.step >= max_step {
orbit.lines.push_back(scale.m_to_unit_dvec(pos.0).as_vec3());
// insert_at_nearest_distance(&mut orbit.lines, (pos.0 * M_TO_UNIT).as_vec3());
orbit.lines.push_back(scale.m_to_unit_dvec(pos.current).as_vec3());
// insert_at_nearest_distance(&mut orbit.lines, (pos.current * M_TO_UNIT).as_vec3());
orbit.step = 0.0;
} else {
orbit.step += time.delta_seconds() * orbit.orbit_line_multiplier;
Expand All @@ -74,8 +75,8 @@ fn update_lines(
let speed = speed.0 as f32 * (substeps.0 as f32);
let max_step = (orbit.period as f32 / speed) * MULTIPLIER;
if orbit.step >= max_step {
let raw_p_pos = scale.m_to_unit_dvec(p_pos.0).as_vec3();
let raw_pos = scale.m_to_unit_dvec(pos.0).as_vec3();
let raw_p_pos = scale.m_to_unit_dvec(p_pos.current).as_vec3();
let raw_pos = scale.m_to_unit_dvec(pos.current).as_vec3();
orbit.lines.push_back(raw_pos - raw_p_pos);
//insert_at_nearest_distance(&mut orbit.lines, raw_pos - raw_p_pos);
orbit.step = 0.0;
Expand Down Expand Up @@ -104,7 +105,7 @@ fn draw_orbit_line(
if let Some((_, p_pos, _, _)) = planet_query.iter().find(|(_, _, children, _)| {
children.0.contains(&entity)
}) {
let raw_p_pos = scale.m_to_unit_dvec(p_pos.0).as_vec3();
let raw_p_pos = scale.m_to_unit_dvec(p_pos.current).as_vec3();
draw_lines(orbit, offset.value + raw_p_pos, &mut gizmos, transform.translation)
}
}
Expand Down
Loading

0 comments on commit e4bf557

Please sign in to comment.