use std::ops::{Div, DivAssign, Mul, MulAssign}; use alga::general::Real; use base::allocator::Allocator; use base::constraint::{DimEq, ShapeConstraint}; use base::dimension::{Dim, U1, U2}; use base::storage::{Storage, StorageMut}; use base::{DefaultAllocator, Matrix, Unit, Vector, Vector2}; use geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex}; /* * This file provides: * =================== * * UnitComplex × UnitComplex * UnitComplex × Rotation -> UnitComplex * Rotation × UnitComplex -> UnitComplex * * UnitComplex ÷ UnitComplex * UnitComplex ÷ Rotation -> UnitComplex * Rotation ÷ UnitComplex -> UnitComplex * * * UnitComplex × Point * UnitComplex × Vector * UnitComplex × Unit * * UnitComplex × Isometry * UnitComplex × Similarity * UnitComplex × Translation -> Isometry * * NOTE: -UnitComplex is already provided by `Unit`. * * (Assignment Operators) * * UnitComplex ×= UnitComplex * UnitComplex ×= Rotation * * UnitComplex ÷= UnitComplex * UnitComplex ÷= Rotation * * Rotation ×= UnitComplex * Rotation ÷= UnitComplex * */ // UnitComplex × UnitComplex impl Mul> for UnitComplex { type Output = UnitComplex; #[inline] fn mul(self, rhs: UnitComplex) -> UnitComplex { Unit::new_unchecked(self.unwrap() * rhs.unwrap()) } } impl<'a, N: Real> Mul> for &'a UnitComplex { type Output = UnitComplex; #[inline] fn mul(self, rhs: UnitComplex) -> UnitComplex { Unit::new_unchecked(self.complex() * rhs.unwrap()) } } impl<'b, N: Real> Mul<&'b UnitComplex> for UnitComplex { type Output = UnitComplex; #[inline] fn mul(self, rhs: &'b UnitComplex) -> UnitComplex { Unit::new_unchecked(self.unwrap() * rhs.complex()) } } impl<'a, 'b, N: Real> Mul<&'b UnitComplex> for &'a UnitComplex { type Output = UnitComplex; #[inline] fn mul(self, rhs: &'b UnitComplex) -> UnitComplex { Unit::new_unchecked(self.complex() * rhs.complex()) } } // UnitComplex ÷ UnitComplex impl Div> for UnitComplex { type Output = UnitComplex; #[inline] fn div(self, rhs: UnitComplex) -> UnitComplex { Unit::new_unchecked(self.unwrap() * rhs.conjugate().unwrap()) } } impl<'a, N: Real> Div> for &'a UnitComplex { type Output = UnitComplex; #[inline] fn div(self, rhs: UnitComplex) -> UnitComplex { Unit::new_unchecked(self.complex() * rhs.conjugate().unwrap()) } } impl<'b, N: Real> Div<&'b UnitComplex> for UnitComplex { type Output = UnitComplex; #[inline] fn div(self, rhs: &'b UnitComplex) -> UnitComplex { Unit::new_unchecked(self.unwrap() * rhs.conjugate().unwrap()) } } impl<'a, 'b, N: Real> Div<&'b UnitComplex> for &'a UnitComplex { type Output = UnitComplex; #[inline] fn div(self, rhs: &'b UnitComplex) -> UnitComplex { Unit::new_unchecked(self.complex() * rhs.conjugate().unwrap()) } } macro_rules! complex_op_impl( ($Op: ident, $op: ident; ($RDim: ident, $CDim: ident) $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; $action: expr; $($lives: tt),*) => { impl<$($lives ,)* N: Real $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs where DefaultAllocator: Allocator { type Output = $Result; #[inline] fn $op($lhs, $rhs: $Rhs) -> Self::Output { $action } } } ); macro_rules! complex_op_impl_all( ($Op: ident, $op: ident; ($RDim: ident, $CDim: ident) $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; [val val] => $action_val_val: expr; [ref val] => $action_ref_val: expr; [val ref] => $action_val_ref: expr; [ref ref] => $action_ref_ref: expr;) => { complex_op_impl!($Op, $op; ($RDim, $CDim) $(for $Storage: $StoragesBound $(<$($BoundParam),*>)*),*; $lhs: $Lhs, $rhs: $Rhs, Output = $Result; $action_val_val; ); complex_op_impl!($Op, $op; ($RDim, $CDim) $(for $Storage: $StoragesBound $(<$($BoundParam),*>)*),*; $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Result; $action_ref_val; 'a); complex_op_impl!($Op, $op; ($RDim, $CDim) $(for $Storage: $StoragesBound $(<$($BoundParam),*>)*),*; $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Result; $action_val_ref; 'b); complex_op_impl!($Op, $op; ($RDim, $CDim) $(for $Storage: $StoragesBound $(<$($BoundParam),*>)*),*; $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Result; $action_ref_ref; 'a, 'b); } ); // UnitComplex × Rotation complex_op_impl_all!( Mul, mul; (U2, U2); self: UnitComplex, rhs: Rotation, Output = UnitComplex; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => self * UnitComplex::from_rotation_matrix(rhs); ); // UnitComplex ÷ Rotation complex_op_impl_all!( Div, div; (U2, U2); self: UnitComplex, rhs: Rotation, Output = UnitComplex; [val val] => &self / &rhs; [ref val] => self / &rhs; [val ref] => &self / rhs; [ref ref] => self * UnitComplex::from_rotation_matrix(rhs).inverse(); ); // Rotation × UnitComplex complex_op_impl_all!( Mul, mul; (U2, U2); self: Rotation, rhs: UnitComplex, Output = UnitComplex; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => UnitComplex::from_rotation_matrix(self) * rhs; ); // Rotation ÷ UnitComplex complex_op_impl_all!( Div, div; (U2, U2); self: Rotation, rhs: UnitComplex, Output = UnitComplex; [val val] => &self / &rhs; [ref val] => self / &rhs; [val ref] => &self / rhs; [ref ref] => UnitComplex::from_rotation_matrix(self) * rhs.inverse(); ); // UnitComplex × Point complex_op_impl_all!( Mul, mul; (U2, U1); self: UnitComplex, rhs: Point2, Output = Point2; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => Point2::from(self * &rhs.coords); ); // UnitComplex × Vector complex_op_impl_all!( Mul, mul; (U2, U1) for S: Storage; self: UnitComplex, rhs: Vector, Output = Vector2; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => { let i = self.as_ref().im; let r = self.as_ref().re; Vector2::new(r * rhs[0] - i * rhs[1], i * rhs[0] + r * rhs[1]) }; ); // UnitComplex × Unit complex_op_impl_all!( Mul, mul; (U2, U1) for S: Storage; self: UnitComplex, rhs: Unit>, Output = Unit>; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => Unit::new_unchecked(self * rhs.as_ref()); ); // UnitComplex × Isometry complex_op_impl_all!( Mul, mul; (U2, U1); self: UnitComplex, rhs: Isometry>, Output = Isometry>; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => { let shift = self * &rhs.translation.vector; Isometry::from_parts(Translation::from(shift), self * &rhs.rotation) }; ); // UnitComplex × Similarity complex_op_impl_all!( Mul, mul; (U2, U1); self: UnitComplex, rhs: Similarity>, Output = Similarity>; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => Similarity::from_isometry(self * &rhs.isometry, rhs.scaling()); ); // UnitComplex × Translation complex_op_impl_all!( Mul, mul; (U2, U1); self: UnitComplex, rhs: Translation, Output = Isometry>; [val val] => Isometry::from_parts(Translation::from(&self * rhs.vector), self); [ref val] => Isometry::from_parts(Translation::from( self * rhs.vector), self.clone()); [val ref] => Isometry::from_parts(Translation::from(&self * &rhs.vector), self); [ref ref] => Isometry::from_parts(Translation::from( self * &rhs.vector), self.clone()); ); // Translation × UnitComplex complex_op_impl_all!( Mul, mul; (U2, U1); self: Translation, right: UnitComplex, Output = Isometry>; [val val] => Isometry::from_parts(self, right); [ref val] => Isometry::from_parts(self.clone(), right); [val ref] => Isometry::from_parts(self, right.clone()); [ref ref] => Isometry::from_parts(self.clone(), right.clone()); ); // UnitComplex ×= UnitComplex impl MulAssign> for UnitComplex { #[inline] fn mul_assign(&mut self, rhs: UnitComplex) { *self = &*self * rhs } } impl<'b, N: Real> MulAssign<&'b UnitComplex> for UnitComplex { #[inline] fn mul_assign(&mut self, rhs: &'b UnitComplex) { *self = &*self * rhs } } // UnitComplex /= UnitComplex impl DivAssign> for UnitComplex { #[inline] fn div_assign(&mut self, rhs: UnitComplex) { *self = &*self / rhs } } impl<'b, N: Real> DivAssign<&'b UnitComplex> for UnitComplex { #[inline] fn div_assign(&mut self, rhs: &'b UnitComplex) { *self = &*self / rhs } } // UnitComplex ×= Rotation impl MulAssign> for UnitComplex where DefaultAllocator: Allocator { #[inline] fn mul_assign(&mut self, rhs: Rotation) { *self = &*self * rhs } } impl<'b, N: Real> MulAssign<&'b Rotation> for UnitComplex where DefaultAllocator: Allocator { #[inline] fn mul_assign(&mut self, rhs: &'b Rotation) { *self = &*self * rhs } } // UnitComplex ÷= Rotation impl DivAssign> for UnitComplex where DefaultAllocator: Allocator { #[inline] fn div_assign(&mut self, rhs: Rotation) { *self = &*self / rhs } } impl<'b, N: Real> DivAssign<&'b Rotation> for UnitComplex where DefaultAllocator: Allocator { #[inline] fn div_assign(&mut self, rhs: &'b Rotation) { *self = &*self / rhs } } // Rotation ×= UnitComplex impl MulAssign> for Rotation where DefaultAllocator: Allocator { #[inline] fn mul_assign(&mut self, rhs: UnitComplex) { self.mul_assign(rhs.to_rotation_matrix()) } } impl<'b, N: Real> MulAssign<&'b UnitComplex> for Rotation where DefaultAllocator: Allocator { #[inline] fn mul_assign(&mut self, rhs: &'b UnitComplex) { self.mul_assign(rhs.to_rotation_matrix()) } } // Rotation ÷= UnitComplex impl DivAssign> for Rotation where DefaultAllocator: Allocator { #[inline] fn div_assign(&mut self, rhs: UnitComplex) { self.div_assign(rhs.to_rotation_matrix()) } } impl<'b, N: Real> DivAssign<&'b UnitComplex> for Rotation where DefaultAllocator: Allocator { #[inline] fn div_assign(&mut self, rhs: &'b UnitComplex) { self.div_assign(rhs.to_rotation_matrix()) } } // Matrix = UnitComplex * Matrix impl UnitComplex { /// Performs the multiplication `rhs = self * rhs` in-place. pub fn rotate>( &self, rhs: &mut Matrix, ) where ShapeConstraint: DimEq, { assert_eq!( rhs.nrows(), 2, "Unit complex rotation: the input matrix must have exactly two rows." ); let i = self.as_ref().im; let r = self.as_ref().re; for j in 0..rhs.ncols() { unsafe { let a = *rhs.get_unchecked(0, j); let b = *rhs.get_unchecked(1, j); *rhs.get_unchecked_mut(0, j) = r * a - i * b; *rhs.get_unchecked_mut(1, j) = i * a + r * b; } } } /// Performs the multiplication `lhs = lhs * self` in-place. pub fn rotate_rows>( &self, lhs: &mut Matrix, ) where ShapeConstraint: DimEq, { assert_eq!( lhs.ncols(), 2, "Unit complex rotation: the input matrix must have exactly two columns." ); let i = self.as_ref().im; let r = self.as_ref().re; // FIXME: can we optimize that to iterate on one column at a time ? for j in 0..lhs.nrows() { unsafe { let a = *lhs.get_unchecked(j, 0); let b = *lhs.get_unchecked(j, 1); *lhs.get_unchecked_mut(j, 0) = r * a + i * b; *lhs.get_unchecked_mut(j, 1) = -i * a + r * b; } } } }