nalgebra/geometry/
transform_ops.rs

1// The macros break if the references are taken out, for some reason.
2#![allow(clippy::op_ref)]
3
4use num::{One, Zero};
5use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign};
6
7use simba::scalar::{ClosedAddAssign, ClosedMulAssign, RealField, SubsetOf};
8
9use crate::base::allocator::Allocator;
10use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
11use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
12
13use crate::geometry::{
14    Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory,
15    TCategoryMul, TGeneral, TProjective, Transform, Translation, UnitComplex, UnitQuaternion,
16};
17
18/*
19 *
20 * In the following, we provide:
21 * =========================
22 *
23 * Index<(usize, usize)>
24 * IndexMut<(usize, usize)> (where TCategory == TGeneral)
25 *
26 * (Operators)
27 *
28 * Transform × Isometry
29 * Transform × Rotation
30 * Transform × Similarity
31 * Transform × Transform
32 * Transform × UnitQuaternion
33 * Transform × UnitComplex
34 * Transform × Translation
35 * Transform × Vector
36 * Transform × Point
37 *
38 * Isometry       × Transform
39 * Rotation       × Transform
40 * Similarity     × Transform
41 * Translation    × Transform
42 * UnitQuaternion × Transform
43 * UnitComplex    × Transform
44 *
45 * TODO: Transform ÷ Isometry
46 * Transform ÷ Rotation
47 * TODO: Transform ÷ Similarity
48 * Transform ÷ Transform
49 * Transform ÷ UnitQuaternion
50 * Transform ÷ Translation
51 *
52 * TODO: Isometry       ÷ Transform
53 * Rotation       ÷ Transform
54 * TODO: Similarity     ÷ Transform
55 * Translation    ÷ Transform
56 * UnitQuaternion ÷ Transform
57 * TODO: UnitComplex ÷ Transform
58 *
59 *
60 * (Assignment Operators)
61 *
62 *
63 * Transform ×= Transform
64 * Transform ×= Similarity
65 * Transform ×= Isometry
66 * Transform ×= Rotation
67 * Transform ×= UnitQuaternion
68 * Transform ×= UnitComplex
69 * Transform ×= Translation
70 *
71 * Transform ÷= Transform
72 * TODO: Transform ÷= Similarity
73 * TODO: Transform ÷= Isometry
74 * Transform ÷= Rotation
75 * Transform ÷= UnitQuaternion
76 * Transform ÷= UnitComplex
77 *
78 */
79
80/*
81 *
82 * Indexing.
83 *
84 */
85impl<T: RealField, C: TCategory, const D: usize> Index<(usize, usize)> for Transform<T, C, D>
86where
87    Const<D>: DimNameAdd<U1>,
88    DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
89{
90    type Output = T;
91
92    #[inline]
93    fn index(&self, ij: (usize, usize)) -> &T {
94        self.matrix().index(ij)
95    }
96}
97
98// Only general transformations are mutably indexable.
99impl<T: RealField, const D: usize> IndexMut<(usize, usize)> for Transform<T, TGeneral, D>
100where
101    Const<D>: DimNameAdd<U1>,
102    DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
103{
104    #[inline]
105    fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
106        self.matrix_mut().index_mut(ij)
107    }
108}
109
110// Transform × Vector
111md_impl_all!(
112    Mul, mul where T: RealField;
113    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
114    const D;
115    for C;
116    where Const<D>: DimNameAdd<U1>, C: TCategory,
117          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
118    self: Transform<T, C, D>, rhs: SVector<T, D>, Output = SVector<T, D>;
119    [val val] => &self * &rhs;
120    [ref val] =>  self * &rhs;
121    [val ref] => &self *  rhs;
122    [ref ref] => {
123        let transform = self.matrix().fixed_view::<D, D>(0, 0);
124
125        if C::has_normalizer() {
126            let normalizer = self.matrix().fixed_view::<1, D>(D, 0);
127            let n = normalizer.tr_dot(rhs);
128
129            if !n.is_zero() {
130                return transform * (rhs / n);
131            }
132        }
133
134        transform * rhs
135    };
136);
137
138// Transform × Point
139md_impl_all!(
140    Mul, mul where T: RealField;
141    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
142    const D;
143    for C;
144    where Const<D>: DimNameAdd<U1>, C: TCategory,
145          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
146    self: Transform<T, C, D>, rhs: Point<T, D>, Output = Point<T, D>;
147    [val val] => &self * &rhs;
148    [ref val] =>  self * &rhs;
149    [val ref] => &self *  rhs;
150    [ref ref] => {
151        let transform   = self.matrix().fixed_view::<D, D>(0, 0);
152        let translation = self.matrix().fixed_view::<D, 1>(0, D);
153
154        if C::has_normalizer() {
155            let normalizer = self.matrix().fixed_view::<1, D>(D, 0);
156            #[allow(clippy::suspicious_arithmetic_impl)]
157            let n = normalizer.tr_dot(&rhs.coords) + unsafe { self.matrix().get_unchecked((D, D)).clone() };
158
159            if !n.is_zero() {
160                return (transform * rhs + translation) / n;
161            }
162        }
163
164        transform * rhs + translation
165    };
166);
167
168// Transform × Transform
169md_impl_all!(
170    Mul, mul where T: RealField;
171    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
172    const D;
173    for CA, CB;
174    where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory,
175          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
176    self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
177    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.into_inner());
178    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.into_inner());
179    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.matrix());
180    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.matrix());
181);
182
183// Transform × Rotation
184md_impl_all!(
185    Mul, mul
186    where T: RealField;
187    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
188    const D;
189    for C;
190    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
191          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
192    self: Transform<T, C, D>, rhs: Rotation<T, D>, Output = Transform<T, C::Representative, D>;
193    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
194    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
195    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
196    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
197);
198
199// Rotation × Transform
200md_impl_all!(
201    Mul, mul where T: RealField;
202    (Const<D>, Const<D>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
203    const D;
204    for C;
205    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
206          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
207    self: Rotation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
208    [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
209    [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
210    [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
211    [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
212);
213
214// Transform × UnitQuaternion
215md_impl_all!(
216    Mul, mul where T: RealField;
217    (U4, U4), (U4, U1)
218    const;
219    for C;
220    where C: TCategoryMul<TAffine>;
221    self: Transform<T, C, 3>, rhs: UnitQuaternion<T>, Output = Transform<T, C::Representative, 3>;
222    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
223    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
224    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.clone().to_homogeneous());
225    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.clone().to_homogeneous());
226);
227
228// Transform × UnitComplex
229md_impl_all!(
230    Mul, mul where T: RealField;
231    (U3, U3), (U2, U1)
232    const;
233    for C;
234    where C: TCategoryMul<TAffine>;
235    self: Transform<T, C, 2>, rhs: UnitComplex<T>, Output = Transform<T, C::Representative, 2>;
236    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
237    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
238    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.clone().to_homogeneous());
239    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.clone().to_homogeneous());
240);
241
242// UnitQuaternion × Transform
243md_impl_all!(
244    Mul, mul where T: RealField;
245    (U4, U1), (U4, U4)
246    const;
247    for C;
248    where C: TCategoryMul<TAffine>;
249    self: UnitQuaternion<T>, rhs: Transform<T, C, 3>, Output = Transform<T, C::Representative, 3>;
250    [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
251    [ref val] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.into_inner());
252    [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
253    [ref ref] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.matrix());
254);
255
256// UnitComplex × Transform
257md_impl_all!(
258    Mul, mul where T: RealField;
259    (U2, U1), (U3, U3)
260    const;
261    for C;
262    where C: TCategoryMul<TAffine>;
263    self: UnitComplex<T>, rhs: Transform<T, C, 2>, Output = Transform<T, C::Representative, 2>;
264    [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
265    [ref val] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.into_inner());
266    [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
267    [ref ref] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.matrix());
268);
269
270// Transform × Isometry
271md_impl_all!(
272    Mul, mul where T: RealField;
273    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
274    const D;
275    for C, R;
276    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
277          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
278    self: Transform<T, C, D>, rhs: Isometry<T, R, D>, Output = Transform<T, C::Representative, D>;
279    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
280    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
281    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
282    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
283);
284
285// Isometry × Transform
286md_impl_all!(
287    Mul, mul where T: RealField;
288    (Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
289    const D;
290    for C, R;
291    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
292          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
293    self: Isometry<T, R, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
294    [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
295    [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
296    [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
297    [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
298);
299
300// Transform × Similarity
301md_impl_all!(
302    Mul, mul where T: RealField;
303    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
304    const D;
305    for C, R;
306    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
307          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
308    self: Transform<T, C, D>, rhs: Similarity<T, R, D>, Output = Transform<T, C::Representative, D>;
309    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
310    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
311    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
312    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
313);
314
315// Similarity × Transform
316md_impl_all!(
317    Mul, mul where T: RealField;
318    (Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
319    const D;
320    for C, R;
321    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
322          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
323    self: Similarity<T, R, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
324    [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
325    [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
326    [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
327    [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
328);
329
330/*
331 *
332 * TODO: don't explicitly build the homogeneous translation matrix.
333 * Directly apply the translation, just as in `Matrix::{append,prepend}_translation`. This has not
334 * been done yet because of the `DimNameDiff` requirement (which is not automatically deduced from
335 * `DimNameAdd` requirement).
336 *
337 */
338// Transform × Translation
339md_impl_all!(
340    Mul, mul where T: RealField;
341    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
342    const D;
343    for C;
344    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
345          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
346    self: Transform<T, C, D>, rhs: Translation<T, D>, Output = Transform<T, C::Representative, D>;
347    [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
348    [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
349    [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
350    [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
351);
352
353// Translation × Transform
354md_impl_all!(
355    Mul, mul where T: RealField;
356    (Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
357    const D;
358    for C;
359    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
360          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
361    self: Translation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
362    [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
363    [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
364    [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
365    [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
366);
367
368// Transform ÷ Transform
369md_impl_all!(
370    Div, div where T: RealField;
371    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
372    const D;
373    for CA, CB;
374    where Const<D>: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>,
375          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
376    self: Transform<T, CA, D>, rhs: Transform<T, CB, D>, Output = Transform<T, CA::Representative, D>;
377    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
378    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
379    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.clone().inverse() };
380    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.clone().inverse() };
381);
382
383// Transform ÷ Rotation
384md_impl_all!(
385    Div, div where T: RealField;
386    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
387    const D;
388    for C;
389    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
390          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
391    self: Transform<T, C, D>, rhs: Rotation<T, D>, Output = Transform<T, C::Representative, D>;
392    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
393    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
394    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
395    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
396);
397
398// Rotation ÷ Transform
399md_impl_all!(
400    Div, div where T: RealField;
401    (Const<D>, Const<D>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
402    const D;
403    for C;
404    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
405          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
406    self: Rotation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
407    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
408    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
409    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
410    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
411);
412
413// Transform ÷ UnitQuaternion
414md_impl_all!(
415    Div, div where T: RealField;
416    (U4, U4), (U4, U1)
417    const;
418    for C;
419    where C: TCategoryMul<TAffine>;
420    self: Transform<T, C, 3>, rhs: UnitQuaternion<T>, Output = Transform<T, C::Representative, 3>;
421    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
422    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
423    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
424    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
425);
426
427// UnitQuaternion ÷ Transform
428md_impl_all!(
429    Div, div where T: RealField;
430    (U4, U1), (U4, U4)
431    const;
432    for C;
433    where C: TCategoryMul<TAffine>;
434    self: UnitQuaternion<T>, rhs: Transform<T, C, 3>, Output = Transform<T, C::Representative, 3>;
435    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
436    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
437    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
438    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
439);
440
441//      // Transform ÷ Isometry
442//      md_impl_all!(
443//          Div, div where T: RealField;
444//          (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
445//          for Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >
446//          where SB::Alloc: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1> >;
447//          self: Transform<T, C, D>, rhs: Isometry<T, R, D>, Output = Transform<T, C::Representative, D>;
448//          [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.inverse().to_homogeneous());
449//          [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
450//          [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.inverse().to_homogeneous());
451//          [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
452//      );
453
454//      // Isometry ÷ Transform
455//      md_impl_all!(
456//          Div, div where T: RealField;
457//          (Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
458//          for Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >
459//          where SA::Alloc: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1> >;
460//          self: Isometry<T, R, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
461//          [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
462//          [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
463//          [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
464//          [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
465//      );
466
467//      // Transform ÷ Similarity
468//      md_impl_all!(
469//          Div, div where T: RealField;
470//          (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
471//          for Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >
472//          where SB::Alloc: Allocator<D, D >
473//          where SB::Alloc: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1> >;
474//          self: Transform<T, C, D>, rhs: Similarity<T, R, D>, Output = Transform<T, C::Representative, D>;
475//          [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
476//          [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
477//          [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
478//          [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
479//      );
480
481//      // Similarity ÷ Transform
482//      md_impl_all!(
483//          Div, div where T: RealField;
484//          (Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
485//          for Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >
486//          where SA::Alloc: Allocator<D, D >
487//          where SA::Alloc: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1> >;
488//          self: Similarity<T, R, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
489//          [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
490//          [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
491//          [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
492//          [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
493//      );
494
495// Transform ÷ Translation
496md_impl_all!(
497    Div, div where T: RealField;
498    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
499    const D;
500    for C;
501    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
502          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
503    self: Transform<T, C, D>, rhs: Translation<T, D>, Output = Transform<T, C::Representative, D>;
504    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
505    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
506    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
507    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
508);
509
510// Translation ÷ Transform
511md_impl_all!(
512    Div, div where T: RealField;
513    (Const<D>, U1), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
514    const D;
515    for C;
516    where Const<D>: DimNameAdd<U1>, C: TCategoryMul<TAffine>,
517          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
518    self: Translation<T, D>, rhs: Transform<T, C, D>, Output = Transform<T, C::Representative, D>;
519    [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
520    [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
521    [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
522    [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs };
523);
524
525// Transform ×= Transform
526md_assign_impl_all!(
527    MulAssign, mul_assign where T: RealField;
528    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
529    const D;
530    for CA, CB;
531    where Const<D>: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>,
532          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
533    self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
534    [val] => *self.matrix_mut_unchecked() *= rhs.into_inner();
535    [ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
536);
537
538// Transform ×= Similarity
539md_assign_impl_all!(
540    MulAssign, mul_assign where T: RealField;
541    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
542    const D;
543    for C, R;
544    where Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
545          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
546    self: Transform<T, C, D>, rhs: Similarity<T, R, D>;
547    [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
548    [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
549);
550
551// Transform ×= Isometry
552md_assign_impl_all!(
553    MulAssign, mul_assign where T: RealField;
554    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
555    const D;
556    for C, R;
557    where Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >,
558          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
559    self: Transform<T, C, D>, rhs: Isometry<T, R, D>;
560    [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
561    [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
562);
563
564/*
565 *
566 * TODO: don't explicitly build the homogeneous translation matrix.
567 * Directly apply the translation, just as in `Matrix::{append,prepend}_translation`. This has not
568 * been done yet because of the `DimNameDiff` requirement (which is not automatically deduced from
569 * `DimNameAdd` requirement).
570 *
571 */
572// Transform ×= Translation
573md_assign_impl_all!(
574    MulAssign, mul_assign where T: RealField;
575    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
576    const D;
577    for C;
578    where Const<D>: DimNameAdd<U1>, C: TCategory,
579          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
580    self: Transform<T, C, D>, rhs: Translation<T, D>;
581    [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
582    [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
583);
584
585// Transform ×= Rotation
586md_assign_impl_all!(
587    MulAssign, mul_assign where T: RealField;
588    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
589    const D;
590    for C;
591    where Const<D>: DimNameAdd<U1>, C: TCategory,
592          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
593    self: Transform<T, C, D>, rhs: Rotation<T, D>;
594    [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
595    [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
596);
597
598// Transform ×= UnitQuaternion
599md_assign_impl_all!(
600    MulAssign, mul_assign where T: RealField;
601    (U4, U4), (U4, U1)
602    const;
603    for C;
604    where C: TCategory;
605    self: Transform<T, C, 3>, rhs: UnitQuaternion<T>;
606    [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
607    [ref] => *self.matrix_mut_unchecked() *= rhs.clone().to_homogeneous();
608);
609
610// Transform ×= UnitComplex
611md_assign_impl_all!(
612    MulAssign, mul_assign where T: RealField;
613    (U3, U3), (U2, U1)
614    const;
615    for C;
616    where C: TCategory;
617    self: Transform<T, C, 2>, rhs: UnitComplex<T>;
618    [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
619    [ref] => *self.matrix_mut_unchecked() *= rhs.clone().to_homogeneous();
620);
621
622// Transform ÷= Transform
623md_assign_impl_all!(
624    DivAssign, div_assign where T: RealField;
625    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>)
626    const D;
627    for CA, CB;
628    where Const<D>: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>,
629          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
630    self: Transform<T, CA, D>, rhs: Transform<T, CB, D>;
631    [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
632    [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() };
633);
634
635//      // Transform ÷= Similarity
636//      md_assign_impl_all!(
637//          DivAssign, div_assign;
638//          (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
639//          for Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
640//          self: Transform<T, C, D>, rhs: Similarity<T, R, D>;
641//          [val] => *self *= rhs.inverse();
642//          [ref] => *self *= rhs.inverse();
643//      );
644//
645//
646//      // Transform ÷= Isometry
647//      md_assign_impl_all!(
648//          DivAssign, div_assign;
649//          (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
650//          for Const<D>: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> >;
651//          self: Transform<T, C, D>, rhs: Isometry<T, R, D>;
652//          [val] => *self *= rhs.inverse();
653//          [ref] => *self *= rhs.inverse();
654//      );
655
656// Transform ÷= Translation
657md_assign_impl_all!(
658    DivAssign, div_assign where T: RealField;
659    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, U1)
660    const D;
661    for C;
662    where Const<D>: DimNameAdd<U1>, C: TCategory,
663          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
664    self: Transform<T, C, D>, rhs: Translation<T, D>;
665    [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
666    [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
667);
668
669// Transform ÷= Rotation
670md_assign_impl_all!(
671    DivAssign, div_assign where T: RealField;
672    (DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>), (Const<D>, Const<D>)
673    const D;
674    for C;
675    where Const<D>: DimNameAdd<U1>, C: TCategory,
676          DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>;
677    self: Transform<T, C, D>, rhs: Rotation<T, D>;
678    [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
679    [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
680);
681
682// Transform ÷= UnitQuaternion
683md_assign_impl_all!(
684    DivAssign, div_assign where T: RealField;
685    (U4, U4), (U4, U1)
686    const;
687    for C;
688    where C: TCategory;
689    self: Transform<T, C, 3>, rhs: UnitQuaternion<T>;
690    [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
691    [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
692);
693
694// Transform ÷= UnitComplex
695md_assign_impl_all!(
696    DivAssign, div_assign where T: RealField;
697    (U3, U3), (U2, U1)
698    const;
699    for C;
700    where C: TCategory;
701    self: Transform<T, C, 2>, rhs: UnitComplex<T>;
702    [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
703    [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
704);