1use core::fmt;
4
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[derive(Clone, Copy, Debug, Default, PartialEq)]
12pub struct Angle(f64);
13
14impl Angle {
15 pub const fn from_degrees(degrees: f64) -> Self {
17 Self(degrees)
18 }
19
20 pub fn from_radians(radians: f64) -> Self {
22 Self(radians.to_degrees())
23 }
24
25 pub const fn degrees(self) -> f64 {
27 self.0
28 }
29
30 pub fn radians(self) -> f64 {
32 self.0.to_radians()
33 }
34
35 pub fn normalized_0_360(self) -> Self {
37 Self(self.0.rem_euclid(360.0))
38 }
39
40 pub fn normalized_signed(self) -> Self {
42 let degrees = self.normalized_0_360().degrees();
43 if degrees >= 180.0 {
44 Self(degrees - 360.0)
45 } else {
46 Self(degrees)
47 }
48 }
49
50 pub const fn is_finite(self) -> bool {
52 self.0.is_finite()
53 }
54}
55
56impl fmt::Display for Angle {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 write!(f, "{}°", self.0)
59 }
60}
61
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
64#[derive(Clone, Copy, Debug, Default, PartialEq)]
65pub struct Longitude(Angle);
66
67impl Longitude {
68 pub fn from_degrees(degrees: f64) -> Self {
70 Self(Angle::from_degrees(degrees).normalized_0_360())
71 }
72
73 pub const fn degrees(self) -> f64 {
75 self.0.degrees()
76 }
77
78 pub const fn angle(self) -> Angle {
80 self.0
81 }
82}
83
84impl From<Angle> for Longitude {
85 fn from(value: Angle) -> Self {
86 Self::from_degrees(value.degrees())
87 }
88}
89
90impl fmt::Display for Longitude {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 fmt::Display::fmt(&self.0, f)
93 }
94}
95
96#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103#[derive(Clone, Copy, Debug, Default, PartialEq)]
104pub struct Latitude(Angle);
105
106impl Latitude {
107 pub const fn from_degrees(degrees: f64) -> Self {
109 Self(Angle::from_degrees(degrees))
110 }
111
112 pub const fn degrees(self) -> f64 {
114 self.0.degrees()
115 }
116
117 pub const fn angle(self) -> Angle {
119 self.0
120 }
121}
122
123impl From<Angle> for Latitude {
124 fn from(value: Angle) -> Self {
125 Self::from_degrees(value.degrees())
126 }
127}
128
129impl fmt::Display for Latitude {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 fmt::Display::fmt(&self.0, f)
132 }
133}