#[derive(Debug, Clone, PartialEq)]
pub struct HipparcosStar {
pub hip: u32,
pub ra_rad: f64,
pub dec_rad: f64,
pub pm_ra: f64,
pub pm_dec: f64,
pub hpmag: f32,
pub b_v: f32,
}
impl HipparcosStar {
pub fn hp_to_v(&self) -> f32 {
let b = self.b_v;
let delta = 0.304 * b - 0.202 * b * b + 0.107 * b * b * b - 0.045 * b * b * b * b;
self.hpmag - delta
}
}
fn parse_hipparcos_star(record: &str) -> Option<HipparcosStar> {
if record.len() < 158 {
return None;
}
Some(HipparcosStar {
hip: record[0..6].trim().parse().ok()?,
ra_rad: record[15..28].trim().parse().ok()?,
dec_rad: record[29..42].trim().parse().ok()?,
pm_ra: record[51..59].trim().parse().ok()?,
pm_dec: record[60..68].trim().parse().ok()?,
hpmag: record[129..136].trim().parse().ok()?,
b_v: record[152..158].trim().parse().ok()?,
})
}
pub fn load_hipparcos_catalog(data: &str) -> Vec<HipparcosStar> {
data.lines().filter_map(parse_hipparcos_star).collect()
}
pub fn load_hipparcos_catalog_from_file<P: AsRef<std::path::Path>>(
path: P,
) -> crate::Result<Vec<HipparcosStar>> {
let data = std::fs::read_to_string(path)?;
let total_lines = data.lines().filter(|l| !l.trim().is_empty()).count();
let stars = load_hipparcos_catalog(&data);
if total_lines > 0 && stars.is_empty() {
return Err(crate::error::Error::InvalidCatalog(format!(
"Hipparcos catalog: parsed 0 stars from {total_lines} non-empty lines (wrong format?)"
)));
}
let dropped = total_lines - stars.len();
if dropped > 0 {
tracing::warn!("Hipparcos catalog: skipped {dropped} unparseable line(s)");
}
Ok(stars)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore]
fn load_hipparcos_from_file() {
let fname = "data/hip2.dat";
let data = std::fs::read_to_string(fname).expect("Failed to read Hipparcos catalog file");
let stars = load_hipparcos_catalog(&data);
assert!(!stars.is_empty());
}
}