use crate::corrections::refraction;
use crate::observer::Observer;
use crate::spatial::{deg2dms, deg2hms, great_circle_distance, radec2lb, DEGRA};
use crate::time::Time;
pub struct Target<'a> {
pub name: Option<&'a str>,
pub ra: f64,
pub dec: f64,
}
impl<'a> Target<'a> {
pub fn new(ra: f64, dec: f64, name: Option<&str>) -> Target {
Target { name, ra, dec }
}
pub fn altitude(&self, observer: &Observer, time: &Time) -> f64 {
let (ra, dec) = (self.ra, self.dec);
let ha = ((observer.local_sidereal_time(time) - ra) % 360.0) * DEGRA;
let lat = observer.lat * DEGRA;
let dec = dec * DEGRA;
let alt = (dec.sin() * lat.sin() + dec.cos() * lat.cos() * ha.cos()).asin() / DEGRA;
alt + refraction(alt)
}
pub fn airmass(&self, observer: &Observer, time: &Time) -> f64 {
let alt = self.altitude(observer, time);
if alt <= 0.0 {
return std::f64::NEG_INFINITY;
}
let sinarg = alt + 244.0 / (165.0 + 47.0 * alt.powf(1.1));
1.0 / (sinarg * DEGRA).sin()
}
pub fn separation(&self, other: &Target) -> f64 {
great_circle_distance(self.ra, self.dec, other.ra, other.dec)
}
pub fn separations(&self, others: &Vec<Target>) -> Vec<f64> {
let mut separations = Vec::new();
for other in others {
separations.push(self.separation(other));
}
separations
}
pub fn to_string(&self) -> String {
if let Some(name) = &self.name {
return format!("Name: {}, RA: {}, DEC: {}", name, self.ra, self.dec);
}
format!("RA: {}, DEC: {} (no name)", self.ra, self.dec)
}
pub fn radec2hmsdms(&self) -> (String, String) {
(deg2hms(self.ra), deg2dms(self.dec))
}
pub fn radec2lb(&self) -> (f64, f64) {
radec2lb(self.ra, self.dec)
}
}
impl<'a> std::fmt::Display for Target<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Some(name) = &self.name {
write!(f, "Name: {}, RA: {}, DEC: {}", name, self.ra, self.dec)
} else {
write!(f, "RA: {}, DEC: {} (no name)", self.ra, self.dec)
}
}
}