#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CloudType {
Cumulus,
Stratus,
Cirrus,
Cumulonimbus,
Altocumulus,
}
pub struct CloudLayer {
pub cloud_type: CloudType,
pub base_altitude_m: f64,
pub thickness_m: f64,
pub coverage: f64,
pub density: f64,
pub wind_speed_ms: f64,
pub wind_direction: [f64; 2],
}
impl CloudLayer {
pub fn cumulus() -> Self {
Self {
cloud_type: CloudType::Cumulus,
base_altitude_m: 2_000.0,
thickness_m: 1_500.0,
coverage: 0.4,
density: 0.3,
wind_speed_ms: 8.0,
wind_direction: [1.0, 0.0],
}
}
pub fn stratus() -> Self {
Self {
cloud_type: CloudType::Stratus,
base_altitude_m: 500.0,
thickness_m: 500.0,
coverage: 0.7,
density: 0.5,
wind_speed_ms: 5.0,
wind_direction: [0.7, 0.7],
}
}
pub fn cirrus() -> Self {
Self {
cloud_type: CloudType::Cirrus,
base_altitude_m: 8_000.0,
thickness_m: 1_000.0,
coverage: 0.3,
density: 0.05,
wind_speed_ms: 30.0,
wind_direction: [1.0, 0.2],
}
}
pub fn cumulonimbus() -> Self {
Self {
cloud_type: CloudType::Cumulonimbus,
base_altitude_m: 1_000.0,
thickness_m: 12_000.0,
coverage: 0.15,
density: 0.8,
wind_speed_ms: 15.0,
wind_direction: [0.5, 0.5],
}
}
}
pub struct CloudSystem {
pub layers: Vec<CloudLayer>,
pub time_offset_s: f64,
}
impl CloudSystem {
pub fn earth_default() -> Self {
Self {
layers: vec![
CloudLayer::cumulus(),
CloudLayer::stratus(),
CloudLayer::cirrus(),
],
time_offset_s: 0.0,
}
}
pub fn step(&mut self, dt_s: f64) {
self.time_offset_s += dt_s;
}
pub fn sample_density(&self, altitude_m: f64, _lat: f64, _lon: f64) -> f64 {
let mut total = 0.0;
for layer in &self.layers {
let top = layer.base_altitude_m + layer.thickness_m;
if altitude_m >= layer.base_altitude_m && altitude_m <= top {
let t = (altitude_m - layer.base_altitude_m) / layer.thickness_m;
let profile = 4.0 * t * (1.0 - t);
total += layer.density * layer.coverage * profile;
}
}
total.min(1.0)
}
}