1use core::fmt::{Display, Formatter};
10use core::marker::PhantomData;
11
12use crate::units::angle::Angle;
13use crate::units::FromUnits;
14
15#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
18pub enum RotationDirection {
19 #[default]
22 PositiveClockwise,
23
24 PositiveCounterClockwise,
28}
29
30impl FromUnits<Angle> for RotationDirection {
31 fn from(&self, value: Angle, units: Self) -> Angle {
32 value
33 * match self {
34 RotationDirection::PositiveClockwise => match units {
35 RotationDirection::PositiveClockwise => 1.0,
36 RotationDirection::PositiveCounterClockwise => -1.0,
37 },
38 RotationDirection::PositiveCounterClockwise => match units {
39 RotationDirection::PositiveClockwise => -1.0,
40 RotationDirection::PositiveCounterClockwise => 1.0,
41 },
42 }
43 }
44}
45
46#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
49pub enum CompassReference {
50 #[default]
52 TrueNorth,
53
54 MagneticNorth,
56
57 East,
59}
60
61impl FromUnits<Angle> for CompassReference {
62 fn from(&self, value: Angle, units: Self) -> Angle {
63 match self {
64 CompassReference::TrueNorth => match units {
65 CompassReference::TrueNorth => value,
66 _ => todo!(),
67 },
68 CompassReference::MagneticNorth => match units {
69 CompassReference::MagneticNorth => value,
70 _ => todo!(),
71 },
72 CompassReference::East => match units {
73 CompassReference::East => value,
74 _ => todo!(),
75 },
76 }
77 }
78}
79
80pub type Heading = Compass<HeadingType>;
82
83#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
85pub struct HeadingType;
86
87pub type Track = Compass<TrackType>;
89
90#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
92pub struct TrackType;
93
94pub type Bearing = Compass<BearingType>;
96
97#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
99pub struct BearingType;
100
101pub type Course = Compass<CourseType>;
103
104#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
106pub struct CourseType;
107
108pub type Azimuth = Compass<AzimuthType>;
110
111#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
113pub struct AzimuthType;
114
115#[derive(Debug, Copy, Clone, Default, PartialEq)]
117pub struct Compass<T> {
118 angle: Angle,
119 direction: RotationDirection,
120 reference: CompassReference,
121 _ign: PhantomData<T>,
122}
123
124impl<T> Display for Compass<T> {
125 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
126 write!(
127 f,
128 "{} {:?} {:?}",
129 self.angle, self.direction, self.reference
130 )
131 }
132}
133
134impl<T> Compass<T> {
135 #[must_use]
138 pub const fn new_heading(
139 angle: Angle,
140 direction: RotationDirection,
141 reference: CompassReference,
142 ) -> Compass<HeadingType> {
143 Compass {
144 angle,
145 direction,
146 reference,
147 _ign: PhantomData,
148 }
149 }
150
151 #[must_use]
154 pub const fn new_track(
155 angle: Angle,
156 direction: RotationDirection,
157 reference: CompassReference,
158 ) -> Compass<TrackType> {
159 Compass {
160 angle,
161 direction,
162 reference,
163 _ign: PhantomData,
164 }
165 }
166
167 #[must_use]
170 pub const fn new_bearing(
171 angle: Angle,
172 direction: RotationDirection,
173 reference: CompassReference,
174 ) -> Compass<BearingType> {
175 Compass {
176 angle,
177 direction,
178 reference,
179 _ign: PhantomData,
180 }
181 }
182
183 #[must_use]
186 pub const fn new_course(
187 angle: Angle,
188 direction: RotationDirection,
189 reference: CompassReference,
190 ) -> Compass<CourseType> {
191 Compass {
192 angle,
193 direction,
194 reference,
195 _ign: PhantomData,
196 }
197 }
198
199 #[must_use]
202 pub const fn new_azimuth(
203 angle: Angle,
204 direction: RotationDirection,
205 reference: CompassReference,
206 ) -> Compass<AzimuthType> {
207 Compass {
208 angle,
209 direction,
210 reference,
211 _ign: PhantomData,
212 }
213 }
214
215 #[must_use]
216 pub const fn angle(&self) -> &Angle {
217 &self.angle
218 }
219
220 #[must_use]
221 pub const fn direction(&self) -> &RotationDirection {
222 &self.direction
223 }
224
225 #[must_use]
226 pub const fn reference(&self) -> &CompassReference {
227 &self.reference
228 }
229
230 #[must_use]
231 pub fn as_direction_reference(
232 &self,
233 direction: RotationDirection,
234 reference: CompassReference,
235 ) -> Compass<T> {
236 let angle = direction.from(self.angle, self.direction);
237 let angle = reference.from(angle, self.reference);
238 Compass {
239 angle,
240 direction,
241 reference,
242 _ign: PhantomData,
243 }
244 }
245}
246
247#[derive(Debug, Clone, PartialEq)]
252pub struct CompassOffset<T, B> {
253 compass: Compass<T>,
254 offset: Angle,
255 direction: RotationDirection,
256 _ign: PhantomData<B>,
257}
258
259impl<T, B> CompassOffset<T, B> {
260 #[must_use]
261 pub fn compass(&self) -> &Compass<T> {
262 &self.compass
263 }
264
265 #[must_use]
266 pub fn offset(&self) -> &Angle {
267 &self.offset
268 }
269
270 #[must_use]
271 pub fn direction(&self) -> &RotationDirection {
272 &self.direction
273 }
274}
275
276pub type RelativeBearing = CompassOffset<HeadingType, BearingType>;
278
279impl Compass<HeadingType> {
280 #[must_use]
283 pub fn relative_bearing(self, direction: RotationDirection, offset: Angle) -> RelativeBearing {
284 CompassOffset {
285 compass: self,
286 offset,
287 direction,
288 _ign: PhantomData,
289 }
290 }
291}
292
293#[derive(Debug, Copy, Clone, PartialEq)]
297pub enum CompassDirection {
298 Heading(Heading),
299 Track(Track),
300 Bearing(Bearing),
301 Course(Course),
302 Azimuth(Azimuth),
303}
304
305impl Display for CompassDirection {
306 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
307 match self {
308 CompassDirection::Heading(h) => {
309 write!(f, "Heading({h})")
310 }
311 CompassDirection::Track(t) => {
312 write!(f, "Track({t})")
313 }
314 CompassDirection::Bearing(b) => {
315 write!(f, "Bearing({b})")
316 }
317 CompassDirection::Course(c) => {
318 write!(f, "Course({c})")
319 }
320 CompassDirection::Azimuth(a) => {
321 write!(f, "Azimuth({a})")
322 }
323 }
324 }
325}