This commit moves the library into a usable state.
There is still some work to do with defining integers and whole numbers better, but for now the library is usable and reasonably tested.
This commit is contained in:
@ -3,3 +3,531 @@
|
||||
//!
|
||||
//! [1]: https://en.wikipedia.org/wiki/Quaternion
|
||||
//! [2]: https://en.wikipedia.org/wiki/Dual_quaternion
|
||||
use std::num::{Zero, One};
|
||||
use std::ops::{Add, Sub, Mul, Div, Neg};
|
||||
|
||||
use super::real::Real;
|
||||
use super::vector::{Vector, EuclideanVector, Vector3};
|
||||
|
||||
|
||||
/// A Quaternion is a combination of a scalar and a vector
|
||||
/// of complex numbers.
|
||||
///
|
||||
/// [S, V] = [S, Xi + Yj + Zk]
|
||||
///
|
||||
/// Remember that the complex number axes combine
|
||||
/// in the following manner.
|
||||
///
|
||||
/// i^2 = j^2 = k^2 = -1
|
||||
///
|
||||
/// | | |
|
||||
/// |:-------:|:-------:|
|
||||
/// | ij = 1 | ik = -1 |
|
||||
/// | jk = 1 | kj = -1 |
|
||||
/// | ki = 1 | ji = -1 |
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Quaternion<T> where T: Real
|
||||
{
|
||||
/// TODO: Describe this.
|
||||
pub scalar: T,
|
||||
|
||||
/// TODO: Describe this.
|
||||
pub vector: Vector3<T>
|
||||
}
|
||||
|
||||
|
||||
/// A macro that will define a binary operation
|
||||
/// for a Quaternion and its components for
|
||||
/// scalar values.
|
||||
macro_rules! binary_operator_impl
|
||||
{
|
||||
($traitName: ident :: $funcName: ident, $structName: ident) =>
|
||||
{
|
||||
impl<T> $traitName<T> for $structName<T> where T: Real
|
||||
{
|
||||
type Output = $structName<T>;
|
||||
|
||||
fn $funcName(self, scalar: T) -> $structName<T>
|
||||
{
|
||||
$structName::new(self.scalar.$funcName(scalar),
|
||||
self.vector.$funcName(scalar))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> $traitName<T> for &'a $structName<T> where T: Real
|
||||
{
|
||||
type Output = $structName<T>;
|
||||
|
||||
fn $funcName(self, scalar: T) -> $structName<T>
|
||||
{
|
||||
$structName::new(self.scalar.$funcName(scalar),
|
||||
self.vector.$funcName(scalar))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> $traitName<&'a T> for $structName<T> where T: Real
|
||||
{
|
||||
type Output = $structName<T>;
|
||||
|
||||
fn $funcName(self, scalar: &'a T) -> $structName<T>
|
||||
{
|
||||
$structName::new(self.scalar.$funcName(*scalar),
|
||||
self.vector.$funcName(*scalar))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T> where T: Real
|
||||
{
|
||||
type Output = $structName<T>;
|
||||
|
||||
fn $funcName(self, scalar: &'b T) -> $structName<T>
|
||||
{
|
||||
$structName::new(self.scalar.$funcName(*scalar),
|
||||
self.vector.$funcName(*scalar))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Implement the Quaternion's methods.
|
||||
impl<T> Quaternion<T> where T: Real
|
||||
{
|
||||
/// Create a new Quaternion from a given scalar and Vector.
|
||||
///
|
||||
///```
|
||||
/// // Create a new Quaternion<f64> where all
|
||||
/// // the components are 5.5f64.
|
||||
/// use sigils::vector::*;
|
||||
/// use sigils::quaternion::*;
|
||||
///
|
||||
/// let quaternion =
|
||||
/// Quaternion::<f64>::new(5.5f64, Vector3::new(5.5f64, 5.5f64, 5.5f64));
|
||||
/// # assert_eq!(quaternion.scalar, 5.5f64);
|
||||
/// # assert_eq!(quaternion.vector.x, 5.5f64);
|
||||
/// # assert_eq!(quaternion.vector.y, 5.5f64);
|
||||
/// # assert_eq!(quaternion.vector.z, 5.5f64);
|
||||
///```
|
||||
pub fn new(s: T, v: Vector3<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion {scalar: s, vector: v}
|
||||
}
|
||||
|
||||
/// Create a new Quaternion from the given values.
|
||||
///
|
||||
///```
|
||||
/// // Create a new Quaternion<f32> where all
|
||||
/// // the components are 5.5f32.
|
||||
/// use sigils::quaternion::*;
|
||||
///
|
||||
/// let quaternion =
|
||||
/// Quaternion::<f32>::from_values(5.5f32, 5.5f32, 5.5f32, 5.5f32);
|
||||
/// # assert_eq!(quaternion.scalar, 5.5f32);
|
||||
/// # assert_eq!(quaternion.vector.x, 5.5f32);
|
||||
/// # assert_eq!(quaternion.vector.y, 5.5f32);
|
||||
/// # assert_eq!(quaternion.vector.z, 5.5f32);
|
||||
///```
|
||||
pub fn from_values(s: T, xi: T, yj: T, zk: T) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(s, Vector3::new(xi, yj, zk))
|
||||
}
|
||||
|
||||
/// Create an identity Quaternion. This is a Quaternion
|
||||
/// with a zero Vector and a scalar of one.
|
||||
///
|
||||
///```
|
||||
/// // Create a new identity Quaternion<f32>.
|
||||
/// use sigils::quaternion::*;
|
||||
///
|
||||
/// let quaternion =
|
||||
/// Quaternion::<f32>::identity();
|
||||
/// # assert_eq!(quaternion.scalar, 1.0f32);
|
||||
/// # assert_eq!(quaternion.vector.x, 0.0f32);
|
||||
/// # assert_eq!(quaternion.vector.y, 0.0f32);
|
||||
/// # assert_eq!(quaternion.vector.z, 0.0f32);
|
||||
///```
|
||||
pub fn identity() -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(T::one(), Vector3::zero())
|
||||
}
|
||||
|
||||
/// Get the squared magnitude of the Quaternion.
|
||||
/// This is basically a length equation.
|
||||
///
|
||||
/// S^2 + V^2
|
||||
///
|
||||
///```
|
||||
/// // Create a new Quaternion<f64> where all
|
||||
/// // the components are 5.5f64 and get its
|
||||
/// // squared magnitude.
|
||||
/// use sigils::vector::*;
|
||||
/// use sigils::quaternion::*;
|
||||
///
|
||||
/// let quaternion =
|
||||
/// Quaternion::<f64>::from_values(5.5f64, 5.5f64, 5.5f64, 5.5f64);
|
||||
/// let magnitude = quaternion.get_magnitude_squared();
|
||||
/// # assert_eq!(magnitude, 121.0f64);
|
||||
///```
|
||||
pub fn get_magnitude_squared(&self) -> T
|
||||
{
|
||||
(self.scalar * self.scalar) + self.vector.get_length_squared()
|
||||
}
|
||||
|
||||
/// Get the magnitude of the Quaternion.
|
||||
/// This is basically a length equation.
|
||||
///
|
||||
///```
|
||||
/// // Create a new Quaternion<f32> where all
|
||||
/// // the components are 5.5f32 and get its
|
||||
/// // magnitude.
|
||||
/// use sigils::quaternion::*;
|
||||
///
|
||||
/// let quaternion =
|
||||
/// Quaternion::<f32>::from_values(5.5f32, 5.5f32, 5.5f32, 5.5f32);
|
||||
/// let magnitude = quaternion.get_magnitude();
|
||||
/// # assert_eq!(magnitude, 11.0f32);
|
||||
///```
|
||||
pub fn get_magnitude(&self) -> T
|
||||
{
|
||||
let magnitude: T;
|
||||
|
||||
// Calculate the magnitude for the Quaternion
|
||||
// and make sure the magnitude is actually
|
||||
// a number.
|
||||
magnitude = self.get_magnitude_squared().sqrt();
|
||||
assert!(magnitude.is_finite());
|
||||
|
||||
// Return the calculated magnitude.
|
||||
magnitude
|
||||
}
|
||||
|
||||
/// Set this Quaternion to the identity Quaternion.
|
||||
/// This is a Quaternion with a zero Vector and
|
||||
/// a scalar of one.
|
||||
pub fn set_identity(&mut self)
|
||||
{
|
||||
self.scalar = T::one();
|
||||
self.vector = Vector3::zero();
|
||||
}
|
||||
|
||||
/// Negates only the Vector component.
|
||||
pub fn conjugate_self(&mut self)
|
||||
{
|
||||
self.vector = -self.vector;
|
||||
}
|
||||
|
||||
/// Normalizes this Quaternions values.
|
||||
///
|
||||
/// [S/magnitude, V/magnitude]
|
||||
pub fn normalize_self(&mut self)
|
||||
{
|
||||
let inverse_mag: T;
|
||||
|
||||
// Get the inverse of the magnitude.
|
||||
inverse_mag = T::one() / self.get_magnitude();
|
||||
|
||||
// Multily the scalar and Vector components
|
||||
// by the inverse magnitude.
|
||||
self.scalar = self.scalar * inverse_mag;
|
||||
self.vector = self.vector * inverse_mag;
|
||||
}
|
||||
|
||||
/// Invert this Quaternion.
|
||||
pub fn invert_self(&mut self)
|
||||
{
|
||||
// Conjugate this Quaternion
|
||||
// and then normalize it.
|
||||
self.conjugate_self();
|
||||
self.normalize_self();
|
||||
}
|
||||
|
||||
/// Create a new Quaternion that is the same
|
||||
/// as this Quaternion with a negated Vector component.
|
||||
pub fn conjugate(&self) -> Quaternion<T>
|
||||
{
|
||||
// Create a new Quaternion that has
|
||||
// the same scalar component value and
|
||||
// a negated version of the Vector component.
|
||||
Quaternion::new(self.scalar.clone(), -self.vector.clone())
|
||||
}
|
||||
|
||||
/// Create a new Quaternion that is a copy of this
|
||||
/// Quaternion with normalized values.
|
||||
///
|
||||
/// [S/magnitude, V/magnitude]
|
||||
pub fn normalize(&self) -> Quaternion<T>
|
||||
{
|
||||
let inverse_mag: T;
|
||||
|
||||
inverse_mag = T::one() / self.get_magnitude();
|
||||
|
||||
self * inverse_mag
|
||||
}
|
||||
|
||||
/// Create a new Quaternion that is a normalized
|
||||
/// conjugate of this Quaternion.
|
||||
pub fn invert(&self) -> Quaternion<T>
|
||||
{
|
||||
self.conjugate().normalize()
|
||||
}
|
||||
|
||||
// TODO: Add binary operations for editing self.
|
||||
}
|
||||
|
||||
// Implement the Zero and One traits for the Quaternion.
|
||||
impl<T> Zero for Quaternion<T> where T: Real
|
||||
{
|
||||
fn zero() -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(T::zero(), Vector3::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> One for Quaternion<T> where T: Real
|
||||
{
|
||||
fn one() -> Quaternion<T>
|
||||
{
|
||||
Quaternion::identity()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement the binary operations for Quaternions and scalars.
|
||||
binary_operator_impl!(Mul::mul, Quaternion);
|
||||
//binary_operator_impl!(Div::div, Quaternion);
|
||||
//binary_operator_impl!(Neg::neg, Quaternion);
|
||||
|
||||
// Implement Negating a Quaternion.
|
||||
impl<T> Neg for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn neg(self) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(-self.scalar, -self.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Neg for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn neg(self) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(-self.scalar, -self.vector)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement Adding Quaternions.
|
||||
impl<T> Add<Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn add(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar + _rhs.scalar,
|
||||
self.vector + _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Add<Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn add(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar + _rhs.scalar,
|
||||
self.vector + _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Add<&'a Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn add(self, _rhs: &'a Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar + _rhs.scalar,
|
||||
self.vector + _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T> Add<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn add(self, _rhs: &'b Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar + _rhs.scalar,
|
||||
self.vector + _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement subtracting Quaternions.
|
||||
impl<T> Sub<Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn sub(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar - _rhs.scalar,
|
||||
self.vector - _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Sub<Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn sub(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar - _rhs.scalar,
|
||||
self.vector - _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Sub<&'a Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn sub(self, _rhs: &'a Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar - _rhs.scalar,
|
||||
self.vector - _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T> Sub<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn sub(self, _rhs: &'b Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
Quaternion::new(self.scalar - _rhs.scalar,
|
||||
self.vector - _rhs.vector)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement Dividing Quaternions.
|
||||
impl<T> Div<Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn div(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
self * _rhs.invert()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Div<Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn div(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
self * _rhs.invert()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Div<&'a Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn div(self, _rhs: &'a Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
self * _rhs.invert()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T> Div<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn div(self, _rhs: &'b Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
self * _rhs.invert()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement multiplying Quaternions and Vectors.
|
||||
impl<T> Mul<Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn mul(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
multiply_quaternions(self.scalar, self.vector.x,
|
||||
self.vector.y, self.vector.z,
|
||||
_rhs.scalar, _rhs.vector.x,
|
||||
_rhs.vector.y, _rhs.vector.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Mul<Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn mul(self, _rhs: Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
multiply_quaternions(self.scalar, self.vector.x,
|
||||
self.vector.y, self.vector.z,
|
||||
_rhs.scalar, _rhs.vector.x,
|
||||
_rhs.vector.y, _rhs.vector.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Mul<&'a Quaternion<T>> for Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn mul(self, _rhs: &'a Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
multiply_quaternions(self.scalar, self.vector.x,
|
||||
self.vector.y, self.vector.z,
|
||||
_rhs.scalar, _rhs.vector.x,
|
||||
_rhs.vector.y, _rhs.vector.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T> Mul<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
|
||||
{
|
||||
type Output = Quaternion<T>;
|
||||
|
||||
fn mul(self, _rhs: &'b Quaternion<T>) -> Quaternion<T>
|
||||
{
|
||||
multiply_quaternions(self.scalar, self.vector.x,
|
||||
self.vector.y, self.vector.z,
|
||||
_rhs.scalar, _rhs.vector.x,
|
||||
_rhs.vector.y, _rhs.vector.z)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// This is a private function for multiplying the
|
||||
/// values of two Quaternions. This was created to
|
||||
/// follow the DRY principle.
|
||||
///
|
||||
/// Qa = [Sa, A] = [Sa, Xai + Yaj + Zak]
|
||||
/// Qb = [Sb, B] = [Sb, Xbi + Ybj + Zbk]
|
||||
///
|
||||
/// QaQb = [Sa, A][Sb, B] = [Sa, Xai + Yaj + Zak][Sb, Xbi + Ybj + Zbk]
|
||||
/// QaQb = (SaSb - XaXb - YaYb - ZaZb) +
|
||||
/// (SaXb + XaSb + YaZb - ZaYb)i +
|
||||
/// (SaYb - XaZb + SbYa + ZaXb)j +
|
||||
/// (SaZb + XaYb - YaXb + SbZa)k
|
||||
fn multiply_quaternions<T>(sa: T, xa: T, ya: T, za: T,
|
||||
sb: T, xb: T, yb: T, zb: T)
|
||||
-> Quaternion<T> where T: Real
|
||||
{
|
||||
let i: T;
|
||||
let j: T;
|
||||
let k: T;
|
||||
let scalar: T;
|
||||
|
||||
i = (sa * xb) + (xa * sb) + (ya * zb) - (za * yb);
|
||||
j = (sa * yb) - (xa * zb) + (ya * sb) + (za * xb);
|
||||
k = (sa * zb) + (xa * yb) - (ya * xb) + (za * sb);
|
||||
scalar = (sa * sb) - (xa * xb) - (ya * yb) - (za * zb);
|
||||
|
||||
Quaternion::new(scalar, Vector3::new(i, j, k))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user