1use {
2 crate::{Quaternion, UnitQuaternion, Q32, Q64, UQ32, UQ64},
3 core::ops::{
4 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
5 },
6 num_traits::{Inv, Num, Zero},
7};
8
9#[cfg(feature = "unstable")]
10use crate::{PureQuaternion, PQ32, PQ64};
11
12impl<T> Add<Quaternion<T>> for Quaternion<T>
13where
14 T: Add<T, Output = T>,
15{
16 type Output = Quaternion<T>;
17
18 #[inline]
19 fn add(self, rhs: Quaternion<T>) -> Self::Output {
20 Self::new(
21 self.w + rhs.w,
22 self.x + rhs.x,
23 self.y + rhs.y,
24 self.z + rhs.z,
25 )
26 }
27}
28
29impl<T> Add<T> for Quaternion<T>
30where
31 T: Add<T, Output = T>,
32{
33 type Output = Quaternion<T>;
34
35 #[inline]
36 fn add(self, rhs: T) -> Self::Output {
37 Self::new(self.w + rhs, self.x, self.y, self.z)
38 }
39}
40
41impl<T> Add<UnitQuaternion<T>> for Quaternion<T>
42where
43 T: Add<T, Output = T>,
44{
45 type Output = Quaternion<T>;
46
47 #[inline]
48 fn add(self, rhs: UnitQuaternion<T>) -> Self {
49 self + rhs.into_inner()
50 }
51}
52
53#[cfg(feature = "unstable")]
54impl<T> Add<PureQuaternion<T>> for Quaternion<T>
55where
56 T: Add<T, Output = T>,
57{
58 type Output = Quaternion<T>;
59
60 #[inline]
61 fn add(self, rhs: PureQuaternion<T>) -> Self::Output {
62 Self::new(self.w, self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
63 }
64}
65
66impl<T> Sub<Quaternion<T>> for Quaternion<T>
67where
68 T: Sub<T, Output = T>,
69{
70 type Output = Quaternion<T>;
71
72 #[inline]
73 fn sub(self, rhs: Quaternion<T>) -> Self::Output {
74 Self::new(
75 self.w - rhs.w,
76 self.x - rhs.x,
77 self.y - rhs.y,
78 self.z - rhs.z,
79 )
80 }
81}
82
83impl<T> Sub<T> for Quaternion<T>
84where
85 T: Sub<T, Output = T>,
86{
87 type Output = Quaternion<T>;
88
89 #[inline]
90 fn sub(self, rhs: T) -> Self::Output {
91 Self::new(self.w - rhs, self.x, self.y, self.z)
92 }
93}
94
95impl<T> Sub<UnitQuaternion<T>> for Quaternion<T>
96where
97 T: Sub<T, Output = T>,
98{
99 type Output = Quaternion<T>;
100
101 #[inline]
102 fn sub(self, rhs: UnitQuaternion<T>) -> Self {
103 self - rhs.into_inner()
104 }
105}
106
107#[cfg(feature = "unstable")]
108impl<T> Sub<PureQuaternion<T>> for Quaternion<T>
109where
110 T: Sub<T, Output = T>,
111{
112 type Output = Quaternion<T>;
113
114 #[inline]
115 fn sub(self, rhs: PureQuaternion<T>) -> Self::Output {
116 Self::new(self.w, self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
117 }
118}
119
120impl<T> Mul<Quaternion<T>> for Quaternion<T>
121where
122 T: Add<T, Output = T> + Sub<T, Output = T> + Mul<T, Output = T> + Clone,
123{
124 type Output = Quaternion<T>;
125
126 #[inline]
127 fn mul(self, rhs: Quaternion<T>) -> Self::Output {
128 let a = self.w.clone() * rhs.w.clone()
129 - self.x.clone() * rhs.x.clone()
130 - self.y.clone() * rhs.y.clone()
131 - self.z.clone() * rhs.z.clone();
132 let b = self.w.clone() * rhs.x.clone()
133 + self.x.clone() * rhs.w.clone()
134 + self.y.clone() * rhs.z.clone()
135 - self.z.clone() * rhs.y.clone();
136 let c = self.w.clone() * rhs.y.clone() - self.x.clone() * rhs.z.clone()
137 + self.y.clone() * rhs.w.clone()
138 + self.z.clone() * rhs.x.clone();
139 let d =
140 self.w * rhs.z + self.x * rhs.y - self.y * rhs.x + self.z * rhs.w;
141 Self::new(a, b, c, d)
142 }
143}
144
145impl<T> Mul<T> for Quaternion<T>
146where
147 T: Mul<T, Output = T> + Clone,
148{
149 type Output = Quaternion<T>;
150
151 #[inline]
152 fn mul(self, rhs: T) -> Self::Output {
153 Self::new(
154 self.w * rhs.clone(),
155 self.x * rhs.clone(),
156 self.y * rhs.clone(),
157 self.z * rhs,
158 )
159 }
160}
161
162impl<T> Mul<UnitQuaternion<T>> for Quaternion<T>
163where
164 Quaternion<T>: Mul<Output = Quaternion<T>>,
165{
166 type Output = Quaternion<T>;
167
168 #[inline]
169 fn mul(self, rhs: UnitQuaternion<T>) -> Self::Output {
170 self * rhs.into_inner()
171 }
172}
173
174#[cfg(feature = "unstable")]
175impl<T> Mul<PureQuaternion<T>> for Quaternion<T>
176where
177 T: Neg<Output = T>
178 + Add<T, Output = T>
179 + Sub<T, Output = T>
180 + Mul<T, Output = T>
181 + Neg<Output = T>
182 + Clone,
183{
184 type Output = Quaternion<T>;
185
186 #[inline]
187 #[rustfmt::skip]
188 fn mul(self, rhs: PureQuaternion<T>) -> Self::Output {
189 let a = - self.x.clone() * rhs.x.clone()
190 - self.y.clone() * rhs.y.clone()
191 - self.z.clone() * rhs.z.clone();
192 let b = self.w.clone() * rhs.x.clone()
193 + self.y.clone() * rhs.z.clone()
194 - self.z.clone() * rhs.y.clone();
195 let c = self.w.clone() * rhs.y.clone()
196 - self.x.clone() * rhs.z.clone()
197 + self.z.clone() * rhs.x.clone();
198 let d = self.w * rhs.z
199 + self.x * rhs.y
200 - self.y * rhs.x;
201 Self::new(a, b, c, d)
202 }
203}
204
205impl<T> Div<Quaternion<T>> for Quaternion<T>
206where
207 T: Num + Clone + Neg<Output = T>,
208{
209 type Output = Quaternion<T>;
210
211 #[allow(clippy::suspicious_arithmetic_impl)]
212 #[inline]
213 fn div(self, rhs: Quaternion<T>) -> Self {
214 self * rhs.inv()
215 }
216}
217
218impl<T> Div<T> for Quaternion<T>
219where
220 T: Div<T, Output = T> + Clone,
221{
222 type Output = Quaternion<T>;
223
224 #[inline]
225 fn div(self, rhs: T) -> Self::Output {
226 Self::new(
227 self.w / rhs.clone(),
228 self.x / rhs.clone(),
229 self.y / rhs.clone(),
230 self.z / rhs,
231 )
232 }
233}
234
235impl<T> Div<UnitQuaternion<T>> for Quaternion<T>
236where
237 Quaternion<T>: Mul<Output = Quaternion<T>>,
238 T: Neg<Output = T> + Clone,
239{
240 type Output = Quaternion<T>;
241
242 #[allow(clippy::suspicious_arithmetic_impl)]
243 #[inline]
244 fn div(self, rhs: UnitQuaternion<T>) -> Self::Output {
245 self * rhs.into_inner().conj()
246 }
247}
248
249#[cfg(feature = "unstable")]
250impl<T> Div<PureQuaternion<T>> for Quaternion<T>
251where
252 T: Num + Clone + Neg<Output = T>,
253{
254 type Output = Quaternion<T>;
255
256 #[allow(clippy::suspicious_arithmetic_impl)]
257 #[inline]
258 fn div(self, rhs: PureQuaternion<T>) -> Self::Output {
259 self * rhs.inv()
260 }
261}
262
263macro_rules! impl_bin_op_assign {
264 (impl $bin_op_assign_trait:ident::$bin_op_assign:ident as $bin_op_trait:ident::$bin_op:ident for $generic:ident) => {
265 impl<T, S> $bin_op_assign_trait<S> for $generic<T>
266 where
267 Self: $bin_op_trait<S, Output = Self> + Clone,
268 {
269 #[inline]
270 fn $bin_op_assign(&mut self, other: S) {
271 *self = self.clone().$bin_op(other);
272 }
273 }
274 };
275}
276
277impl_bin_op_assign!(impl AddAssign::add_assign as Add::add for Quaternion);
278impl_bin_op_assign!(impl SubAssign::sub_assign as Sub::sub for Quaternion);
279impl_bin_op_assign!(impl MulAssign::mul_assign as Mul::mul for Quaternion);
280impl_bin_op_assign!(impl DivAssign::div_assign as Div::div for Quaternion);
281
282macro_rules! impl_op_with_ref {
283 (impl<$T:ident> $bin_op_trait:ident::$bin_op:ident for $lhs_type:ty, $rhs_type:ty) => {
284 impl<$T> $bin_op_trait<&$rhs_type> for $lhs_type
285 where
286 Self: $bin_op_trait<$rhs_type>,
287 $rhs_type: Clone,
288 {
289 type Output = <Self as $bin_op_trait<$rhs_type>>::Output;
290
291 fn $bin_op(self, rhs: &$rhs_type) -> Self::Output {
292 self.$bin_op(rhs.clone())
293 }
294 }
295
296 impl<$T> $bin_op_trait<&$rhs_type> for &$lhs_type
297 where
298 $lhs_type: $bin_op_trait<$rhs_type> + Clone,
299 $rhs_type: Clone,
300 {
301 type Output = <$lhs_type as $bin_op_trait<$rhs_type>>::Output;
302
303 fn $bin_op(self, rhs: &$rhs_type) -> Self::Output {
304 self.clone().$bin_op(rhs.clone())
305 }
306 }
307
308 impl<$T> $bin_op_trait<$rhs_type> for &$lhs_type
309 where
310 $lhs_type: $bin_op_trait<$rhs_type> + Clone,
311 {
312 type Output = <$lhs_type as $bin_op_trait<$rhs_type>>::Output;
313
314 fn $bin_op(self, rhs: $rhs_type) -> Self::Output {
315 self.clone().$bin_op(rhs)
316 }
317 }
318 };
319}
320
321impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, Quaternion<T>);
322impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, Quaternion<T>);
323impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, Quaternion<T>);
324impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, Quaternion<T>);
325impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, UnitQuaternion<T>);
326impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, UnitQuaternion<T>);
327impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, UnitQuaternion<T>);
328impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, UnitQuaternion<T>);
329impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, T);
330impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, T);
331impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, T);
332impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, T);
333#[cfg(feature = "unstable")]
334impl_op_with_ref!(impl<T> Add::add for Quaternion<T>, PureQuaternion<T>);
335#[cfg(feature = "unstable")]
336impl_op_with_ref!(impl<T> Sub::sub for Quaternion<T>, PureQuaternion<T>);
337#[cfg(feature = "unstable")]
338impl_op_with_ref!(impl<T> Mul::mul for Quaternion<T>, PureQuaternion<T>);
339#[cfg(feature = "unstable")]
340impl_op_with_ref!(impl<T> Div::div for Quaternion<T>, PureQuaternion<T>);
341
342macro_rules! impl_ops_lhs_real {
343 ($($real:ty),*) => {
344 $(
345 impl Add<Quaternion<$real>> for $real {
346 type Output = Quaternion<$real>;
347
348 #[inline]
349 fn add(self, mut rhs: Quaternion<$real>) -> Self::Output {
350 rhs.w += self;
351 rhs
352 }
353 }
354
355 impl Sub<Quaternion<$real>> for $real {
356 type Output = Quaternion<$real>;
357
358 #[inline]
359 fn sub(self, rhs: Quaternion<$real>) -> Self::Output {
360 let zero = <$real>::zero();
361 Quaternion::new(self - rhs.w, zero - rhs.x, zero - rhs.y, zero - rhs.z)
362 }
363 }
364
365 impl Mul<Quaternion<$real>> for $real {
366 type Output = Quaternion<$real>;
367
368 #[inline]
369 fn mul(self, rhs: Quaternion<$real>) -> Self::Output {
370 Quaternion::new(self * rhs.w, self * rhs.x, self * rhs.y, self * rhs.z)
371 }
372 }
373 )*
374 };
375}
376
377impl_ops_lhs_real!(
378 usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64
379);
380
381impl Div<Q32> for f32 {
382 type Output = Q32;
383
384 #[inline]
385 fn div(mut self, rhs: Q32) -> Self::Output {
386 self /= rhs.norm_sqr();
387 Quaternion::new(
388 self * rhs.w,
389 self * -rhs.x,
390 self * -rhs.y,
391 self * -rhs.z,
392 )
393 }
394}
395
396impl Div<Q64> for f64 {
397 type Output = Q64;
398
399 #[inline]
400 fn div(mut self, rhs: Q64) -> Self::Output {
401 self /= rhs.norm_sqr();
402 Quaternion::new(
403 self * rhs.w,
404 self * -rhs.x,
405 self * -rhs.y,
406 self * -rhs.z,
407 )
408 }
409}
410
411impl<T> Neg for Quaternion<T>
412where
413 T: Neg<Output = T>,
414{
415 type Output = Self;
416
417 #[inline]
418 fn neg(self) -> Self::Output {
419 Self::new(-self.w, -self.x, -self.y, -self.z)
420 }
421}
422
423impl<T> Add<UnitQuaternion<T>> for UnitQuaternion<T>
424where
425 Quaternion<T>: Add<Output = Quaternion<T>>,
426{
427 type Output = Quaternion<T>;
428
429 #[inline]
430 fn add(self, rhs: UnitQuaternion<T>) -> Self::Output {
431 self.into_inner() + rhs.into_inner()
432 }
433}
434
435impl<T> Add<Quaternion<T>> for UnitQuaternion<T>
436where
437 Quaternion<T>: Add<Output = Quaternion<T>>,
438{
439 type Output = Quaternion<T>;
440
441 #[inline]
442 fn add(self, rhs: Quaternion<T>) -> Self::Output {
443 self.into_inner() + rhs
444 }
445}
446
447impl<T> Add<T> for UnitQuaternion<T>
448where
449 Quaternion<T>: Add<T, Output = Quaternion<T>>,
450{
451 type Output = Quaternion<T>;
452
453 #[inline]
454 fn add(self, rhs: T) -> Self::Output {
455 self.into_inner() + rhs
456 }
457}
458
459impl Add<UQ32> for f32 {
460 type Output = Q32;
461
462 #[inline]
463 fn add(self, rhs: UQ32) -> Self::Output {
464 self + rhs.into_inner()
465 }
466}
467
468impl Add<UQ64> for f64 {
469 type Output = Q64;
470
471 #[inline]
472 fn add(self, rhs: UQ64) -> Self::Output {
473 self + rhs.into_inner()
474 }
475}
476
477#[cfg(feature = "unstable")]
478impl<T> Add<PureQuaternion<T>> for UnitQuaternion<T>
479where
480 Quaternion<T>: Add<PureQuaternion<T>, Output = Quaternion<T>>,
481{
482 type Output = Quaternion<T>;
483
484 #[inline]
485 fn add(self, rhs: PureQuaternion<T>) -> Self::Output {
486 self.into_inner() + rhs
487 }
488}
489
490impl<T> Sub<UnitQuaternion<T>> for UnitQuaternion<T>
491where
492 Quaternion<T>: Sub<Output = Quaternion<T>>,
493{
494 type Output = Quaternion<T>;
495
496 #[inline]
497 fn sub(self, rhs: UnitQuaternion<T>) -> Self::Output {
498 self.into_inner() - rhs.into_inner()
499 }
500}
501
502impl<T> Sub<Quaternion<T>> for UnitQuaternion<T>
503where
504 Quaternion<T>: Sub<Output = Quaternion<T>>,
505{
506 type Output = Quaternion<T>;
507
508 #[inline]
509 fn sub(self, rhs: Quaternion<T>) -> Self::Output {
510 self.into_inner() - rhs
511 }
512}
513
514impl<T> Sub<T> for UnitQuaternion<T>
515where
516 Quaternion<T>: Sub<T, Output = Quaternion<T>>,
517{
518 type Output = Quaternion<T>;
519
520 #[inline]
521 fn sub(self, rhs: T) -> Self::Output {
522 self.into_inner() - rhs
523 }
524}
525
526impl Sub<UQ32> for f32 {
527 type Output = Q32;
528
529 #[inline]
530 fn sub(self, rhs: UQ32) -> Self::Output {
531 self - rhs.into_inner()
532 }
533}
534
535impl Sub<UQ64> for f64 {
536 type Output = Q64;
537
538 #[inline]
539 fn sub(self, rhs: UQ64) -> Self::Output {
540 self - rhs.into_inner()
541 }
542}
543
544#[cfg(feature = "unstable")]
545impl<T> Sub<PureQuaternion<T>> for UnitQuaternion<T>
546where
547 Quaternion<T>: Sub<PureQuaternion<T>, Output = Quaternion<T>>,
548{
549 type Output = Quaternion<T>;
550
551 #[inline]
552 fn sub(self, rhs: PureQuaternion<T>) -> Self::Output {
553 self.into_inner() - rhs
554 }
555}
556
557impl<T> Mul<Quaternion<T>> for UnitQuaternion<T>
558where
559 Quaternion<T>: Mul<Output = Quaternion<T>>,
560{
561 type Output = Quaternion<T>;
562
563 #[inline]
564 fn mul(self, rhs: Quaternion<T>) -> Self::Output {
565 self.into_inner() * rhs
566 }
567}
568
569impl<T> Mul<T> for UnitQuaternion<T>
570where
571 Quaternion<T>: Mul<T, Output = Quaternion<T>>,
572{
573 type Output = Quaternion<T>;
574
575 #[inline]
576 fn mul(self, rhs: T) -> Self::Output {
577 self.into_inner() * rhs
578 }
579}
580
581impl Mul<UQ32> for f32 {
582 type Output = Q32;
583
584 #[inline]
585 fn mul(self, rhs: UQ32) -> Self::Output {
586 self * rhs.into_inner()
587 }
588}
589
590impl Mul<UQ64> for f64 {
591 type Output = Q64;
592
593 #[inline]
594 fn mul(self, rhs: UQ64) -> Self::Output {
595 self * rhs.into_inner()
596 }
597}
598
599#[cfg(feature = "unstable")]
600impl<T> Mul<PureQuaternion<T>> for UnitQuaternion<T>
601where
602 Quaternion<T>: Mul<PureQuaternion<T>, Output = Quaternion<T>>,
603{
604 type Output = Quaternion<T>;
605
606 #[inline]
607 fn mul(self, rhs: PureQuaternion<T>) -> Self::Output {
608 self.into_inner() * rhs
609 }
610}
611
612impl<T> Div<UnitQuaternion<T>> for UnitQuaternion<T>
613where
614 Quaternion<T>: Mul<Output = Quaternion<T>>,
615 T: Clone + Neg<Output = T>,
616{
617 type Output = UnitQuaternion<T>;
618
619 #[allow(clippy::suspicious_arithmetic_impl)]
620 #[inline]
621 fn div(self, rhs: UnitQuaternion<T>) -> Self::Output {
622 self * rhs.conj()
623 }
624}
625
626impl<T> Div<Quaternion<T>> for UnitQuaternion<T>
627where
628 Quaternion<T>: Div<Output = Quaternion<T>>,
629{
630 type Output = Quaternion<T>;
631
632 #[inline]
633 fn div(self, rhs: Quaternion<T>) -> Self::Output {
634 self.into_inner() / rhs
635 }
636}
637
638impl<T> Div<T> for UnitQuaternion<T>
639where
640 Quaternion<T>: Div<T, Output = Quaternion<T>>,
641{
642 type Output = Quaternion<T>;
643
644 #[inline]
645 fn div(self, rhs: T) -> Self::Output {
646 self.into_inner() / rhs
647 }
648}
649
650impl Div<UQ32> for f32 {
651 type Output = Q32;
652
653 #[allow(clippy::suspicious_arithmetic_impl)]
654 #[inline]
655 fn div(self, rhs: UQ32) -> Self::Output {
656 self * rhs.inv().into_inner()
657 }
658}
659
660impl Div<UQ64> for f64 {
661 type Output = Q64;
662
663 #[allow(clippy::suspicious_arithmetic_impl)]
664 #[inline]
665 fn div(self, rhs: UQ64) -> Self::Output {
666 self * rhs.inv().into_inner()
667 }
668}
669
670#[cfg(feature = "unstable")]
671impl<T> Div<PureQuaternion<T>> for UnitQuaternion<T>
672where
673 Quaternion<T>: Div<PureQuaternion<T>, Output = Quaternion<T>>,
674{
675 type Output = Quaternion<T>;
676
677 #[inline]
678 fn div(self, rhs: PureQuaternion<T>) -> Self::Output {
679 self.into_inner() / rhs
680 }
681}
682
683impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, UnitQuaternion<T>);
684impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, UnitQuaternion<T>);
685impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, UnitQuaternion<T>);
686impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, UnitQuaternion<T>);
687impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, Quaternion<T>);
688impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, Quaternion<T>);
689impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, Quaternion<T>);
690impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, Quaternion<T>);
691impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, T);
692impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, T);
693impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, T);
694impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, T);
695#[cfg(feature = "unstable")]
696impl_op_with_ref!(impl<T> Add::add for UnitQuaternion<T>, PureQuaternion<T>);
697#[cfg(feature = "unstable")]
698impl_op_with_ref!(impl<T> Sub::sub for UnitQuaternion<T>, PureQuaternion<T>);
699#[cfg(feature = "unstable")]
700impl_op_with_ref!(impl<T> Mul::mul for UnitQuaternion<T>, PureQuaternion<T>);
701#[cfg(feature = "unstable")]
702impl_op_with_ref!(impl<T> Div::div for UnitQuaternion<T>, PureQuaternion<T>);
703
704impl_bin_op_assign!(impl MulAssign::mul_assign as Mul::mul for UnitQuaternion);
705impl_bin_op_assign!(impl DivAssign::div_assign as Div::div for UnitQuaternion);
706
707#[cfg(feature = "unstable")]
708impl<T> Add<PureQuaternion<T>> for PureQuaternion<T>
709where
710 T: Add<T, Output = T>,
711{
712 type Output = PureQuaternion<T>;
713
714 #[inline]
715 fn add(self, rhs: PureQuaternion<T>) -> Self::Output {
716 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
717 }
718}
719
720#[cfg(feature = "unstable")]
721impl<T> Add<Quaternion<T>> for PureQuaternion<T>
722where
723 T: Add<T, Output = T>,
724{
725 type Output = Quaternion<T>;
726
727 #[inline]
728 fn add(self, rhs: Quaternion<T>) -> Self::Output {
729 Quaternion::new(rhs.w, self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
730 }
731}
732
733#[cfg(feature = "unstable")]
734impl<T> Add<T> for PureQuaternion<T> {
735 type Output = Quaternion<T>;
736
737 #[inline]
738 fn add(self, rhs: T) -> Self::Output {
739 Self::Output::new(rhs, self.x, self.y, self.z)
740 }
741}
742
743#[cfg(feature = "unstable")]
744impl<T> Add<UnitQuaternion<T>> for PureQuaternion<T>
745where
746 T: Add<T, Output = T>,
747{
748 type Output = Quaternion<T>;
749
750 #[inline]
751 fn add(self, rhs: UnitQuaternion<T>) -> Self::Output {
752 self + rhs.into_inner()
753 }
754}
755
756#[cfg(feature = "unstable")]
757impl Add<PQ32> for f32 {
758 type Output = Q32;
759
760 #[inline]
761 fn add(self, rhs: PQ32) -> Self::Output {
762 Self::Output::new(self, rhs.x, rhs.y, rhs.z)
763 }
764}
765
766#[cfg(feature = "unstable")]
767impl Add<PQ64> for f64 {
768 type Output = Q64;
769
770 #[inline]
771 fn add(self, rhs: PQ64) -> Self::Output {
772 Self::Output::new(self, rhs.x, rhs.y, rhs.z)
773 }
774}
775
776#[cfg(feature = "unstable")]
777impl<T> Sub<PureQuaternion<T>> for PureQuaternion<T>
778where
779 T: Sub<T, Output = T>,
780{
781 type Output = PureQuaternion<T>;
782
783 #[inline]
784 fn sub(self, rhs: PureQuaternion<T>) -> Self::Output {
785 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
786 }
787}
788
789#[cfg(feature = "unstable")]
790impl<T> Sub<Quaternion<T>> for PureQuaternion<T>
791where
792 T: Sub<T, Output = T> + Neg<Output = T>,
793{
794 type Output = Quaternion<T>;
795
796 #[inline]
797 fn sub(self, rhs: Quaternion<T>) -> Self::Output {
798 Quaternion::new(-rhs.w, self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
799 }
800}
801
802#[cfg(feature = "unstable")]
803impl<T> Sub<T> for PureQuaternion<T>
804where
805 T: Neg<Output = T>,
806{
807 type Output = Quaternion<T>;
808
809 #[inline]
810 fn sub(self, rhs: T) -> Self::Output {
811 Self::Output::new(-rhs, self.x, self.y, self.z)
812 }
813}
814
815#[cfg(feature = "unstable")]
816impl<T> Sub<UnitQuaternion<T>> for PureQuaternion<T>
817where
818 T: Sub<T, Output = T> + Neg<Output = T>,
819{
820 type Output = Quaternion<T>;
821
822 #[inline]
823 fn sub(self, rhs: UnitQuaternion<T>) -> Self::Output {
824 self - rhs.into_inner()
825 }
826}
827
828#[cfg(feature = "unstable")]
829impl Sub<PQ32> for f32 {
830 type Output = Q32;
831
832 #[inline]
833 fn sub(self, rhs: PQ32) -> Self::Output {
834 Self::Output::new(self, -rhs.x, -rhs.y, -rhs.z)
835 }
836}
837
838#[cfg(feature = "unstable")]
839impl Sub<PQ64> for f64 {
840 type Output = Q64;
841
842 #[inline]
843 fn sub(self, rhs: PQ64) -> Self::Output {
844 Self::Output::new(self, -rhs.x, -rhs.y, -rhs.z)
845 }
846}
847
848#[cfg(feature = "unstable")]
849impl<T> Mul<PureQuaternion<T>> for PureQuaternion<T>
850where
851 T: Neg<Output = T>
852 + Add<T, Output = T>
853 + Sub<T, Output = T>
854 + Mul<T, Output = T>
855 + Clone,
856{
857 type Output = Quaternion<T>;
858
859 #[inline]
860 #[rustfmt::skip]
861 fn mul(self, rhs: PureQuaternion<T>) -> Self::Output {
862 Quaternion::new(
863 -(self.x.clone() * rhs.x.clone() + self.y.clone() * rhs.y.clone() + self.z.clone() * rhs.z.clone()),
864 self.y.clone() * rhs.z.clone() - self.z.clone() * rhs.y.clone(),
865 self.z.clone() * rhs.x.clone() - self.x.clone() * rhs.z.clone(),
866 self.x.clone() * rhs.y.clone() - self.y.clone() * rhs.x.clone(),
867 )
868 }
869}
870
871#[cfg(feature = "unstable")]
872impl<T> Mul<Quaternion<T>> for PureQuaternion<T>
873where
874 T: Neg<Output = T>
875 + Add<T, Output = T>
876 + Sub<T, Output = T>
877 + Mul<T, Output = T>
878 + Clone,
879{
880 type Output = Quaternion<T>;
881
882 #[inline]
883 #[rustfmt::skip]
884 fn mul(self, rhs: Quaternion<T>) -> Self::Output {
885 let a = - self.x.clone() * rhs.x.clone()
886 - self.y.clone() * rhs.y.clone()
887 - self.z.clone() * rhs.z.clone();
888 let b = self.x.clone() * rhs.w.clone()
889 + self.y.clone() * rhs.z.clone()
890 - self.z.clone() * rhs.y.clone();
891 let c = - self.x.clone() * rhs.z.clone()
892 + self.y.clone() * rhs.w.clone()
893 + self.z.clone() * rhs.x.clone();
894 let d = self.x * rhs.y
895 - self.y * rhs.x
896 + self.z * rhs.w;
897 Self::Output::new(a, b, c, d)
898 }
899}
900
901#[cfg(feature = "unstable")]
902impl<T> Mul<T> for PureQuaternion<T>
903where
904 T: Mul<T, Output = T> + Clone,
905{
906 type Output = PureQuaternion<T>;
907
908 #[inline]
909 #[rustfmt::skip]
910 fn mul(self, rhs: T) -> Self::Output {
911 Self::new(self.x * rhs.clone(),
912 self.y * rhs.clone(),
913 self.z * rhs)
914 }
915}
916
917#[cfg(feature = "unstable")]
918impl<T> Mul<UnitQuaternion<T>> for PureQuaternion<T>
919where
920 PureQuaternion<T>: Mul<Quaternion<T>, Output = Quaternion<T>>,
921{
922 type Output = Quaternion<T>;
923
924 #[inline]
925 fn mul(self, rhs: UnitQuaternion<T>) -> Self::Output {
926 self * rhs.into_inner()
927 }
928}
929
930#[cfg(feature = "unstable")]
931impl Mul<PQ32> for f32 {
932 type Output = PQ32;
933
934 #[inline]
935 #[rustfmt::skip]
936 fn mul(self, rhs: PQ32) -> Self::Output {
937 Self::Output::new(self * rhs.x,
938 self * rhs.y,
939 self * rhs.z)
940 }
941}
942
943#[cfg(feature = "unstable")]
944impl Mul<PQ64> for f64 {
945 type Output = PQ64;
946
947 #[inline]
948 #[rustfmt::skip]
949 fn mul(self, rhs: PQ64) -> Self::Output {
950 Self::Output::new(self * rhs.x,
951 self * rhs.y,
952 self * rhs.z)
953 }
954}
955
956#[cfg(feature = "unstable")]
957impl<T> Div<PureQuaternion<T>> for PureQuaternion<T>
958where
959 T: Num + Clone + Neg<Output = T>,
960{
961 type Output = Quaternion<T>;
962
963 #[allow(clippy::suspicious_arithmetic_impl)]
964 #[inline]
965 fn div(self, rhs: PureQuaternion<T>) -> Self::Output {
966 self * rhs.inv()
967 }
968}
969
970#[cfg(feature = "unstable")]
971impl<T> Div<Quaternion<T>> for PureQuaternion<T>
972where
973 T: Num + Clone + Neg<Output = T>,
974{
975 type Output = Quaternion<T>;
976
977 #[allow(clippy::suspicious_arithmetic_impl)]
978 #[inline]
979 fn div(self, rhs: Quaternion<T>) -> Self::Output {
980 self * rhs.inv()
981 }
982}
983
984#[cfg(feature = "unstable")]
985impl<T> Div<T> for PureQuaternion<T>
986where
987 T: Div<T, Output = T> + Clone,
988{
989 type Output = PureQuaternion<T>;
990
991 #[inline]
992 fn div(self, rhs: T) -> Self::Output {
993 Self::new(self.x / rhs.clone(), self.y / rhs.clone(), self.z / rhs)
994 }
995}
996
997#[cfg(feature = "unstable")]
998impl<T> Div<UnitQuaternion<T>> for PureQuaternion<T>
999where
1000 T: Num + Clone + Neg<Output = T>,
1001{
1002 type Output = Quaternion<T>;
1003
1004 #[allow(clippy::suspicious_arithmetic_impl)]
1005 #[inline]
1006 fn div(self, rhs: UnitQuaternion<T>) -> Self::Output {
1007 self * rhs.inv()
1008 }
1009}
1010
1011#[cfg(feature = "unstable")]
1012impl Div<PQ32> for f32 {
1013 type Output = PQ32;
1014
1015 #[allow(clippy::suspicious_arithmetic_impl)]
1016 #[inline]
1017 fn div(self, rhs: PQ32) -> Self::Output {
1018 self * rhs.inv()
1019 }
1020}
1021
1022#[cfg(feature = "unstable")]
1023impl Div<PQ64> for f64 {
1024 type Output = PQ64;
1025
1026 #[allow(clippy::suspicious_arithmetic_impl)]
1027 #[inline]
1028 fn div(self, rhs: PQ64) -> Self::Output {
1029 self * rhs.inv()
1030 }
1031}
1032
1033#[cfg(feature = "unstable")]
1034impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, PureQuaternion<T>);
1035#[cfg(feature = "unstable")]
1036impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, PureQuaternion<T>);
1037#[cfg(feature = "unstable")]
1038impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, PureQuaternion<T>);
1039#[cfg(feature = "unstable")]
1040impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, PureQuaternion<T>);
1041#[cfg(feature = "unstable")]
1042impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, Quaternion<T>);
1043#[cfg(feature = "unstable")]
1044impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, Quaternion<T>);
1045#[cfg(feature = "unstable")]
1046impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, Quaternion<T>);
1047#[cfg(feature = "unstable")]
1048impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, Quaternion<T>);
1049#[cfg(feature = "unstable")]
1050impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, T);
1051#[cfg(feature = "unstable")]
1052impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, T);
1053#[cfg(feature = "unstable")]
1054impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, T);
1055#[cfg(feature = "unstable")]
1056impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, T);
1057#[cfg(feature = "unstable")]
1058impl_op_with_ref!(impl<T> Add::add for PureQuaternion<T>, UnitQuaternion<T>);
1059#[cfg(feature = "unstable")]
1060impl_op_with_ref!(impl<T> Sub::sub for PureQuaternion<T>, UnitQuaternion<T>);
1061#[cfg(feature = "unstable")]
1062impl_op_with_ref!(impl<T> Mul::mul for PureQuaternion<T>, UnitQuaternion<T>);
1063#[cfg(feature = "unstable")]
1064impl_op_with_ref!(impl<T> Div::div for PureQuaternion<T>, UnitQuaternion<T>);
1065
1066#[cfg(feature = "unstable")]
1067impl_bin_op_assign!(impl AddAssign::add_assign as Add::add for PureQuaternion);
1068#[cfg(feature = "unstable")]
1069impl_bin_op_assign!(impl SubAssign::sub_assign as Sub::sub for PureQuaternion);
1070#[cfg(feature = "unstable")]
1071impl_bin_op_assign!(impl MulAssign::mul_assign as Mul::mul for PureQuaternion);
1072#[cfg(feature = "unstable")]
1073impl_bin_op_assign!(impl DivAssign::div_assign as Div::div for PureQuaternion);
1074
1075#[cfg(test)]
1076mod tests {
1077
1078 use crate::{Quaternion, Q32, Q64, UQ32, UQ64};
1079 #[cfg(feature = "unstable")]
1080 use crate::{PQ32, PQ64};
1081
1082 #[test]
1083 fn test_add_quaternion() {
1084 assert_eq!(Q32::ONE + Q32::J, Q32::new(1.0, 0.0, 1.0, 0.0));
1086 assert_eq!(
1087 Q64::new(1.0, 2.0, 3.0, 4.0) + Q64::new(1.0, 3.0, 10.0, -5.0),
1088 Q64::new(2.0, 5.0, 13.0, -1.0)
1089 );
1090 }
1091
1092 #[test]
1093 fn test_add_real() {
1094 assert_eq!(Q32::I + 1.0, Q32::new(1.0, 1.0, 0.0, 0.0));
1096 assert_eq!(
1097 Q32::new(1.0, 2.0, 3.0, 4.0) + 42.0,
1098 Q32::new(43.0, 2.0, 3.0, 4.0)
1099 );
1100 }
1101
1102 #[test]
1103 fn test_add_quaternion_and_unit_quaternion() {
1104 assert_eq!(Q32::I + UQ32::J, Q32::new(0.0, 1.0, 1.0, 0.0));
1106 assert_eq!(
1107 Q64::new(1.0, 2.0, 3.0, 4.0) + UQ64::K,
1108 Q64::new(1.0, 2.0, 3.0, 5.0)
1109 );
1110 }
1111
1112 #[test]
1113 #[cfg(feature = "unstable")]
1114 fn test_add_quaternion_and_pure_quaternion() {
1115 assert_eq!(
1117 Q32::I + PQ32::new(1.0, 2.0, 3.0),
1118 Q32::new(0.0, 2.0, 2.0, 3.0)
1119 );
1120 assert_eq!(
1121 Q64::new(1.0, 2.0, 3.0, 4.0) + PQ64::new(1.0, 3.0, 10.0),
1122 Q64::new(1.0, 3.0, 6.0, 14.0)
1123 );
1124 }
1125
1126 #[test]
1127 fn test_sub_quaternion() {
1128 assert_eq!(Q32::ONE - Q32::J, Q32::new(1.0, 0.0, -1.0, 0.0));
1130 assert_eq!(
1131 Q64::new(1.0, 2.0, 3.0, 4.0) - Q64::new(1.0, 3.0, 10.0, -5.0),
1132 Q64::new(0.0, -1.0, -7.0, 9.0)
1133 );
1134 }
1135
1136 #[test]
1137 fn test_sub_real() {
1138 assert_eq!(Q32::I - 1.0, Q32::new(-1.0, 1.0, 0.0, 0.0));
1140 assert_eq!(
1141 Q32::new(1.0, 2.0, 3.0, 4.0) - 42.0,
1142 Q32::new(-41.0, 2.0, 3.0, 4.0)
1143 );
1144 }
1145
1146 #[test]
1147 #[cfg(feature = "unstable")]
1148 fn test_sub_quaternion_and_unit_quaternion() {
1149 assert_eq!(Q32::I - UQ32::J, Q32::new(0.0, 1.0, -1.0, 0.0));
1151 assert_eq!(
1152 Q64::new(1.0, 2.0, 3.0, 4.0) - UQ64::K,
1153 Q64::new(1.0, 2.0, 3.0, 3.0)
1154 );
1155 }
1156
1157 #[test]
1158 fn test_mul_quaternion() {
1159 assert_eq!(Q32::ONE * Q32::ONE, Q32::ONE);
1161 assert_eq!(Q32::ONE * Q32::I, Q32::I);
1162 assert_eq!(Q32::ONE * Q32::J, Q32::J);
1163 assert_eq!(Q32::ONE * Q32::K, Q32::K);
1164 assert_eq!(Q32::I * Q32::ONE, Q32::I);
1165 assert_eq!(Q32::J * Q32::ONE, Q32::J);
1166 assert_eq!(Q32::K * Q32::ONE, Q32::K);
1167 assert_eq!(Q32::I * Q32::I, -Q32::ONE);
1168 assert_eq!(Q32::J * Q32::J, -Q32::ONE);
1169 assert_eq!(Q32::K * Q32::K, -Q32::ONE);
1170 assert_eq!(Q32::I * Q32::J, Q32::K);
1171 assert_eq!(Q32::J * Q32::K, Q32::I);
1172 assert_eq!(Q32::K * Q32::I, Q32::J);
1173 assert_eq!(Q32::J * Q32::I, -Q32::K);
1174 assert_eq!(Q32::K * Q32::J, -Q32::I);
1175 assert_eq!(Q32::I * Q32::K, -Q32::J);
1176 assert_eq!(
1177 Q64::new(1.0, 2.0, 3.0, 4.0) * Q64::new(1.0, 3.0, 10.0, -5.0),
1178 Q64::new(-15.0, -50.0, 35.0, 10.0)
1179 );
1180 }
1181
1182 #[test]
1183 fn test_mul_real() {
1184 assert_eq!(Q32::I * 1.0, Q32::I);
1186 assert_eq!(
1187 Q32::new(1.0, 2.0, 3.0, 4.0) * 42.0,
1188 Q32::new(42.0, 84.0, 126.0, 168.0)
1189 );
1190 }
1191
1192 #[test]
1193 fn test_mul_quaternion_by_unit_quaternion() {
1194 assert_eq!(Q32::I * UQ32::J, Q32::K);
1196 assert_eq!(Q64::J * UQ64::K, Q64::I);
1197 assert_eq!(
1198 Q32::new(1.0, 2.0, 3.0, 4.0) * UQ32::K,
1199 Q32::new(-4.0, 3.0, -2.0, 1.0)
1200 );
1201 }
1202
1203 #[test]
1204 #[cfg(feature = "unstable")]
1205 fn test_mul_quaternion_by_pure_quaternion() {
1206 assert_eq!(
1208 Q32::I * PQ32::new(1.0, 2.0, 3.0),
1209 Q32::new(-1.0, 0.0, -3.0, 2.0)
1210 );
1211 assert_eq!(
1212 Q64::new(1.0, 2.0, 3.0, 4.0) * PQ64::new(1.0, 3.0, 10.0),
1213 Q64::new(1.0, 2.0, 3.0, 4.0) * Q64::new(0.0, 1.0, 3.0, 10.0)
1214 );
1215 }
1216
1217 #[test]
1218 fn test_div_quaternion() {
1219 assert_eq!(Q32::ONE / Q32::ONE * Q32::ONE, Q32::ONE);
1221 assert_eq!(Q32::ONE / Q32::I * Q32::I, Q32::ONE);
1222 assert_eq!(Q32::ONE / Q32::J * Q32::J, Q32::ONE);
1223 assert_eq!(Q32::ONE / Q32::K * Q32::K, Q32::ONE);
1224 assert_eq!(Q32::I / Q32::ONE * Q32::ONE, Q32::I);
1225 assert_eq!(Q32::J / Q32::ONE * Q32::ONE, Q32::J);
1226 assert_eq!(Q32::K / Q32::ONE * Q32::ONE, Q32::K);
1227 assert_eq!(Q32::I / Q32::I * Q32::I, Q32::I);
1228 assert_eq!(Q32::J / Q32::J * Q32::J, Q32::J);
1229 assert_eq!(Q32::K / Q32::K * Q32::K, Q32::K);
1230 assert_eq!(Q32::I / Q32::J * Q32::J, Q32::I);
1231 assert_eq!(Q32::J / Q32::K * Q32::K, Q32::J);
1232 assert_eq!(Q32::K / Q32::I * Q32::I, Q32::K);
1233 assert_eq!(Q32::J / Q32::I * Q32::I, Q32::J);
1234 assert_eq!(Q32::K / Q32::J * Q32::J, Q32::K);
1235 assert_eq!(Q32::I / Q32::K * Q32::K, Q32::I);
1236 let q = Q64::new(1.0, 2.0, 3.0, 4.0);
1237 let r = Q64::new(1.0, 3.0, 10.0, -5.0);
1238 assert!((q / r * r - q).norm_sqr() < f64::EPSILON);
1239 }
1240
1241 #[test]
1242 fn test_div_real() {
1243 assert_eq!(Q32::I * 1.0, Q32::I);
1245 assert_eq!(
1246 Q32::new(1.0, 2.0, 3.0, 4.0) / 4.0,
1247 Q32::new(0.25, 0.5, 0.75, 1.0)
1248 );
1249 }
1250
1251 #[test]
1252 fn test_div_quaternion_by_unit_quaternion() {
1253 assert_eq!(Q32::I / UQ32::J, -Q32::K);
1255 assert_eq!(Q64::J / UQ64::K, -Q64::I);
1256 assert_eq!(
1257 Q32::new(1.0, 2.0, 3.0, 4.0) / UQ32::K,
1258 Q32::new(4.0, -3.0, 2.0, -1.0)
1259 );
1260 }
1261
1262 #[test]
1263 #[cfg(feature = "unstable")]
1264 fn test_div_quaternion_by_pure_quaternion() {
1265 assert_eq!(
1267 Q32::I / PQ32::new(1.0, 2.0, 3.0),
1268 Q32::new(1.0, 0.0, 3.0, -2.0) / 14.0
1269 );
1270 assert_eq!(
1271 Q64::new(1.0, 2.0, 3.0, 4.0) / PQ64::new(1.0, 3.0, 10.0),
1272 Q64::new(1.0, 2.0, 3.0, 4.0) / Q64::new(0.0, 1.0, 3.0, 10.0)
1273 );
1274 }
1275
1276 #[test]
1277 fn test_add_assign() {
1278 let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1280 q += 4.0;
1281 assert_eq!(q, Quaternion::new(5.0, 2.0, 3.0, 4.0));
1282 }
1283
1284 #[test]
1285 fn test_sub_assign() {
1286 let mut q = Q64::new(1.0, 2.0, 3.0, 4.0);
1288 q -= Q64::new(4.0, 8.0, 6.0, 1.0);
1289 assert_eq!(q, Quaternion::new(-3.0, -6.0, -3.0, 3.0));
1290 }
1291
1292 #[test]
1293 fn test_mul_assign() {
1294 let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1296 q *= UQ32::I;
1297 assert_eq!(q, Quaternion::new(-2.0, 1.0, 4.0, -3.0));
1298 }
1299
1300 #[test]
1301 #[cfg(feature = "unstable")]
1302 fn test_div_assign() {
1303 let mut q = Quaternion::new(1.0f32, 2.0f32, 3.0f32, 4.0f32);
1305 q /= PQ32::new(4.0f32, 0.0, 0.0);
1306 assert_eq!(q, Quaternion::new(0.5f32, -0.25f32, -1.0f32, 0.75f32));
1307 }
1308
1309 #[test]
1310 #[allow(clippy::op_ref)]
1311 fn test_add_with_ref() {
1312 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1314 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1315 assert_eq!(lhs + rhs, &lhs + rhs);
1316 assert_eq!(lhs + rhs, lhs + &rhs);
1317 assert_eq!(lhs + rhs, &lhs + &rhs);
1318 }
1319
1320 #[test]
1321 #[allow(clippy::op_ref)]
1322 fn test_sub_with_ref() {
1323 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1325 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1326 assert_eq!(lhs - rhs, &lhs - rhs);
1327 assert_eq!(lhs - rhs, lhs - &rhs);
1328 assert_eq!(lhs - rhs, &lhs - &rhs);
1329 }
1330
1331 #[test]
1332 #[allow(clippy::op_ref)]
1333 fn test_mul_with_ref() {
1334 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1336 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1337 assert_eq!(lhs * rhs, &lhs * rhs);
1338 assert_eq!(lhs * rhs, lhs * &rhs);
1339 assert_eq!(lhs * rhs, &lhs * &rhs);
1340 }
1341
1342 #[test]
1343 #[allow(clippy::op_ref)]
1344 fn test_div_with_ref() {
1345 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1347 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1348 assert_eq!(lhs / rhs, &lhs / rhs);
1349 assert_eq!(lhs / rhs, lhs / &rhs);
1350 assert_eq!(lhs / rhs, &lhs / &rhs);
1351 }
1352
1353 #[test]
1354 #[cfg(any(feature = "std", feature = "libm"))]
1355 #[allow(clippy::op_ref)]
1356 fn test_add_unit_quaternion_with_ref() {
1357 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1360 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1361 assert_eq!(lhs + rhs, &lhs + rhs);
1362 assert_eq!(lhs + rhs, lhs + &rhs);
1363 assert_eq!(lhs + rhs, &lhs + &rhs);
1364 }
1365
1366 #[test]
1367 #[cfg(any(feature = "std", feature = "libm"))]
1368 #[allow(clippy::op_ref)]
1369 fn test_sub_unit_quaternion_with_ref() {
1370 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1373 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1374 assert_eq!(lhs - rhs, &lhs - rhs);
1375 assert_eq!(lhs - rhs, lhs - &rhs);
1376 assert_eq!(lhs - rhs, &lhs - &rhs);
1377 }
1378
1379 #[test]
1380 #[cfg(any(feature = "std", feature = "libm"))]
1381 #[allow(clippy::op_ref)]
1382 fn test_mul_unit_quaternion_with_ref() {
1383 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1386 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1387 assert_eq!(lhs * rhs, &lhs * rhs);
1388 assert_eq!(lhs * rhs, lhs * &rhs);
1389 assert_eq!(lhs * rhs, &lhs * &rhs);
1390 }
1391
1392 #[test]
1393 #[cfg(any(feature = "std", feature = "libm"))]
1394 #[allow(clippy::op_ref)]
1395 fn test_div_unit_quaternion_with_ref() {
1396 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1399 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1400 assert_eq!(lhs / rhs, &lhs / rhs);
1401 assert_eq!(lhs / rhs, lhs / &rhs);
1402 assert_eq!(lhs / rhs, &lhs / &rhs);
1403 }
1404
1405 #[test]
1406 #[allow(clippy::op_ref)]
1407 fn test_add_real_with_ref() {
1408 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1411 let rhs = 5.0;
1412 assert_eq!(lhs + rhs, &lhs + rhs);
1413 assert_eq!(lhs + rhs, lhs + &rhs);
1414 assert_eq!(lhs + rhs, &lhs + &rhs);
1415 }
1416
1417 #[test]
1418 #[allow(clippy::op_ref)]
1419 fn test_sub_real_with_ref() {
1420 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1423 let rhs = 5.0;
1424 assert_eq!(lhs - rhs, &lhs - rhs);
1425 assert_eq!(lhs - rhs, lhs - &rhs);
1426 assert_eq!(lhs - rhs, &lhs - &rhs);
1427 }
1428
1429 #[test]
1430 #[allow(clippy::op_ref)]
1431 fn test_mul_real_with_ref() {
1432 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1435 let rhs = 5.0;
1436 assert_eq!(lhs * rhs, &lhs * rhs);
1437 assert_eq!(lhs * rhs, lhs * &rhs);
1438 assert_eq!(lhs * rhs, &lhs * &rhs);
1439 }
1440
1441 #[test]
1442 #[allow(clippy::op_ref)]
1443 fn test_div_real_with_ref() {
1444 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1446 let rhs = 5.0;
1447 assert_eq!(lhs / rhs, &lhs / rhs);
1448 assert_eq!(lhs / rhs, lhs / &rhs);
1449 assert_eq!(lhs / rhs, &lhs / &rhs);
1450 }
1451
1452 #[test]
1453 #[cfg(feature = "unstable")]
1454 #[allow(clippy::op_ref)]
1455 fn test_add_pure_quaternion_with_ref() {
1456 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1458 let rhs = PQ32::new(5.0, 6.0, 7.0);
1459 assert_eq!(lhs + rhs, &lhs + rhs);
1460 assert_eq!(lhs + rhs, lhs + &rhs);
1461 assert_eq!(lhs + rhs, &lhs + &rhs);
1462 }
1463
1464 #[test]
1465 #[cfg(feature = "unstable")]
1466 #[allow(clippy::op_ref)]
1467 fn test_sub_pure_quaternion_with_ref() {
1468 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1470 let rhs = PQ32::new(5.0, 6.0, 7.0);
1471 assert_eq!(lhs - rhs, &lhs - rhs);
1472 assert_eq!(lhs - rhs, lhs - &rhs);
1473 assert_eq!(lhs - rhs, &lhs - &rhs);
1474 }
1475
1476 #[test]
1477 #[cfg(feature = "unstable")]
1478 #[allow(clippy::op_ref)]
1479 fn test_mul_pure_quaternion_with_ref() {
1480 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1482 let rhs = PQ32::new(5.0, 6.0, 7.0);
1483 assert_eq!(lhs * rhs, &lhs * rhs);
1484 assert_eq!(lhs * rhs, lhs * &rhs);
1485 assert_eq!(lhs * rhs, &lhs * &rhs);
1486 }
1487
1488 #[test]
1489 #[cfg(feature = "unstable")]
1490 #[allow(clippy::op_ref)]
1491 fn test_div_pure_quaternion_with_ref() {
1492 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0);
1494 let rhs = PQ32::new(5.0, 6.0, 7.0);
1495 assert_eq!(lhs / rhs, &lhs / rhs);
1496 assert_eq!(lhs / rhs, lhs / &rhs);
1497 assert_eq!(lhs / rhs, &lhs / &rhs);
1498 }
1499
1500 #[test]
1501 fn test_add_lhs_real() {
1502 assert_eq!(42.0 + Quaternion::I, Quaternion::new(42.0, 1.0, 0.0, 0.0));
1504 assert_eq!(
1505 1 + Quaternion::new(2, 4, 6, 8),
1506 Quaternion::new(3, 4, 6, 8)
1507 );
1508 }
1509
1510 #[test]
1511 fn test_sub_lhs_real() {
1512 assert_eq!(42.0 - Quaternion::I, Quaternion::new(42.0, -1.0, 0.0, 0.0));
1514 assert_eq!(
1515 1 - Quaternion::new(2, 4, 6, 8),
1516 Quaternion::new(-1, -4, -6, -8)
1517 );
1518 }
1519
1520 #[test]
1521 fn test_mul_lhs_real() {
1522 assert_eq!(42.0 * Quaternion::I, Quaternion::new(0.0, 42.0, 0.0, 0.0));
1524 assert_eq!(
1525 2 * Quaternion::new(1, 2, 3, 4),
1526 Quaternion::new(2, 4, 6, 8)
1527 );
1528 }
1529
1530 #[test]
1531 fn test_div_lhs_real() {
1532 assert_eq!(
1534 42.0f32 / Quaternion::I,
1535 Quaternion::new(0.0, -42.0, 0.0, 0.0)
1536 );
1537 assert_eq!(
1538 4.0f64 / Quaternion::new(1.0, 1.0, 1.0, 1.0),
1539 Quaternion::new(1.0, -1.0, -1.0, -1.0)
1540 );
1541 }
1542
1543 #[test]
1544 fn test_neg() {
1545 assert_eq!(
1547 -Q64::new(1.0, -2.0, 3.0, -4.0),
1548 Q64::new(-1.0, 2.0, -3.0, 4.0)
1549 );
1550 }
1551
1552 #[test]
1553 fn test_unit_quaternion_add() {
1554 assert_eq!(UQ32::I + UQ32::J, Q32::new(0.0, 1.0, 1.0, 0.0));
1556 }
1557
1558 #[test]
1559 fn test_unit_quaternion_add_quaternion() {
1560 assert_eq!(UQ32::J + Q32::K, Q32::new(0.0, 0.0, 1.0, 1.0));
1562 }
1563
1564 #[test]
1565 fn test_unit_quaternion_add_underlying() {
1566 assert_eq!(UQ32::J + 2.0f32, Q32::new(2.0, 0.0, 1.0, 0.0));
1568 }
1569
1570 #[test]
1571 fn test_f32_add_unit_quaternion() {
1572 assert_eq!(3.0f32 + UQ32::K, Q32::new(3.0, 0.0, 0.0, 1.0));
1574 }
1575
1576 #[test]
1577 fn test_f64_add_unit_quaternion() {
1578 assert_eq!(4.0f64 + UQ64::I, Q64::new(4.0, 1.0, 0.0, 0.0));
1580 }
1581
1582 #[test]
1583 #[cfg(feature = "unstable")]
1584 fn test_unit_quaternion_add_pure_quaternion() {
1585 assert_eq!(
1587 UQ32::J + PQ32::new(1.0, 2.0, 3.0),
1588 Q32::new(0.0, 1.0, 3.0, 3.0)
1589 );
1590 }
1591
1592 #[test]
1593 fn test_unit_quaternion_sub() {
1594 assert_eq!(UQ32::I - UQ32::J, Q32::new(0.0, 1.0, -1.0, 0.0));
1596 }
1597
1598 #[test]
1599 fn test_unit_quaternion_sub_quaternion() {
1600 assert_eq!(UQ32::J - Q32::K, Q32::new(0.0, 0.0, 1.0, -1.0));
1602 }
1603
1604 #[test]
1605 fn test_unit_quaternion_sub_underlying() {
1606 assert_eq!(UQ32::J - 2.0f32, Q32::new(-2.0, 0.0, 1.0, 0.0));
1608 }
1609
1610 #[test]
1611 fn test_f32_sub_unit_quaternion() {
1612 assert_eq!(3.0f32 - UQ32::K, Q32::new(3.0, 0.0, 0.0, -1.0));
1614 }
1615
1616 #[test]
1617 fn test_f64_sub_unit_quaternion() {
1618 assert_eq!(4.0f64 - UQ64::I, Q64::new(4.0, -1.0, 0.0, 0.0));
1620 }
1621
1622 #[test]
1623 #[cfg(feature = "unstable")]
1624 fn test_unit_quaternion_sub_pure_quaternion() {
1625 assert_eq!(
1627 UQ32::J - PQ32::new(1.0, 2.0, 3.0),
1628 Q32::new(0.0, -1.0, -1.0, -3.0)
1629 );
1630 }
1631
1632 #[test]
1633 fn test_unit_quaternion_mul() {
1634 assert_eq!(UQ32::I * UQ32::J, UQ32::K);
1636 }
1637
1638 #[test]
1639 fn test_unit_quaternion_mul_quaternion() {
1640 assert_eq!(UQ32::J * Q32::K, Q32::new(0.0, 1.0, 0.0, 0.0));
1642 }
1643
1644 #[test]
1645 fn test_unit_quaternion_mul_underlying() {
1646 assert_eq!(UQ32::J * 2.0f32, Q32::new(0.0, 0.0, 2.0, 0.0));
1648 }
1649
1650 #[test]
1651 fn test_f32_mul_unit_quaternion() {
1652 assert_eq!(3.0f32 * UQ32::K, Q32::new(0.0, 0.0, 0.0, 3.0));
1654 }
1655
1656 #[test]
1657 fn test_f64_mul_unit_quaternion() {
1658 assert_eq!(4.0f64 * UQ64::I, Q64::new(0.0, 4.0, 0.0, 0.0));
1660 }
1661
1662 #[test]
1663 #[cfg(feature = "unstable")]
1664 fn test_unit_quaternion_mul_pure_quaternion() {
1665 assert_eq!(
1667 UQ32::J * PQ32::new(1.0, 2.0, 3.0),
1668 Q32::new(-2.0, 3.0, 0.0, -1.0)
1669 );
1670 }
1671
1672 #[test]
1673 fn test_unit_quaternion_div() {
1674 assert_eq!(UQ32::I / UQ32::J, -UQ32::K);
1676 }
1677
1678 #[test]
1679 fn test_unit_quaternion_div_quaternion() {
1680 assert_eq!(UQ32::J / Q32::K, Q32::new(0.0, -1.0, 0.0, 0.0));
1682 }
1683
1684 #[test]
1685 fn test_unit_quaternion_div_underlying() {
1686 assert_eq!(UQ32::J / 2.0f32, Q32::new(0.0, 0.0, 0.5, 0.0));
1688 }
1689
1690 #[test]
1691 fn test_f32_div_unit_quaternion() {
1692 assert_eq!(3.0f32 / UQ32::K, Q32::new(0.0, 0.0, 0.0, -3.0));
1694 }
1695
1696 #[test]
1697 fn test_f64_div_unit_quaternion() {
1698 assert_eq!(4.0f64 / UQ64::I, Q64::new(0.0, -4.0, 0.0, 0.0));
1700 }
1701
1702 #[test]
1703 #[cfg(feature = "unstable")]
1704 fn test_unit_quaternion_div_pure_quaternion() {
1705 assert_eq!(
1707 UQ32::J / PQ32::new(1.0, 2.0, 3.0),
1708 Q32::new(2.0, -3.0, 0.0, 1.0) / 14.0
1709 );
1710 }
1711
1712 #[test]
1713 #[cfg(any(feature = "std", feature = "libm"))]
1714 #[allow(clippy::op_ref)]
1715 fn test_add_with_ref_unit_quaternion() {
1716 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1718 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1719 assert_eq!(lhs + rhs, &lhs + rhs);
1720 assert_eq!(lhs + rhs, lhs + &rhs);
1721 assert_eq!(lhs + rhs, &lhs + &rhs);
1722 }
1723
1724 #[test]
1725 #[cfg(any(feature = "std", feature = "libm"))]
1726 #[allow(clippy::op_ref)]
1727 fn test_sub_with_ref_unit_quaternion() {
1728 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1730 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1731 assert_eq!(lhs - rhs, &lhs - rhs);
1732 assert_eq!(lhs - rhs, lhs - &rhs);
1733 assert_eq!(lhs - rhs, &lhs - &rhs);
1734 }
1735
1736 #[test]
1737 #[cfg(any(feature = "std", feature = "libm"))]
1738 #[allow(clippy::op_ref)]
1739 fn test_mul_with_ref_unit_quaternion() {
1740 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1742 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1743 assert_eq!(lhs * rhs, &lhs * rhs);
1744 assert_eq!(lhs * rhs, lhs * &rhs);
1745 assert_eq!(lhs * rhs, &lhs * &rhs);
1746 }
1747
1748 #[test]
1749 #[cfg(any(feature = "std", feature = "libm"))]
1750 #[allow(clippy::op_ref)]
1751 fn test_div_with_ref_unit_quaternion() {
1752 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1754 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0).normalize().unwrap();
1755 assert_eq!(lhs / rhs, &lhs / rhs);
1756 assert_eq!(lhs / rhs, lhs / &rhs);
1757 assert_eq!(lhs / rhs, &lhs / &rhs);
1758 }
1759
1760 #[test]
1761 #[cfg(any(feature = "std", feature = "libm"))]
1762 #[allow(clippy::op_ref)]
1763 fn test_add_quaternion_with_ref_unit_quaternion() {
1764 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1766 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1767 assert_eq!(lhs + rhs, &lhs + rhs);
1768 assert_eq!(lhs + rhs, lhs + &rhs);
1769 assert_eq!(lhs + rhs, &lhs + &rhs);
1770 }
1771
1772 #[test]
1773 #[cfg(any(feature = "std", feature = "libm"))]
1774 #[allow(clippy::op_ref)]
1775 fn test_sub_quaternion_with_ref_unit_quaternion() {
1776 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1778 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1779 assert_eq!(lhs - rhs, &lhs - rhs);
1780 assert_eq!(lhs - rhs, lhs - &rhs);
1781 assert_eq!(lhs - rhs, &lhs - &rhs);
1782 }
1783
1784 #[test]
1785 #[cfg(any(feature = "std", feature = "libm"))]
1786 #[allow(clippy::op_ref)]
1787 fn test_mul_quaternion_with_ref_unit_quaternion() {
1788 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1790 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1791 assert_eq!(lhs * rhs, &lhs * rhs);
1792 assert_eq!(lhs * rhs, lhs * &rhs);
1793 assert_eq!(lhs * rhs, &lhs * &rhs);
1794 }
1795
1796 #[test]
1797 #[cfg(any(feature = "std", feature = "libm"))]
1798 #[allow(clippy::op_ref)]
1799 fn test_div_quaternion_with_ref_unit_quaternion() {
1800 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1802 let rhs = Quaternion::new(5.0, 6.0, 7.0, 8.0);
1803 assert_eq!(lhs / rhs, &lhs / rhs);
1804 assert_eq!(lhs / rhs, lhs / &rhs);
1805 assert_eq!(lhs / rhs, &lhs / &rhs);
1806 }
1807
1808 #[test]
1809 #[cfg(any(feature = "std", feature = "libm"))]
1810 #[allow(clippy::op_ref)]
1811 fn test_add_real_with_ref_unit_quaternion() {
1812 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1814 let rhs = 5.0;
1815 assert_eq!(lhs + rhs, &lhs + rhs);
1816 assert_eq!(lhs + rhs, lhs + &rhs);
1817 assert_eq!(lhs + rhs, &lhs + &rhs);
1818 }
1819
1820 #[test]
1821 #[cfg(any(feature = "std", feature = "libm"))]
1822 #[allow(clippy::op_ref)]
1823 fn test_sub_real_with_ref_unit_quaternion() {
1824 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1826 let rhs = 5.0;
1827 assert_eq!(lhs - rhs, &lhs - rhs);
1828 assert_eq!(lhs - rhs, lhs - &rhs);
1829 assert_eq!(lhs - rhs, &lhs - &rhs);
1830 }
1831
1832 #[test]
1833 #[cfg(any(feature = "std", feature = "libm"))]
1834 #[allow(clippy::op_ref)]
1835 fn test_mul_real_with_ref_unit_quaternion() {
1836 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1838 let rhs = 5.0;
1839 assert_eq!(lhs * rhs, &lhs * rhs);
1840 assert_eq!(lhs * rhs, lhs * &rhs);
1841 assert_eq!(lhs * rhs, &lhs * &rhs);
1842 }
1843
1844 #[test]
1845 #[cfg(any(feature = "std", feature = "libm"))]
1846 #[allow(clippy::op_ref)]
1847 fn test_div_real_with_ref_unit_quaternion() {
1848 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1850 let rhs = 5.0;
1851 assert_eq!(lhs / rhs, &lhs / rhs);
1852 assert_eq!(lhs / rhs, lhs / &rhs);
1853 assert_eq!(lhs / rhs, &lhs / &rhs);
1854 }
1855
1856 #[test]
1857 #[cfg(any(feature = "std", feature = "libm"))]
1858 #[cfg(feature = "unstable")]
1859 #[allow(clippy::op_ref)]
1860 fn test_add_pure_quaternion_with_ref_unit_quaternion() {
1861 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1864 let rhs = PQ32::new(5.0, 6.0, 7.0);
1865 assert_eq!(lhs + rhs, &lhs + rhs);
1866 assert_eq!(lhs + rhs, lhs + &rhs);
1867 assert_eq!(lhs + rhs, &lhs + &rhs);
1868 }
1869
1870 #[test]
1871 #[cfg(any(feature = "std", feature = "libm"))]
1872 #[cfg(feature = "unstable")]
1873 #[allow(clippy::op_ref)]
1874 fn test_sub_pure_quaternion_with_ref_unit_quaternion() {
1875 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1878 let rhs = PQ32::new(5.0, 6.0, 7.0);
1879 assert_eq!(lhs - rhs, &lhs - rhs);
1880 assert_eq!(lhs - rhs, lhs - &rhs);
1881 assert_eq!(lhs - rhs, &lhs - &rhs);
1882 }
1883
1884 #[test]
1885 #[cfg(any(feature = "std", feature = "libm"))]
1886 #[cfg(feature = "unstable")]
1887 #[allow(clippy::op_ref)]
1888 fn test_mul_pure_quaternion_with_ref_unit_quaternion() {
1889 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1892 let rhs = PQ32::new(5.0, 6.0, 7.0);
1893 assert_eq!(lhs * rhs, &lhs * rhs);
1894 assert_eq!(lhs * rhs, lhs * &rhs);
1895 assert_eq!(lhs * rhs, &lhs * &rhs);
1896 }
1897
1898 #[test]
1899 #[cfg(any(feature = "std", feature = "libm"))]
1900 #[cfg(feature = "unstable")]
1901 #[allow(clippy::op_ref)]
1902 fn test_div_pure_quaternion_with_ref_unit_quaternion() {
1903 let lhs = Quaternion::new(1.0, 2.0, 3.0, 4.0).normalize().unwrap();
1906 let rhs = PQ32::new(5.0, 6.0, 7.0);
1907 assert_eq!(lhs / rhs, &lhs / rhs);
1908 assert_eq!(lhs / rhs, lhs / &rhs);
1909 assert_eq!(lhs / rhs, &lhs / &rhs);
1910 }
1911
1912 #[test]
1913 fn test_mul_assign_unit_quaternion() {
1914 let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1916 q *= UQ32::I;
1917 assert_eq!(q, Quaternion::new(-2.0, 1.0, 4.0, -3.0));
1918 }
1919
1920 #[test]
1921 fn test_div_assign_unit_quaternion() {
1922 let mut q = Q32::new(1.0, 2.0, 3.0, 4.0);
1924 q /= UQ32::I;
1925 assert_eq!(q, Quaternion::new(2.0, -1.0, -4.0, 3.0));
1926 }
1927
1928 #[test]
1929 #[cfg(feature = "unstable")]
1930 fn test_pure_quaternion_add() {
1931 assert_eq!(
1933 PQ32::new(1.0, 2.0, 3.0) + PQ32::new(4.0, 5.0, 6.0),
1934 PQ32::new(5.0, 7.0, 9.0)
1935 );
1936 }
1937
1938 #[test]
1939 #[cfg(feature = "unstable")]
1940 fn test_pure_quaternion_add_quaternion() {
1941 assert_eq!(
1943 PQ32::new(1.0, 2.0, 3.0) + Q32::new(4.0, 5.0, 6.0, 7.0),
1944 Q32::new(4.0, 6.0, 8.0, 10.0)
1945 );
1946 }
1947
1948 #[test]
1949 #[cfg(feature = "unstable")]
1950 fn test_pure_quaternion_add_real() {
1951 assert_eq!(
1953 PQ32::new(1.0, 2.0, 3.0) + 4.0,
1954 Q32::new(4.0, 1.0, 2.0, 3.0)
1955 );
1956 }
1957
1958 #[test]
1959 #[cfg(feature = "unstable")]
1960 fn test_pure_quaternion_add_unit_quaternion() {
1961 assert_eq!(
1963 PQ32::new(1.0, 2.0, 3.0) + UQ32::I,
1964 Q32::new(0.0, 2.0, 2.0, 3.0)
1965 );
1966 }
1967
1968 #[test]
1969 #[cfg(feature = "unstable")]
1970 fn test_f32_add_pure_quaternion() {
1971 assert_eq!(
1973 3.0f32 + PQ32::new(1.0, 2.0, 3.0),
1974 Q32::new(3.0, 1.0, 2.0, 3.0)
1975 );
1976 }
1977
1978 #[test]
1979 #[cfg(feature = "unstable")]
1980 fn test_f64_add_pure_quaternion() {
1981 assert_eq!(
1983 4.0f64 + PQ64::new(1.0, 2.0, 3.0),
1984 Q64::new(4.0, 1.0, 2.0, 3.0)
1985 );
1986 }
1987
1988 #[test]
1989 #[cfg(feature = "unstable")]
1990 fn test_pure_quaternion_sub() {
1991 assert_eq!(
1993 PQ32::new(1.0, 2.0, 3.0) - PQ32::new(4.0, 5.0, 6.0),
1994 PQ32::new(-3.0, -3.0, -3.0)
1995 );
1996 }
1997
1998 #[test]
1999 #[cfg(feature = "unstable")]
2000 fn test_pure_quaternion_sub_quaternion() {
2001 assert_eq!(
2003 PQ32::new(1.0, 2.0, 3.0) - Q32::new(4.0, 5.0, 6.0, 7.0),
2004 Q32::new(-4.0, -4.0, -4.0, -4.0)
2005 );
2006 }
2007
2008 #[test]
2009 #[cfg(feature = "unstable")]
2010 fn test_pure_quaternion_sub_real() {
2011 assert_eq!(
2013 PQ32::new(1.0, 2.0, 3.0) - 4.0,
2014 Q32::new(-4.0, 1.0, 2.0, 3.0)
2015 );
2016 }
2017
2018 #[test]
2019 #[cfg(feature = "unstable")]
2020 fn test_pure_quaternion_sub_unit_quaternion() {
2021 assert_eq!(
2023 PQ32::new(1.0, 2.0, 3.0) - UQ32::J,
2024 Q32::new(0.0, 1.0, 1.0, 3.0)
2025 );
2026 }
2027
2028 #[test]
2029 #[cfg(feature = "unstable")]
2030 fn test_f32_sub_pure_quaternion() {
2031 assert_eq!(
2033 3.0f32 - PQ32::new(1.0, 2.0, 3.0),
2034 Q32::new(3.0, -1.0, -2.0, -3.0)
2035 );
2036 }
2037
2038 #[test]
2039 #[cfg(feature = "unstable")]
2040 fn test_f64_sub_pure_quaternion() {
2041 assert_eq!(
2043 4.0f64 - PQ64::new(1.0, 2.0, 3.0),
2044 Q64::new(4.0, -1.0, -2.0, -3.0)
2045 );
2046 }
2047
2048 #[test]
2049 #[cfg(feature = "unstable")]
2050 fn test_pure_quaternion_mul() {
2051 assert_eq!(
2053 PQ32::new(1.0, 2.0, 3.0) * PQ32::new(4.0, 5.0, 6.0),
2054 Q32::new(0.0, 1.0, 2.0, 3.0) * Q32::new(0.0, 4.0, 5.0, 6.0)
2055 );
2056 }
2057
2058 #[test]
2059 #[cfg(feature = "unstable")]
2060 fn test_pure_quaternion_mul_quaternion() {
2061 assert_eq!(
2063 PQ32::new(1.0, 2.0, 3.0) * Q32::new(4.0, 5.0, 6.0, 7.0),
2064 Q32::new(0.0, 1.0, 2.0, 3.0) * Q32::new(4.0, 5.0, 6.0, 7.0)
2065 );
2066 }
2067
2068 #[test]
2069 #[cfg(feature = "unstable")]
2070 fn test_pure_quaternion_mul_real() {
2071 assert_eq!(PQ32::new(1.0, 2.0, 3.0) * 4.0, PQ32::new(4.0, 8.0, 12.0));
2073 }
2074
2075 #[test]
2076 #[cfg(feature = "unstable")]
2077 fn test_pure_quaternion_mul_unit_quaternion() {
2078 assert_eq!(
2080 PQ32::new(1.0, 2.0, 3.0) * UQ32::I,
2081 Q32::new(0.0, 1.0, 2.0, 3.0) * Q32::new(0.0, 1.0, 0.0, 0.0)
2082 );
2083 }
2084
2085 #[test]
2086 #[cfg(feature = "unstable")]
2087 fn test_f32_mul_pure_quaternion() {
2088 assert_eq!(3.0f32 * PQ32::new(1.0, 2.0, 3.0), PQ32::new(3.0, 6.0, 9.0));
2090 }
2091
2092 #[test]
2093 #[cfg(feature = "unstable")]
2094 fn test_f64_mul_pure_quaternion() {
2095 assert_eq!(
2097 4.0f64 * PQ64::new(1.0, 2.0, 3.0),
2098 PQ64::new(4.0, 8.0, 12.0)
2099 );
2100 }
2101
2102 #[test]
2103 #[cfg(feature = "unstable")]
2104 fn test_pure_quaternion_div() {
2105 assert_eq!(
2107 PQ32::new(1.0, 2.0, 3.0) / PQ32::new(4.0, 5.0, 6.0),
2108 Q32::new(0.0, 1.0, 2.0, 3.0) / Q32::new(0.0, 4.0, 5.0, 6.0)
2109 );
2110 }
2111
2112 #[test]
2113 #[cfg(feature = "unstable")]
2114 fn test_pure_quaternion_div_quaternion() {
2115 assert_eq!(
2117 PQ32::new(1.0, 2.0, 3.0) / Q32::new(4.0, 5.0, 6.0, 7.0),
2118 Q32::new(0.0, 1.0, 2.0, 3.0) / Q32::new(4.0, 5.0, 6.0, 7.0)
2119 );
2120 }
2121
2122 #[test]
2123 #[cfg(feature = "unstable")]
2124 fn test_pure_quaternion_div_real() {
2125 assert_eq!(PQ32::new(1.0, 2.0, 3.0) / 4.0, PQ32::new(0.25, 0.5, 0.75));
2127 }
2128
2129 #[test]
2130 #[cfg(feature = "unstable")]
2131 fn test_pure_quaternion_div_unit_quaternion() {
2132 assert_eq!(
2134 PQ32::new(1.0, 2.0, 3.0) / UQ32::I,
2135 Q32::new(0.0, 1.0, 2.0, 3.0) / Q32::new(0.0, 1.0, 0.0, 0.0)
2136 );
2137 }
2138
2139 #[test]
2140 #[cfg(feature = "unstable")]
2141 fn test_f32_div_pure_quaternion() {
2142 assert_eq!(
2144 4.0f32 / PQ32::new(1.0, 2.0, 3.0),
2145 PQ32::new(-4.0, -8.0, -12.0) / 14.0
2146 );
2147 }
2148
2149 #[test]
2150 #[cfg(feature = "unstable")]
2151 fn test_f64_div_pure_quaternion() {
2152 assert_eq!(
2154 4.0f64 / PQ64::new(1.0, 2.0, 3.0),
2155 PQ64::new(-4.0, -8.0, -12.0) / 14.0
2156 );
2157 }
2158
2159 #[test]
2160 #[cfg(feature = "unstable")]
2161 #[allow(clippy::op_ref)]
2162 fn test_pure_quaternion_add_ref() {
2163 let lhs = PQ32::new(1.0, 2.0, 3.0);
2165 let rhs = PQ32::new(4.0, 5.0, 6.0);
2166 assert_eq!(lhs + rhs, &lhs + rhs);
2167 assert_eq!(lhs + rhs, lhs + &rhs);
2168 assert_eq!(lhs + rhs, &lhs + &rhs);
2169 }
2170
2171 #[test]
2172 #[cfg(feature = "unstable")]
2173 #[allow(clippy::op_ref)]
2174 fn test_pure_quaternion_sub_ref() {
2175 let lhs = PQ32::new(1.0, 2.0, 3.0);
2177 let rhs = PQ32::new(4.0, 5.0, 6.0);
2178 assert_eq!(lhs - rhs, &lhs - rhs);
2179 assert_eq!(lhs - rhs, lhs - &rhs);
2180 assert_eq!(lhs - rhs, &lhs - &rhs);
2181 }
2182
2183 #[test]
2184 #[cfg(feature = "unstable")]
2185 #[allow(clippy::op_ref)]
2186 fn test_pure_quaternion_mul_ref() {
2187 let lhs = PQ32::new(1.0, 2.0, 3.0);
2189 let rhs = PQ32::new(4.0, 5.0, 6.0);
2190 assert_eq!(lhs * rhs, &lhs * rhs);
2191 assert_eq!(lhs * rhs, lhs * &rhs);
2192 assert_eq!(lhs * rhs, &lhs * &rhs);
2193 }
2194
2195 #[test]
2196 #[cfg(feature = "unstable")]
2197 #[allow(clippy::op_ref)]
2198 fn test_pure_quaternion_div_ref() {
2199 let lhs = PQ32::new(1.0, 2.0, 3.0);
2201 let rhs = PQ32::new(4.0, 5.0, 6.0);
2202 assert_eq!(lhs / rhs, &lhs / rhs);
2203 assert_eq!(lhs / rhs, lhs / &rhs);
2204 assert_eq!(lhs / rhs, &lhs / &rhs);
2205 }
2206
2207 #[test]
2208 #[cfg(feature = "unstable")]
2209 #[allow(clippy::op_ref)]
2210 fn test_pure_quaternion_add_quaternion_ref() {
2211 let lhs = PQ32::new(1.0, 2.0, 3.0);
2213 let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2214 assert_eq!(lhs + rhs, &lhs + rhs);
2215 assert_eq!(lhs + rhs, lhs + &rhs);
2216 assert_eq!(lhs + rhs, &lhs + &rhs);
2217 }
2218
2219 #[test]
2220 #[cfg(feature = "unstable")]
2221 #[allow(clippy::op_ref)]
2222 fn test_pure_quaternion_sub_quaternion_ref() {
2223 let lhs = PQ32::new(1.0, 2.0, 3.0);
2225 let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2226 assert_eq!(lhs - rhs, &lhs - rhs);
2227 assert_eq!(lhs - rhs, lhs - &rhs);
2228 assert_eq!(lhs - rhs, &lhs - &rhs);
2229 }
2230
2231 #[test]
2232 #[cfg(feature = "unstable")]
2233 #[allow(clippy::op_ref)]
2234 fn test_pure_quaternion_mul_quaternion_ref() {
2235 let lhs = PQ32::new(1.0, 2.0, 3.0);
2238 let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2239 assert_eq!(lhs * rhs, &lhs * rhs);
2240 assert_eq!(lhs * rhs, lhs * &rhs);
2241 assert_eq!(lhs * rhs, &lhs * &rhs);
2242 }
2243
2244 #[test]
2245 #[cfg(feature = "unstable")]
2246 #[allow(clippy::op_ref)]
2247 fn test_pure_quaternion_div_quaternion_ref() {
2248 let lhs = PQ32::new(1.0, 2.0, 3.0);
2250 let rhs = Q32::new(4.0, 5.0, 6.0, 7.0);
2251 assert_eq!(lhs / rhs, &lhs / rhs);
2252 assert_eq!(lhs / rhs, lhs / &rhs);
2253 assert_eq!(lhs / rhs, &lhs / &rhs);
2254 }
2255
2256 #[test]
2257 #[cfg(feature = "unstable")]
2258 #[allow(clippy::op_ref)]
2259 fn test_pure_quaternion_add_real_ref() {
2260 let lhs = PQ32::new(1.0, 2.0, 3.0);
2262 let rhs = 4.0;
2263 assert_eq!(lhs + rhs, &lhs + rhs);
2264 assert_eq!(lhs + rhs, lhs + &rhs);
2265 assert_eq!(lhs + rhs, &lhs + &rhs);
2266 }
2267
2268 #[test]
2269 #[cfg(feature = "unstable")]
2270 #[allow(clippy::op_ref)]
2271 fn test_pure_quaternion_sub_real_ref() {
2272 let lhs = PQ32::new(1.0, 2.0, 3.0);
2275 let rhs = 4.0;
2276 assert_eq!(lhs - rhs, &lhs - rhs);
2277 assert_eq!(lhs - rhs, lhs - &rhs);
2278 assert_eq!(lhs - rhs, &lhs - &rhs);
2279 }
2280
2281 #[test]
2282 #[cfg(feature = "unstable")]
2283 #[allow(clippy::op_ref)]
2284 fn test_pure_quaternion_mul_real_ref() {
2285 let lhs = PQ32::new(1.0, 2.0, 3.0);
2288 let rhs = 4.0;
2289 assert_eq!(lhs * rhs, &lhs * rhs);
2290 assert_eq!(lhs * rhs, lhs * &rhs);
2291 assert_eq!(lhs * rhs, &lhs * &rhs);
2292 }
2293
2294 #[test]
2295 #[cfg(feature = "unstable")]
2296 #[allow(clippy::op_ref)]
2297 fn test_pure_quaternion_div_real_ref() {
2298 let lhs = PQ32::new(1.0, 2.0, 3.0);
2300 let rhs = 4.0;
2301 assert_eq!(lhs / rhs, &lhs / rhs);
2302 assert_eq!(lhs / rhs, lhs / &rhs);
2303 assert_eq!(lhs / rhs, &lhs / &rhs);
2304 }
2305
2306 #[test]
2307 #[cfg(feature = "unstable")]
2308 #[allow(clippy::op_ref)]
2309 fn test_pure_quaternion_add_unit_quaternion_ref() {
2310 let lhs = PQ32::new(1.0, 2.0, 3.0);
2313 let rhs = UQ32::I;
2314 assert_eq!(lhs + rhs, &lhs + rhs);
2315 assert_eq!(lhs + rhs, lhs + &rhs);
2316 assert_eq!(lhs + rhs, &lhs + &rhs);
2317 }
2318
2319 #[test]
2320 #[cfg(feature = "unstable")]
2321 #[allow(clippy::op_ref)]
2322 fn test_pure_quaternion_sub_unit_quaternion_ref() {
2323 let lhs = PQ32::new(1.0, 2.0, 3.0);
2326 let rhs = UQ32::I;
2327 assert_eq!(lhs - rhs, &lhs - rhs);
2328 assert_eq!(lhs - rhs, lhs - &rhs);
2329 assert_eq!(lhs - rhs, &lhs - &rhs);
2330 }
2331
2332 #[test]
2333 #[cfg(feature = "unstable")]
2334 #[allow(clippy::op_ref)]
2335 fn test_pure_quaternion_mul_unit_quaternion_ref() {
2336 let lhs = PQ32::new(1.0, 2.0, 3.0);
2339 let rhs = UQ32::I;
2340 assert_eq!(lhs * rhs, &lhs * rhs);
2341 assert_eq!(lhs * rhs, lhs * &rhs);
2342 assert_eq!(lhs * rhs, &lhs * &rhs);
2343 }
2344 #[test]
2345 #[cfg(feature = "unstable")]
2346 #[allow(clippy::op_ref)]
2347 fn test_pure_quaternion_div_unit_quaternion_ref() {
2348 let lhs = PQ32::new(1.0, 2.0, 3.0);
2351 let rhs = UQ32::I;
2352 assert_eq!(lhs / rhs, &lhs / rhs);
2353 assert_eq!(lhs / rhs, lhs / &rhs);
2354 assert_eq!(lhs / rhs, &lhs / &rhs);
2355 }
2356
2357 #[test]
2358 #[cfg(feature = "unstable")]
2359 fn test_pure_quaternion_add_assign() {
2360 let mut q = PQ32::new(1.0, 2.0, 3.0);
2362 q += PQ32::new(4.0, 5.0, 6.0);
2363 assert_eq!(q, PQ32::new(5.0, 7.0, 9.0));
2364 }
2365
2366 #[test]
2367 #[cfg(feature = "unstable")]
2368 fn test_pure_quaternion_sub_assign() {
2369 let mut q = PQ32::new(1.0, 2.0, 3.0);
2371 q -= PQ32::new(4.0, 5.0, 6.0);
2372 assert_eq!(q, PQ32::new(-3.0, -3.0, -3.0));
2373 }
2374
2375 #[test]
2376 #[cfg(feature = "unstable")]
2377 fn test_pure_quaternion_mul_assign() {
2378 let mut q = PQ32::new(1.0, 2.0, 3.0);
2380 q *= 2.0f32;
2381 assert_eq!(q, PQ32::new(2.0, 4.0, 6.0));
2382 }
2383
2384 #[test]
2385 #[cfg(feature = "unstable")]
2386 fn test_pure_quaternion_div_assign() {
2387 let mut q = PQ32::new(1.0, 2.0, 3.0);
2389 q /= 4.0f32;
2390 assert_eq!(q, PQ32::new(0.25, 0.5, 0.75));
2391 }
2392}