pub mod position;
pub use position::Position;
pub mod direction;
pub use direction::Direction;
#[inline]
pub fn canonicalize_azimuth(angle: qtty::angular::Degrees) -> qtty::angular::Degrees {
angle.normalize()
}
#[inline]
pub fn canonicalize_polar(angle: qtty::angular::Degrees) -> qtty::angular::Degrees {
let wrapped = angle.wrap_signed(); let v = wrapped.value();
if v > 90.0 {
qtty::angular::Degrees::new(180.0 - v)
} else if v < -90.0 {
qtty::angular::Degrees::new(-180.0 - v)
} else {
wrapped
}
}
#[inline]
#[must_use]
pub fn canonicalize_polar_azimuth(
polar: qtty::angular::Degrees,
azimuth: qtty::angular::Degrees,
) -> (qtty::angular::Degrees, qtty::angular::Degrees) {
use qtty::angular::Degrees;
let wrapped = polar.wrap_signed();
let v = wrapped.value();
let mut azimuth_deg = azimuth.value();
let polar = if v > 90.0 {
azimuth_deg += 180.0;
Degrees::new(180.0 - v)
} else if v < -90.0 {
azimuth_deg += 180.0;
Degrees::new(-180.0 - v)
} else {
wrapped
};
(polar, Degrees::new(azimuth_deg).normalize())
}
#[inline]
pub(crate) fn xyz_to_polar_azimuth(
x: f64,
y: f64,
z: f64,
) -> (qtty::angular::Degrees, qtty::angular::Degrees) {
use qtty::angular::Degrees;
let z_clamped = z.clamp(-1.0, 1.0);
let polar = Degrees::new(z_clamped.asin().to_degrees());
let azimuth = Degrees::new(y.atan2(x).to_degrees()).normalize();
(polar, azimuth)
}
#[inline]
pub(crate) fn angular_separation_impl(
polar1: qtty::angular::Degrees,
azimuth1: qtty::angular::Degrees,
polar2: qtty::angular::Degrees,
azimuth2: qtty::angular::Degrees,
) -> qtty::angular::Degrees {
use qtty::angular::Radians;
use qtty::units::{Degree, Radian};
let az1 = azimuth1.to::<Radian>();
let po1 = polar1.to::<Radian>();
let az2 = azimuth2.to::<Radian>();
let po2 = polar2.to::<Radian>();
let x = (po1.cos() * po2.sin()) - (po1.sin() * po2.cos() * (az2 - az1).cos());
let y = po2.cos() * (az2 - az1).sin();
let z = (po1.sin() * po2.sin()) + (po1.cos() * po2.cos() * (az2 - az1).cos());
let angle_rad = (x * x + y * y).sqrt().atan2(z);
Radians::new(angle_rad).to::<Degree>()
}