Add all permutations of matrix ops, and remove operator methods

Completes #247
This commit is contained in:
Brendan Zabarauskas 2015-12-21 21:02:40 +11:00
parent 32a981161a
commit 1d886f6197
5 changed files with 121 additions and 377 deletions

View file

@ -263,16 +263,13 @@ pub trait Matrix where
Self: Index<usize, Output = <Self as Matrix>::Column>,
Self: IndexMut<usize, Output = <Self as Matrix>::Column>,
Self: ApproxEq<Epsilon = <Self as Matrix>::Element>,
// FIXME: blocked by rust-lang/rust#20671
//
// for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
// for<'a, 'b> &'a Self: Sub<&'b Self, Output = Self>,
// for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>,
// for<'a, 'b> &'a Self: Mul<&'b V, Output = V>,
//
// for<'a> &'a Self: Mul<S, Output = Self>,
// for<'a> &'a Self: Div<S, Output = Self>,
// for<'a> &'a Self: Rem<S, Output = Self>,
Self: Add<Self, Output = Self>,
Self: Sub<Self, 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>,
{
/// The type of the elements in the matrix.
type Element: BaseFloat;
@ -316,22 +313,6 @@ pub trait Matrix where
/// Create a matrix with all of the elements set to zero.
fn zero() -> Self;
/// Multiply the matrix by another matrix,
fn mul_m(&self, other: &Self::Transpose) -> Self;
/// Multiply the matrix by a column vector.
fn mul_v(&self, column: Self::Column) -> Self::Column;
/// Multiply this matrix by a scalar, returning the new matrix.
fn mul_s(&self, scalar: Self::Element) -> Self;
/// Divide this matrix by a scalar, returning the new matrix.
fn div_s(&self, scalar: Self::Element) -> Self;
/// Multiply this matrix by a scalar, in-place.
fn mul_self_s(&mut self, scalar: Self::Element);
/// Divide this matrix by a scalar, in-place.
fn div_self_s(&mut self, scalar: Self::Element);
/// Transpose this matrix, returning a new matrix.
fn transpose(&self) -> Self::Transpose;
}
@ -344,6 +325,8 @@ pub trait SquareMatrix where
Row = <Self as SquareMatrix>::ColumnRow,
Transpose = Self,
>,
Self: Mul<<Self as Matrix>::Column, Output = <Self as Matrix>::Column>,
Self: Mul<Self, Output = Self>,
{
// FIXME: Will not be needed once equality constraints in where clauses are implemented
/// The row/column vector of the matrix.
@ -362,19 +345,6 @@ pub trait SquareMatrix where
/// matrix with another has no effect.
fn identity() -> Self;
/// Add this matrix with another matrix, returning the new metrix.
fn add_m(&self, m: &Self) -> Self;
/// Subtract another matrix from this matrix, returning the new matrix.
fn sub_m(&self, m: &Self) -> Self;
/// Add this matrix with another matrix, in-place.
fn add_self_m(&mut self, m: &Self);
/// Subtract another matrix from this matrix, in-place.
fn sub_self_m(&mut self, m: &Self);
/// Multiply this matrix by another matrix, in-place.
fn mul_self_m(&mut self, m: &Self) { *self = self.mul_m(m); }
/// Transpose this matrix in-place.
fn transpose_self(&mut self);
/// Take the determinant of this matrix.
@ -453,30 +423,6 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
S::zero(), S::zero())
}
#[inline]
fn mul_m(&self, other: &Matrix2<S>) -> Matrix2<S> { self * other }
#[inline]
fn mul_v(&self, v: Vector2<S>) -> Vector2<S> { self * v }
#[inline]
fn mul_s(&self, s: S) -> Matrix2<S> { self * s }
#[inline]
fn div_s(&self, s: S) -> Matrix2<S> { self / s }
#[inline]
fn mul_self_s(&mut self, s: S) {
self[0] = self[0] * s;
self[1] = self[1] * s;
}
#[inline]
fn div_self_s(&mut self, s: S) {
self[0] = self[0] / s;
self[1] = self[1] / s;
}
fn transpose(&self) -> Matrix2<S> {
Matrix2::new(self[0][0], self[1][0],
self[0][1], self[1][1])
@ -503,24 +449,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
Matrix2::from_value(S::one())
}
#[inline]
fn add_m(&self, m: &Matrix2<S>) -> Matrix2<S> { self + m }
#[inline]
fn sub_m(&self, m: &Matrix2<S>) -> Matrix2<S> { self - m }
#[inline]
fn add_self_m(&mut self, m: &Matrix2<S>) {
self[0] = self[0] + m[0];
self[1] = self[1] + m[1];
}
#[inline]
fn sub_self_m(&mut self, m: &Matrix2<S>) {
self[0] = self[0] - m[0];
self[1] = self[1] - m[1];
}
#[inline]
fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0));
@ -601,32 +529,6 @@ impl<S: BaseFloat> Matrix for Matrix3<S> {
S::zero(), S::zero(), S::zero())
}
#[inline]
fn mul_m(&self, other: &Matrix3<S>) -> Matrix3<S> { self * other }
#[inline]
fn mul_v(&self, v: Vector3<S>) -> Vector3<S> { self * v}
#[inline]
fn mul_s(&self, s: S) -> Matrix3<S> { self * s }
#[inline]
fn div_s(&self, s: S) -> Matrix3<S> { self / s }
#[inline]
fn mul_self_s(&mut self, s: S) {
self[0] = self[0] * s;
self[1] = self[1] * s;
self[2] = self[2] * s;
}
#[inline]
fn div_self_s(&mut self, s: S) {
self[0] = self[0] / s;
self[1] = self[1] / s;
self[2] = self[2] / s;
}
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],
@ -656,26 +558,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
Matrix3::from_value(S::one())
}
#[inline]
fn add_m(&self, m: &Matrix3<S>) -> Matrix3<S> { self + m }
#[inline]
fn sub_m(&self, m: &Matrix3<S>) -> Matrix3<S> { self - m }
#[inline]
fn add_self_m(&mut self, m: &Matrix3<S>) {
self[0] = self[0] + m[0];
self[1] = self[1] + m[1];
self[2] = self[2] + m[2];
}
#[inline]
fn sub_self_m(&mut self, m: &Matrix3<S>) {
self[0] = self[0] - m[0];
self[1] = self[1] - m[1];
self[2] = self[2] - m[2];
}
#[inline]
fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0));
@ -770,34 +652,6 @@ impl<S: BaseFloat> Matrix for Matrix4<S> {
S::zero(), S::zero(), S::zero(), S::zero())
}
#[inline]
fn mul_m(&self, other: &Matrix4<S>) -> Matrix4<S> { self * other }
#[inline]
fn mul_v(&self, v: Vector4<S>) -> Vector4<S> { self * v }
#[inline]
fn mul_s(&self, s: S) -> Matrix4<S> { self * s }
#[inline]
fn div_s(&self, s: S) -> Matrix4<S> { self / s }
#[inline]
fn mul_self_s(&mut self, s: S) {
self[0] = self[0] * s;
self[1] = self[1] * s;
self[2] = self[2] * s;
self[3] = self[3] * s;
}
#[inline]
fn div_self_s(&mut self, s: S) {
self[0] = self[0] / s;
self[1] = self[1] / s;
self[2] = self[2] / s;
self[3] = self[3] / s;
}
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],
@ -830,28 +684,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
Matrix4::from_value(S::one())
}
#[inline]
fn add_m(&self, m: &Matrix4<S>) -> Matrix4<S> { self + m }
#[inline]
fn sub_m(&self, m: &Matrix4<S>) -> Matrix4<S> { self - m }
#[inline]
fn add_self_m(&mut self, m: &Matrix4<S>) {
self[0] = self[0] + m[0];
self[1] = self[1] + m[1];
self[2] = self[2] + m[2];
self[3] = self[3] + m[3];
}
#[inline]
fn sub_self_m(&mut self, m: &Matrix4<S>) {
self[0] = self[0] - m[0];
self[1] = self[1] - m[1];
self[2] = self[2] - m[2];
self[3] = self[3] - m[3];
}
fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0));
self.swap_elements((0, 2), (2, 0));
@ -1010,116 +842,71 @@ impl<S: BaseFloat> Neg for Matrix4<S> {
}
}
macro_rules! impl_scalar_binary_operator {
($Binop:ident :: $binop:ident, $MatrixN:ident { $($field:ident),+ }) => {
impl<'a, S: BaseFloat> $Binop<S> for &'a $MatrixN<S> {
type Output = $MatrixN<S>;
macro_rules! impl_binary_operators {
($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => {
impl_binary_operator!(<S: BaseFloat> Mul<S> for $MatrixN<S> {
fn mul(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field * scalar),+ } }
});
impl_binary_operator!(<S: BaseFloat> Div<S> for $MatrixN<S> {
fn div(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field / scalar),+ } }
});
impl_binary_operator!(<S: BaseFloat> Rem<S> for $MatrixN<S> {
fn rem(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field % scalar),+ } }
});
#[inline]
fn $binop(self, s: S) -> $MatrixN<S> {
$MatrixN { $($field: self.$field.$binop(s)),+ }
}
}
impl_binary_operator!(<S: BaseFloat> Add<$MatrixN<S> > for $MatrixN<S> {
fn add(lhs, rhs) -> $MatrixN<S> { $MatrixN { $($field: lhs.$field + rhs.$field ),+ } }
});
impl_binary_operator!(<S: BaseFloat> Sub<$MatrixN<S> > for $MatrixN<S> {
fn sub(lhs, rhs) -> $MatrixN<S> { $MatrixN { $($field: lhs.$field - rhs.$field ),+ } }
});
impl_binary_operator!(<S: BaseFloat> Mul<$VectorN<S> > for $MatrixN<S> {
fn mul(matrix, vector) -> $VectorN<S> { $VectorN::new($(matrix.row($row_index).dot(vector.clone())),+) }
});
}
}
impl_scalar_binary_operator!(Mul::mul, Matrix2 { x, y });
impl_scalar_binary_operator!(Mul::mul, Matrix3 { x, y, z });
impl_scalar_binary_operator!(Mul::mul, Matrix4 { x, y, z, w });
impl_scalar_binary_operator!(Div::div, Matrix2 { x, y });
impl_scalar_binary_operator!(Div::div, Matrix3 { x, y, z });
impl_scalar_binary_operator!(Div::div, Matrix4 { x, y, z, w });
impl_scalar_binary_operator!(Rem::rem, Matrix2 { x, y });
impl_scalar_binary_operator!(Rem::rem, Matrix3 { x, y, z });
impl_scalar_binary_operator!(Rem::rem, Matrix4 { x, y, z, w });
impl_binary_operators!(Matrix2, Vector2 { x: 0, y: 1 });
impl_binary_operators!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
impl_binary_operators!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
macro_rules! impl_binary_operator {
($Binop:ident :: $binop:ident, $MatrixN:ident { $($field:ident),+ }) => {
impl<'a, 'b, S: BaseFloat> $Binop<&'a $MatrixN<S>> for &'b $MatrixN<S> {
type Output = $MatrixN<S>;
#[inline]
fn $binop(self, other: &'a $MatrixN<S>) -> $MatrixN<S> {
$MatrixN { $($field: self.$field.$binop(other.$field)),+ }
}
}
impl_binary_operator!(<S: BaseFloat> Mul<Matrix2<S> > for Matrix2<S> {
fn mul(lhs, rhs) -> Matrix2<S> {
Matrix2::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]),
lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1]))
}
});
impl_binary_operator!(<S: BaseFloat> Mul<Matrix3<S> > for Matrix3<S> {
fn mul(lhs, rhs) -> Matrix3<S> {
Matrix3::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]), lhs.row(2).dot(rhs[0]),
lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1]), lhs.row(2).dot(rhs[1]),
lhs.row(0).dot(rhs[2]), lhs.row(1).dot(rhs[2]), lhs.row(2).dot(rhs[2]))
}
});
// Using self.row(0).dot(other[0]) like the other matrix multiplies
// causes the LLVM to miss identical loads and multiplies. This optimization
// causes the code to be auto vectorized properly increasing the performance
// around ~4 times.
macro_rules! dot_matrix4 {
($A:expr, $B:expr, $I:expr, $J:expr) => {
($A[0][$I]) * ($B[$J][0]) +
($A[1][$I]) * ($B[$J][1]) +
($A[2][$I]) * ($B[$J][2]) +
($A[3][$I]) * ($B[$J][3])
};
}
impl_binary_operator!(Add::add, Matrix2 { x, y });
impl_binary_operator!(Add::add, Matrix3 { x, y, z });
impl_binary_operator!(Add::add, Matrix4 { x, y, z, w });
impl_binary_operator!(Sub::sub, Matrix2 { x, y });
impl_binary_operator!(Sub::sub, Matrix3 { x, y, z });
impl_binary_operator!(Sub::sub, Matrix4 { x, y, z, w });
macro_rules! impl_vector_mul_operators {
($MatrixN:ident, $VectorN:ident { $($row_index:expr),+ }) => {
impl<'a, S: BaseFloat> Mul<$VectorN<S>> for &'a $MatrixN<S> {
type Output = $VectorN<S>;
fn mul(self, v: $VectorN<S>) -> $VectorN<S> {
$VectorN::new($(self.row($row_index).dot(v)),+)
}
}
impl<'a, 'b, S: BaseFloat> Mul<&'a $VectorN<S>> for &'b $MatrixN<S> {
type Output = $VectorN<S>;
fn mul(self, v: &'a $VectorN<S>) -> $VectorN<S> {
$VectorN::new($(self.row($row_index).dot(*v)),+)
}
}
impl_binary_operator!(<S: BaseFloat> Mul<Matrix4<S> > for Matrix4<S> {
fn mul(lhs, rhs) -> Matrix4<S> {
Matrix4::new(dot_matrix4!(lhs, rhs, 0, 0), dot_matrix4!(lhs, rhs, 1, 0), dot_matrix4!(lhs, rhs, 2, 0), dot_matrix4!(lhs, rhs, 3, 0),
dot_matrix4!(lhs, rhs, 0, 1), dot_matrix4!(lhs, rhs, 1, 1), dot_matrix4!(lhs, rhs, 2, 1), dot_matrix4!(lhs, rhs, 3, 1),
dot_matrix4!(lhs, rhs, 0, 2), dot_matrix4!(lhs, rhs, 1, 2), dot_matrix4!(lhs, rhs, 2, 2), dot_matrix4!(lhs, rhs, 3, 2),
dot_matrix4!(lhs, rhs, 0, 3), dot_matrix4!(lhs, rhs, 1, 3), dot_matrix4!(lhs, rhs, 2, 3), dot_matrix4!(lhs, rhs, 3, 3))
}
}
impl_vector_mul_operators!(Matrix2, Vector2 { 0, 1 });
impl_vector_mul_operators!(Matrix3, Vector3 { 0, 1, 2 });
impl_vector_mul_operators!(Matrix4, Vector4 { 0, 1, 2, 3 });
impl<'a, 'b, S: BaseFloat> Mul<&'a Matrix2<S>> for &'b Matrix2<S> {
type Output = Matrix2<S>;
fn mul(self, other: &'a Matrix2<S>) -> Matrix2<S> {
Matrix2::new(self.row(0).dot(other[0]), self.row(1).dot(other[0]),
self.row(0).dot(other[1]), self.row(1).dot(other[1]))
}
}
impl<'a, 'b, S: BaseFloat> Mul<&'a Matrix3<S>> for &'b Matrix3<S> {
type Output = Matrix3<S>;
fn mul(self, other: &'a Matrix3<S>) -> Matrix3<S> {
Matrix3::new(self.row(0).dot(other[0]),self.row(1).dot(other[0]),self.row(2).dot(other[0]),
self.row(0).dot(other[1]),self.row(1).dot(other[1]),self.row(2).dot(other[1]),
self.row(0).dot(other[2]),self.row(1).dot(other[2]),self.row(2).dot(other[2]))
}
}
impl<'a, 'b, S: BaseFloat> Mul<&'a Matrix4<S>> for &'b Matrix4<S> {
type Output = Matrix4<S>;
fn mul(self, other: &'a Matrix4<S>) -> Matrix4<S> {
// Using self.row(0).dot(other[0]) like the other matrix multiplies
// causes the LLVM to miss identical loads and multiplies. This optimization
// causes the code to be auto vectorized properly increasing the performance
// around ~4 times.
macro_rules! dot_matrix4 {
($A:expr, $B:expr, $I:expr, $J:expr) => {
($A[0][$I]) * ($B[$J][0]) +
($A[1][$I]) * ($B[$J][1]) +
($A[2][$I]) * ($B[$J][2]) +
($A[3][$I]) * ($B[$J][3])
};
};
Matrix4::new(dot_matrix4!(self, other, 0, 0), dot_matrix4!(self, other, 1, 0), dot_matrix4!(self, other, 2, 0), dot_matrix4!(self, other, 3, 0),
dot_matrix4!(self, other, 0, 1), dot_matrix4!(self, other, 1, 1), dot_matrix4!(self, other, 2, 1), dot_matrix4!(self, other, 3, 1),
dot_matrix4!(self, other, 0, 2), dot_matrix4!(self, other, 1, 2), dot_matrix4!(self, other, 2, 2), dot_matrix4!(self, other, 3, 2),
dot_matrix4!(self, other, 0, 3), dot_matrix4!(self, other, 1, 3), dot_matrix4!(self, other, 2, 3), dot_matrix4!(self, other, 3, 3))
}
}
});
macro_rules! index_operators {
($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {

View file

@ -15,7 +15,7 @@
use angle::{Angle, Rad};
use approx::ApproxEq;
use matrix::{Matrix, SquareMatrix};
use matrix::SquareMatrix;
use matrix::{Matrix2, Matrix3};
use num::BaseFloat;
use point::{Point, Point2, Point3};
@ -150,7 +150,7 @@ pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
///
/// // This is exactly equivalent to using the raw matrix itself:
/// let unit_y2: Matrix2<_> = rot.into();
/// let unit_y2 = unit_y2.mul_v(unit_x);
/// let unit_y2 = unit_y2 * unit_x;
/// assert_eq!(unit_y2, unit_y);
///
/// // Note that we can also concatenate rotations:
@ -190,13 +190,13 @@ impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
}
#[inline]
fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat.mul_v(vec) }
fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat * vec }
#[inline]
fn concat(&self, other: &Basis2<S>) -> Basis2<S> { Basis2 { mat: self.mat.mul_m(&other.mat) } }
fn concat(&self, other: &Basis2<S>) -> Basis2<S> { Basis2 { mat: self.mat * other.mat } }
#[inline]
fn concat_self(&mut self, other: &Basis2<S>) { self.mat.mul_self_m(&other.mat); }
fn concat_self(&mut self, other: &Basis2<S>) { self.mat = self.mat * other.mat; }
// TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster
@ -274,13 +274,13 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
}
#[inline]
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat.mul_v(vec) }
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat * vec }
#[inline]
fn concat(&self, other: &Basis3<S>) -> Basis3<S> { Basis3 { mat: self.mat.mul_m(&other.mat) } }
fn concat(&self, other: &Basis3<S>) -> Basis3<S> { Basis3 { mat: self.mat * other.mat } }
#[inline]
fn concat_self(&mut self, other: &Basis3<S>) { self.mat.mul_self_m(&other.mat); }
fn concat_self(&mut self, other: &Basis3<S>) { self.mat = self.mat * other.mat; }
// TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster

