use crate::units::angular::{Degree, Milliradian, Radian};
use crate::{Prod, Quantity, Unit};
#[cfg(feature = "astro")]
use crate::units::angular::{Arcminute, Arcsecond};
pub use crate::dimension::SolidAngle;
pub trait SolidAngleUnit: Unit<Dim = SolidAngle> {}
impl<T: Unit<Dim = SolidAngle>> SolidAngleUnit for T {}
pub type SolidAngleOf<A> = Quantity<Prod<A, A>>;
pub type SquareDegree = Prod<Degree, Degree>;
pub type SquareDegrees = Quantity<SquareDegree>;
pub type Steradian = Prod<Radian, Radian>;
pub type Steradians = Quantity<Steradian>;
pub type SquareMilliradian = Prod<Milliradian, Milliradian>;
pub type SquareMilliradians = Quantity<SquareMilliradian>;
#[cfg(feature = "astro")]
pub type SquareArcminute = Prod<Arcminute, Arcminute>;
#[cfg(feature = "astro")]
pub type SquareArcminutes = Quantity<SquareArcminute>;
#[cfg(feature = "astro")]
pub type SquareArcsecond = Prod<Arcsecond, Arcsecond>;
#[cfg(feature = "astro")]
pub type SquareArcseconds = Quantity<SquareArcsecond>;
#[macro_export]
#[doc(hidden)]
macro_rules! solid_angle_units {
($cb:path) => {
$cb!(SquareDegree, Steradian, SquareMilliradian);
};
}
solid_angle_units!(crate::impl_unit_from_conversions);
#[cfg(feature = "cross-unit-ops")]
solid_angle_units!(crate::impl_unit_cross_unit_ops);
#[cfg(feature = "astro")]
crate::impl_unit_from_conversions_between!(
SquareDegree, Steradian, SquareMilliradian;
SquareArcminute, SquareArcsecond
);
#[cfg(all(feature = "astro", feature = "cross-unit-ops"))]
crate::impl_unit_cross_unit_ops_between!(
SquareDegree, Steradian, SquareMilliradian;
SquareArcminute, SquareArcsecond
);
#[cfg(feature = "astro")]
#[macro_export]
#[doc(hidden)]
macro_rules! solid_angle_astro_units {
($cb:path) => {
$cb!(SquareArcminute, SquareArcsecond);
};
}
#[cfg(all(test, feature = "astro"))]
solid_angle_astro_units!(crate::assert_units_are_builtin);
#[cfg(test)]
solid_angle_units!(crate::assert_units_are_builtin);
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use crate::angular::{Degrees, Radians};
use approx::assert_relative_eq;
const STERADIAN_IN_SQDEG: f64 =
(180.0 / core::f64::consts::PI) * (180.0 / core::f64::consts::PI);
#[test]
fn square_degree_is_canonical() {
assert_eq!(SquareDegree::RATIO, 1.0);
}
#[test]
fn steradian_to_square_degree_ratio() {
assert_relative_eq!(Steradian::RATIO, STERADIAN_IN_SQDEG, max_relative = 1e-12);
}
#[test]
fn radian_squared_is_steradian() {
let r = Radians::new(1.0);
let omega: Steradians = r * r;
assert_relative_eq!(omega.value(), 1.0, max_relative = 1e-12);
}
#[test]
fn degree_squared_is_square_degree() {
let d = Degrees::new(3.0);
let omega: SquareDegrees = d * d;
assert_relative_eq!(omega.value(), 9.0, max_relative = 1e-12);
}
#[test]
fn steradian_to_square_degree_conversion() {
let sr = Steradians::new(1.0);
let sqd: SquareDegrees = sr.to();
assert_relative_eq!(sqd.value(), STERADIAN_IN_SQDEG, max_relative = 1e-12);
}
#[test]
fn full_sphere_in_square_degrees() {
let full = Steradians::new(4.0 * core::f64::consts::PI);
let sqd: SquareDegrees = full.to();
assert_relative_eq!(sqd.value(), 41_252.961_249_419_3, max_relative = 1e-9);
}
#[test]
#[cfg(feature = "astro")]
fn square_arcsecond_to_steradian() {
let one = Quantity::<SquareArcsecond>::new(1.0);
let sr: Steradians = one.to();
let expected = (core::f64::consts::PI / (180.0 * 3600.0)).powi(2);
assert_relative_eq!(sr.value(), expected, max_relative = 1e-12);
}
#[test]
#[cfg(feature = "astro")]
fn square_arcminute_in_square_degrees() {
let one = Quantity::<SquareArcminute>::new(3600.0);
let sqd: SquareDegrees = one.to();
assert_relative_eq!(sqd.value(), 1.0, max_relative = 1e-12);
}
#[test]
fn square_milliradian_to_steradian() {
let one = Quantity::<SquareMilliradian>::new(1.0);
let sr: Steradians = one.to();
assert_relative_eq!(sr.value(), 1e-6, max_relative = 1e-12);
}
}