measures/inner/exact/
unsigned_direction.rs

1#[macro_export] // Don't add nor remove the first three lines and the last two lines.
2macro_rules! inner_define_unsigned_direction {
3    { $with_points:ident } => {
4        /// Direction in a plane, represented by an angle with value
5        /// between zero (included) and a cycle (excluded),
6        /// with generic angular unit of measurement, generic value type,
7        /// and with a dynamic value.
8        pub struct UnsignedDirection<Unit, Number = f64>
9        where
10            Unit: AngleMeasurementUnit,
11            Number: ArithmeticOps,
12        {
13            pub value: Number,
14            phantom: PhantomData<Unit>,
15        }
16
17        impl<Unit, Number> UnsignedDirection<Unit, Number>
18        where
19            Unit: AngleMeasurementUnit,
20            Number: ArithmeticOps,
21        {
22            // Returns the only value that in the current Unit represents `x` and
23            // is between minus half cycle (included) and plus half cycle (excluded).
24            fn normalize(x: Number) -> Number {
25                let one_cycle = Number::from_f64(Unit::CYCLE_FRACTION);
26                let x2 = x % one_cycle;
27                if x2 >= Number::ZERO {
28                    x2
29                } else {
30                    x2 + one_cycle
31                }
32            }
33
34            /// UnsignedDirection::new(Number) -> UnsignedDirection
35            pub fn new(value: Number) -> Self {
36                Self {
37                    value: Self::normalize(value),
38                    phantom: PhantomData,
39                }
40            }
41
42            measures::if_all_true! { { $with_points }
43                /// UnsignedDirection::from_measure_point(MeasurePoint) -> UnsignedDirection
44                pub fn from_measure_point(m: MeasurePoint<Unit, Number>) -> Self {
45                    Self::new(m.value)
46                }
47
48                /// UnsignedDirection.to_measure_point() -> MeasurePoint
49                pub const fn to_measure_point(self) -> MeasurePoint<Unit, Number> {
50                    MeasurePoint::<Unit, Number>::new(self.value)
51                }
52            }
53
54            /// UnsignedDirection.to_signed_direction() -> SignedDirection
55            pub fn to_signed_direction(self) -> SignedDirection<Unit, Number> {
56                SignedDirection::<Unit, Number>::new(self.value)
57            }
58
59            /// UnsignedDirection.convert() -> UnsignedDirection
60            pub fn convert<DestUnit>(self) -> UnsignedDirection<DestUnit, Number>
61            where
62                DestUnit: AngleMeasurementUnit<Property = Unit::Property>,
63            {
64                UnsignedDirection::<DestUnit, Number> {
65                    value: self.value * Number::from_f64(Unit::RATIO / DestUnit::RATIO)
66                        + Number::from_f64((Unit::OFFSET - DestUnit::OFFSET) / DestUnit::RATIO),
67                    phantom: PhantomData,
68                }
69            }
70
71            /// UnsignedDirection.lossless_into() -> UnsignedDirection
72            pub fn lossless_into<DestNumber>(self) -> UnsignedDirection<Unit, DestNumber>
73            where
74                DestNumber: ArithmeticOps + From<Number>,
75            {
76                UnsignedDirection::<Unit, DestNumber>::new(DestNumber::from(self.value))
77            }
78
79            /// UnsignedDirection.lossy_into() -> UnsignedDirection
80            pub fn lossy_into<DestNumber>(self) -> UnsignedDirection<Unit, DestNumber>
81            where
82                DestNumber: ArithmeticOps + LossyFrom<Number>,
83            {
84                UnsignedDirection::<Unit, DestNumber> {
85                    value: DestNumber::lossy_from(self.value),
86                    phantom: PhantomData,
87                }
88            }
89        }
90
91        impl<Unit, Number> Default for UnsignedDirection<Unit, Number>
92        where
93            Unit: AngleMeasurementUnit,
94            Number: ArithmeticOps,
95        {
96            /// UnsignedDirection::default() -> UnsignedDirection
97            /// It returns the zero direction (to the right).
98            fn default() -> Self {
99                Self::new(Number::ZERO)
100            }
101        }
102
103        measures::if_all_true! { { $with_points }
104            impl<Unit, Number> From<UnsignedDirection<Unit, Number>> for MeasurePoint<Unit, Number>
105            where
106                Unit: AngleMeasurementUnit,
107                Number: ArithmeticOps,
108            {
109                /// MeasurePoint::from(UnsignedDirection) -> MeasurePoint
110                /// UnsignedDirection.into() -> MeasurePoint
111                fn from(m: UnsignedDirection<Unit, Number>) -> Self {
112                    MeasurePoint::<Unit, Number>::new(m.value)
113                }
114            }
115        }
116
117        impl<Unit> From<UnsignedDirection<Unit, f32>> for UnsignedDirection<Unit, f64>
118        where
119            Unit: AngleMeasurementUnit,
120        {
121            /// UnsignedDirection<f64>::from(UnsignedDirection<f32>) -> UnsignedDirection<f64>
122            /// UnsignedDirection<f32>.into() -> UnsignedDirection<f64>
123            fn from(m: UnsignedDirection<Unit, f32>) -> Self {
124                Self::new(m.value as f64)
125            }
126        }
127
128        impl<Unit, Number> Add<Measure<Unit, Number>> for UnsignedDirection<Unit, Number>
129        where
130            Unit: AngleMeasurementUnit,
131            Number: ArithmeticOps,
132        {
133            type Output = Self;
134
135            /// UnsignedDirection + AngleMeasure -> UnsignedDirection
136            fn add(self, other: Measure<Unit, Number>) -> Self::Output {
137                Self::new(self.value + other.value)
138            }
139        }
140
141        impl<Unit, Number> AddAssign<Measure<Unit, Number>> for UnsignedDirection<Unit, Number>
142        where
143            Unit: AngleMeasurementUnit,
144            Number: ArithmeticOps,
145        {
146            /// UnsignedDirection += AngleMeasure
147            fn add_assign(&mut self, other: Measure<Unit, Number>) {
148                *self = *self + other;
149            }
150        }
151
152        impl<Unit, Number> Sub<Measure<Unit, Number>> for UnsignedDirection<Unit, Number>
153        where
154            Unit: AngleMeasurementUnit,
155            Number: ArithmeticOps,
156        {
157            type Output = Self;
158
159            /// UnsignedDirection - AngleMeasure -> UnsignedDirection
160            fn sub(self, other: Measure<Unit, Number>) -> Self::Output {
161                Self::new(self.value - other.value)
162            }
163        }
164
165        impl<Unit, Number> SubAssign<Measure<Unit, Number>> for UnsignedDirection<Unit, Number>
166        where
167            Unit: AngleMeasurementUnit,
168            Number: ArithmeticOps,
169        {
170            /// UnsignedDirection -= AngleMeasure
171            fn sub_assign(&mut self, other: Measure<Unit, Number>) {
172                *self = *self - other;
173            }
174        }
175
176        impl<Unit, Number> Sub<UnsignedDirection<Unit, Number>> for UnsignedDirection<Unit, Number>
177        where
178            Unit: AngleMeasurementUnit,
179            Number: ArithmeticOps,
180        {
181            type Output = Measure<Unit, Number>;
182
183            /// UnsignedDirection - UnsignedDirection -> AngleMeasure
184            fn sub(self, other: UnsignedDirection<Unit, Number>) -> Self::Output {
185                let diff = self.value - other.value;
186                let cycle = Number::from_f64(Unit::CYCLE_FRACTION);
187                let half_cycle = cycle * Number::HALF;
188                Self::Output::new(if diff > half_cycle {
189                    diff - cycle
190                } else if diff < -half_cycle {
191                    diff + cycle
192                } else {
193                    diff
194                })
195            }
196        }
197
198        impl<Unit, Number> Trigonometry for UnsignedDirection<Unit, Number>
199        where
200            Unit: AngleMeasurementUnit,
201            Number: ArithmeticOps,
202        {
203            type Output = Number;
204
205            /// UnsignedDirection.cos() -> Number
206            fn cos(self) -> Self::Output {
207                self.convert::<Radian>().value.cos()
208            }
209
210            /// UnsignedDirection.sin() -> Number
211            fn sin(self) -> Self::Output {
212                self.convert::<Radian>().value.sin()
213            }
214
215            /// UnsignedDirection.tan() -> Number
216            fn tan(self) -> Self::Output {
217                self.convert::<Radian>().value.tan()
218            }
219
220            /// UnsignedDirection.sin_cos() -> (Number, Number)
221            fn sin_cos(self) -> (Self::Output, Self::Output) {
222                self.convert::<Radian>().value.sin_cos()
223            }
224        }
225
226        impl<Unit, Number> PartialEq<UnsignedDirection<Unit, Number>> for UnsignedDirection<Unit, Number>
227        where
228            Unit: AngleMeasurementUnit,
229            Number: ArithmeticOps,
230        {
231            /// UnsignedDirection == UnsignedDirection -> bool
232            fn eq(&self, other: &UnsignedDirection<Unit, Number>) -> bool {
233                self.value == other.value
234            }
235        }
236
237        impl<Unit, Number> PartialOrd<UnsignedDirection<Unit, Number>> for UnsignedDirection<Unit, Number>
238        where
239            Unit: AngleMeasurementUnit,
240            Number: ArithmeticOps,
241        {
242            /// UnsignedDirection < UnsignedDirection -> bool
243            fn partial_cmp(&self, other: &UnsignedDirection<Unit, Number>) -> Option<core::cmp::Ordering> {
244                self.value.partial_cmp(&other.value)
245            }
246        }
247
248        impl<Unit, Number> Clone for UnsignedDirection<Unit, Number>
249        where
250            Unit: AngleMeasurementUnit,
251            Number: ArithmeticOps,
252        {
253            /// UnsignedDirection.clone() -> UnsignedDirection
254            fn clone(&self) -> Self {
255                *self
256            }
257        }
258
259        /// UnsignedDirection = UnsignedDirection
260        impl<Unit, Number> Copy for UnsignedDirection<Unit, Number>
261        where
262            Unit: AngleMeasurementUnit,
263            Number: ArithmeticOps,
264        {
265        }
266
267        impl<Unit, Number> fmt::Display for UnsignedDirection<Unit, Number>
268        where
269            Unit: AngleMeasurementUnit,
270            Number: ArithmeticOps,
271        {
272            /// format!("{}", UnsignedDirection) -> String
273            /// UnsignedDirection.to_string() -> String
274            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
275                formatter.write_str("at ")?;
276                fmt::Display::fmt(&self.value, formatter)?;
277                formatter.write_str(Unit::SUFFIX)?;
278                formatter.write_str(" (in 0°..360°)")
279            }
280        }
281
282        impl<Unit, Number> fmt::Debug for UnsignedDirection<Unit, Number>
283        where
284            Unit: AngleMeasurementUnit,
285            Number: ArithmeticOps,
286        {
287            /// format!("{:?}", UnsignedDirection) -> String
288            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
289                formatter.write_str("at ")?;
290                fmt::Display::fmt(&self.value, formatter)?;
291                formatter.write_str(Unit::SUFFIX)?;
292                formatter.write_str(" (in 0°..360°)")
293            }
294        }
295    };
296}