use std::fmt;
use approx::ApproxEq;
use num_complex::Complex;
use alga::general::Real;
use core::{Unit, SquareMatrix, Vector1, Matrix3};
use core::dimension::U2;
use geometry::Rotation2;
/// A complex number with a norm equal to 1.
///
///
///
/// Due to a [bug](https://github.com/rust-lang/rust/issues/32077) in rustdoc, the documentation
/// below has been written manually lists only method signatures.
/// Trait implementations are not listed either.
///
///
///
/// Please refer directly to the documentation written above each function definition on the source
/// code for more details.
///
///
/// Methods
///
///
/// fn angle(&self) -> N
///
///
///
/// fn angle_to(&self, other: &Self) -> N
///
///
///
/// fn complex(&self) -> &Complex
///
///
///
/// fn conjugate(&self) -> Self
///
///
///
///
///
/// fn from_angle(angle: N) -> Self
///
///
///
/// fn from_complex(q: Complex) -> Self
///
///
///
/// fn from_rotation_matrix(rotmat: &RotationBase) -> Self
///
///
///
/// fn from_scaled_axis(axisangle: ColumnVector) -> Self
///
///
///
/// fn identity() -> Self
///
///
///
/// fn inverse(&self) -> Self
///
///
///
///
///
/// fn new(angle: N) -> Self
///
///
///
/// fn powf(&self, n: N) -> Self
///
///
///
/// fn rotation_between(a: &ColumnVector, b: &ColumnVector) -> Self
///
///
///
/// fn rotation_to(&self, other: &Self) -> Self
///
///
///
/// fn scaled_axis(&self) -> Vector1
///
///
///
/// fn scaled_rotation_between(a: &ColumnVector, b: &ColumnVector, s: N) -> Self
///
///
///
/// fn to_homogeneous(&self) -> Matrix3
///
///
///
pub type UnitComplex = Unit>;
impl UnitComplex {
/// The rotation angle in `]-pi; pi]` of this unit complex number.
#[inline]
pub fn angle(&self) -> N {
self.im.atan2(self.re)
}
/// The rotation angle returned as a 1-dimensional vector.
#[inline]
pub fn scaled_axis(&self) -> Vector1 {
Vector1::new(self.angle())
}
/// The underlying complex number.
///
/// Same as `self.as_ref()`.
#[inline]
pub fn complex(&self) -> &Complex {
self.as_ref()
}
/// Compute the conjugate of this unit complex number.
#[inline]
pub fn conjugate(&self) -> Self {
UnitComplex::new_unchecked(self.conj())
}
/// Inverts this complex number if it is not zero.
#[inline]
pub fn inverse(&self) -> Self {
self.conjugate()
}
/// The rotation angle needed to make `self` and `other` coincide.
#[inline]
pub fn angle_to(&self, other: &Self) -> N {
let delta = self.rotation_to(other);
delta.angle()
}
/// The unit complex number needed to make `self` and `other` coincide.
///
/// The result is such that: `self.rotation_to(other) * self == other`.
#[inline]
pub fn rotation_to(&self, other: &Self) -> Self {
other / self
}
/// Compute in-place the conjugate of this unit complex number.
#[inline]
pub fn conjugate_mut(&mut self) {
let me = self.as_mut_unchecked();
me.im = -me.im;
}
/// Inverts in-place this unit complex number.
#[inline]
pub fn inverse_mut(&mut self) {
self.conjugate_mut()
}
/// Raise this unit complex number to a given floating power.
///
/// This returns the unit complex number that identifies a rotation angle equal to
/// `self.angle() × n`.
#[inline]
pub fn powf(&self, n: N) -> Self {
Self::from_angle(self.angle() * n)
}
/// Builds the rotation matrix corresponding to this unit complex number.
#[inline]
pub fn to_rotation_matrix(&self) -> Rotation2 {
let r = self.re;
let i = self.im;
Rotation2::from_matrix_unchecked(
SquareMatrix::<_, U2, _>::new(
r, -i,
i, r
)
)
}
/// Converts this unit complex number into its equivalent homogeneous transformation matrix.
#[inline]
pub fn to_homogeneous(&self) -> Matrix3 {
self.to_rotation_matrix().to_homogeneous()
}
}
impl fmt::Display for UnitComplex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UnitComplex angle: {}", self.angle())
}
}
impl ApproxEq for UnitComplex {
type Epsilon = N;
#[inline]
fn default_epsilon() -> Self::Epsilon {
N::default_epsilon()
}
#[inline]
fn default_max_relative() -> Self::Epsilon {
N::default_max_relative()
}
#[inline]
fn default_max_ulps() -> u32 {
N::default_max_ulps()
}
#[inline]
fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
self.re.relative_eq(&other.re, epsilon, max_relative) &&
self.im.relative_eq(&other.im, epsilon, max_relative)
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.re.ulps_eq(&other.re, epsilon, max_ulps) &&
self.im.ulps_eq(&other.im, epsilon, max_ulps)
}
}