#[allow(unused_imports)]
use crate::math::F64Ext;
use nalgebra::Vector3;
pub const SUN_RADIUS_KM: f64 = 695700.0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShadowModel {
Cylindrical,
Conical,
}
pub fn illumination(
observer_pos: &Vector3<f64>,
light_pos: &Vector3<f64>,
occulter_pos: &Vector3<f64>,
light_radius: f64,
occulter_radius: f64,
model: ShadowModel,
) -> f64 {
match model {
ShadowModel::Cylindrical => {
illumination_cylindrical(observer_pos, light_pos, occulter_pos, occulter_radius)
}
ShadowModel::Conical => illumination_conical(
observer_pos,
light_pos,
occulter_pos,
light_radius,
occulter_radius,
),
}
}
pub fn illumination_central(
observer_pos: &Vector3<f64>,
light_pos: &Vector3<f64>,
occulter_radius: f64,
light_radius: f64,
model: ShadowModel,
) -> f64 {
illumination(
observer_pos,
light_pos,
&Vector3::zeros(),
light_radius,
occulter_radius,
model,
)
}
fn illumination_cylindrical(
observer_pos: &Vector3<f64>,
light_pos: &Vector3<f64>,
occulter_pos: &Vector3<f64>,
occulter_radius: f64,
) -> f64 {
let obs_rel = observer_pos - occulter_pos;
let light_rel = light_pos - occulter_pos;
let light_dir = light_rel.normalize();
let projection = obs_rel.dot(&light_dir);
if projection >= 0.0 {
return 1.0;
}
let perp = obs_rel - projection * light_dir;
let perp_dist = perp.magnitude();
if perp_dist < occulter_radius {
0.0 } else {
1.0 }
}
fn illumination_conical(
observer_pos: &Vector3<f64>,
light_pos: &Vector3<f64>,
occulter_pos: &Vector3<f64>,
light_radius: f64,
occulter_radius: f64,
) -> f64 {
let obs_to_light = light_pos - observer_pos;
let obs_to_occulter = occulter_pos - observer_pos;
let d_light = obs_to_light.magnitude();
let d_occulter = obs_to_occulter.magnitude();
if d_light < 1e-10 || d_occulter < 1e-10 {
return 1.0;
}
let cos_angle = obs_to_light.dot(&obs_to_occulter) / (d_light * d_occulter);
if cos_angle < 0.0 {
return 1.0; }
let sin_a = (light_radius / d_light).clamp(-1.0, 1.0);
let sin_b = (occulter_radius / d_occulter).clamp(-1.0, 1.0);
let a = sin_a.asin(); let b = sin_b.asin();
let c = cos_angle.clamp(-1.0, 1.0).acos();
if c >= a + b {
return 1.0;
}
if b >= a && c <= b - a {
return 0.0;
}
if a > b && c <= a - b {
let ratio = b / a;
return 1.0 - ratio * ratio;
}
partial_eclipse_illumination(a, b, c)
}
fn partial_eclipse_illumination(a: f64, b: f64, c: f64) -> f64 {
let a2 = a * a;
let b2 = b * b;
let c2 = c * c;
let arg1 = ((c2 + a2 - b2) / (2.0 * c * a)).clamp(-1.0, 1.0);
let arg2 = ((c2 + b2 - a2) / (2.0 * c * b)).clamp(-1.0, 1.0);
let s1 = -c + a + b;
let s2 = c + a - b;
let s3 = c - a + b;
let s4 = c + a + b;
let product = s1 * s2 * s3 * s4;
let sqrt_term = if product > 0.0 { product.sqrt() } else { 0.0 };
let overlap = a2 * arg1.acos() + b2 * arg2.acos() - 0.5 * sqrt_term;
let illum = 1.0 - overlap / (core::f64::consts::PI * a2);
illum.clamp(0.0, 1.0)
}