use crate::weather::RainIntensity;
#[must_use]
pub fn rain_intensity_from_rate(rate_mm_hr: f64) -> Option<RainIntensity> {
if rate_mm_hr <= 0.0 {
None
} else if rate_mm_hr < 2.5 {
Some(RainIntensity::Light)
} else if rate_mm_hr < 7.5 {
Some(RainIntensity::Moderate)
} else if rate_mm_hr < 50.0 {
Some(RainIntensity::Heavy)
} else {
Some(RainIntensity::Torrential)
}
}
#[must_use]
pub fn snow_amplitude_scale(snow_liquid_ratio: f64) -> f32 {
(1.0 / snow_liquid_ratio.max(1.0)) as f32
}
#[must_use]
pub fn wind_speed_raw(speed_ms: f64) -> f32 {
speed_ms.max(0.0) as f32
}
#[must_use]
pub fn wind_speed_normalized(speed_ms: f64) -> f32 {
(speed_ms / 20.0).clamp(0.0, 1.0) as f32
}
#[must_use]
pub fn wind_from_beaufort(beaufort: u8) -> f32 {
(beaufort as f32 / 12.0).clamp(0.0, 1.0)
}
#[must_use]
pub fn gustiness_from_shear(shear_ms_per_km: f64) -> f32 {
(shear_ms_per_km / 20.0).clamp(0.0, 1.0) as f32
}
#[must_use]
pub fn gustiness_stability_modifier(unstable: bool) -> f32 {
if unstable { 0.3 } else { -0.2 }
}
#[must_use]
pub fn weather_from_threat_level(level: u8) -> (f32, f32, Option<RainIntensity>) {
match level {
0 | 1 => (f32::MAX, 5.0, None),
2 => (3000.0, 8.0, Some(RainIntensity::Moderate)),
3 => (1500.0, 14.0, Some(RainIntensity::Heavy)),
4 => (500.0, 22.0, Some(RainIntensity::Torrential)),
_ => (100.0, 30.0, Some(RainIntensity::Torrential)),
}
}
#[must_use]
pub fn thunder_distance_from_flash(time_since_flash_s: f32, temperature_celsius: f32) -> f32 {
let speed_of_sound = 331.3 + 0.606 * temperature_celsius;
time_since_flash_s * speed_of_sound
}
#[must_use]
pub fn thunder_distance_cutoff(distance_m: f32) -> f32 {
(5000.0 / (1.0 + distance_m * 0.002)).clamp(60.0, 5000.0)
}
#[must_use]
pub fn gain_from_distance(distance_ref: f32, distance: f32) -> f32 {
if distance <= distance_ref {
return 1.0;
}
distance_ref / distance
}
#[must_use]
pub fn fire_intensity_from_temperature(flame_temp_k: f64) -> f32 {
((flame_temp_k - 500.0) / 2500.0).clamp(0.0, 1.0) as f32
}
#[must_use]
pub fn fire_intensity_from_convection(watts: f64) -> f32 {
(watts / 50_000.0).clamp(0.0, 1.0) as f32
}
#[must_use]
pub fn fire_intensity_blended(flame_temp_k: f64, convection_watts: f64) -> f32 {
let thermal = fire_intensity_from_temperature(flame_temp_k);
let convective = fire_intensity_from_convection(convection_watts);
(0.6 * thermal + 0.4 * convective).clamp(0.0, 1.0)
}
#[must_use]
pub fn foliage_contact_from_growth(growth_modifier: f32) -> f32 {
growth_modifier.clamp(0.0, 1.0)
}
#[must_use]
pub fn foliage_contact_from_diversity(shannon_h: f32) -> f32 {
(shannon_h / 2.0).clamp(0.0, 1.0)
}
#[must_use]
pub fn is_bare_season(growth_modifier: f32) -> bool {
growth_modifier < 0.1
}
#[must_use]
pub fn whoosh_type_from_reynolds(reynolds: f64) -> crate::aero::WhooshType {
if reynolds > 500_000.0 {
crate::aero::WhooshType::Vehicle
} else {
crate::aero::WhooshType::Projectile
}
}