nalgebra/geometry/
rotation_ops.rs

1/*
2 *
3 * This provides the following operator overladings:
4 *
5 * Index<(usize, usize)>
6 *
7 * Rotation × Rotation
8 * Rotation ÷ Rotation
9 * Rotation × Matrix
10 * Matrix   × Rotation
11 * Matrix   ÷ Rotation
12 * Rotation × Point
13 * Rotation × Unit<Vector>
14 *
15 *
16 * Rotation ×= Rotation
17 * Matrix   ×= Rotation
18 */
19
20use num::{One, Zero};
21use std::ops::{Div, DivAssign, Index, Mul, MulAssign};
22
23use simba::scalar::{ClosedAddAssign, ClosedMulAssign};
24
25use crate::base::allocator::Allocator;
26use crate::base::constraint::{AreMultipliable, ShapeConstraint};
27use crate::base::dimension::{Dim, U1};
28use crate::base::storage::Storage;
29use crate::base::{
30    Const, DefaultAllocator, Matrix, OMatrix, SMatrix, SVector, Scalar, Unit, Vector,
31};
32
33use crate::geometry::{Point, Rotation};
34
35impl<T: Scalar, const D: usize> Index<(usize, usize)> for Rotation<T, D> {
36    type Output = T;
37
38    #[inline]
39    fn index(&self, row_col: (usize, usize)) -> &T {
40        self.matrix().index(row_col)
41    }
42}
43
44// Rotation × Rotation
45md_impl_all!(
46    Mul, mul;
47    (Const<D>, Const<D>), (Const<D>, Const<D>)
48    const D;
49    for;
50    where;
51    self: Rotation<T, D>, right: Rotation<T, D>, Output = Rotation<T, D>;
52    [val val] => Rotation::from_matrix_unchecked(self.into_inner() * right.into_inner());
53    [ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.into_inner());
54    [val ref] => Rotation::from_matrix_unchecked(self.into_inner() * right.matrix());
55    [ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix());
56);
57
58// Rotation ÷ Rotation
59// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method?
60md_impl_all!(
61    Div, div;
62    (Const<D>, Const<D>), (Const<D>, Const<D>)
63    const D;
64    for;
65    where;
66    self: Rotation<T, D>, right: Rotation<T, D>, Output = Rotation<T, D>;
67    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
68    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
69    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
70    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
71);
72
73// Rotation × Matrix
74md_impl_all!(
75    Mul, mul;
76    (Const<D1>, Const<D1>), (R2, C2)
77    const D1;
78    for R2, C2, SB;
79    where R2: Dim, C2: Dim, SB: Storage<T, R2, C2>,
80          DefaultAllocator: Allocator<Const<D1>, C2>,
81          ShapeConstraint: AreMultipliable<Const<D1>, Const<D1>, R2, C2>;
82    self: Rotation<T, D1>, right: Matrix<T, R2, C2, SB>, Output = OMatrix<T, Const<D1>, C2>;
83    [val val] => self.into_inner() * right;
84    [ref val] => self.matrix() * right;
85    [val ref] => self.into_inner() * right;
86    [ref ref] => self.matrix() * right;
87);
88
89// Matrix × Rotation
90md_impl_all!(
91    Mul, mul;
92    (R1, C1), (Const<D2>, Const<D2>)
93    const D2;
94    for R1, C1, SA;
95    where R1: Dim, C1: Dim, SA: Storage<T, R1, C1>,
96          DefaultAllocator: Allocator<R1, Const<D2>>,
97          ShapeConstraint:  AreMultipliable<R1, C1, Const<D2>, Const<D2>>;
98    self: Matrix<T, R1, C1, SA>, right: Rotation<T, D2>, Output = OMatrix<T, R1, Const<D2>>;
99    [val val] => self * right.into_inner();
100    [ref val] => self * right.into_inner();
101    [val ref] => self * right.matrix();
102    [ref ref] => self * right.matrix();
103);
104
105// Matrix ÷ Rotation
106md_impl_all!(
107    Div, div;
108    (R1, C1), (Const<D2>, Const<D2>)
109    const D2;
110    for R1, C1, SA;
111    where R1: Dim, C1: Dim, SA: Storage<T, R1, C1>,
112          DefaultAllocator: Allocator<R1, Const<D2>>,
113          ShapeConstraint: AreMultipliable<R1, C1, Const<D2>, Const<D2>>;
114    self: Matrix<T, R1, C1, SA>, right: Rotation<T, D2>, Output = OMatrix<T, R1, Const<D2>>;
115    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
116    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
117    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
118    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
119);
120
121// Rotation × Point
122// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended
123// behavior?
124md_impl_all!(
125    Mul, mul;
126    (Const<D>, Const<D>), (Const<D>, U1)
127    const D;
128    for;
129    where ShapeConstraint:  AreMultipliable<Const<D>, Const<D>, Const<D>, U1>;
130    self: Rotation<T, D>, right: Point<T, D>, Output = Point<T, D>;
131    [val val] => self.into_inner() * right;
132    [ref val] => self.matrix() * right;
133    [val ref] => self.into_inner() * right;
134    [ref ref] => self.matrix() * right;
135);
136
137// Rotation × Unit<Vector>
138md_impl_all!(
139    Mul, mul;
140    (Const<D>, Const<D>), (Const<D>, U1)
141    const D;
142    for S;
143    where S: Storage<T, Const<D>>,
144          ShapeConstraint: AreMultipliable<Const<D>, Const<D>, Const<D>, U1>;
145    self: Rotation<T, D>, right: Unit<Vector<T, Const<D>, S>>, Output = Unit<SVector<T, D>>;
146    [val val] => Unit::new_unchecked(self.into_inner() * right.into_inner());
147    [ref val] => Unit::new_unchecked(self.matrix() * right.into_inner());
148    [val ref] => Unit::new_unchecked(self.into_inner() * right.as_ref());
149    [ref ref] => Unit::new_unchecked(self.matrix() * right.as_ref());
150);
151
152// Rotation ×= Rotation
153// TODO: try not to call `inverse()` explicitly.
154
155md_assign_impl_all!(
156    MulAssign, mul_assign;
157    (Const<D>, Const<D>), (Const<D>, Const<D>)
158    const D; for; where;
159    self: Rotation<T, D>, right: Rotation<T, D>;
160    [val] => self.matrix_mut_unchecked().mul_assign(right.into_inner());
161    [ref] => self.matrix_mut_unchecked().mul_assign(right.matrix());
162);
163
164md_assign_impl_all!(
165    DivAssign, div_assign;
166    (Const<D>, Const<D>), (Const<D>, Const<D>)
167    const D; for; where;
168    self: Rotation<T, D>, right: Rotation<T, D>;
169    [val] => self.matrix_mut_unchecked().mul_assign(right.inverse().into_inner());
170    [ref] => self.matrix_mut_unchecked().mul_assign(right.inverse().matrix());
171);
172
173// Matrix *= Rotation
174// TODO: try not to call `inverse()` explicitly.
175// TODO: this shares the same limitations as for the current impl. of MulAssign for matrices.
176// (In particular the number of matrix column must be equal to the number of rotation columns,
177// i.e., equal to the rotation dimension.
178
179md_assign_impl_all!(
180    MulAssign, mul_assign;
181    (Const<R1>, Const<C1>), (Const<C1>, Const<C1>)
182    const R1, C1; for; where;
183    self: SMatrix<T, R1, C1>, right: Rotation<T, C1>;
184    [val] => self.mul_assign(right.into_inner());
185    [ref] => self.mul_assign(right.matrix());
186);
187
188md_assign_impl_all!(
189    DivAssign, div_assign;
190    (Const<R1>, Const<C1>), (Const<C1>, Const<C1>)
191    const R1, C1; for; where;
192    self: SMatrix<T, R1, C1>, right: Rotation<T, C1>;
193    [val] => self.mul_assign(right.inverse().into_inner());
194    [ref] => self.mul_assign(right.inverse().matrix());
195);