use super::*;
use qtty_derive::Unit;
use core::f64::consts::PI;
use crate::units::time::{JulianYear, Second};
use crate::units::velocity::astro::SPEED_OF_LIGHT_M_PER_S;
pub(crate) const AU_IN_METERS: f64 = 149_597_870_700.0;
pub(crate) const ARCSECONDS_PER_RADIAN: f64 = 648_000.0 / PI;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "au", dimension = Length, ratio = AU_IN_METERS)]
pub struct AstronomicalUnit;
pub type Au = AstronomicalUnit;
pub type AstronomicalUnits = Quantity<Au>;
pub const AU: AstronomicalUnits = AstronomicalUnits::new(1.0);
const SECONDS_PER_JULIAN_YEAR: f64 = JulianYear::RATIO / Second::RATIO;
const METERS_PER_LIGHT_YEAR: f64 = SPEED_OF_LIGHT_M_PER_S * SECONDS_PER_JULIAN_YEAR;
const PARSEC_RATIO: f64 = AU_IN_METERS * ARCSECONDS_PER_RADIAN;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "ly", dimension = Length, ratio = METERS_PER_LIGHT_YEAR)]
pub struct LightYear;
pub type Ly = LightYear;
pub type LightYears = Quantity<Ly>;
pub const LY: LightYears = LightYears::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "pc", dimension = Length, ratio = PARSEC_RATIO)]
pub struct Parsec;
pub type Pc = Parsec;
pub type Parsecs = Quantity<Pc>;
pub const PC: Parsecs = Parsecs::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "kpc", dimension = Length, ratio = 1_000.0 * PARSEC_RATIO)]
pub struct Kiloparsec;
pub type Kiloparsecs = Quantity<Kiloparsec>;
pub const KPC: Kiloparsecs = Kiloparsecs::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Mpc", dimension = Length, ratio = 1_000_000.0 * PARSEC_RATIO)]
pub struct Megaparsec;
pub type Megaparsecs = Quantity<Megaparsec>;
pub const MPC: Megaparsecs = Megaparsecs::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Gpc", dimension = Length, ratio = 1_000_000_000.0 * PARSEC_RATIO)]
pub struct Gigaparsec;
pub type Gigaparsecs = Quantity<Gigaparsec>;
pub const GPC: Gigaparsecs = Gigaparsecs::new(1.0);
pub mod nominal {
use super::*;
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Rsun", dimension = Length, ratio = 695_700_000.0)]
pub struct SolarRadius;
pub type SolarRadiuses = Quantity<SolarRadius>;
pub const RSUN: SolarRadiuses = SolarRadiuses::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Rearth", dimension = Length, ratio = 6_371_000.0)]
pub struct EarthRadius;
pub type EarthRadii = Quantity<EarthRadius>;
pub const R_EARTH: EarthRadii = EarthRadii::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Rearth_eq", dimension = Length, ratio = 6_378_137.0)]
pub struct EarthEquatorialRadius;
pub type EarthEquatorialRadii = Quantity<EarthEquatorialRadius>;
pub const R_EARTH_EQ: EarthEquatorialRadii = EarthEquatorialRadii::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Rearth_p", dimension = Length, ratio = 6_356_752.314_2)]
pub struct EarthPolarRadius;
pub type EarthPolarRadii = Quantity<EarthPolarRadius>;
pub const R_EARTH_P: EarthPolarRadii = EarthPolarRadii::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Rmoon", dimension = Length, ratio = 1_737_400.0)]
pub struct LunarRadius;
pub type LunarRadii = Quantity<LunarRadius>;
pub const R_MOON: LunarRadii = LunarRadii::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Rjup", dimension = Length, ratio = 71_492_000.0)]
pub struct JupiterRadius;
pub type JupiterRadii = Quantity<JupiterRadius>;
pub const R_JUPITER: JupiterRadii = JupiterRadii::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "LD", dimension = Length, ratio = 384_400_000.0)]
pub struct LunarDistance;
pub type LunarDistances = Quantity<LunarDistance>;
pub const LD: LunarDistances = LunarDistances::new(1.0);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
#[unit(symbol = "Dsun", dimension = Length, ratio = 2.0 * 695_700_000.0)]
pub struct SolarDiameter;
pub type SolarDiameters = Quantity<SolarDiameter>;
pub const D_SUN: SolarDiameters = SolarDiameters::new(1.0);
crate::impl_unit_from_conversions_between!(
Meter, Decimeter, Centimeter, Millimeter, Micrometer, Nanometer, Picometer, Femtometer,
Attometer, Zeptometer, Yoctometer, Decameter, Hectometer, Kilometer, Megameter, Gigameter,
Terameter, Petameter, Exameter, Zettameter, Yottameter;
SolarRadius, SolarDiameter, EarthRadius, EarthEquatorialRadius, EarthPolarRadius,
LunarRadius, JupiterRadius, LunarDistance
);
#[cfg(feature = "cross-unit-ops")]
crate::impl_unit_cross_unit_ops_between!(
Meter, Decimeter, Centimeter, Millimeter, Micrometer, Nanometer, Picometer, Femtometer,
Attometer, Zeptometer, Yoctometer, Decameter, Hectometer, Kilometer, Megameter, Gigameter,
Terameter, Petameter, Exameter, Zettameter, Yottameter;
SolarRadius, SolarDiameter, EarthRadius, EarthEquatorialRadius, EarthPolarRadius,
LunarRadius, JupiterRadius, LunarDistance
);
}
crate::impl_unit_from_conversions_between!(
Meter, Decimeter, Centimeter, Millimeter, Micrometer, Nanometer, Picometer, Femtometer,
Attometer, Zeptometer, Yoctometer, Decameter, Hectometer, Kilometer, Megameter, Gigameter,
Terameter, Petameter, Exameter, Zettameter, Yottameter;
AstronomicalUnit, LightYear, Parsec, Kiloparsec, Megaparsec, Gigaparsec
);
#[cfg(feature = "cross-unit-ops")]
crate::impl_unit_cross_unit_ops_between!(
Meter, Decimeter, Centimeter, Millimeter, Micrometer, Nanometer, Picometer, Femtometer,
Attometer, Zeptometer, Yoctometer, Decameter, Hectometer, Kilometer, Megameter, Gigameter,
Terameter, Petameter, Exameter, Zettameter, Yottameter;
AstronomicalUnit, LightYear, Parsec, Kiloparsec, Megaparsec, Gigaparsec
);
crate::__impl_from_each_extra_to_bases!(
{AstronomicalUnit, LightYear, Parsec, Kiloparsec, Megaparsec, Gigaparsec}
nominal::SolarRadius, nominal::SolarDiameter, nominal::EarthRadius,
nominal::EarthEquatorialRadius, nominal::EarthPolarRadius,
nominal::JupiterRadius, nominal::LunarRadius, nominal::LunarDistance
);
#[cfg(feature = "cross-unit-ops")]
crate::__impl_cross_ops_each_extra_to_bases!(
{AstronomicalUnit, LightYear, Parsec, Kiloparsec, Megaparsec, Gigaparsec}
nominal::SolarRadius, nominal::SolarDiameter, nominal::EarthRadius,
nominal::EarthEquatorialRadius, nominal::EarthPolarRadius,
nominal::JupiterRadius, nominal::LunarRadius, nominal::LunarDistance
);
#[macro_export]
#[doc(hidden)]
macro_rules! length_nominal_units {
($cb:path) => {
$cb!(
SolarRadius,
SolarDiameter,
EarthRadius,
EarthEquatorialRadius,
EarthPolarRadius,
LunarRadius,
JupiterRadius,
LunarDistance
);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! length_astro_units {
($cb:path) => {
$cb!(
AstronomicalUnit,
LightYear,
Parsec,
Kiloparsec,
Megaparsec,
Gigaparsec,
);
};
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use crate::units::time::{JulianYears, Second};
use approx::{assert_abs_diff_eq, assert_relative_eq};
use proptest::prelude::*;
#[test]
fn astronomical_unit_to_meters() {
let au = AstronomicalUnits::new(1.0);
let meters: Meters = au.to();
assert_abs_diff_eq!(meters.value(), AU_IN_METERS, epsilon = 1e-3);
}
#[test]
fn parsec_to_au() {
let parsec = Parsecs::new(1.0);
let au: AstronomicalUnits = parsec.to();
assert_relative_eq!(au.value(), ARCSECONDS_PER_RADIAN, max_relative = 1e-15);
}
#[test]
fn light_year_matches_c_times_julian_year() {
let julian_year_seconds = JulianYears::new(1.0).to::<Second>();
let expected_meters = SPEED_OF_LIGHT_M_PER_S * julian_year_seconds.value();
let meters: Meters = LightYears::new(1.0).to();
assert_relative_eq!(meters.value(), expected_meters, max_relative = 1e-15);
}
#[test]
fn solar_diameter_is_two_solar_radii() {
let diameter = nominal::SolarDiameters::new(1.0);
let radius: nominal::SolarRadiuses = diameter.to();
assert_abs_diff_eq!(radius.value(), 2.0, epsilon = 1e-12);
}
proptest! {
#[test]
fn au_meter_roundtrip(v in -1.0e6_f64..1.0e6_f64) {
let au = AstronomicalUnits::new(v);
let roundtrip: AstronomicalUnits = au.to::<Meter>().to();
prop_assert!((roundtrip.value() - v).abs() <= v.abs().max(1.0) * 1e-12);
}
}
}