use affn::cartesian::Position;
use affn::{ReferenceCenter, ReferenceFrame};
use qtty::length::{Meter, Meters};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EclipseState {
Sunlight,
Penumbra,
Umbra,
}
pub fn eclipse_state<C, F>(
sat: &Position<C, F, Meter>,
sun: &Position<C, F, Meter>,
sun_radius: Meters,
occulter_center: &Position<C, F, Meter>,
occulter_radius: Meters,
) -> EclipseState
where
C: ReferenceCenter<Params = ()>,
F: ReferenceFrame,
{
let f = super::occultation::occultation_fraction(
sat,
sun,
sun_radius,
occulter_center,
occulter_radius,
);
if f >= 1.0 - 1e-9 {
EclipseState::Umbra
} else if f > 0.0 {
EclipseState::Penumbra
} else {
EclipseState::Sunlight
}
}
pub fn solar_eclipsing<C, F>(
sat: &Position<C, F, Meter>,
sun: &Position<C, F, Meter>,
sun_radius: Meters,
occulter_center: &Position<C, F, Meter>,
occulter_radius: Meters,
) -> bool
where
C: ReferenceCenter<Params = ()>,
F: ReferenceFrame,
{
!matches!(
eclipse_state(sat, sun, sun_radius, occulter_center, occulter_radius),
EclipseState::Sunlight
)
}
#[cfg(test)]
mod tests {
use super::*;
use affn::cartesian::Position;
use affn::DeriveReferenceCenter;
use affn::DeriveReferenceFrame;
use qtty::length::{Meter, Meters};
use qtty::Quantity;
#[derive(Debug, Clone, Copy, DeriveReferenceCenter)]
struct C;
#[derive(Debug, Clone, Copy, DeriveReferenceFrame)]
struct F;
type P = Position<C, F, Meter>;
fn p(x: f64, y: f64, z: f64) -> P {
P::new(x, y, z)
}
fn m(x: f64) -> Meters {
Quantity::<Meter>::new(x)
}
#[test]
fn eclipse_umbra_when_fully_covered() {
let sat = p(0.0, 0.0, 0.0);
let sun = p(0.0, 0.0, 1.5e11);
let body = p(0.0, 0.0, 1.0e7);
assert_eq!(
eclipse_state(&sat, &sun, m(6.96e8), &body, m(6.378e8)),
EclipseState::Umbra
);
}
#[test]
fn eclipse_sunlight_when_unobstructed() {
let sat = p(0.0, 0.0, 0.0);
let sun = p(0.0, 0.0, 1.5e11);
let body = p(0.0, 1.0e10, 0.0);
assert_eq!(
eclipse_state(&sat, &sun, m(6.96e8), &body, m(6.378e6)),
EclipseState::Sunlight
);
}
}