Skip to content

Commit e4bf557

Browse files
committed
add integrator options, add verlet integration, load spice files in parallel
1 parent 6592244 commit e4bf557

23 files changed

+554
-333
lines changed

scenarios/solar_system.sim

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/simulation/components/anise.rs

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@ use crate::simulation::ui::toast::{error_toast, success_toast, ToastContainer};
77
use crate::simulation::{SimState, SimStateType};
88
use anise::constants::frames::SSB_J2000;
99
use anise::constants::orientations::J2000;
10-
use anise::errors::AlmanacError;
1110
use anise::math::Vector3;
12-
use anise::prelude::{Almanac, Epoch, Frame};
11+
use anise::naif::daf::DAF;
12+
use anise::naif::spk::summary::SPKSummaryRecord;
13+
use anise::prelude::{Almanac, Epoch, Frame, SPK};
14+
use anise::structure::PlanetaryDataSet;
1315
use bevy::app::Plugin;
1416
use bevy::math::DVec3;
15-
use bevy::prelude::{in_state, IntoSystemConfigs, Local, Name, Query, Res, ResMut, Resource, Update};
16-
use bevy_async_task::{AsyncTaskRunner, AsyncTaskStatus};
17+
use bevy::prelude::{in_state, IntoSystemConfigs, Name, Query, Res, ResMut, Resource, Update};
18+
use bevy_async_task::{AsyncTaskPool, AsyncTaskStatus};
19+
use std::fs;
20+
21+
enum AlmanacType {
22+
SPK(DAF<SPKSummaryRecord>),
23+
PCA(PlanetaryDataSet)
24+
}
25+
26+
struct Error(String);
1727

1828
pub struct AnisePlugin;
1929

