use glam::{DMat3, DVec3};
use crate::atmosphere::AtmosphereConfig;
use crate::sources::GravitySourceEntry;
use crate::vehicle_config::VehicleConfig;
use crate::SimulationTime;
use astrodyn_ephemeris::{Ephemeris, EphemerisBody};
#[derive(Debug, Clone)]
pub struct MassTreeAttachment {
pub child_idx: usize,
pub parent_idx: usize,
pub offset: DVec3,
pub t_parent_child: DMat3,
}
pub struct SimulationBuilder {
pub time: SimulationTime,
pub dt: f64,
pub atmosphere: Option<AtmosphereConfig>,
pub atmosphere_planet_source: Option<usize>,
pub ephemeris: Option<Ephemeris>,
pub polar_motion: Option<(f64, f64)>,
pub sun_source: Option<usize>,
pub moon_source: Option<usize>,
pub sources: Vec<(String, GravitySourceEntry)>,
pub source_ephem_bodies: Vec<Option<(EphemerisBody, EphemerisBody)>>,
pub bodies: Vec<VehicleConfig>,
pub mass_tree_names: Vec<Option<String>>,
pub mass_tree_attachments: Vec<MassTreeAttachment>,
}
impl SimulationBuilder {
pub fn new(time: SimulationTime, dt: f64) -> Self {
Self {
time,
dt,
atmosphere: None,
atmosphere_planet_source: None,
ephemeris: None,
polar_motion: None,
sun_source: None,
moon_source: None,
sources: Vec::new(),
source_ephem_bodies: Vec::new(),
bodies: Vec::new(),
mass_tree_names: Vec::new(),
mass_tree_attachments: Vec::new(),
}
}
pub fn atmosphere(mut self, config: AtmosphereConfig, planet_source: usize) -> Self {
self.atmosphere = Some(config);
self.atmosphere_planet_source = Some(planet_source);
self
}
pub fn atmosphere_from_planet(
mut self,
model: crate::AtmosphereModel,
planet: &crate::PlanetConfig,
planet_source: usize,
) -> Self {
self.atmosphere = Some(AtmosphereConfig::from_planet(model, planet));
self.atmosphere_planet_source = Some(planet_source);
self
}
pub fn ephemeris(mut self, eph: Ephemeris) -> Self {
self.ephemeris = Some(eph);
self
}
pub fn polar_motion(mut self, xp: f64, yp: f64) -> Self {
self.polar_motion = Some((xp, yp));
self
}
pub fn sun(mut self, idx: usize) -> Self {
self.sun_source = Some(idx);
self
}
pub fn moon(mut self, idx: usize) -> Self {
self.moon_source = Some(idx);
self
}
pub fn add_source(&mut self, name: impl Into<String>, entry: GravitySourceEntry) -> usize {
let idx = self.sources.len();
self.sources.push((name.into(), entry));
self.source_ephem_bodies.push(None);
idx
}
pub fn set_source_ephemeris(
&mut self,
idx: usize,
target: EphemerisBody,
observer: EphemerisBody,
) -> &mut Self {
assert!(
idx < self.source_ephem_bodies.len(),
"set_source_ephemeris: source index {idx} out of range \
({} sources added)",
self.source_ephem_bodies.len()
);
self.source_ephem_bodies[idx] = Some((target, observer));
self
}
pub fn add_third_body_with_ephemeris(
&mut self,
name: impl Into<String>,
planet: &crate::PlanetConfig,
target: EphemerisBody,
observer: EphemerisBody,
) -> usize {
let entry = crate::sources::GravitySourceEntry::third_body(
planet,
astrodyn_quantities::aliases::Position::<astrodyn_quantities::frame::RootInertial>::zero(),
);
let idx = self.add_source(name, entry);
self.set_source_ephemeris(idx, target, observer);
idx
}
pub fn add_body(&mut self, config: VehicleConfig) -> usize {
let idx = self.bodies.len();
self.bodies.push(config);
self.mass_tree_names.push(None);
idx
}
pub fn register_in_mass_tree(&mut self, body_idx: usize, name: impl Into<String>) -> &mut Self {
assert!(
body_idx < self.bodies.len(),
"register_in_mass_tree: body index {body_idx} out of range \
({} bodies added)",
self.bodies.len()
);
assert!(
self.bodies[body_idx].mass.is_some(),
"register_in_mass_tree: body {body_idx} has no mass properties"
);
self.mass_tree_names[body_idx] = Some(name.into());
self
}
pub fn attach_bodies(
&mut self,
child_idx: usize,
parent_idx: usize,
offset: DVec3,
t_parent_child: DMat3,
) -> &mut Self {
assert!(
child_idx < self.bodies.len(),
"attach_bodies: child body index {child_idx} out of range \
({} bodies added)",
self.bodies.len()
);
assert!(
parent_idx < self.bodies.len(),
"attach_bodies: parent body index {parent_idx} out of range \
({} bodies added)",
self.bodies.len()
);
assert!(
self.mass_tree_names[child_idx].is_some(),
"attach_bodies: child body {child_idx} not registered in mass tree"
);
assert!(
self.mass_tree_names[parent_idx].is_some(),
"attach_bodies: parent body {parent_idx} not registered in mass tree"
);
self.mass_tree_attachments.push(MassTreeAttachment {
child_idx,
parent_idx,
offset,
t_parent_child,
});
self
}
}