2016-12-05 05:44:42 +08:00
|
|
|
|
use std::fmt;
|
2017-02-13 01:17:09 +08:00
|
|
|
|
use approx::ApproxEq;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
use num_complex::Complex;
|
|
|
|
|
|
|
|
|
|
use alga::general::Real;
|
2017-02-13 01:17:09 +08:00
|
|
|
|
use core::{Unit, SquareMatrix, Vector1, Matrix3};
|
|
|
|
|
use core::dimension::U2;
|
|
|
|
|
use geometry::Rotation2;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
|
|
|
|
/// A complex number with a norm equal to 1.
|
2017-02-16 05:04:34 +08:00
|
|
|
|
///
|
|
|
|
|
/// <center>
|
|
|
|
|
/// <big><b>
|
|
|
|
|
/// 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.<br>
|
|
|
|
|
/// Trait implementations are not listed either.
|
|
|
|
|
/// </b></big>
|
|
|
|
|
/// </center>
|
|
|
|
|
///
|
|
|
|
|
/// Please refer directly to the documentation written above each function definition on the source
|
|
|
|
|
/// code for more details.
|
|
|
|
|
///
|
|
|
|
|
///
|
|
|
|
|
/// <h2 id="methods">Methods</h2>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">angle</a>(&self) -> N</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">angle_to</a>(&self, other: &Self) -> N</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">complex</a>(&self) -> &Complex</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">conjugate</a>(&self) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">conjugate_mut</a>(&mut self)</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">from_angle</a>(angle: N) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">from_complex</a>(q: Complex) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">from_rotation_matrix</a>(rotmat: &RotationBase) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">from_scaled_axis</a>(axisangle: ColumnVector) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">identity</a>() -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">inverse</a>(&self) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">inverse_mut</a>(&mut self)</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">new</a>(angle: N) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">powf</a>(&self, n: N) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">rotation_between</a>(a: &ColumnVector<N, U2, SB>, b: &ColumnVector) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">rotation_to</a>(&self, other: &Self) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">scaled_axis</a>(&self) -> Vector1</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">scaled_rotation_between</a>(a: &ColumnVector<N, U2, SB>, b: &ColumnVector, s: N) -> Self</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">to_homogeneous</a>(&self) -> Matrix3</code>
|
|
|
|
|
/// </h4>
|
|
|
|
|
///
|
|
|
|
|
/// <h4 class="method"><span class="invisible">
|
|
|
|
|
/// <code>fn <a class="fnname">to_rotation_matrix</a>(&self) -> Rotation2</code>
|
|
|
|
|
/// </h4>
|
2016-12-05 05:44:42 +08:00
|
|
|
|
pub type UnitComplex<N> = Unit<Complex<N>>;
|
|
|
|
|
|
|
|
|
|
impl<N: Real> UnitComplex<N> {
|
|
|
|
|
/// The rotation angle in `]-pi; pi]` of this unit complex number.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn angle(&self) -> N {
|
2017-02-13 01:17:09 +08:00
|
|
|
|
self.im.atan2(self.re)
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The rotation angle returned as a 1-dimensional vector.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn scaled_axis(&self) -> Vector1<N> {
|
|
|
|
|
Vector1::new(self.angle())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The underlying complex number.
|
|
|
|
|
///
|
|
|
|
|
/// Same as `self.as_ref()`.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn complex(&self) -> &Complex<N> {
|
|
|
|
|
self.as_ref()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Compute the conjugate of this unit complex number.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn conjugate(&self) -> Self {
|
2017-02-13 01:17:09 +08:00
|
|
|
|
UnitComplex::new_unchecked(self.conj())
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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]
|
2017-02-13 01:17:09 +08:00
|
|
|
|
pub fn to_rotation_matrix(&self) -> Rotation2<N> {
|
|
|
|
|
let r = self.re;
|
|
|
|
|
let i = self.im;
|
2016-12-05 05:44:42 +08:00
|
|
|
|
|
2017-02-13 01:17:09 +08:00
|
|
|
|
Rotation2::from_matrix_unchecked(
|
2016-12-05 05:44:42 +08:00
|
|
|
|
SquareMatrix::<_, U2, _>::new(
|
|
|
|
|
r, -i,
|
|
|
|
|
i, r
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Converts this unit complex number into its equivalent homogeneous transformation matrix.
|
|
|
|
|
#[inline]
|
2017-02-13 01:17:09 +08:00
|
|
|
|
pub fn to_homogeneous(&self) -> Matrix3<N> {
|
|
|
|
|
self.to_rotation_matrix().to_homogeneous()
|
2016-12-05 05:44:42 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<N: Real + fmt::Display> fmt::Display for UnitComplex<N> {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
write!(f, "UnitComplex angle: {}", self.angle())
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-02-13 01:17:09 +08:00
|
|
|
|
|
|
|
|
|
impl<N: Real> ApproxEq for UnitComplex<N> {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|