use crate::astro::proper_motion::{
propagate_space_motion_since_j2000, ProperMotionError, StarSpaceMotion,
};
use crate::coordinates::spherical::direction;
use crate::coordinates::spherical::position;
use crate::coordinates::{centers::Geocentric, frames::EquatorialMeanJ2000, spherical::Position};
use crate::qtty::length::nominal::SolarRadiuses;
use crate::qtty::velocity::Velocity;
use crate::qtty::*;
use crate::targets::CoordinateWithPM;
use crate::time::JulianDate;
use std::borrow::Cow;
#[derive(Clone, Debug)]
pub struct Star<'a> {
pub name: Cow<'a, str>,
pub distance: LightYears,
pub mass: SolarMasses,
pub radius: SolarRadiuses,
pub luminosity: SolarLuminosities,
pub coordinate: CoordinateWithPM<Position<Geocentric, EquatorialMeanJ2000, LightYear>>,
pub parallax: Option<MilliArcseconds>,
pub radial_velocity: Option<Velocity<Kilometer, unit::Second>>,
}
impl<'a> Star<'a> {
pub const fn new_const(
name: &'static str,
distance: LightYears,
mass: SolarMasses,
radius: SolarRadiuses,
luminosity: SolarLuminosities,
coordinate: CoordinateWithPM<Position<Geocentric, EquatorialMeanJ2000, LightYear>>,
) -> Star<'static> {
Star {
name: Cow::Borrowed(name),
distance,
mass,
radius,
luminosity,
coordinate,
parallax: None,
radial_velocity: None,
}
}
pub fn new<N>(
name: N,
distance: LightYears,
mass: SolarMasses,
radius: SolarRadiuses,
luminosity: SolarLuminosities,
coordinate: CoordinateWithPM<Position<Geocentric, EquatorialMeanJ2000, LightYear>>,
) -> Star<'a>
where
N: Into<Cow<'a, str>>,
{
Star {
name: name.into(),
distance,
mass,
radius,
luminosity,
coordinate,
parallax: None,
radial_velocity: None,
}
}
pub const fn with_parallax(mut self, parallax: MilliArcseconds) -> Self {
self.parallax = Some(parallax);
self
}
pub const fn with_radial_velocity(mut self, rv: Velocity<Kilometer, unit::Second>) -> Self {
self.radial_velocity = Some(rv);
self
}
pub fn position_at(
&self,
jd: JulianDate,
) -> Result<position::EquatorialMeanJ2000<AstronomicalUnit>, ProperMotionError> {
let pos_ly = self.coordinate.get_position();
let r_au = pos_ly.distance.to::<AstronomicalUnit>();
let pos_au = position::EquatorialMeanJ2000::<AstronomicalUnit>::new(
pos_ly.ra(),
pos_ly.dec(),
r_au.value(),
);
match (
self.parallax,
self.radial_velocity,
&self.coordinate.proper_motion,
) {
(Some(parallax), Some(rv), Some(pm)) => {
let mas_per_yr_factor = 3_600_000.0_f64; let pm_dec_mas = pm.pm_dec.value() * mas_per_yr_factor;
let pm_ra_mas = match pm.ra_convention {
crate::astro::proper_motion::RaProperMotionConvention::MuAlphaStar => {
pm.pm_ra.value() * mas_per_yr_factor
}
crate::astro::proper_motion::RaProperMotionConvention::MuAlpha => {
let cos_dec = pos_au.dec().cos();
pm.pm_ra.value() * mas_per_yr_factor * cos_dec
}
};
let motion = StarSpaceMotion {
pm_ra_cos_dec: crate::qtty::angular_rate::AngularRate::new(pm_ra_mas),
pm_dec: crate::qtty::angular_rate::AngularRate::new(pm_dec_mas),
parallax,
radial_velocity: rv,
};
propagate_space_motion_since_j2000(pos_au, motion, jd)
}
(_, _, Some(pm)) => {
crate::astro::proper_motion::set_proper_motion_since_j2000(pos_au, pm.clone(), jd)
}
(_, _, None) => Ok(pos_au),
}
}
pub fn has_full_space_motion(&self) -> bool {
self.parallax.is_some()
&& self.radial_velocity.is_some()
&& self.coordinate.proper_motion.is_some()
}
}
impl From<&Star<'_>> for direction::ICRS {
fn from(star: &Star<'_>) -> Self {
let pos = star.coordinate.get_position();
Self::new(pos.azimuth, pos.polar)
}
}
impl crate::targets::Trackable for Star<'_> {
type Coords = direction::ICRS;
#[inline]
fn track(&self, _jd: JulianDate) -> Self::Coords {
direction::ICRS::from(self)
}
}