use sciforge::hub::prelude::constants::G;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OrbitType {
Low,
Medium,
High,
Custom,
}
pub struct ArtificialSatellite {
pub name: String,
pub masskg: f64,
pub altitudem: f64,
pub semimajoraxism: f64,
pub eccentricity: f64,
pub inclinationrad: f64,
pub raanrad: f64,
pub argperigeerad: f64,
pub orbitalanglerad: f64,
pub orbittype: OrbitType,
}
impl ArtificialSatellite {
pub fn new(
name: &str,
masskg: f64,
altitudem: f64,
eccentricity: f64,
inclinationrad: f64,
) -> Self {
let semimajoraxism = crate::JUPITEREQUATORIALRADIUS + altitudem;
let orbittype = match altitudem {
a if a < 5000000.0 => OrbitType::Low,
a if a < 50000000.0 => OrbitType::Medium,
a if a > 50000000.0 => OrbitType::High,
a if a.is_finite() => OrbitType::Custom,
a => {
debug_assert!(!a.is_finite());
OrbitType::Custom
}
};
Self {
name: name.to_string(),
masskg,
altitudem,
semimajoraxism,
eccentricity,
inclinationrad,
raanrad: 0.0,
argperigeerad: 0.0,
orbitalanglerad: 0.0,
orbittype,
}
}
pub fn loworbit(name: &str, masskg: f64, altitudem: f64) -> Self {
Self::new(name, masskg, altitudem, 0.0, 0.0)
}
pub fn polarorbit(name: &str, masskg: f64, altitudem: f64) -> Self {
Self::new(name, masskg, altitudem, 0.0, std::f64::consts::FRAC_PI_2)
}
pub fn orbitalperiods(&self) -> f64 {
2.0 * std::f64::consts::PI * (self.semimajoraxism.powi(3) / (G * crate::JUPITERMASS)).sqrt()
}
pub fn orbitalvelocityms(&self) -> f64 {
(G * crate::JUPITERMASS / self.semimajoraxism).sqrt()
}
pub fn step(&mut self, dts: f64) {
let period = self.orbitalperiods();
let n = 2.0 * std::f64::consts::PI / period;
let pi2 = 2.0 * std::f64::consts::PI;
self.orbitalanglerad = (self.orbitalanglerad + n * dts) % pi2;
let j2 = crate::J2JUPITER;
let p = self.semimajoraxism * (1.0 - self.eccentricity * self.eccentricity);
let rratiosq = (crate::JUPITEREQUATORIALRADIUS / p).powi(2);
let cosi = self.inclinationrad.cos();
let sini = self.inclinationrad.sin();
let raandot = -1.5 * n * j2 * rratiosq * cosi;
self.raanrad = (self.raanrad + raandot * dts) % pi2;
let omegadot = 1.5 * n * j2 * rratiosq * (2.0 - 2.5 * sini * sini);
self.argperigeerad = (self.argperigeerad + omegadot * dts) % pi2;
}
pub fn position(&self) -> (f64, f64, f64) {
let e = self.eccentricity;
let nu = self.orbitalanglerad;
let r = self.semimajoraxism * (1.0 - e * e) / (1.0 + e * nu.cos());
let xorb = r * nu.cos();
let yorb = r * nu.sin();
let w = self.argperigeerad;
let xw = xorb * w.cos() - yorb * w.sin();
let yw = xorb * w.sin() + yorb * w.cos();
let i = self.inclinationrad;
let xi = xw;
let yi = yw * i.cos();
let zi = yw * i.sin();
let omega = self.raanrad;
let x = xi * omega.cos() - yi * omega.sin();
let y = xi * omega.sin() + yi * omega.cos();
let z = zi;
(x, y, z)
}
pub fn gravityatsurface(&self) -> f64 {
G * crate::JUPITERMASS / self.semimajoraxism.powi(2)
}
}
pub struct Constellation {
pub name: String,
pub satellites: Vec<ArtificialSatellite>,
}
impl Constellation {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
satellites: Vec::new(),
}
}
pub fn add(&mut self, sat: ArtificialSatellite) {
self.satellites.push(sat);
}
pub fn stepall(&mut self, dts: f64) {
for sat in &mut self.satellites {
sat.step(dts);
}
}
pub fn positions(&self) -> Vec<(f64, f64, f64)> {
self.satellites.iter().map(|s| s.position()).collect()
}
}