use glam::{DMat3, DVec3};
use astrodyn::{
AerodynamicForce, AtmosphereState, DragConfig, DynamicsConfig, EulerSequence, FrameDerivatives,
FrameSwitchConfig, GeodeticState, GravityAccelerationTyped, GravityControls, GravitySource,
LvlhFrame, MassPropertiesTyped, OrbitalElements, RadiationForce, RootInertial, RotationModel,
RotationalStateTyped, SelfPlanet, SelfRef, SrpModel, TotalForce, TranslationalStateTyped,
VehicleConfig,
};
use astrodyn::{ContactFacet, FrameId, GroundFacet, IntegrationFrame, MassBodyId, MassPointState};
#[derive(Debug, Clone)]
pub struct ContactPairConfig {
pub body_a: usize,
pub facet_a: ContactFacet,
pub body_b: usize,
pub facet_b: ContactFacet,
}
#[derive(Debug, Clone)]
pub struct GroundContactPairConfig {
pub body_a: usize,
pub vehicle_facet: ContactFacet,
pub ground_facet: GroundFacet,
pub pending_initial_impulse: Option<GroundContactImpulse>,
}
#[derive(Debug, Clone, Copy)]
pub struct GroundContactImpulse {
pub force_inertial: DVec3,
pub torque_body: DVec3,
}
#[derive(Debug, Clone, Copy)]
pub struct FrameAttachState {
pub parent_frame_id: FrameId,
pub attach_offset: MassPointState,
}
pub(crate) struct GravityData {
pub source: GravitySource,
pub velocity: DVec3,
pub delta_c20: f64,
pub tidal_config: Option<astrodyn::TidalConfig>,
pub rotation_model: RotationModel,
pub planet_omega: f64,
}
#[derive(Debug, Clone)]
pub struct VehicleOutput {
pub trans: TranslationalStateTyped<IntegrationFrame>,
pub integ_frame_id: FrameId,
pub rot: Option<RotationalStateTyped<SelfRef>>,
pub trans_accel: DVec3,
pub rot_accel: Option<DVec3>,
pub orbital_elements: Option<OrbitalElements<SelfPlanet>>,
pub euler_angles: Option<[f64; 3]>,
pub lvlh_frame: Option<LvlhFrame>,
pub geodetic_state: Option<GeodeticState>,
pub solar_beta: Option<f64>,
pub earth_lighting: Option<astrodyn::EarthLightingState>,
}
pub(crate) struct SimBody {
pub trans: TranslationalStateTyped<IntegrationFrame>,
pub rot: Option<RotationalStateTyped<SelfRef>>,
pub mass: Option<MassPropertiesTyped<SelfRef>>,
pub mass_body_id: Option<MassBodyId>,
pub kinematic_only: bool,
pub frame_attach: Option<FrameAttachState>,
pub config: DynamicsConfig,
pub gravity_controls: GravityControls<usize>,
pub integrator: astrodyn::IntegratorType,
pub drag: Option<DragConfig>,
pub flat_plate_state: Option<astrodyn::FlatPlateState<astrodyn::SelfRef>>,
pub cannonball_srp: Option<(f64, f64, f64)>,
pub shadow_body: Option<(usize, f64)>,
pub t_struct_body: DMat3,
pub compute_gravity_torque: bool,
pub atmospheric_state: AtmosphereState<SelfPlanet>,
pub external_force: DVec3,
pub external_torque: DVec3,
pub external_force_struct: DVec3,
pub external_torque_struct: DVec3,
pub integ_frame_id: FrameId,
pub body_frame_id: FrameId,
pub frame_switches: Vec<FrameSwitchConfig>,
pub gravity_accel: GravityAccelerationTyped<RootInertial>,
pub total_force: TotalForce,
pub frame_derivs: FrameDerivatives,
pub aero_force: Option<AerodynamicForce>,
pub radiation_force: Option<RadiationForce>,
pub gravity_torque: Option<DVec3>,
pub orbital_elements_source: Option<usize>,
pub euler_sequence: Option<EulerSequence>,
pub compute_lvlh: bool,
pub geodetic_planet: Option<(usize, f64, f64)>,
pub compute_solar_beta: bool,
pub earth_lighting_config: Option<(f64, f64, f64)>,
pub orbital_elements: Option<OrbitalElements<SelfPlanet>>,
pub euler_angles: Option<[f64; 3]>,
pub lvlh_frame: Option<LvlhFrame>,
pub geodetic_state: Option<GeodeticState>,
pub solar_beta: Option<f64>,
pub earth_lighting: Option<astrodyn::EarthLightingState>,
pub gj_state: Option<astrodyn::GaussJacksonState>,
pub abm4_state: Option<astrodyn::Abm4State>,
}
impl SimBody {
pub(crate) fn from_config(
config: VehicleConfig,
integ_frame_id: FrameId,
body_frame_id: FrameId,
) -> Self {
let has_rot = config.rot.is_some();
let dynamics_config = DynamicsConfig {
translational_dynamics: true,
rotational_dynamics: has_rot,
three_dof: !has_rot,
};
let (flat_plate_state, cannonball_srp) = match config.srp {
Some(SrpModel::FlatPlate(fps)) => (Some(fps), None),
Some(SrpModel::Cannonball {
cx_area,
albedo,
diffuse,
}) => (None, Some((cx_area, albedo, diffuse))),
None => (None, None),
};
let shadow_body = config.shadow_body.map(|sb| (sb.source_idx, sb.radius));
Self {
trans: config.trans.relabel_to::<IntegrationFrame>(),
rot: config.rot,
mass: config.mass,
mass_body_id: None,
kinematic_only: false,
frame_attach: None,
config: dynamics_config,
gravity_controls: config.gravity_controls,
integrator: config.integrator,
drag: config.drag,
flat_plate_state,
cannonball_srp,
shadow_body,
t_struct_body: config.t_struct_body,
compute_gravity_torque: config.compute_gravity_gradient,
atmospheric_state: AtmosphereState::<SelfPlanet>::default(),
external_force: config.external_force.raw_si(),
external_torque: config.external_torque.raw_si(),
external_force_struct: DVec3::ZERO,
external_torque_struct: DVec3::ZERO,
integ_frame_id,
body_frame_id,
frame_switches: config.frame_switches,
gravity_accel: GravityAccelerationTyped::<RootInertial>::default(),
total_force: TotalForce::default(),
frame_derivs: FrameDerivatives::default(),
aero_force: None,
radiation_force: None,
gravity_torque: None,
orbital_elements_source: config.derived.orbital_elements_source,
euler_sequence: config.derived.euler_sequence,
compute_lvlh: config.derived.lvlh,
geodetic_planet: config
.derived
.geodetic
.map(|g| (g.source_idx, g.r_eq, g.r_pol)),
compute_solar_beta: config.derived.solar_beta,
earth_lighting_config: config
.derived
.earth_lighting
.map(|e| (e.earth_radius, e.moon_radius, e.sun_radius)),
orbital_elements: None,
euler_angles: None,
lvlh_frame: None,
geodetic_state: None,
solar_beta: None,
earth_lighting: None,
gj_state: None,
abm4_state: None,
}
}
pub(crate) fn output(&self) -> VehicleOutput {
VehicleOutput {
trans: self.trans,
integ_frame_id: self.integ_frame_id,
rot: self.rot,
trans_accel: self.frame_derivs.trans_accel,
rot_accel: self.rot.map(|_| self.frame_derivs.rot_accel),
orbital_elements: self.orbital_elements.clone(),
euler_angles: self.euler_angles,
lvlh_frame: self.lvlh_frame,
geodetic_state: self.geodetic_state,
solar_beta: self.solar_beta,
earth_lighting: self.earth_lighting.clone(),
}
}
}