use std::f64::consts::{PI, TAU};
const GON_RAD: f64 = PI / 200.;
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Angle {
rad: f64,
}
impl Angle {
pub fn from_rad(rad: f64) -> Self {
Self { rad }
}
pub fn from_deg(deg: f64) -> Self {
Self::from_rad(deg.to_radians())
}
pub fn from_rev(rev: f64) -> Self {
Self::from_rad(rev * TAU)
}
pub fn from_gon(gon: f64) -> Self {
Self::from_rad(gon * GON_RAD)
}
pub fn rad(&self) -> f64 {
self.rad
}
pub fn deg(&self) -> f64 {
self.rad.to_degrees()
}
pub fn rev(&self) -> f64 {
self.rad / TAU
}
pub fn gon(&self) -> f64 {
self.rad / GON_RAD
}
pub fn normalized(&self) -> Self {
Self {
rad: Self::wrap(self.rad),
}
}
fn wrap(rad: f64) -> f64 {
let modulo = rad % TAU;
if modulo < 0. {
TAU + modulo
} else {
modulo
}
}
}
impl std::ops::Add for Angle {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::from_rad(self.rad + rhs.rad)
}
}
impl std::ops::AddAssign for Angle {
fn add_assign(&mut self, rhs: Self) {
self.rad += rhs.rad;
}
}
impl std::ops::Sub for Angle {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::from_rad(self.rad - rhs.rad)
}
}
impl std::ops::SubAssign for Angle {
fn sub_assign(&mut self, rhs: Self) {
self.rad -= rhs.rad;
}
}
impl std::ops::Mul<f64> for Angle {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Self::from_rad(self.rad * rhs)
}
}
impl std::ops::Mul<Angle> for f64 {
type Output = Angle;
fn mul(self, rhs: Angle) -> Self::Output {
rhs * self
}
}
impl std::ops::MulAssign<f64> for Angle {
fn mul_assign(&mut self, rhs: f64) {
self.rad *= rhs;
}
}
impl std::ops::Div<f64> for Angle {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self::from_rad(self.rad / rhs)
}
}
impl std::ops::DivAssign<f64> for Angle {
fn div_assign(&mut self, rhs: f64) {
self.rad /= rhs;
}
}
impl std::ops::Div for Angle {
type Output = f64;
fn div(self, rhs: Self) -> Self::Output {
self.rad / rhs.rad
}
}