@@ -97,52 +107,68 @@ fn spk_file_loading(
97107
mut toasts: ResMut<ToastContainer>,
98108
mut scenario_data: ResMut<ScenarioData>,
99109
mut loading_state: ResMut<LoadingState>,
100-
mut task_executor: AsyncTaskRunner<Result<Almanac, AlmanacError>>,
101-
mut to_load: Local<Option<Vec<String>>>,
110+
mut task_pool: AsyncTaskPool<Result<AlmanacType, Error>>,
102111
sim_type: Res<SimStateType>
103112
) {
104113
if loading_state.loaded_spice_files || !loading_state.spawned_bodies {
105114
return;
106115
}
107-
if *sim_type != SimStateType::Editor {
116+
if *sim_type != SimStateType::Editor || scenario_data.spice_files.is_empty() || (loading_state.spice_loaded > 0 && loading_state.spice_loaded == loading_state.spice_total) {
108117
loading_state.loaded_spice_files = true;
109118
return;
110119
}
111-
if to_load.is_none() {
112-
*to_load = Some(scenario_data.spice_files.clone());
113-
loading_state.spice_total = to_load.as_ref().unwrap().len() as i32;
114-
}
115-
let to_load_v = to_load.as_mut().unwrap();
116-
match task_executor.poll() {
117-
AsyncTaskStatus::Idle => {
118-
if !to_load_v.is_empty() {
119-
println!("Loading SPICE file: {}", to_load_v.last().unwrap());
120-
let path = to_load_v.pop().unwrap();
121-
task_executor.start(load_spice_file(path, almanac.0.clone()));
120+
if task_pool.is_idle() && loading_state.spice_total == 0 {
121+
loading_state.spice_total = scenario_data.spice_files.iter().count() as i32;
122+
for path in &scenario_data.spice_files {
123+
if path.ends_with(".bsp") {
124+
task_pool.spawn(load_spk(path.clone()));
125+
} else if path.ends_with(".pca") {
126+
task_pool.spawn(load_pca(path.clone()));
122127
} else {
123-
loading_state.loaded_spice_files = true;
124-
*to_load = None;
128+
toasts.0.add(error_toast(format!("Unsupported SPICE file type: {}", path).as_str()));
125129
}
126130
}
127-
AsyncTaskStatus::Pending => {
128-
// <Insert loading screen>
129-
}
130-
AsyncTaskStatus::Finished(r) => {
131-
if let Ok(v) = r {
132-
almanac.0 = v;
133-
} else if let Err(e) = r {
134-
toasts.0.add(error_toast(format!("Couldn't load SPICE file: {}", e).as_str()));
131+
}
132+
for status in task_pool.iter_poll() {
133+
if let AsyncTaskStatus::Finished(t) = status {
134+
match t {
135+
Ok(AlmanacType::SPK(daf)) => {
136+
let spk = almanac.0.with_spk(daf);
137+
if let Ok(s) = spk {
138+
almanac.0 = s;
139+
loading_state.spice_loaded += 1;
140+
} else if let Err(e) = spk {
141+
toasts.0.add(error_toast(format!("Couldn't load SPICE file: {:?}", e).as_str()));
142+
}
143+
}
144+
Ok(AlmanacType::PCA(set)) => {
145+
almanac.0 = almanac.0.with_planetary_data(set);
146+
loading_state.spice_loaded += 1;
147+
}
148+
Err(e) => {
149+
toasts.0.add(error_toast(format!("Couldn't load SPICE file: {:?}", e.0).as_str()));
150+
}
135151
}
136152
loading_state.spice_loaded += 1;
137153
}
138154
}
139155
}
140156

141-
async fn load_spice_file(
157+
async fn load_spk(
142158
path: String,
143-
almanac: Almanac
144-
) -> Result<Almanac, AlmanacError> {
145-
almanac.load(format!("data/{}", path).as_str())
159+
) -> Result<AlmanacType, Error> {
160+
let spk = SPK::load(format!("data/{}", path).as_str()).map_err(|e| Error(format!("{:?}", e)))?;
161+
Ok(AlmanacType::SPK(spk))
162+
}
163+
164+
async fn load_pca(
165+
path: String
166+
) -> Result<AlmanacType, Error> {
167+
let path = format!("data/{}", path);
168+
let data = fs::read(path).map_err(|e| Error(format!("{:?}", e)))?;
169+
let bytes: &[u8] = data.as_slice();
170+
let set = PlanetaryDataSet::from_bytes(bytes);
171+
Ok(AlmanacType::PCA(set))
146172
}
147173

148174
pub fn load_spice_files(
@@ -161,15 +187,4 @@ pub fn load_spice_files(
161187
if !missing_paths.is_empty() {
162188
toasts.0.add(error_toast(format!("Couldn't load the following SPICE files: {}", missing_paths.join(", ")).as_str()));
163189
}
164-
}
165-
166-
/*fn get_target_frames(
167-
almanac: &Almanac
168-
) -> Vec<Frame> {
169-
let mut frames = almanac.spk_data.iter().filter(|s| s.is_some()).map(|s| s.as_ref().unwrap()).map(|s| {
170-
s.data_summaries().unwrap().iter().map(|d| d.target_frame())
171-
}).flatten().collect::<Vec<Frame>>();
172-
frames.dedup_by_key(|f| f.ephemeris_id);
173-
println!("{:?}", frames);
174-
Vec::new()
175-
}*/
190+
}

src/simulation/components/apsis.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::simulation::components::body::{BodyChildren, BodyParent, Moon, Planet, SimPosition, Star, Velocity};
22
use crate::simulation::components::horizons::AniseMetadata;
3-
use crate::simulation::components::physics::apply_physics;
3+
use crate::simulation::integration::{paused, SimulationStep};
44
use crate::simulation::scenario::setup::ScenarioData;
55
use crate::simulation::ui::SimTime;
66
use crate::simulation::SimState;
77
use crate::utils::sim_state_type_simulation;
8-
use bevy::prelude::{Transform, Vec3};
8+
use bevy::prelude::{not, Transform, Vec3};
99
use bevy::{math::DVec3, prelude::{in_state, App, Component, Entity, IntoSystemConfigs, Plugin, Query, Reflect, Res, Update, With, Without}};
1010
use std::collections::HashMap;
1111

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

2222
}
@@ -57,15 +57,15 @@ fn update_apsis(
5757
}
5858
}
5959
if let Some(p_pos) = parent {
60-
let new_distance = p_pos.0.distance(position.0) as f32;
60+
let new_distance = p_pos.current.distance(position.current) as f32;
6161
//perihelion
6262
if apsis.perihelion.distance > new_distance || apsis.perihelion.distance == 0.0 {
6363
apsis.perihelion.distance = new_distance;
64-
apsis.perihelion.position = position.0;
64+
apsis.perihelion.position = position.current;
6565
}
6666
if apsis.aphelion.distance < new_distance || apsis.perihelion.distance == 0.0 {
6767
apsis.aphelion.distance = new_distance;
68-
apsis.aphelion.position = position.0;
68+
apsis.aphelion.position = position.current;
6969
}
7070
}
7171
}
@@ -78,15 +78,15 @@ fn update_apsis(
7878
}
7979
}
8080
if let Some(p_pos) = parent {
81-
let new_distance = p_pos.0.distance(position.0) as f32;
81+
let new_distance = p_pos.current.distance(position.current) as f32;
8282
//perihelion
8383
if apsis.perihelion.distance > new_distance || apsis.perihelion.distance == 0.0 {
8484
apsis.perihelion.distance = new_distance;
85-
apsis.perihelion.position = position.0;
85+
apsis.perihelion.position = position.current;
8686
}
8787
if apsis.aphelion.distance < new_distance || apsis.perihelion.distance == 0.0 {
8888
apsis.aphelion.distance = new_distance;
89-
apsis.aphelion.position = position.0;
89+
apsis.aphelion.position = position.current;
9090
}
9191
}
9292
}

src/simulation/components/body.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,20 @@ impl Default for OrbitSettings {
9393
}
9494

9595
#[derive(Component, Clone, Default)]
96-
pub struct SimPosition(pub DVec3);
96+
pub struct SimPosition {
97+
98+
pub current: DVec3,
99+
pub previous: Option<DVec3>,
100+
101+
}
102+
103+
impl SimPosition {
104+
105+
pub fn new(value: DVec3) -> Self {
106+
SimPosition { current: value, previous: None }
107+
}
108+
109+
}
97110

98111
#[derive(Component, Clone)]
99112
pub struct BodyShape {
@@ -202,7 +215,7 @@ impl From<SerializedBody> for BodyBundle {
202215
fn from(value: SerializedBody) -> Self {
203216
BodyBundle {
204217
mass: Mass(value.data.mass),
205-
sim_position: SimPosition(DVec3::from(value.data.starting_position) * 1000.0),
218+
sim_position: SimPosition::new(DVec3::from(value.data.starting_position) * 1000.0),
206219
vel: Velocity(DVec3::from(value.data.starting_velocity) * 1000.0),
207220
name: Name::new(value.data.name),
208221
model_path: ModelPath(format!("models/{}#Scene0", value.data.model_path)),
@@ -232,7 +245,7 @@ impl BodyBundle {
232245
pub fn empty(index: i32) -> Self {
233246
BodyBundle {
234247
mass: Mass(0.0),
235-
sim_position: SimPosition(DVec3::ZERO),
248+
sim_position: SimPosition::new(DVec3::ZERO),
236249
vel: Velocity(DVec3::ZERO),
237250
name: Name::new(format!("New body {}", index)),
238251
model_path: ModelPath("models/earth.glb#Scene0".to_string()),

src/simulation/components/editor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,12 @@ pub fn update_body_positions(
165165
} else {
166166
let (_, position, mut transform) = bodies.get_mut(entity).unwrap();
167167
transform.translation = Vec3::ZERO;
168-
scale.m_to_unit_dvec(position.0).as_vec3()
168+
scale.m_to_unit_dvec(position.current).as_vec3()
169169
}
170170
} else {
171171
Vec3::ZERO
172172
};
173173
for (_, position, mut transform) in bodies.iter_mut() {
174-
transform.translation = scale.m_to_unit_dvec(position.0).as_vec3() - offset;
174+
transform.translation = scale.m_to_unit_dvec(position.current).as_vec3() - offset;
175175
}
176176
}

src/simulation/components/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use crate::simulation::components::direction::DirectionPlugin;
55
use crate::simulation::components::horizons::HorizonsPlugin;
66
use crate::simulation::components::lock_on::LockOnPlugin;
77
use crate::simulation::components::motion_line::MotionLinePlugin;
8-
use crate::simulation::components::physics::PhysicsPlugin;
98
use crate::simulation::components::reset::ResetPlugin;
109
use crate::simulation::components::rotation::RotationPlugin;
1110
use crate::simulation::components::scale::ScalePlugin;
1211
use crate::simulation::components::selection::SelectionPlugin;
1312
use crate::simulation::components::shape::DiameterPlugin;
1413
use crate::simulation::components::speed::SpeedPlugin;
14+
use crate::simulation::integration::IntegrationPlugin;
1515
use bevy::app::Plugin;
1616

1717
pub mod apsis;
@@ -20,7 +20,6 @@ pub mod camera;
2020
pub mod shape;
2121
pub mod direction;
2222
pub mod lock_on;
23-
pub mod physics;
2423
pub mod body;
2524
pub mod motion_line;
2625
pub mod rotation;
@@ -43,10 +42,10 @@ impl Plugin for SimComponentPlugin {
4342
// .add_plugins(PanOrbitCameraPlugin)
4443
.add_plugins(DiameterPlugin)
4544
.add_plugins(DirectionPlugin)
45+
.add_plugins(IntegrationPlugin)
4646
.add_plugins(LockOnPlugin)
4747
.add_plugins(ScalePlugin)
4848
.add_plugins(MotionLinePlugin)
49-
.add_plugins(PhysicsPlugin)
5049
.add_plugins(ResetPlugin)
5150
.add_plugins(RotationPlugin)
5251
.add_plugins(SelectionPlugin)

src/simulation/components/motion_line.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::simulation::components::body::{BillboardVisible, BodyChildren, BodyShape, Moon, OrbitSettings, Planet, SimPosition, Star};
2-
use crate::simulation::components::physics::{apply_physics, Pause, SubSteps};
32
use crate::simulation::components::scale::SimulationScale;
43
use crate::simulation::components::speed::Speed;
4+
use crate::simulation::integration::{paused, Pause, SimulationStep, SubSteps};
55
use crate::utils::sim_state_type_simulation;
6+
use bevy::prelude::not;
67
use bevy::{prelude::{App, Camera, Entity, Gizmos, IntoSystemConfigs, Plugin, PreUpdate, Query, Res, Resource, Transform, Vec3, With, Without}, time::Time};
78
use bevy_panorbit_camera::PanOrbitCamera;
89

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

@@ -57,8 +58,8 @@ fn update_lines(
5758
let speed = speed.0 as f32 * (substeps.0 as f32);
5859
let max_step = (orbit.period as f32 / speed) * MULTIPLIER;
5960
if orbit.step >= max_step {
60-
orbit.lines.push_back(scale.m_to_unit_dvec(pos.0).as_vec3());
61-
// insert_at_nearest_distance(&mut orbit.lines, (pos.0 * M_TO_UNIT).as_vec3());
61+
orbit.lines.push_back(scale.m_to_unit_dvec(pos.current).as_vec3());
62+
// insert_at_nearest_distance(&mut orbit.lines, (pos.current * M_TO_UNIT).as_vec3());
6263
orbit.step = 0.0;
6364
} else {
6465
orbit.step += time.delta_seconds() * orbit.orbit_line_multiplier;
@@ -74,8 +75,8 @@ fn update_lines(
7475
let speed = speed.0 as f32 * (substeps.0 as f32);
7576
let max_step = (orbit.period as f32 / speed) * MULTIPLIER;
7677
if orbit.step >= max_step {
77-
let raw_p_pos = scale.m_to_unit_dvec(p_pos.0).as_vec3();
78-
let raw_pos = scale.m_to_unit_dvec(pos.0).as_vec3();
78+
let raw_p_pos = scale.m_to_unit_dvec(p_pos.current).as_vec3();
79+
let raw_pos = scale.m_to_unit_dvec(pos.current).as_vec3();
7980
orbit.lines.push_back(raw_pos - raw_p_pos);
8081
//insert_at_nearest_distance(&mut orbit.lines, raw_pos - raw_p_pos);
8182
orbit.step = 0.0;
@@ -104,7 +105,7 @@ fn draw_orbit_line(
104105
if let Some((_, p_pos, _, _)) = planet_query.iter().find(|(_, _, children, _)| {
105106
children.0.contains(&entity)
106107
}) {
107-
let raw_p_pos = scale.m_to_unit_dvec(p_pos.0).as_vec3();
108+
let raw_p_pos = scale.m_to_unit_dvec(p_pos.current).as_vec3();
108109
draw_lines(orbit, offset.value + raw_p_pos, &mut gizmos, transform.translation)
109110
}
110111
}

0 commit comments

Comments
 (0)