use geometry_cs::{CartesianFamily, CoordinateSystem, GeographicFamily, SphericalFamily};
#[cfg(feature = "std")]
use geometry_tag::SameAs;
use geometry_trait::Point;
pub trait AzimuthStrategy<P1: Point, P2: Point> {
type Out;
fn azimuth(&self, p1: &P1, p2: &P2) -> Self::Out;
}
pub trait DefaultAzimuth<Family> {
type Strategy: Default;
}
impl DefaultAzimuth<CartesianFamily> for CartesianFamily {
type Strategy = CartesianAzimuth;
}
impl DefaultAzimuth<SphericalFamily> for SphericalFamily {
type Strategy = crate::spherical::SphericalAzimuth;
}
impl DefaultAzimuth<GeographicFamily> for GeographicFamily {
type Strategy = crate::geographic::GeographicAzimuth;
}
pub type DefaultAzimuthStrategy<P> =
<<<P as Point>::Cs as CoordinateSystem>::Family as DefaultAzimuth<
<<P as Point>::Cs as CoordinateSystem>::Family,
>>::Strategy;
#[derive(Debug, Default, Clone, Copy)]
pub struct CartesianAzimuth;
#[cfg(feature = "std")]
impl<P1, P2> AzimuthStrategy<P1, P2> for CartesianAzimuth
where
P1: Point<Scalar = f64>,
P2: Point<Scalar = f64>,
<P1::Cs as CoordinateSystem>::Family: SameAs<CartesianFamily>,
<P2::Cs as CoordinateSystem>::Family: SameAs<CartesianFamily>,
{
type Out = f64;
#[inline]
fn azimuth(&self, p1: &P1, p2: &P2) -> f64 {
let dx = p2.get::<0>() - p1.get::<0>();
let dy = p2.get::<1>() - p1.get::<1>();
dx.atan2(dy)
}
}
#[cfg(test)]
mod tests {
use super::{AzimuthStrategy, CartesianAzimuth};
use geometry_cs::Cartesian;
use geometry_model::Point2D;
type P = Point2D<f64, Cartesian>;
#[test]
fn north_is_zero() {
let a = P::new(0.0, 0.0);
let b = P::new(0.0, 1.0);
assert!((CartesianAzimuth.azimuth(&a, &b) - 0.0).abs() < 1e-12);
}
#[test]
fn east_is_half_pi() {
let a = P::new(0.0, 0.0);
let b = P::new(1.0, 0.0);
assert!((CartesianAzimuth.azimuth(&a, &b) - core::f64::consts::FRAC_PI_2).abs() < 1e-12);
}
#[test]
fn west_is_minus_half_pi() {
let a = P::new(0.0, 0.0);
let b = P::new(-1.0, 0.0);
assert!((CartesianAzimuth.azimuth(&a, &b) + core::f64::consts::FRAC_PI_2).abs() < 1e-12);
}
#[test]
fn diagonal_is_quarter_pi() {
let a = P::new(0.0, 0.0);
let b = P::new(1.0, 1.0);
assert!((CartesianAzimuth.azimuth(&a, &b) - core::f64::consts::FRAC_PI_4).abs() < 1e-12);
}
#[test]
fn northwest_diagonal_is_minus_quarter_pi() {
let a = P::new(0.0, 0.0);
let b = P::new(-1.0, 1.0);
assert!((CartesianAzimuth.azimuth(&a, &b) + core::f64::consts::FRAC_PI_4).abs() < 1e-12);
}
}