measures/inner/exact/
signed_direction.rs

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