use astrodyn::{Planet, RootInertial};
use bevy::prelude::*;
use crate::components::*;
use crate::frame_param::FrameOrigin;
use super::util::body_integ_origin_in_root;
pub fn orbital_elements_system<P: Planet>(
mut query: Query<(
&TranslationalStateC<P>,
&OrbitalElementsConfigC,
&mut OrbitalElementsC<P>,
)>,
sources: Query<&GravitySourceC>,
) {
for (state, config, mut elements) in &mut query {
let Ok(source) = sources.get(config.gravity_source) else {
elements.0 = Default::default();
continue;
};
let mu_p = astrodyn::GravParam::<P>::from_si(source.mu);
match astrodyn::compute_orbital_elements_typed::<P>(mu_p, state.position, state.velocity) {
Ok(oe) => elements.0 = oe,
Err(_) => elements.0 = Default::default(),
}
}
}
pub fn euler_angles_system(
mut query: Query<(
Option<&RotationalStateC>,
&EulerAnglesConfigC,
&mut EulerAnglesC,
)>,
) {
for (rot_opt, config, mut angles) in &mut query {
if let Some(rot) = rot_opt {
let rot_untyped = astrodyn::typed_bridge::rot_typed_to_raw(&rot.0);
angles.0 = astrodyn::compute_body_euler_angles_typed(&rot_untyped, config.sequence);
} else {
angles.0 = Default::default();
}
}
}
pub fn lvlh_system<P: Planet>(mut query: Query<(&TranslationalStateC<P>, &mut LvlhFrameC)>) {
for (state, mut lvlh) in &mut query {
lvlh.0 = astrodyn::compute_body_lvlh_frame_typed::<P>(state.position, state.velocity);
}
}
pub fn geodetic_system<P: Planet>(
mut query: Query<(
&TranslationalStateC<P>,
&GeodeticConfigC,
&mut GeodeticStateC,
)>,
planets: Query<(&PlanetFixedRotationC<P>, &PlanetC)>,
) {
for (state, config, mut geodetic) in &mut query {
let Ok((rot, planet)) = planets.get(config.planet) else {
geodetic.0 = Default::default();
continue;
};
use astrodyn::F64Ext;
geodetic.0 = astrodyn::compute_body_geodetic_typed::<P>(
state.position,
rot.0.matrix_ref(),
planet.r_eq.m(),
planet.r_pol.m(),
);
}
}
#[allow(clippy::type_complexity)]
pub fn solar_beta_system<P: Planet>(
frame_origin: FrameOrigin,
root_frame_entity: Res<crate::RootFrameEntityR>,
parents: Query<&ChildOf>,
mut query: Query<
(
&TranslationalStateC<P>,
Option<&FrameEntityC>,
&mut SolarBetaC,
),
Without<SunMarker>,
>,
sun_query: Query<&TranslationalStateC<P>, With<SunMarker>>,
) {
let sun_state = match sun_query.single() {
Ok(s) => s,
Err(bevy::ecs::query::QuerySingleError::NoEntities(_)) => {
for (_, _, mut beta) in &mut query {
beta.0 = Default::default();
}
return;
}
Err(bevy::ecs::query::QuerySingleError::MultipleEntities(_)) => {
panic!(
"Multiple entities with SunMarker found in solar_beta_system. \
JEOD assumes exactly one Sun body; ensure exactly one SunMarker entity exists."
);
}
};
for (state, body_frame, mut beta) in &mut query {
let (integ_origin, integ_origin_vel) =
body_integ_origin_in_root(body_frame, &parents, root_frame_entity.0, &frame_origin);
let body_pos_rel = state.position.relabel_to::<RootInertial>();
let body_vel_rel = state.velocity.relabel_to::<RootInertial>();
let body_pos = body_pos_rel + integ_origin;
let body_vel = body_vel_rel + integ_origin_vel;
let sun_pos = sun_state.position.relabel_to::<RootInertial>();
beta.0 = astrodyn::compute_body_solar_beta_typed(body_pos, body_vel, sun_pos).value;
}
}