use crate::config::parameters::*;
use crate::engine::orbits::OrbitalElements;
use crate::types::gas_giant::GasGiant;
use crate::types::ice_giant::IceGiant;
use crate::types::terrestrial::TerrestrialPlanet;
#[derive(Debug, Clone)]
pub struct SystemGeneratorConfig {
pub star_name: String,
pub star_mass: f64,
pub star_temperature: f64,
pub star_radius: f64,
pub n_planets: usize,
pub inner_limit_au: f64,
pub outer_limit_au: f64,
pub frost_line_au: f64,
pub seed: u64,
}
impl SystemGeneratorConfig {
pub fn solar_like(n_planets: usize) -> Self {
Self {
star_name: String::from("Star"),
star_mass: SOLAR_MASS,
star_temperature: SOLAR_TEMPERATURE,
star_radius: SOLAR_RADIUS,
n_planets,
inner_limit_au: 0.3,
outer_limit_au: 40.0,
frost_line_au: 2.7,
seed: 42,
}
}
pub fn m_dwarf(n_planets: usize) -> Self {
Self {
star_name: String::from("Star"),
star_mass: 0.089 * SOLAR_MASS,
star_temperature: 2566.0,
star_radius: 0.121 * SOLAR_RADIUS,
n_planets,
inner_limit_au: 0.01,
outer_limit_au: 0.1,
frost_line_au: 0.03,
seed: 42,
}
}
}
pub fn titius_bode_au(n_planets: usize, a0: f64, b: f64, c: f64) -> Vec<f64> {
(0..n_planets).map(|n| a0 + b * c.powi(n as i32)).collect()
}
pub fn titius_bode_solar(n_planets: usize) -> Vec<f64> {
titius_bode_au(n_planets, 0.0, 0.3, 2.0)
}
fn simple_hash(seed: u64, idx: u64) -> f64 {
let mut x = seed.wrapping_mul(6364136223846793005).wrapping_add(idx);
x ^= x >> 33;
x = x.wrapping_mul(0xff51afd7ed558ccd);
x ^= x >> 33;
(x as f64) / (u64::MAX as f64)
}
pub enum GeneratedPlanet {
Terrestrial(TerrestrialPlanet),
GasGiant(GasGiant),
IceGiant(IceGiant),
}
pub fn generate_system(config: &SystemGeneratorConfig) -> Vec<GeneratedPlanet> {
let n = config.n_planets;
let ln_inner = config.inner_limit_au.ln();
let ln_outer = config.outer_limit_au.ln();
let axes_au: Vec<f64> = (0..n)
.map(|i| {
let frac = if n > 1 {
i as f64 / (n - 1) as f64
} else {
0.5
};
(ln_inner + frac * (ln_outer - ln_inner)).exp()
})
.collect();
let mut planets = Vec::with_capacity(n);
for (idx, &a_au) in axes_au.iter().enumerate() {
let name = format!("{} {}", config.star_name, (b'b' + idx as u8) as char);
let ecc = simple_hash(config.seed, 10 + idx as u64) * 0.1;
let inc_deg = simple_hash(config.seed, 20 + idx as u64) * 5.0;
let omega_big_deg = (360.0 / n as f64) * idx as f64;
let omega_small_deg = simple_hash(config.seed, 200 + idx as u64) * 360.0;
let m0_deg = simple_hash(config.seed, 300 + idx as u64) * 360.0;
let elements = OrbitalElements::from_au_deg(
a_au,
ecc,
inc_deg,
omega_big_deg,
omega_small_deg,
m0_deg,
);
if a_au < config.frost_line_au {
let u = simple_hash(config.seed, 100 + idx as u64);
let mass = EARTH_MASS * (0.1 + 4.9 * u);
let radius = radius_from_mass(mass);
planets.push(GeneratedPlanet::Terrestrial(TerrestrialPlanet::new(
&name,
&config.star_name,
mass,
radius,
1.0e-3,
inc_deg * DEG,
elements,
)));
} else if a_au < config.frost_line_au * 5.0 {
let u = simple_hash(config.seed, 100 + idx as u64);
let mass = JUPITER_MASS * (0.1 + 5.0 * u);
let radius = radius_from_mass(mass);
planets.push(GeneratedPlanet::GasGiant(GasGiant::new(
&name,
&config.star_name,
mass,
radius,
1.5e-2,
3.0 * DEG,
elements,
)));
} else {
let u = simple_hash(config.seed, 100 + idx as u64);
let mass = EARTH_MASS * (10.0 + 30.0 * u);
let radius = radius_from_mass(mass);
planets.push(GeneratedPlanet::IceGiant(IceGiant::new(
&name,
&config.star_name,
mass,
radius,
3.3e-3,
30.0 * DEG,
elements,
)));
}
}
planets
}