#[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 column(record: &[u8], range: std::ops::Range<usize>) -> Option<&str> {
std::str::from_utf8(record.get(range)?).ok()
}
fn parse_hipparcos_star(record: &str) -> Option<HipparcosStar> {
let bytes = record.as_bytes();
if bytes.len() < 158 {
return None;
}
Some(HipparcosStar {
hip: column(bytes, 0..6)?.trim().parse().ok()?,
ra_rad: column(bytes, 15..28)?.trim().parse().ok()?,
dec_rad: column(bytes, 29..42)?.trim().parse().ok()?,
pm_ra: column(bytes, 51..59)?.trim().parse().ok()?,
pm_dec: column(bytes, 60..68)?.trim().parse().ok()?,
hpmag: column(bytes, 129..136)?.trim().parse().ok()?,
b_v: column(bytes, 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]
fn multibyte_utf8_line_is_skipped_not_panicked() {
let mut line = String::from(" 12é"); line.push_str(&" ".repeat(160));
assert!(parse_hipparcos_star(&line).is_none());
let junk = "é".repeat(100);
assert!(parse_hipparcos_star(&junk).is_none());
}
#[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());
}
}