1#![allow(clippy::op_ref)]
3
4use num::{One, Zero};
5use std::ops::{Div, DivAssign, Mul, MulAssign};
6
7use simba::scalar::{ClosedAddAssign, ClosedMulAssign};
8use simba::simd::SimdRealField;
9
10use crate::base::{SVector, Scalar};
11
12use crate::geometry::{
13 AbstractRotation, Isometry, Point, Rotation, Similarity, Translation, UnitComplex,
14 UnitQuaternion,
15};
16
17macro_rules! similarity_binop_impl(
71 ($Op: ident, $op: ident;
72 $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
73 $action: expr; $($lives: tt),*) => {
74 impl<$($lives ,)* T: SimdRealField, R, const D: usize> $Op<$Rhs> for $Lhs
75 where T::Element: SimdRealField,
76 R: AbstractRotation<T, D> {
77 type Output = $Output;
78
79 #[inline]
80 fn $op($lhs, $rhs: $Rhs) -> Self::Output {
81 $action
82 }
83 }
84 }
85);
86
87macro_rules! similarity_binop_impl_all(
88 ($Op: ident, $op: ident;
89 $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
90 [val val] => $action_val_val: expr;
91 [ref val] => $action_ref_val: expr;
92 [val ref] => $action_val_ref: expr;
93 [ref ref] => $action_ref_ref: expr;) => {
94 similarity_binop_impl!(
95 $Op, $op;
96 $lhs: $Lhs, $rhs: $Rhs, Output = $Output;
97 $action_val_val; );
98
99 similarity_binop_impl!(
100 $Op, $op;
101 $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Output;
102 $action_ref_val; 'a);
103
104 similarity_binop_impl!(
105 $Op, $op;
106 $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Output;
107 $action_val_ref; 'b);
108
109 similarity_binop_impl!(
110 $Op, $op;
111 $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Output;
112 $action_ref_ref; 'a, 'b);
113 }
114);
115
116macro_rules! similarity_binop_assign_impl_all(
117 ($OpAssign: ident, $op_assign: ident;
118 $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty;
119 [val] => $action_val: expr;
120 [ref] => $action_ref: expr;) => {
121 impl<T: SimdRealField, R, const D: usize> $OpAssign<$Rhs> for $Lhs
122 where T::Element: SimdRealField,
123 R: AbstractRotation<T, D>{
124 #[inline]
125 fn $op_assign(&mut $lhs, $rhs: $Rhs) {
126 $action_val
127 }
128 }
129
130 impl<'b, T: SimdRealField, R, const D: usize> $OpAssign<&'b $Rhs> for $Lhs
131 where T::Element: SimdRealField,
132 R: AbstractRotation<T, D> {
133 #[inline]
134 fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) {
135 $action_ref
136 }
137 }
138 }
139);
140
141similarity_binop_impl_all!(
144 Mul, mul;
145 self: Similarity<T, R, D>, rhs: Similarity<T, R, D>, Output = Similarity<T, R, D>;
146 [val val] => &self * &rhs;
147 [ref val] => self * &rhs;
148 [val ref] => &self * rhs;
149 [ref ref] => {
150 let mut res = self * &rhs.isometry;
151 res.prepend_scaling_mut(rhs.scaling());
152 res
153 };
154);
155
156similarity_binop_impl_all!(
157 Div, div;
158 self: Similarity<T, R, D>, rhs: Similarity<T, R, D>, Output = Similarity<T, R, D>;
159 [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
160 [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
161 [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
162 [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
163);
164
165similarity_binop_assign_impl_all!(
167 MulAssign, mul_assign;
168 self: Similarity<T, R, D>, rhs: Translation<T, D>;
169 [val] => *self *= &rhs;
170 [ref] => {
171 let shift = self.isometry.rotation.transform_vector(&rhs.vector) * self.scaling();
172 self.isometry.translation.vector += shift;
173 };
174);
175
176similarity_binop_assign_impl_all!(
179 MulAssign, mul_assign;
180 self: Similarity<T, R, D>, rhs: Similarity<T, R, D>;
181 [val] => *self *= &rhs;
182 [ref] => {
183 *self *= &rhs.isometry;
184 self.prepend_scaling_mut(rhs.scaling());
185 };
186);
187
188similarity_binop_assign_impl_all!(
189 DivAssign, div_assign;
190 self: Similarity<T, R, D>, rhs: Similarity<T, R, D>;
191 [val] => *self /= &rhs;
192 [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
194);
195
196similarity_binop_assign_impl_all!(
199 MulAssign, mul_assign;
200 self: Similarity<T, R, D>, rhs: Isometry<T, R, D>;
201 [val] => *self *= &rhs;
202 [ref] => {
203 let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling();
204 self.isometry.translation.vector += shift;
205 self.isometry.rotation *= rhs.rotation.clone();
206 };
207);
208
209similarity_binop_assign_impl_all!(
210 DivAssign, div_assign;
211 self: Similarity<T, R, D>, rhs: Isometry<T, R, D>;
212 [val] => *self /= &rhs;
213 [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
215);
216
217md_assign_impl_all!(
220 MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField;
221 (Const<D>, U1), (Const<D>, Const<D>)
222 const D; for; where;
223 self: Similarity<T, Rotation<T, D>, D>, rhs: Rotation<T, D>;
224 [val] => self.isometry.rotation *= rhs;
225 [ref] => self.isometry.rotation *= rhs.clone();
226);
227
228md_assign_impl_all!(
229 DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField;
230 (Const<D>, U1), (Const<D>, Const<D>)
231 const D; for; where;
232 self: Similarity<T, Rotation<T, D>, D>, rhs: Rotation<T, D>;
233 [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
235 [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
236);
237
238md_assign_impl_all!(
239 MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField;
240 (U3, U3), (U3, U3)
241 const; for; where;
242 self: Similarity<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>;
243 [val] => self.isometry.rotation *= rhs;
244 [ref] => self.isometry.rotation *= rhs.clone();
245);
246
247md_assign_impl_all!(
248 DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField;
249 (U3, U3), (U3, U3)
250 const; for; where;
251 self: Similarity<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>;
252 [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
254 [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
255);
256
257md_assign_impl_all!(
258 MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField;
259 (U2, U2), (U2, U2)
260 const; for; where;
261 self: Similarity<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>;
262 [val] => self.isometry.rotation *= rhs;
263 [ref] => self.isometry.rotation *= rhs.clone();
264);
265
266md_assign_impl_all!(
267 DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField;
268 (U2, U2), (U2, U2)
269 const; for; where;
270 self: Similarity<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>;
271 [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
273 [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() };
274);
275
276similarity_binop_impl_all!(
279 Mul, mul;
280 self: Similarity<T, R, D>, rhs: Isometry<T, R, D>, Output = Similarity<T, R, D>;
281 [val val] => &self * &rhs;
282 [ref val] => self * &rhs;
283 [val ref] => &self * rhs;
284 [ref ref] => {
285 let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling();
286 Similarity::from_parts(
287 #[allow(clippy::suspicious_arithmetic_impl)]
288 Translation::from(&self.isometry.translation.vector + shift),
289 self.isometry.rotation.clone() * rhs.rotation.clone(),
290 self.scaling())
291 };
292);
293
294similarity_binop_impl_all!(
295 Div, div;
296 self: Similarity<T, R, D>, rhs: Isometry<T, R, D>, Output = Similarity<T, R, D>;
297 [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
298 [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
299 [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
300 [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
301);
302
303similarity_binop_impl_all!(
306 Mul, mul;
307 self: Isometry<T, R, D>, rhs: Similarity<T, R, D>, Output = Similarity<T, R, D>;
308 [val val] => {
309 let scaling = rhs.scaling();
310 Similarity::from_isometry(self * rhs.isometry, scaling)
311 };
312 [ref val] => {
313 let scaling = rhs.scaling();
314 Similarity::from_isometry(self * rhs.isometry, scaling)
315 };
316 [val ref] => {
317 let scaling = rhs.scaling();
318 Similarity::from_isometry(self * &rhs.isometry, scaling)
319 };
320 [ref ref] => {
321 let scaling = rhs.scaling();
322 Similarity::from_isometry(self * &rhs.isometry, scaling)
323 };
324);
325
326similarity_binop_impl_all!(
327 Div, div;
328 self: Isometry<T, R, D>, rhs: Similarity<T, R, D>, Output = Similarity<T, R, D>;
329 [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
330 [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
331 [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
332 [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() };
333);
334
335similarity_binop_impl_all!(
337 Mul, mul;
338 self: Similarity<T, R, D>, right: Point<T, D>, Output = Point<T, D>;
339 [val val] => {
340 let scaling = self.scaling();
341 self.isometry.translation * (self.isometry.rotation.transform_point(&right) * scaling)
342 };
343 [ref val] => &self.isometry.translation * (self.isometry.rotation.transform_point(&right) * self.scaling());
344 [val ref] => {
345 let scaling = self.scaling();
346 self.isometry.translation * (self.isometry.rotation.transform_point(right) * scaling)
347 };
348 [ref ref] => &self.isometry.translation * (self.isometry.rotation.transform_point(right) * self.scaling());
349);
350
351similarity_binop_impl_all!(
353 Mul, mul;
354 self: Similarity<T, R, D>, right: SVector<T, D>, Output = SVector<T, D>;
355 [val val] => self.isometry.rotation.transform_vector(&right) * self.scaling();
356 [ref val] => self.isometry.rotation.transform_vector(&right) * self.scaling();
357 [val ref] => self.isometry.rotation.transform_vector(right) * self.scaling();
358 [ref ref] => self.isometry.rotation.transform_vector(right) * self.scaling();
359);
360
361similarity_binop_impl_all!(
363 Mul, mul;
364 self: Similarity<T, R, D>, right: Translation<T, D>, Output = Similarity<T, R, D>;
365 [val val] => &self * &right;
366 [ref val] => self * &right;
367 [val ref] => &self * right;
368 [ref ref] => {
369 let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling();
370 Similarity::from_parts(
371 #[allow(clippy::suspicious_arithmetic_impl)]
372 Translation::from(&self.isometry.translation.vector + shift),
373 self.isometry.rotation.clone(),
374 self.scaling())
375 };
376);
377
378similarity_binop_impl_all!(
380 Mul, mul;
381 self: Translation<T, D>, right: Similarity<T, R, D>, Output = Similarity<T, R, D>;
382 [val val] => {
383 let scaling = right.scaling();
384 Similarity::from_isometry(self * right.isometry, scaling)
385 };
386 [ref val] => {
387 let scaling = right.scaling();
388 Similarity::from_isometry(self * right.isometry, scaling)
389 };
390 [val ref] => Similarity::from_isometry(self * &right.isometry, right.scaling());
391 [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling());
392);
393
394macro_rules! similarity_from_composition_impl(
395 ($Op: ident, $op: ident;
396 $($Dims: ident),*;
397 $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
398 $action: expr; $($lives: tt),*) => {
399 impl<$($lives ,)* T: SimdRealField $(, const $Dims: usize)*> $Op<$Rhs> for $Lhs
400 where T::Element: SimdRealField {
401 type Output = $Output;
402
403 #[inline]
404 fn $op($lhs, $rhs: $Rhs) -> Self::Output {
405 $action
406 }
407 }
408 }
409);
410
411macro_rules! similarity_from_composition_impl_all(
412 ($Op: ident, $op: ident;
413 $($Dims: ident),*;
414 $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
415 [val val] => $action_val_val: expr;
416 [ref val] => $action_ref_val: expr;
417 [val ref] => $action_val_ref: expr;
418 [ref ref] => $action_ref_ref: expr;) => {
419
420 similarity_from_composition_impl!(
421 $Op, $op;
422 $($Dims),*;
423 $lhs: $Lhs, $rhs: $Rhs, Output = $Output;
424 $action_val_val; );
425
426 similarity_from_composition_impl!(
427 $Op, $op;
428 $($Dims),*;
429 $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Output;
430 $action_ref_val; 'a);
431
432 similarity_from_composition_impl!(
433 $Op, $op;
434 $($Dims),*;
435 $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Output;
436 $action_val_ref; 'b);
437
438 similarity_from_composition_impl!(
439 $Op, $op;
440 $($Dims),*;
441 $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Output;
442 $action_ref_ref; 'a, 'b);
443 }
444);
445
446similarity_from_composition_impl_all!(
448 Mul, mul;
449 D;
450 self: Similarity<T, Rotation<T, D>, D>, rhs: Rotation<T, D>,
451 Output = Similarity<T, Rotation<T, D>, D>;
452 [val val] => {
453 let scaling = self.scaling();
454 Similarity::from_isometry(self.isometry * rhs, scaling)
455 };
456 [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling());
457 [val ref] => {
458 let scaling = self.scaling();
459 Similarity::from_isometry(self.isometry * rhs, scaling)
460 };
461 [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling());
462);
463
464similarity_from_composition_impl_all!(
466 Mul, mul;
467 D;
468 self: Rotation<T, D>, right: Similarity<T, Rotation<T, D>, D>,
469 Output = Similarity<T, Rotation<T, D>, D>;
470 [val val] => &self * &right;
471 [ref val] => self * &right;
472 [val ref] => &self * right;
473 [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling());
474);
475
476similarity_from_composition_impl_all!(
478 Div, div;
479 D;
480 self: Similarity<T, Rotation<T, D>, D>, rhs: Rotation<T, D>,
481 Output = Similarity<T, Rotation<T, D>, D>;
482 [val val] => {
483 let scaling = self.scaling();
484 Similarity::from_isometry(self.isometry / rhs, scaling)
485 };
486 [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling());
487 [val ref] => {
488 let scaling = self.scaling();
489 Similarity::from_isometry(self.isometry / rhs, scaling)
490 };
491 [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling());
492);
493
494similarity_from_composition_impl_all!(
496 Div, div;
497 D;
498 self: Rotation<T, D>, right: Similarity<T, Rotation<T, D>, D>,
499 Output = Similarity<T, Rotation<T, D>, D>;
500 [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
502 [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
503 [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
504 [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
505);
506
507similarity_from_composition_impl_all!(
509 Mul, mul;
510 ;
511 self: Similarity<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>,
512 Output = Similarity<T, UnitQuaternion<T>, 3>;
513 [val val] => {
514 let scaling = self.scaling();
515 Similarity::from_isometry(self.isometry * rhs, scaling)
516 };
517 [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling());
518 [val ref] => {
519 let scaling = self.scaling();
520 Similarity::from_isometry(self.isometry * rhs, scaling)
521 };
522 [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling());
523);
524
525similarity_from_composition_impl_all!(
527 Mul, mul;
528 ;
529 self: UnitQuaternion<T>, right: Similarity<T, UnitQuaternion<T>, 3>,
530 Output = Similarity<T, UnitQuaternion<T>, 3>;
531 [val val] => &self * &right;
532 [ref val] => self * &right;
533 [val ref] => &self * right;
534 [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling());
535);
536
537similarity_from_composition_impl_all!(
539 Div, div;
540 ;
541 self: Similarity<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>,
542 Output = Similarity<T, UnitQuaternion<T>, 3>;
543 [val val] => {
544 let scaling = self.scaling();
545 Similarity::from_isometry(self.isometry / rhs, scaling)
546 };
547 [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling());
548 [val ref] => {
549 let scaling = self.scaling();
550 Similarity::from_isometry(self.isometry / rhs, scaling)
551 };
552 [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling());
553);
554
555similarity_from_composition_impl_all!(
557 Div, div;
558 ;
559 self: UnitQuaternion<T>, right: Similarity<T, UnitQuaternion<T>, 3>,
560 Output = Similarity<T, UnitQuaternion<T>, 3>;
561 [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
563 [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
564 [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
565 [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() };
566);
567
568similarity_from_composition_impl_all!(
570 Mul, mul;
571 ;
572 self: Similarity<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>,
573 Output = Similarity<T, UnitComplex<T>, 2>;
574 [val val] => {
575 let scaling = self.scaling();
576 Similarity::from_isometry(self.isometry * rhs, scaling)
577 };
578 [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling());
579 [val ref] => {
580 let scaling = self.scaling();
581 Similarity::from_isometry(self.isometry * rhs, scaling)
582 };
583 [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling());
584);
585
586similarity_from_composition_impl_all!(
588 Div, div;
589 ;
590 self: Similarity<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>,
591 Output = Similarity<T, UnitComplex<T>, 2>;
592 [val val] => {
593 let scaling = self.scaling();
594 Similarity::from_isometry(self.isometry / rhs, scaling)
595 };
596 [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling());
597 [val ref] => {
598 let scaling = self.scaling();
599 Similarity::from_isometry(self.isometry / rhs, scaling)
600 };
601 [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling());
602);