/// Convert RA/Dec to Altitude/Azimuth. /// All inputs and outputs in degrees. pub fn radec_to_altaz( ra_deg: f64, dec_deg: f64, lst_deg: f64, lat_deg: f64, ) -> (f64, f64) { let ha = (lst_deg - ra_deg).rem_euclid(360.0); let ha_rad = ha.to_radians(); let dec_rad = dec_deg.to_radians(); let lat_rad = lat_deg.to_radians(); let sin_alt = dec_rad.sin() * lat_rad.sin() + dec_rad.cos() * lat_rad.cos() * ha_rad.cos(); let alt_rad = sin_alt.asin(); let cos_az = (dec_rad.sin() - lat_rad.sin() * sin_alt) / (lat_rad.cos() * alt_rad.cos()); let cos_az = cos_az.clamp(-1.0, 1.0); let az_rad = cos_az.acos(); let az_deg = if ha_rad.sin() < 0.0 { az_rad.to_degrees() } else { 360.0 - az_rad.to_degrees() }; (alt_rad.to_degrees(), az_deg) } /// Rozenberg airmass formula — valid to horizon. pub fn airmass(alt_deg: f64) -> f64 { if alt_deg <= 0.0 { return 40.0; // clamp at horizon } let z_rad = (90.0 - alt_deg).to_radians(); 1.0 / (z_rad.cos() + 0.025 * (-11.0 * z_rad.cos()).exp()) } /// Extinction in magnitudes. k = 0.20 mag/airmass (Bortle 5 site). pub fn extinction_mag(alt_deg: f64) -> f64 { airmass(alt_deg) * 0.20 }