use core::fmt;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Angle(f64);
impl Angle {
pub const fn from_degrees(degrees: f64) -> Self {
Self(degrees)
}
pub fn from_radians(radians: f64) -> Self {
Self(radians.to_degrees())
}
pub const fn degrees(self) -> f64 {
self.0
}
pub fn radians(self) -> f64 {
self.0.to_radians()
}
pub fn normalized_0_360(self) -> Self {
Self(self.0.rem_euclid(360.0))
}
pub fn normalized_signed(self) -> Self {
let degrees = self.normalized_0_360().degrees();
if degrees >= 180.0 {
Self(degrees - 360.0)
} else {
Self(degrees)
}
}
pub const fn is_finite(self) -> bool {
self.0.is_finite()
}
}
impl fmt::Display for Angle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}°", self.0)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Longitude(Angle);
impl Longitude {
pub fn from_degrees(degrees: f64) -> Self {
Self(Angle::from_degrees(degrees).normalized_0_360())
}
pub const fn degrees(self) -> f64 {
self.0.degrees()
}
pub const fn angle(self) -> Angle {
self.0
}
}
impl From<Angle> for Longitude {
fn from(value: Angle) -> Self {
Self::from_degrees(value.degrees())
}
}
impl fmt::Display for Longitude {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Latitude(Angle);
impl Latitude {
pub const fn from_degrees(degrees: f64) -> Self {
Self(Angle::from_degrees(degrees))
}
pub const fn degrees(self) -> f64 {
self.0.degrees()
}
pub const fn angle(self) -> Angle {
self.0
}
}
impl From<Angle> for Latitude {
fn from(value: Angle) -> Self {
Self::from_degrees(value.degrees())
}
}
impl fmt::Display for Latitude {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}