Unify trait hierarchies for vectors, quaternions and matrices
This commit is contained in:
parent
b4063ea72a
commit
886e2fb240
4 changed files with 105 additions and 97 deletions
128
src/matrix.rs
128
src/matrix.rs
|
@ -248,41 +248,86 @@ impl<S: BaseFloat> Matrix4<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> VectorSpace for Matrix2<S> {
|
||||
type Scalar = S;
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Matrix2<S> {
|
||||
Matrix2::new(S::zero(), S::zero(),
|
||||
S::zero(), S::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> VectorSpace for Matrix3<S> {
|
||||
type Scalar = S;
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Matrix3<S> {
|
||||
Matrix3::new(S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> VectorSpace for Matrix4<S> {
|
||||
type Scalar = S;
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Matrix4<S> {
|
||||
Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(), S::zero())
|
||||
}
|
||||
}
|
||||
|
||||
/// A column-major matrix of arbitrary dimensions.
|
||||
pub trait Matrix where
|
||||
///
|
||||
/// Because this is constrained to the `VectorSpace` trait, this means that
|
||||
/// following operators are required to be implemented:
|
||||
///
|
||||
/// Matrix addition:
|
||||
///
|
||||
/// - `Add<Output = Self>`
|
||||
/// - `Sub<Output = Self>`
|
||||
/// - `Neg<Output = Self>`
|
||||
///
|
||||
/// Scalar multiplication:
|
||||
///
|
||||
/// - `Mul<Self::Scalar, Output = Self>`
|
||||
/// - `Div<Self::Scalar, Output = Self>`
|
||||
/// - `Rem<Self::Scalar, Output = Self>`
|
||||
///
|
||||
/// Note that matrix multiplication is not required for implementors of this
|
||||
/// trait. This is due to the complexities of implementing these operators with
|
||||
/// Rust's current type system. For the multiplication of square matrices,
|
||||
/// see `SquareMatrix`.
|
||||
pub trait Matrix: VectorSpace where
|
||||
Self::Scalar: BaseFloat,
|
||||
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Index<usize, Output = <Self as Matrix>::Column>,
|
||||
Self: IndexMut<usize, Output = <Self as Matrix>::Column>,
|
||||
Self: ApproxEq<Epsilon = <Self as Matrix>::Element>,
|
||||
|
||||
Self: Add<Self, Output = Self>,
|
||||
Self: Sub<Self, Output = Self>,
|
||||
Self: Neg<Output = Self>,
|
||||
|
||||
Self: Mul<<Self as Matrix>::Element, Output = Self>,
|
||||
Self: Div<<Self as Matrix>::Element, Output = Self>,
|
||||
Self: Rem<<Self as Matrix>::Element, Output = Self>,
|
||||
Self: ApproxEq<Epsilon = <Self as VectorSpace>::Scalar>,
|
||||
{
|
||||
/// The type of the elements in the matrix.
|
||||
type Element: BaseFloat;
|
||||
|
||||
/// The row vector of the matrix.
|
||||
type Row: Array<Element = Self::Element>;
|
||||
/// The column vector of the matrix.
|
||||
type Column: Array<Element = Self::Element>;
|
||||
type Row: VectorSpace<Scalar = Self::Scalar> + Array<Element = Self::Scalar>;
|
||||
|
||||
/// The type of the transposed matrix
|
||||
type Transpose: Matrix<Element = Self::Element, Row = Self::Column, Column = Self::Row>;
|
||||
/// The column vector of the matrix.
|
||||
type Column: VectorSpace<Scalar = Self::Scalar> + Array<Element = Self::Scalar>;
|
||||
|
||||
/// The result of transposing the matrix
|
||||
type Transpose: Matrix<Scalar = Self::Scalar, Row = Self::Column, Column = Self::Row>;
|
||||
|
||||
/// Get the pointer to the first element of the array.
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *const Self::Element {
|
||||
fn as_ptr(&self) -> *const Self::Scalar {
|
||||
&self[0][0]
|
||||
}
|
||||
|
||||
/// Get a mutable pointer to the first element of the array.
|
||||
#[inline]
|
||||
fn as_mut_ptr(&mut self) -> *mut Self::Element {
|
||||
fn as_mut_ptr(&mut self) -> *mut Self::Scalar {
|
||||
&mut self[0][0]
|
||||
}
|
||||
|
||||
|
@ -302,15 +347,14 @@ pub trait Matrix where
|
|||
/// Swap the values at index `a` and `b`
|
||||
fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize));
|
||||
|
||||
/// Create a matrix with all of the elements set to zero.
|
||||
fn zero() -> Self;
|
||||
|
||||
/// Transpose this matrix, returning a new matrix.
|
||||
fn transpose(&self) -> Self::Transpose;
|
||||
}
|
||||
|
||||
/// A column-major major matrix where the rows and column vectors are of the same dimensions.
|
||||
pub trait SquareMatrix where
|
||||
Self::Scalar: BaseFloat,
|
||||
|
||||
Self: Matrix<
|
||||
// FIXME: Can be cleaned up once equality constraints in where clauses are implemented
|
||||
Column = <Self as SquareMatrix>::ColumnRow,
|
||||
|
@ -326,12 +370,12 @@ pub trait SquareMatrix where
|
|||
/// This is used to constrain the column and rows to be of the same type in lieu of equality
|
||||
/// constraints being implemented for `where` clauses. Once those are added, this type will
|
||||
/// likely go away.
|
||||
type ColumnRow: Array<Element = Self::Element>;
|
||||
type ColumnRow: VectorSpace<Scalar = Self::Scalar> + Array<Element = Self::Scalar>;
|
||||
|
||||
/// Create a new diagonal matrix using the supplied value.
|
||||
fn from_value(value: Self::Element) -> Self;
|
||||
fn from_value(value: Self::Scalar) -> Self;
|
||||
/// Create a matrix from a non-uniform scale
|
||||
fn from_diagonal(diagonal: Self::Column) -> Self;
|
||||
fn from_diagonal(diagonal: Self::ColumnRow) -> Self;
|
||||
|
||||
/// The [identity matrix](https://en.wikipedia.org/wiki/Identity_matrix). Multiplying this
|
||||
/// matrix with another has no effect.
|
||||
|
@ -340,14 +384,14 @@ pub trait SquareMatrix where
|
|||
/// Transpose this matrix in-place.
|
||||
fn transpose_self(&mut self);
|
||||
/// Take the determinant of this matrix.
|
||||
fn determinant(&self) -> Self::Element;
|
||||
fn determinant(&self) -> Self::Scalar;
|
||||
|
||||
/// Return a vector containing the diagonal of this matrix.
|
||||
fn diagonal(&self) -> Self::Column;
|
||||
fn diagonal(&self) -> Self::ColumnRow;
|
||||
|
||||
/// Return the trace of this matrix. That is, the sum of the diagonal.
|
||||
#[inline]
|
||||
fn trace(&self) -> Self::Element { self.diagonal().sum() }
|
||||
fn trace(&self) -> Self::Scalar { self.diagonal().sum() }
|
||||
|
||||
/// Invert this matrix, returning a new matrix. `m.mul_m(m.invert())` is
|
||||
/// the identity matrix. Returns `None` if this matrix is not invertible
|
||||
|
@ -363,7 +407,7 @@ pub trait SquareMatrix where
|
|||
|
||||
/// Test if this matrix is invertible.
|
||||
#[inline]
|
||||
fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&Self::Element::zero()) }
|
||||
fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&Self::Scalar::zero()) }
|
||||
|
||||
/// Test if this matrix is the identity matrix. That is, it is diagonal
|
||||
/// and every element in the diagonal is one.
|
||||
|
@ -380,7 +424,6 @@ pub trait SquareMatrix where
|
|||
}
|
||||
|
||||
impl<S: BaseFloat> Matrix for Matrix2<S> {
|
||||
type Element = S;
|
||||
type Column = Vector2<S>;
|
||||
type Row = Vector2<S>;
|
||||
type Transpose = Matrix2<S>;
|
||||
|
@ -409,12 +452,6 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
|
|||
unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Matrix2<S> {
|
||||
Matrix2::new(S::zero(), S::zero(),
|
||||
S::zero(), S::zero())
|
||||
}
|
||||
|
||||
fn transpose(&self) -> Matrix2<S> {
|
||||
Matrix2::new(self[0][0], self[1][0],
|
||||
self[0][1], self[1][1])
|
||||
|
@ -483,7 +520,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
|
|||
}
|
||||
|
||||
impl<S: BaseFloat> Matrix for Matrix3<S> {
|
||||
type Element = S;
|
||||
type Column = Vector3<S>;
|
||||
type Row = Vector3<S>;
|
||||
type Transpose = Matrix3<S>;
|
||||
|
@ -514,13 +550,6 @@ impl<S: BaseFloat> Matrix for Matrix3<S> {
|
|||
unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Matrix3<S> {
|
||||
Matrix3::new(S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero())
|
||||
}
|
||||
|
||||
fn transpose(&self) -> Matrix3<S> {
|
||||
Matrix3::new(self[0][0], self[1][0], self[2][0],
|
||||
self[0][1], self[1][1], self[2][1],
|
||||
|
@ -603,7 +632,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
|
|||
}
|
||||
|
||||
impl<S: BaseFloat> Matrix for Matrix4<S> {
|
||||
type Element = S;
|
||||
type Column = Vector4<S>;
|
||||
type Row = Vector4<S>;
|
||||
type Transpose = Matrix4<S>;
|
||||
|
@ -636,14 +664,6 @@ impl<S: BaseFloat> Matrix for Matrix4<S> {
|
|||
unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Matrix4<S> {
|
||||
Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(), S::zero(),
|
||||
S::zero(), S::zero(), S::zero(), S::zero())
|
||||
}
|
||||
|
||||
fn transpose(&self) -> Matrix4<S> {
|
||||
Matrix4::new(self[0][0], self[1][0], self[2][0], self[3][0],
|
||||
self[0][1], self[1][1], self[2][1], self[3][1],
|
||||
|
|
|
@ -25,7 +25,6 @@ use rust_num::{One, Zero};
|
|||
|
||||
use approx::ApproxEq;
|
||||
use array::Array;
|
||||
use matrix::Matrix;
|
||||
use num::{BaseNum, BaseFloat};
|
||||
use vector::*;
|
||||
|
||||
|
|
|
@ -54,62 +54,40 @@ impl<S: BaseFloat> Quaternion<S> {
|
|||
Quaternion { s: s, v: v }
|
||||
}
|
||||
|
||||
/// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
|
||||
#[inline]
|
||||
pub fn zero() -> Quaternion<S> {
|
||||
Quaternion::new(S::zero(), S::zero(), S::zero(), S::zero())
|
||||
}
|
||||
|
||||
/// The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
|
||||
/// The multiplicative identity.
|
||||
#[inline]
|
||||
pub fn one() -> Quaternion<S> {
|
||||
Quaternion::from_sv(S::one(), Vector3::zero())
|
||||
}
|
||||
|
||||
/// The dot product of the quaternion and `q`.
|
||||
#[inline]
|
||||
pub fn dot(self, other: Quaternion<S>) -> S {
|
||||
self.s * other.s + self.v.dot(other.v)
|
||||
}
|
||||
|
||||
/// The conjugate of the quaternion.
|
||||
#[inline]
|
||||
pub fn conjugate(self) -> Quaternion<S> {
|
||||
Quaternion::from_sv(self.s, -self.v)
|
||||
}
|
||||
|
||||
/// The squared magnitude of the quaternion. This is useful for
|
||||
/// magnitude comparisons where the exact magnitude does not need to be
|
||||
/// calculated.
|
||||
#[inline]
|
||||
pub fn magnitude2(self) -> S {
|
||||
self.s * self.s + self.v.magnitude2()
|
||||
}
|
||||
|
||||
/// The magnitude of the quaternion
|
||||
///
|
||||
/// # Performance notes
|
||||
///
|
||||
/// For instances where the exact magnitude of the quaternion does not need
|
||||
/// to be known, for example for quaternion-quaternion magnitude comparisons,
|
||||
/// it is advisable to use the `magnitude2` method instead.
|
||||
#[inline]
|
||||
pub fn magnitude(self) -> S {
|
||||
self.magnitude2().sqrt()
|
||||
}
|
||||
|
||||
/// Normalize this quaternion, returning the new quaternion.
|
||||
#[inline]
|
||||
pub fn normalize(self) -> Quaternion<S> {
|
||||
self * (S::one() / self.magnitude())
|
||||
}
|
||||
|
||||
/// Do a normalized linear interpolation with `other`, by `amount`.
|
||||
pub fn nlerp(self, other: Quaternion<S>, amount: S) -> Quaternion<S> {
|
||||
(self * (S::one() - amount) + other * amount).normalize()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> VectorSpace for Quaternion<S> {
|
||||
type Scalar = S;
|
||||
|
||||
#[inline]
|
||||
fn zero() -> Quaternion<S> {
|
||||
Quaternion::from_sv(S::zero(), Vector3::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: BaseFloat> InnerSpace for Quaternion<S> {
|
||||
#[inline]
|
||||
fn dot(self, other: Quaternion<S>) -> S {
|
||||
self.s * other.s + self.v.dot(other.v)
|
||||
}
|
||||
}
|
||||
|
||||
impl_operator!(<S: BaseFloat> Neg for Quaternion<S> {
|
||||
fn neg(quat) -> Quaternion<S> {
|
||||
Quaternion::from_sv(-quat.s, -quat.v)
|
||||
|
@ -134,6 +112,15 @@ impl_assignment_operator!(<S: BaseFloat> DivAssign<S> for Quaternion<S> {
|
|||
fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; }
|
||||
});
|
||||
|
||||
impl_operator!(<S: BaseFloat> Rem<S> for Quaternion<S> {
|
||||
fn rem(lhs, rhs) -> Quaternion<S> {
|
||||
Quaternion::from_sv(lhs.s % rhs, lhs.v % rhs)
|
||||
}
|
||||
});
|
||||
impl_assignment_operator!(<S: BaseFloat> RemAssign<S> for Quaternion<S> {
|
||||
fn rem_assign(&mut self, scalar) { self.s %= scalar; self.v %= scalar; }
|
||||
});
|
||||
|
||||
impl_operator!(<S: BaseFloat> Mul<Vector3<S> > for Quaternion<S> {
|
||||
fn mul(lhs, rhs) -> Vector3<S> {{
|
||||
let rhs = rhs.clone();
|
||||
|
|
|
@ -104,6 +104,8 @@ use num::{BaseNum, BaseFloat, PartialOrd};
|
|||
/// together and [multiplied](https://en.wikipedia.org/wiki/Scalar_multiplication)
|
||||
/// by scalars.
|
||||
///
|
||||
/// Examples include vectors, matrices, and quaternions.
|
||||
///
|
||||
/// # Required operators
|
||||
///
|
||||
/// ## Vector addition
|
||||
|
@ -144,12 +146,10 @@ use num::{BaseNum, BaseFloat, PartialOrd};
|
|||
/// let downscaled_translation = translation / scale_factor;
|
||||
/// ```
|
||||
pub trait VectorSpace: Copy + Clone where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Array<Element = <Self as VectorSpace>::Scalar>,
|
||||
|
||||
Self: Add<Self, Output = Self>,
|
||||
Self: Sub<Self, Output = Self>,
|
||||
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
Self: Mul<<Self as VectorSpace>::Scalar, Output = Self>,
|
||||
Self: Div<<Self as VectorSpace>::Scalar, Output = Self>,
|
||||
Self: Rem<<Self as VectorSpace>::Scalar, Output = Self>,
|
||||
|
@ -530,6 +530,8 @@ impl<S: BaseNum> Vector4<S> {
|
|||
///
|
||||
/// The dot product allows for the definition of other useful operations, like
|
||||
/// finding the magnitude of a vector or normalizing it.
|
||||
///
|
||||
/// Examples include vectors and quaternions.
|
||||
pub trait InnerSpace: VectorSpace + Sized where
|
||||
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||
<Self as VectorSpace>::Scalar: BaseFloat,
|
||||
|
|
Loading…
Reference in a new issue