use crate::qtty::{KmPerSeconds, MilliArcseconds, Radians};
use core::f64::consts::TAU;
#[derive(Debug, Clone, PartialEq)]
pub struct CatalogRecord {
pub source_id: u64,
pub ra: Radians,
pub dec: Radians,
pub epoch_jyr: f64,
pub pm_ra_cosdec: Option<f64>,
pub pm_dec: Option<f64>,
pub parallax: Option<MilliArcseconds>,
pub radial_velocity: Option<KmPerSeconds>,
pub g_mag: Option<f64>,
pub bp_mag: Option<f64>,
pub rp_mag: Option<f64>,
pub quality_ok: bool,
}
impl CatalogRecord {
pub fn propagate_to(&self, target_epoch_jyr: f64) -> (Radians, Radians) {
let dt_yr = target_epoch_jyr - self.epoch_jyr;
let (Some(mu_a), Some(mu_d)) = (self.pm_ra_cosdec, self.pm_dec) else {
return (self.ra, self.dec);
};
let mas_to_rad = (core::f64::consts::PI / 180.0) / 3_600_000.0;
let cos_d = self.dec.value().cos();
let d_ra = if cos_d.abs() > 1e-12 {
(mu_a * mas_to_rad * dt_yr) / cos_d
} else {
0.0
};
let d_dec = mu_d * mas_to_rad * dt_yr;
let mut ra = (self.ra.value() + d_ra).rem_euclid(TAU);
let mut dec = self.dec.value() + d_dec;
if dec > core::f64::consts::FRAC_PI_2 {
dec = core::f64::consts::PI - dec;
ra = (ra + core::f64::consts::PI).rem_euclid(TAU);
} else if dec < -core::f64::consts::FRAC_PI_2 {
dec = -core::f64::consts::PI - dec;
ra = (ra + core::f64::consts::PI).rem_euclid(TAU);
}
(Radians::new(ra), Radians::new(dec))
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct CatalogFilter {
pub max_g_mag: Option<f64>,
pub require_quality: Option<bool>,
}
pub(super) fn passes_filter(r: &CatalogRecord, f: &CatalogFilter) -> bool {
if let Some(max_g) = f.max_g_mag {
if let Some(g) = r.g_mag {
if g > max_g {
return false;
}
} else {
return false;
}
}
if let Some(q) = f.require_quality {
if r.quality_ok != q {
return false;
}
}
true
}
pub(super) fn inside_cone(
ra: Radians,
dec: Radians,
c_ra: Radians,
c_dec: Radians,
radius: Radians,
) -> bool {
let d_ra = ra.value() - c_ra.value();
let s = (dec.value() - c_dec.value()).sin();
let s2 = (d_ra / 2.0).sin();
let a = (s / 2.0).powi(2) + dec.value().cos() * c_dec.value().cos() * s2 * s2;
let c = 2.0 * a.sqrt().min(1.0).asin();
c <= radius.value()
}