#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs)]
#[cfg(feature = "chrono_0_4")]
use chrono::{DateTime, Datelike, Offset, TimeZone, Timelike};
use crate::errors::{SpaError, MESSAGES};
use crate::spa::{Function, Input, SpaData, Std};
mod earth_periodic_terms;
mod constants;
mod nutation_obliquity_periodic_terms;
pub mod utils;
pub mod spa;
pub mod errors;
pub struct SpaBuilder<T: Clone> {
input: Input<T>,
}
impl SpaBuilder<Std> {
pub fn new() -> SpaBuilder<Std> {
SpaBuilder {
input: Input::new_std(),
}
}
}
impl<T: Clone> SpaBuilder<T> {
#[cfg(feature = "chrono_0_4")]
#[cfg_attr(docsrs, doc(cfg(feature = "chrono_0_4")))]
pub fn from_date_time(date_time: DateTime<T>) -> Self
where T: TimeZone {
let mut input = Input::new_tz(date_time.timezone());
input.year= date_time.year() as i64;
input.month = date_time.month() as i64;
input.day = date_time.day() as i64;
input.hour = date_time.hour() as i64;
input.minute = date_time.minute() as i64;
input.second = date_time.second() as f64 + date_time.nanosecond() as f64 / 1_000_000_000f64;
input.timezone = date_time.offset().fix().local_minus_utc() as f64 / 3600.0;
Self {
input,
}
}
pub fn from_input(input: Input<T>) -> Self {
Self {
input,
}
}
#[cfg(feature = "chrono_0_4")]
#[cfg_attr(docsrs, doc(cfg(feature = "chrono_0_4")))]
pub fn date_time(mut self, date_time: DateTime<T>) -> Self
where T: TimeZone {
self.input.year= date_time.year() as i64;
self.input.month = date_time.month() as i64;
self.input.day = date_time.day() as i64;
self.input.hour = date_time.hour() as i64;
self.input.minute = date_time.minute() as i64;
self.input.second = date_time.second() as f64 + date_time.nanosecond() as f64 / 1_000_000_000f64;
self.input.timezone = date_time.offset().fix().local_minus_utc() as f64 / 3600.0;
self.input.tz = date_time.timezone();
self
}
pub fn date(mut self, year: i64, month: i64, day: i64) -> Result<Self, SpaError> {
if year < -2000 || year > 6000 { return Err(SpaError{ code: 1, message: MESSAGES[1] }) };
if month < 1 || month > 12 { return Err(SpaError{ code: 2, message: MESSAGES[2] }) };
if day < 1 || day > 31 { return Err(SpaError{ code: 3, message: MESSAGES[3] }) };
self.input.year = year;
self.input.month = month;
self.input.day = day;
Ok(self)
}
pub fn time(mut self, hour: i64, minute: i64, second: f64) -> Result<Self, SpaError> {
if hour < 0 || hour > 24 { return Err(SpaError{ code: 4, message: MESSAGES[4] }) };
if minute < 0 || minute > 59 { return Err(SpaError{ code: 5, message: MESSAGES[5] }) };
if second < 0.0 || second >=60.0 { return Err(SpaError{ code: 6, message: MESSAGES[6] }) };
if hour == 24 && minute > 0 { return Err(SpaError{ code: 5, message: MESSAGES[5] }) };
if hour == 24 && second > 0.0 { return Err(SpaError{ code: 6, message: MESSAGES[6] }) };
self.input.hour = hour;
self.input.minute = minute;
self.input.second = second;
Ok(self)
}
pub fn timezone(mut self, timezone: f64) -> Result<Self, SpaError> {
if timezone.abs() > 18.0 { return Err(SpaError{ code: 8, message: MESSAGES[8] }) };
self.input.timezone = timezone;
Ok(self)
}
pub fn lat_long(mut self, latitude: f64, longitude: f64) -> Result<Self, SpaError> {
if longitude.abs() > 180.0 { return Err(SpaError{ code: 9, message: MESSAGES[9] }) };
if latitude.abs() > 90.0 { return Err(SpaError{ code: 10, message: MESSAGES[10] }) };
self.input.latitude = latitude;
self.input.longitude = longitude;
Ok(self)
}
pub fn pressure(mut self, pressure: f64) -> Result<Self, SpaError> {
if pressure < 0.0 || pressure > 5000.0 { return Err(SpaError{ code: 12, message: MESSAGES[12] }) };
self.input.pressure = pressure;
Ok(self)
}
pub fn temperature(mut self, temperature: f64) -> Result<Self, SpaError> {
if temperature <= -273.0 || temperature > 6000.0 { return Err(SpaError{ code: 13, message: MESSAGES[13] }) };
self.input.temperature = temperature;
Ok(self)
}
pub fn atmospheric_refraction(mut self, atmos_refract: f64) -> Result<Self, SpaError> {
if atmos_refract.abs() > 5.0 { return Err(SpaError{ code: 16, message: MESSAGES[16] }) };
self.input.atmos_refract = atmos_refract;
Ok(self)
}
pub fn elevation(mut self, elevation: f64) -> Result<Self, SpaError> {
if elevation < -6500000.0 { return Err(SpaError{ code: 11, message: MESSAGES[11] }) };
self.input.elevation = elevation;
Ok(self)
}
pub fn slope(mut self, slope: f64) -> Result<Self, SpaError> {
if slope.abs() > 360.0 { return Err(SpaError{ code: 14, message: MESSAGES[14] }) };
self.input.slope = slope;
Ok(self)
}
pub fn azimuth_rotation(mut self, azm_rotation: f64) -> Result<Self, SpaError> {
if azm_rotation.abs() > 360.0 { return Err(SpaError{ code: 15, message: MESSAGES[15] }) };
self.input.azm_rotation = azm_rotation;
Ok(self)
}
pub fn delta_ut1(mut self, delta_ut1: f64) -> Result<Self, SpaError> {
if delta_ut1 <= -1.0 || delta_ut1 >= 1.0 { return Err(SpaError{ code: 17, message: MESSAGES[17] }) };
self.input.delta_ut1 = delta_ut1;
Ok(self)
}
pub fn delta_t(mut self, delta_t: f64) -> Result<Self, SpaError> {
if delta_t.abs() > 8000.0 { return Err(SpaError{ code: 7, message: MESSAGES[7] }) };
self.input.delta_t = delta_t;
Ok(self)
}
pub fn execute(mut self, function: Function) -> Result<SpaData<T>, SpaError> {
self.input.function = function;
let mut spa_data = SpaData::new(self.input);
spa_data.spa_calculate()?;
Ok(spa_data)
}
}