#[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; use num::One; use num_complex::Complex; use rand::{Rand, Rng}; use alga::general::Real; use core::{DefaultAllocator, Vector}; use core::dimension::{U1, U2}; use core::storage::Storage; use core::allocator::Allocator; use geometry::{Rotation, UnitComplex}; impl UnitComplex { /// The unit complex number multiplicative identity. #[inline] pub fn identity() -> Self { Self::new_unchecked(Complex::new(N::one(), N::zero())) } /// Builds the unit complex number corresponding to the rotation with the angle. #[inline] pub fn new(angle: N) -> Self { let (sin, cos) = angle.sin_cos(); Self::from_cos_sin_unchecked(cos, sin) } /// Builds the unit complex number corresponding to the rotation with the angle. /// /// Same as `Self::new(angle)`. #[inline] pub fn from_angle(angle: N) -> Self { Self::new(angle) } /// Builds the unit complex number frow the sinus and cosinus of the rotation angle. /// /// The input values are not checked. #[inline] pub fn from_cos_sin_unchecked(cos: N, sin: N) -> Self { UnitComplex::new_unchecked(Complex::new(cos, sin)) } /// Builds a unit complex rotation from an angle in radian wrapped in a 1-dimensional vector. /// /// Equivalent to `Self::new(axisangle[0])`. #[inline] pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::from_angle(axisangle[0]) } /// Creates a new unit complex number from a complex number. /// /// The input complex number will be normalized. #[inline] pub fn from_complex(q: Complex) -> Self { Self::from_complex_and_get(q).0 } /// Creates a new unit complex number from a complex number. /// /// The input complex number will be normalized. Returns the complex number norm as well. #[inline] pub fn from_complex_and_get(q: Complex) -> (Self, N) { let norm = (q.im * q.im + q.re * q.re).sqrt(); (Self::new_unchecked(q / norm), norm) } /// Builds the unit complex number from the corresponding 2D rotation matrix. #[inline] pub fn from_rotation_matrix(rotmat: &Rotation) -> Self where DefaultAllocator: Allocator, { Self::new_unchecked(Complex::new(rotmat[(0, 0)], rotmat[(1, 0)])) } /// The unit complex needed to make `a` and `b` be collinear and point toward the same /// direction. #[inline] pub fn rotation_between(a: &Vector, b: &Vector) -> Self where SB: Storage, SC: Storage, { Self::scaled_rotation_between(a, b, N::one()) } /// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// direction, raised to the power `s`. #[inline] pub fn scaled_rotation_between( a: &Vector, b: &Vector, s: N, ) -> Self where SB: Storage, SC: Storage, { if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) { let sang = na.perp(&nb); let cang = na.dot(&nb); Self::from_angle(sang.atan2(cang) * s) } else { Self::identity() } } } impl One for UnitComplex { #[inline] fn one() -> Self { Self::identity() } } impl Rand for UnitComplex { #[inline] fn rand(rng: &mut R) -> Self { UnitComplex::from_angle(N::rand(rng)) } } #[cfg(feature = "arbitrary")] impl Arbitrary for UnitComplex { #[inline] fn arbitrary(g: &mut G) -> Self { UnitComplex::from_angle(N::arbitrary(g)) } }