use std::f64::consts;
use super::frac;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Angle(f64);
impl Angle {
#[inline]
pub const fn from_rad(r: f64) -> Self { Self(r) }
#[inline]
pub fn from_deg(d: f64) -> Self { Self(d.to_radians()) }
#[inline]
pub fn from_pi_frac(fraction: f64) -> Self { Self(fraction * consts::PI) }
pub fn from_dms(d: i16, m: u8, s: f32) -> Self {
let sign = if d < 0 { -1.0_f64 } else { 1.0_f64 };
let ddd = (d as f64) + sign * ((m as f64) / 60.0) + sign * ((s as f64) / 3600.0);
Self::from_deg(ddd)
}
pub fn to_dms(self) -> (i16, u8, f32) {
let ddd = self.deg();
let sign = ddd.signum();
let abs_ddd = ddd.abs();
let d = (abs_ddd.floor() * sign) as i16;
let m_float = (abs_ddd - abs_ddd.floor()) * 60.0;
let m = m_float.floor() as u8;
let s = ((m_float - m_float.floor()) * 60.0) as f32;
(d, m, s)
}
#[inline]
pub const fn rad(self) -> f64 { self.0 }
#[inline]
pub fn deg(self) -> f64 { self.0.to_degrees() }
#[inline]
pub fn pi_frac(self) -> (f64, f64) { frac::as_frac_pi(self.0) }
pub fn print_rad(self) -> String { format!("{:.4} rad", self.rad()) }
pub fn print_deg(self) -> String { format!("{:.2}°", self.deg()) }
pub fn print_pi_frac(self) -> String {
let (num, den) = self.pi_frac();
if num == 0.0 {
return "0".to_string();
}
if den == 1.0 {
return format!("{} π", num);
}
format!("{} / {} π", num, den)
}
}
#[rustfmt::skip] #[inline] pub const fn rad(r: f64) -> Angle { Angle::from_rad(r) }
#[rustfmt::skip] #[inline] pub fn deg(d: f64) -> Angle { Angle::from_deg(d) }
#[rustfmt::skip] #[inline] pub fn pi_frac(fraction: f64) -> Angle { Angle::from_pi_frac(fraction) }
pub trait AngleExt {
fn deg(self) -> Angle;
fn rad(self) -> Angle;
fn pi_frac(self) -> Angle;
}
impl AngleExt for f64 {
#[rustfmt::skip] #[inline] fn deg(self) -> Angle { Angle::from_deg(self) }
#[rustfmt::skip] #[inline] fn rad(self) -> Angle { Angle::from_rad(self) }
#[rustfmt::skip] #[inline] fn pi_frac(self) -> Angle { Angle::from_pi_frac(self) }
}
#[derive(Debug, Clone, Copy, Default)]
pub enum AngleFmt {
#[default]
Deg,
Rad,
PiFrac,
}
impl AngleFmt {
#[rustfmt::skip] #[inline]
pub fn format(&self, val: f64) -> String {
match self {
Self::Rad => Angle::from_rad(val).print_rad(),
Self::Deg => Angle::from_rad(val).print_deg(),
Self::PiFrac => Angle::from_rad(val).print_pi_frac(),
}
}
}