View file

@ -189,17 +189,17 @@ impl<S: BaseFloat> Transform<Point3<S>> for AffineMatrix3<S> {
#[inline]
fn transform_vector(&self, vec: Vector3<S>) -> Vector3<S> {
self.mat.mul_v(vec.extend(S::zero())).truncate()
(self.mat * vec.extend(S::zero())).truncate()
}
#[inline]
fn transform_point(&self, point: Point3<S>) -> Point3<S> {
Point3::from_homogeneous(self.mat.mul_v(point.to_homogeneous()))
Point3::from_homogeneous(self.mat * point.to_homogeneous())
}
#[inline]
fn concat(&self, other: &AffineMatrix3<S>) -> AffineMatrix3<S> {
AffineMatrix3 { mat: self.mat.mul_m(&other.mat) }
AffineMatrix3 { mat: self.mat * other.mat }
}
#[inline]

View file

@ -78,16 +78,15 @@ pub mod matrix4 {
#[test]
fn test_neg() {
// Matrix2
assert_eq!(-matrix2::A,
Matrix2::new(-1.0f64, -3.0f64,
-2.0f64, -4.0f64));
// Matrix3
assert_eq!(-matrix3::A,
Matrix3::new(-1.0f64, -4.0f64, -7.0f64,
-2.0f64, -5.0f64, -8.0f64,
-3.0f64, -6.0f64, -9.0f64));
// Matrix4
assert_eq!(-matrix4::A,
Matrix4::new(-1.0f64, -5.0f64, -9.0f64, -13.0f64,
-2.0f64, -6.0f64, -10.0f64, -14.0f64,
@ -96,126 +95,84 @@ fn test_neg() {
}
#[test]
fn test_mul_s() {
// Matrix2
assert_eq!(matrix2::A.mul_s(matrix2::F),
fn test_mul_scalar() {
assert_eq!(matrix2::A * matrix2::F,
Matrix2::new(0.5f64, 1.5f64,
1.0f64, 2.0f64));
let mut mut_a = matrix2::A;
mut_a.mul_self_s(matrix2::F);
assert_eq!(mut_a, matrix2::A.mul_s(matrix2::F));
// Matrix3
assert_eq!(matrix3::A.mul_s(matrix3::F),
assert_eq!(matrix3::A * matrix3::F,
Matrix3::new(0.5f64, 2.0f64, 3.5f64,
1.0f64, 2.5f64, 4.0f64,
1.5f64, 3.0f64, 4.5f64));
let mut mut_a = matrix3::A;
mut_a.mul_self_s(matrix3::F);
assert_eq!(mut_a, matrix3::A.mul_s(matrix3::F));
// Matrix4
assert_eq!(matrix4::A.mul_s(matrix4::F),
assert_eq!(matrix4::A * matrix4::F,
Matrix4::new(0.5f64, 2.5f64, 4.5f64, 6.5f64,
1.0f64, 3.0f64, 5.0f64, 7.0f64,
1.5f64, 3.5f64, 5.5f64, 7.5f64,
2.0f64, 4.0f64, 6.0f64, 8.0f64));
let mut mut_a = matrix4::A;
mut_a.mul_self_s(matrix4::F);
assert_eq!(mut_a, matrix4::A.mul_s(matrix4::F));
}
#[test]
fn test_add_m() {
// Matrix2
assert_eq!(matrix2::A.add_m(&matrix2::B),
fn test_add_matrix() {
assert_eq!(matrix2::A + matrix2::B,
Matrix2::new(3.0f64, 7.0f64,
5.0f64, 9.0f64));
let mut mut_a = matrix2::A;
mut_a.add_self_m(&matrix2::B);
assert_eq!(mut_a, matrix2::A.add_m(&matrix2::B));
assert_eq!(mut_a, &matrix2::A + &matrix2::B);
// Matrix3
assert_eq!(matrix3::A.add_m(&matrix3::B),
assert_eq!(matrix3::A + matrix3::B,
Matrix3::new(3.0f64, 9.0f64, 15.0f64,
5.0f64, 11.0f64, 17.0f64,
7.0f64, 13.0f64, 19.0f64));
let mut mut_a = matrix3::A;
mut_a.add_self_m(&matrix3::B);
assert_eq!(mut_a, matrix3::A.add_m(&matrix3::B));
assert_eq!(mut_a, &matrix3::A + &matrix3::B);
// Matrix4
assert_eq!(matrix4::A.add_m(&matrix4::B),
assert_eq!(matrix4::A + matrix4::B,
Matrix4::new(3.0f64, 11.0f64, 19.0f64, 27.0f64,
5.0f64, 13.0f64, 21.0f64, 29.0f64,
7.0f64, 15.0f64, 23.0f64, 31.0f64,
9.0f64, 17.0f64, 25.0f64, 33.0f64));
let mut mut_a = matrix4::A;
mut_a.add_self_m(&matrix4::B);
assert_eq!(mut_a, matrix4::A.add_m(&matrix4::B));
assert_eq!(mut_a, &matrix4::A + &matrix4::B);
}
#[test]
fn test_sub_m() {
// Matrix2
assert_eq!(matrix2::A.sub_m(&matrix2::B),
fn test_sub_matrix() {
assert_eq!(matrix2::A - matrix2::B,
Matrix2::new(-1.0f64, -1.0f64,
-1.0f64, -1.0f64));
let mut mut_a = matrix2::A;
mut_a.sub_self_m(&matrix2::B);
assert_eq!(mut_a, matrix2::A.sub_m(&matrix2::B));
assert_eq!(matrix2::A.sub_m(&matrix2::B), &matrix2::A - &matrix2::B);
// Matrix3
assert_eq!(matrix3::A.sub_m(&matrix3::B),
assert_eq!(matrix3::A - matrix3::B,
Matrix3::new(-1.0f64, -1.0f64, -1.0f64,
-1.0f64, -1.0f64, -1.0f64,
-1.0f64, -1.0f64, -1.0f64));
let mut mut_a = matrix3::A;
mut_a.sub_self_m(&matrix3::B);
assert_eq!(mut_a, matrix3::A.sub_m(&matrix3::B));
assert_eq!(matrix3::A.sub_m(&matrix3::B), &matrix3::A - &matrix3::B);
// Matrix4
assert_eq!(matrix4::A.sub_m(&matrix4::B),
assert_eq!(matrix4::A - matrix4::B,
Matrix4::new(-1.0f64, -1.0f64, -1.0f64, -1.0f64,
-1.0f64, -1.0f64, -1.0f64, -1.0f64,
-1.0f64, -1.0f64, -1.0f64, -1.0f64,
-1.0f64, -1.0f64, -1.0f64, -1.0f64));
let mut mut_a = matrix4::A;
mut_a.sub_self_m(&matrix4::B);
assert_eq!(mut_a, matrix4::A.sub_m(&matrix4::B));
assert_eq!(matrix4::A.sub_m(&matrix4::B), &matrix4::A - &matrix4::B);
}
#[test]
fn test_mul_v() {
assert_eq!(matrix2::A.mul_v(matrix2::V), Vector2::new(5.0f64, 11.0f64));
assert_eq!(matrix3::A.mul_v(matrix3::V), Vector3::new(14.0f64, 32.0f64, 50.0f64));
assert_eq!(matrix4::A.mul_v(matrix4::V), Vector4::new(30.0f64, 70.0f64, 110.0f64, 150.0f64));
fn test_mul_vector() {
assert_eq!(matrix2::A * matrix2::V, Vector2::new(5.0f64, 11.0f64));
assert_eq!(matrix3::A * matrix3::V, Vector3::new(14.0f64, 32.0f64, 50.0f64));
assert_eq!(matrix4::A * matrix4::V, Vector4::new(30.0f64, 70.0f64, 110.0f64, 150.0f64));
}
#[test]
fn test_mul_m() {
assert_eq!(matrix2::A.mul_m(&matrix2::B),
fn test_mul_matrix() {
assert_eq!(matrix2::A * matrix2::B,
Matrix2::new(10.0f64, 22.0f64,
13.0f64, 29.0f64));
assert_eq!(matrix3::A.mul_m(&matrix3::B),
assert_eq!(matrix3::A * matrix3::B,
Matrix3::new(36.0f64, 81.0f64, 126.0f64,
42.0f64, 96.0f64, 150.0f64,
48.0f64, 111.0f64, 174.0f64));
assert_eq!(matrix4::A.mul_m(&matrix4::B),
assert_eq!(matrix4::A * matrix4::B,
Matrix4::new(100.0f64, 228.0f64, 356.0f64, 484.0f64,
110.0f64, 254.0f64, 398.0f64, 542.0f64,
120.0f64, 280.0f64, 440.0f64, 600.0f64,
130.0f64, 306.0f64, 482.0f64, 658.0f64));
assert_eq!(matrix2::A.mul_m(&matrix2::B), &matrix2::A * &matrix2::B);
assert_eq!(matrix3::A.mul_m(&matrix3::B), &matrix3::A * &matrix3::B);
assert_eq!(matrix4::A.mul_m(&matrix4::B), &matrix4::A * &matrix4::B);
assert_eq!(matrix2::A * matrix2::B, &matrix2::A * &matrix2::B);
assert_eq!(matrix3::A * matrix3::B, &matrix3::A * &matrix3::B);
assert_eq!(matrix4::A * matrix4::B, &matrix4::A * &matrix4::B);
}
#[test]
@ -292,11 +249,11 @@ fn test_invert() {
// Matrix4
assert!(Matrix4::<f64>::identity().invert().unwrap().is_identity());
assert!(matrix4::C.invert().unwrap().approx_eq(&
assert!(matrix4::C.invert().unwrap().approx_eq(&(
Matrix4::new( 5.0f64, -4.0f64, 1.0f64, 0.0f64,
-4.0f64, 8.0f64, -4.0f64, 0.0f64,
4.0f64, -8.0f64, 4.0f64, 8.0f64,
-3.0f64, 4.0f64, 1.0f64, -8.0f64).mul_s(0.125f64)));
-3.0f64, 4.0f64, 1.0f64, -8.0f64) * 0.125f64)));
let mut mut_c = matrix4::C;
mut_c.invert_self();
assert_eq!(mut_c, matrix4::C.invert().unwrap());
@ -305,32 +262,32 @@ fn test_invert() {
-0., 0.631364f64, 0.775487f64, 0.0f64,
-0.991261f64, 0.1023f64, -0.083287f64, 0.0f64,
0., -1.262728f64, -1.550973f64, 1.0f64);
assert!(mat_c.invert().unwrap().mul_m(&mat_c).is_identity());
assert!((mat_c.invert().unwrap() * mat_c).is_identity());
let mat_d = Matrix4::new( 0.065455f64, -0.720002f64, 0.690879f64, 0.0f64,
-0., 0.692364f64, 0.721549f64, 0.0f64,
-0.997856f64, -0.047229f64, 0.045318f64, 0.0f64,
0., -1.384727f64, -1.443098f64, 1.0f64);
assert!(mat_d.invert().unwrap().mul_m(&mat_d).is_identity());
assert!((mat_d.invert().unwrap() * mat_d).is_identity());
let mat_e = Matrix4::new( 0.409936f64, 0.683812f64, -0.603617f64, 0.0f64,
0., 0.661778f64, 0.7497f64, 0.0f64,
0.912114f64, -0.307329f64, 0.271286f64, 0.0f64,
-0., -1.323555f64, -1.499401f64, 1.0f64);
assert!(mat_e.invert().unwrap().mul_m(&mat_e).is_identity());
assert!((mat_e.invert().unwrap() * mat_e).is_identity());
let mat_f = Matrix4::new(-0.160691f64, -0.772608f64, 0.614211f64, 0.0f64,
-0., 0.622298f64, 0.78278f64, 0.0f64,
-0.987005f64, 0.125786f64, -0.099998f64, 0.0f64,
0., -1.244597f64, -1.565561f64, 1.0f64);
assert!(mat_f.invert().unwrap().mul_m(&mat_f).is_identity());
assert!((mat_f.invert().unwrap() * mat_f).is_identity());
}
#[test]
fn test_from_translation() {
let mat = Matrix4::from_translation(Vector3::new(1.0f64, 2.0f64, 3.0f64));
let vertex = Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64);
let res = mat.mul_v(vertex);
let res = mat * vertex;
assert_eq!(res, Vector4::new(1., 2., 3., 1.));
}
@ -398,13 +355,13 @@ fn test_predicates() {
fn test_from_angle() {
// Rotate the vector (1, 0) by π/2 radians to the vector (0, 1)
let rot1 = Matrix2::from_angle(rad(0.5f64 * f64::consts::PI));
assert!(rot1.mul_v(Vector2::unit_x()).approx_eq(&Vector2::unit_y()));
assert!((rot1 * Vector2::unit_x()).approx_eq(&Vector2::unit_y()));
// Rotate the vector (-1, 0) by -π/2 radians to the vector (0, 1)
let rot2 = -rot1;
assert!(rot2.mul_v(-Vector2::unit_x()).approx_eq(&Vector2::unit_y()));
assert!((rot2 * -Vector2::unit_x()).approx_eq(&Vector2::unit_y()));
// Rotate the vector (1, 1) by π radians to the vector (-1, -1)
let rot3: Matrix2<f64> = Matrix2::from_angle(rad(f64::consts::PI));
assert!(rot3.mul_v(Vector2::new(1.0, 1.0)).approx_eq(&Vector2::new(-1.0, -1.0)));
assert!((rot3 * Vector2::new(1.0, 1.0)).approx_eq(&Vector2::new(-1.0, -1.0)));
}

View file

@ -15,7 +15,7 @@
extern crate cgmath;
use cgmath::{Vector4, ortho, Matrix, Matrix4};
use cgmath::{Vector4, ortho, Matrix4};
#[test]
fn test_ortho_scale() {
@ -28,9 +28,9 @@ fn test_ortho_scale() {
let vec_far: Vector4<f32> = Vector4::new(1., 1., 1., 1.);
let o: Matrix4<f32> = ortho(-1., 1., -1., 1., -1., 1.);
let near = o.mul_v(vec_near);
let orig = o.mul_v(vec_orig);
let far = o.mul_v(vec_far);
let near = o * vec_near;
let orig = o * vec_orig;
let far = o * vec_far;
assert_eq!(near, Vector4::new(-1f32, -1., 1., 1.));
assert_eq!(orig, Vector4::new(0f32, 0., 0., 1.));
@ -38,9 +38,9 @@ fn test_ortho_scale() {
let o: Matrix4<f32> = ortho(-2., 2., -2., 2., -2., 2.);
let near = o.mul_v(vec_near);
let orig = o.mul_v(vec_orig);
let far = o.mul_v(vec_far);
let near = o * vec_near;
let orig = o * vec_orig;
let far = o * vec_far;
assert_eq!(near, Vector4::new(-0.5f32, -0.5, 0.5, 1.));
assert_eq!(orig, Vector4::new(0f32, 0., 0., 1.));
@ -56,14 +56,14 @@ fn test_ortho_translate() {
let vec_orig: Vector4<f32> = Vector4::new(0., 0., 0., 1.);
let o: Matrix4<f32> = ortho(-1., 1., -1., 1., -1., 1.);
let orig = o.mul_v(vec_orig);
let orig = o * vec_orig;
assert_eq!(orig, Vector4::new(0., 0., 0., 1.));
let o: Matrix4<f32> = ortho(0., 2., 0., 2., 0., 2.);
let orig = o.mul_v(vec_orig);
let orig = o * vec_orig;
assert_eq!(orig, Vector4::new(-1., -1., -1., 1.));
let o: Matrix4<f32> = ortho(-2., 0., -2., 0., -2., 0.);
let orig = o.mul_v(vec_orig);
let orig = o * vec_orig;
assert_eq!(orig, Vector4::new(1., 1., 1., 1.));
}