use crate::{AerodynamicForce, RadiationForce};
use astrodyn_dynamics::forces::{FrameDerivativesTyped, GravityAccelerationTyped, TotalForceTyped};
use astrodyn_dynamics::{
ForceContributions, FrameDerivatives, MassProperties, RotationalState, TotalForce,
};
use astrodyn_quantities::frame::{RootInertial, Vehicle};
use glam::{DMat3, DVec3};
pub fn collect_and_resolve_forces(
aero: Option<&AerodynamicForce>,
srp: Option<&RadiationForce>,
gravity_torque: Option<DVec3>,
rot_state: Option<&RotationalState>,
t_struct_body: DMat3,
mass: Option<&MassProperties>,
gravity_accel: DVec3,
) -> (TotalForce, FrameDerivatives) {
if let Some(aero) = aero {
if aero.force != DVec3::ZERO && rot_state.is_none() {
panic!(
"Non-zero aerodynamic force but no RotationalState. \
In JEOD, T_inertial_struct is a mandatory parameter of aero_drag(). \
Provide RotationalState for any body with aerodynamic forces."
);
}
}
let mut contributions = ForceContributions::default();
if let Some(aero) = aero {
contributions.aero_force_struct = aero.force;
contributions.aero_torque_struct = aero.torque;
}
if let Some(srp) = srp {
contributions.srp_force_inertial = srp.force;
contributions.srp_torque_struct = srp.torque;
}
if let Some(gt) = gravity_torque {
contributions.gravity_torque_body = gt;
}
let t_inertial_body = rot_state.map_or(DMat3::IDENTITY, |r| {
r.quaternion.left_quat_to_transformation()
});
let collected =
astrodyn_dynamics::collect_forces(&contributions, &t_struct_body, &t_inertial_body);
let derivs = if let (Some(rot), Some(m)) = (rot_state, mass) {
astrodyn_dynamics::compute_frame_derivatives(
&collected,
m.inverse_mass,
gravity_accel,
&m.inertia,
&m.inverse_inertia,
rot.ang_vel_body,
)
} else if let Some(m) = mass {
astrodyn_dynamics::compute_translational_derivatives(
collected.force,
m.inverse_mass,
gravity_accel,
)
} else {
FrameDerivatives {
trans_accel: gravity_accel,
rot_accel: DVec3::ZERO,
}
};
(collected, derivs)
}
#[allow(clippy::too_many_arguments)]
pub fn collect_and_resolve_forces_typed<V: Vehicle>(
aero: Option<&AerodynamicForce>,
srp: Option<&RadiationForce>,
gravity_torque: Option<DVec3>,
rot_state: Option<&RotationalState>,
t_struct_body: DMat3,
mass: Option<&MassProperties>,
gravity_accel: GravityAccelerationTyped<RootInertial>,
) -> (
TotalForceTyped<V, RootInertial>,
FrameDerivativesTyped<RootInertial, V>,
) {
let (force, derivs) = collect_and_resolve_forces(
aero,
srp,
gravity_torque,
rot_state,
t_struct_body,
mass,
gravity_accel.grav_accel.raw_si(),
);
(
TotalForceTyped::<V, RootInertial>::from_untyped_unchecked(&force),
FrameDerivativesTyped::<RootInertial, V>::from_untyped_unchecked(&derivs),
)
}