1#[macro_export] macro_rules! inner_define_signed_direction {
3 { $with_points:ident } => {
4 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 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 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 pub fn from_measure_point(m: MeasurePoint<Unit, Number>) -> Self {
46 Self::new(m.value)
47 }
48
49 pub const fn to_measure_point(self) -> MeasurePoint<Unit, Number> {
51 MeasurePoint::<Unit, Number>::new(self.value)
52 }
53 }
54
55 pub fn to_unsigned_direction(self) -> UnsignedDirection<Unit, Number> {
57 UnsignedDirection::<Unit, Number>::new(self.value)
58 }
59
60 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 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 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 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 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 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 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 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 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 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 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 fn cos(self) -> Self::Output {
209 self.convert::<Radian>().value.cos()
210 }
211
212 fn sin(self) -> Self::Output {
214 self.convert::<Radian>().value.sin()
215 }
216
217 fn tan(self) -> Self::Output {
219 self.convert::<Radian>().value.tan()
220 }
221
222 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 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 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 fn clone(&self) -> Self {
257 *self
258 }
259 }
260
261 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 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 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}