use crate::settings::Settings;
use astronav::{
coords::{dms_to_deg, hms_to_deg, star::AltAzBuilder},
time::{gmst_in_degrees, julian_day_number, julian_time, lmst_in_degrees},
};
use chrono::{DateTime, Datelike, Timelike, Utc};
use std::f64::consts::PI;
fn convert_angle(input: &str, factor_deg: f64, factor_min: f64, factor_sec: f64) -> f64 {
let parts: Vec<&str> = input.split(|c| c == ':' || c == ' ').collect();
let deg: f64 = parts[0].parse().unwrap();
let min: f64 = parts[1].parse().unwrap();
let sec: f64 = parts[2].parse().unwrap();
deg * factor_deg + min * factor_min + sec * factor_sec
}
pub fn convert_hour_angle_to_radians(ra: &str) -> f64 {
convert_angle(ra, 15.0, 15.0 / 60.0, 15.0 / 3600.0) * (PI / 180.0)
}
pub fn convert_dec_to_radians(dec: &str) -> f64 {
convert_angle(dec, 1.0, 1.0 / 60.0, 1.0 / 3600.0) * (PI / 180.0)
}
pub fn convert_hour_angle_to_dec(ra: &str) -> f64 {
convert_angle(ra, 15.0, 15.0 / 60.0, 15.0 / 3600.0)
}
pub fn convert_dec_to_deg(dec: &str) -> f64 {
convert_angle(dec, 1.0, 1.0 / 60.0, 1.0 / 3600.0)
}
pub fn convert_deg_to_radians(deg: f64) -> f64 {
deg * (PI / 180.0)
}
pub fn is_visible(ra: &str, dec: &str, date: DateTime<Utc>) -> bool {
let settings = Settings::new().unwrap();
let longitude = *settings.get_longitude();
let julian_day = julian_day_number(date.day() as u8, date.month() as u8, date.year() as u16);
let julian_time_value = julian_time(
julian_day,
date.hour() as u8,
date.minute() as u8,
date.second() as u8,
0.0,
);
let greenwich_mean = gmst_in_degrees(julian_time_value);
let local_mean = lmst_in_degrees(greenwich_mean, longitude as f64);
let alt = AltAzBuilder::new()
.dec(dms_to_deg(dec).unwrap())
.lat(*settings.get_latitude() as f64)
.lmst(local_mean)
.ra(hms_to_deg(ra).unwrap())
.seal()
.build();
let altitude = alt.get_altitude();
let azimuth = alt.get_azimuth();
let conditions = [
((45.0, 135.0), *settings.get_south_altitude() as f64),
((135.0, 225.0), *settings.get_south_altitude() as f64),
((225.0, 315.0), *settings.get_west_altitude() as f64),
];
if !(45.0..=315.0).contains(&azimuth) && altitude > *settings.get_north_altitude() as f64 {
return true;
}
for &((min_az, max_az), min_alt) in conditions.iter() {
if azimuth > min_az && azimuth < max_az && altitude > min_alt {
return true;
}
}
false
}
#[cfg(test)]
mod test {
use super::*;
use chrono::NaiveDateTime;
#[test]
fn test_is_visible_known_object() {
let naive_dt = NaiveDateTime::parse_from_str("2000-01-01 00:00:00", "%Y-%m-%d %H:%M:%S")
.expect("Invalid date string");
let test_date = DateTime::from_naive_utc_and_offset(naive_dt, Utc);
let ra = "12:0:0";
let dec = "0:0:0";
let object_is_visible = is_visible(ra, dec, test_date);
let _ = object_is_visible;
}
#[test]
fn test_is_not_visible() {
let naive_dt = NaiveDateTime::parse_from_str("2000-01-01 00:00:00", "%Y-%m-%d %H:%M:%S")
.expect("Invalid date string");
let test_date = DateTime::from_naive_utc_and_offset(naive_dt, Utc);
let ra = "12:0:0";
let dec = "-80:0:0"; let object_is_visible = is_visible(ra, dec, test_date);
let _ = object_is_visible;
}
}