Merge pull request #281 from bjz/matrix-ops

Implement all by-ref/val permutations of matrix operators, and remove operator methods
This commit is contained in:
Brendan Zabarauskas 2015-12-22 08:03:52 +11:00
commit 1b4420d2af
11 changed files with 204 additions and 471 deletions

View file

@ -7,16 +7,16 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
### Added ### Added
- Add missing by-ref and by-val permutations of `Quaternion` and `Angle` - Add missing by-ref and by-val permutations of `Vector`, `Matrix`, `Point`,
operators. `Quaternion` and `Angle` operators.
- Ease lifetime constraints by removing `'static` from some scalar type - Ease lifetime constraints by removing `'static` from some scalar type
parameters. parameters.
- Weaken type constraints on `perspective` function to take an `Into<Rad<S>>`. - Weaken type constraints on `perspective` function to take an `Into<Rad<S>>`.
- Add `Angle::new` for constructing angles from a unitless scalar. - Add `Angle::new` for constructing angles from a unitless scalar.
### Changed ### Changed
- `Vector`, `Point`, and `Angle` are now constrained to require specific - `Vector`, `Matrix`, `Point`, and `Angle` are now constrained to require
operators to be overloaded. This means that generic code can now use specific operators to be overloaded. This means that generic code can now use
operators, instead of the operator methods. operators, instead of the operator methods.
- Take a `Rad` for `ProjectionFov::fovy`, rather than arbitrary `Angle`s. This - Take a `Rad` for `ProjectionFov::fovy`, rather than arbitrary `Angle`s. This
simplifies the signature of `PerspectiveFov` from `PerspectiveFov<S, A>` to simplifies the signature of `PerspectiveFov` from `PerspectiveFov<S, A>` to
@ -42,11 +42,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Remove `Vector::one`. Vectors don't really have a multiplicative identity. - Remove `Vector::one`. Vectors don't really have a multiplicative identity.
If you really want a `one` vector, you can do something like: If you really want a `one` vector, you can do something like:
`Vector::from_value(1.0)`. `Vector::from_value(1.0)`.
- Remove operator methods from `Vector`, `Point`, and `Angle` traits in favor of - Remove operator methods from `Vector`, `Matrix`, `Point`, and `Angle` traits
operator overloading. in favor of operator overloading.
- Remove `*_self` methods from `Vector`, `Point`, and `Angle`. These were of - Remove `*_self` methods from `Vector`, `Matrix`, `Point`, and `Angle`. These
little performance benefit, and assignment operator overloading will be were of little performance benefit, and assignment operator overloading will
coming soon! be coming soon!
- Remove `#[derive(Hash)]` from `Deg` and `Rad`. This could never really be used - Remove `#[derive(Hash)]` from `Deg` and `Rad`. This could never really be used
these types, because they expect to be given a `BaseFloat` under normal these types, because they expect to be given a `BaseFloat` under normal
circumstances. circumstances.

View file

@ -167,23 +167,23 @@ macro_rules! impl_angle {
fn neg(self) -> $Angle<S> { $Angle::new(-self.s) } fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
} }
impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> { impl_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) } fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) }
}); });
impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> { impl_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) } fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) }
}); });
impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> { impl_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
fn div(lhs, rhs) -> S { lhs.s / rhs.s } fn div(lhs, rhs) -> S { lhs.s / rhs.s }
}); });
impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> { impl_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) } fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) }
}); });
impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> { impl_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) } fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) }
}); });
impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> { impl_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) } fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) }
}); });

View file

@ -18,59 +18,79 @@
#![macro_use] #![macro_use]
/// Generates a binary operator implementation for the permutations of by-ref and by-val /// Generates a binary operator implementation for the permutations of by-ref and by-val
macro_rules! impl_binary_operator { macro_rules! impl_operator {
// When the right operand is a scalar // When it is an unary operator
(<$S:ident: $Constraint:ident> $Binop:ident<$Rhs:ident> for $Lhs:ty { (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty {
fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } fn $op:ident($x:ident) -> $Output:ty { $body:expr }
}) => { }) => {
impl<$S: $Constraint> $Binop<$Rhs> for $Lhs { impl<$S: $Constraint> $Op for $Lhs {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
fn $binop(self, other: $Rhs) -> $Output { fn $op(self) -> $Output {
let $x = self; $body
}
}
impl<'a, $S: $Constraint> $Op for &'a $Lhs {
type Output = $Output;
#[inline]
fn $op(self) -> $Output {
let $x = self; $body
}
}
};
// When the right operand is a scalar
(<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty {
fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
}) => {
impl<$S: $Constraint> $Op<$Rhs> for $Lhs {
type Output = $Output;
#[inline]
fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body let ($lhs, $rhs) = (self, other); $body
} }
} }
impl<'a, $S: $Constraint> $Binop<$Rhs> for &'a $Lhs { impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
fn $binop(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body let ($lhs, $rhs) = (self, other); $body
} }
} }
}; };
// When the right operand is a compound type // When the right operand is a compound type
(<$S:ident: $Constraint:ident> $Binop:ident<$Rhs:ty> for $Lhs:ty { (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty {
fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
}) => { }) => {
impl<$S: $Constraint> $Binop<$Rhs> for $Lhs { impl<$S: $Constraint> $Op<$Rhs> for $Lhs {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
fn $binop(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body let ($lhs, $rhs) = (self, other); $body
} }
} }
impl<'a, $S: $Constraint> $Binop<&'a $Rhs> for $Lhs { impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
fn $binop(self, other: &'a $Rhs) -> $Output { fn $op(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body let ($lhs, $rhs) = (self, other); $body
} }
} }
impl<'a, $S: $Constraint> $Binop<$Rhs> for &'a $Lhs { impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
fn $binop(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body let ($lhs, $rhs) = (self, other); $body
} }
} }
impl<'a, 'b, $S: $Constraint> $Binop<&'a $Rhs> for &'b $Lhs { impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
fn $binop(self, other: &'a $Rhs) -> $Output { fn $op(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs) = (self, other); $body let ($lhs, $rhs) = (self, other); $body
} }
} }

View file

@ -263,16 +263,13 @@ pub trait Matrix where
Self: Index<usize, Output = <Self as Matrix>::Column>, Self: Index<usize, Output = <Self as Matrix>::Column>,
Self: IndexMut<usize, Output = <Self as Matrix>::Column>, Self: IndexMut<usize, Output = <Self as Matrix>::Column>,
Self: ApproxEq<Epsilon = <Self as Matrix>::Element>, Self: ApproxEq<Epsilon = <Self as Matrix>::Element>,
// FIXME: blocked by rust-lang/rust#20671
// Self: Add<Self, Output = Self>,
// for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>, Self: Sub<Self, Output = Self>,
// for<'a, 'b> &'a Self: Sub<&'b Self, Output = Self>,
// for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>, Self: Mul<<Self as Matrix>::Element, Output = Self>,
// for<'a, 'b> &'a Self: Mul<&'b V, Output = V>, Self: Div<<Self as Matrix>::Element, Output = Self>,
// Self: Rem<<Self as Matrix>::Element, Output = Self>,
// for<'a> &'a Self: Mul<S, Output = Self>,
// for<'a> &'a Self: Div<S, Output = Self>,
// for<'a> &'a Self: Rem<S, Output = Self>,
{ {
/// The type of the elements in the matrix. /// The type of the elements in the matrix.
type Element: BaseFloat; type Element: BaseFloat;
@ -316,22 +313,6 @@ pub trait Matrix where
/// Create a matrix with all of the elements set to zero. /// Create a matrix with all of the elements set to zero.
fn zero() -> Self; 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. /// Transpose this matrix, returning a new matrix.
fn transpose(&self) -> Self::Transpose; fn transpose(&self) -> Self::Transpose;
} }
@ -344,6 +325,8 @@ pub trait SquareMatrix where
Row = <Self as SquareMatrix>::ColumnRow, Row = <Self as SquareMatrix>::ColumnRow,
Transpose = Self, Transpose = Self,
>, >,
Self: Mul<<Self as SquareMatrix>::ColumnRow, Output = <Self as SquareMatrix>::ColumnRow>,
Self: Mul<Self, Output = Self>,
{ {
// FIXME: Will not be needed once equality constraints in where clauses are implemented // FIXME: Will not be needed once equality constraints in where clauses are implemented
/// The row/column vector of the matrix. /// The row/column vector of the matrix.
@ -362,19 +345,6 @@ pub trait SquareMatrix where
/// matrix with another has no effect. /// matrix with another has no effect.
fn identity() -> Self; 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. /// Transpose this matrix in-place.
fn transpose_self(&mut self); fn transpose_self(&mut self);
/// Take the determinant of this matrix. /// Take the determinant of this matrix.
@ -453,30 +423,6 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
S::zero(), S::zero()) 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> { fn transpose(&self) -> Matrix2<S> {
Matrix2::new(self[0][0], self[1][0], Matrix2::new(self[0][0], self[1][0],
self[0][1], self[1][1]) self[0][1], self[1][1])
@ -503,24 +449,6 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
Matrix2::from_value(S::one()) 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] #[inline]
fn transpose_self(&mut self) { fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0)); self.swap_elements((0, 1), (1, 0));
@ -601,32 +529,6 @@ impl<S: BaseFloat> Matrix for Matrix3<S> {
S::zero(), S::zero(), S::zero()) 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> { fn transpose(&self) -> Matrix3<S> {
Matrix3::new(self[0][0], self[1][0], self[2][0], Matrix3::new(self[0][0], self[1][0], self[2][0],
self[0][1], self[1][1], self[2][1], 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()) 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] #[inline]
fn transpose_self(&mut self) { fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0)); 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()) 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> { fn transpose(&self) -> Matrix4<S> {
Matrix4::new(self[0][0], self[1][0], self[2][0], self[3][0], 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], 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()) 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) { fn transpose_self(&mut self) {
self.swap_elements((0, 1), (1, 0)); self.swap_elements((0, 1), (1, 0));
self.swap_elements((0, 2), (2, 0)); self.swap_elements((0, 2), (2, 0));
@ -983,143 +815,75 @@ impl<S: BaseFloat> ApproxEq for Matrix4<S> {
} }
} }
impl<S: BaseFloat> Neg for Matrix2<S> { macro_rules! impl_operators {
type Output = Matrix2<S>; ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => {
impl_operator!(<S: BaseFloat> Neg for $MatrixN<S> {
fn neg(matrix) -> $MatrixN<S> { $MatrixN { $($field: -matrix.$field),+ } }
});
#[inline] impl_operator!(<S: BaseFloat> Mul<S> for $MatrixN<S> {
fn neg(self) -> Matrix2<S> { fn mul(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field * scalar),+ } }
Matrix2::from_cols(-self.x, -self.y) });
impl_operator!(<S: BaseFloat> Div<S> for $MatrixN<S> {
fn div(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field / scalar),+ } }
});
impl_operator!(<S: BaseFloat> Rem<S> for $MatrixN<S> {
fn rem(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field % scalar),+ } }
});
impl_operator!(<S: BaseFloat> Add<$MatrixN<S> > for $MatrixN<S> {
fn add(lhs, rhs) -> $MatrixN<S> { $MatrixN { $($field: lhs.$field + rhs.$field),+ } }
});
impl_operator!(<S: BaseFloat> Sub<$MatrixN<S> > for $MatrixN<S> {
fn sub(lhs, rhs) -> $MatrixN<S> { $MatrixN { $($field: lhs.$field - rhs.$field),+ } }
});
impl_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<S: BaseFloat> Neg for Matrix3<S> { impl_operators!(Matrix2, Vector2 { x: 0, y: 1 });
type Output = Matrix3<S>; impl_operators!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
impl_operators!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
#[inline] impl_operator!(<S: BaseFloat> Mul<Matrix2<S> > for Matrix2<S> {
fn neg(self) -> Matrix3<S> { fn mul(lhs, rhs) -> Matrix2<S> {
Matrix3::from_cols(-self.x, -self.y, -self.z) 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_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<S: BaseFloat> Neg for Matrix4<S> { impl_operator!(<S: BaseFloat> Mul<Matrix4<S> > for Matrix4<S> {
type Output = 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),
#[inline] dot_matrix4!(lhs, rhs, 0, 1), dot_matrix4!(lhs, rhs, 1, 1), dot_matrix4!(lhs, rhs, 2, 1), dot_matrix4!(lhs, rhs, 3, 1),
fn neg(self) -> Matrix4<S> { dot_matrix4!(lhs, rhs, 0, 2), dot_matrix4!(lhs, rhs, 1, 2), dot_matrix4!(lhs, rhs, 2, 2), dot_matrix4!(lhs, rhs, 3, 2),
Matrix4::from_cols(-self.x, -self.y, -self.z, -self.w) dot_matrix4!(lhs, rhs, 0, 3), dot_matrix4!(lhs, rhs, 1, 3), dot_matrix4!(lhs, rhs, 2, 3), dot_matrix4!(lhs, rhs, 3, 3))
} }
} });
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>;
#[inline]
fn $binop(self, s: S) -> $MatrixN<S> {
$MatrixN { $($field: self.$field.$binop(s)),+ }
}
}
}
}
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 });
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!(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_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 { macro_rules! index_operators {
($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { ($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {

View file

@ -142,23 +142,23 @@ macro_rules! impl_point {
} }
} }
impl_binary_operator!(<S: BaseNum> Add<$VectorN<S> > for $PointN<S> { impl_operator!(<S: BaseNum> Add<$VectorN<S> > for $PointN<S> {
fn add(lhs, rhs) -> $PointN<S> { $PointN::new($(lhs.$field + rhs.$field),+) } fn add(lhs, rhs) -> $PointN<S> { $PointN::new($(lhs.$field + rhs.$field),+) }
}); });
impl_binary_operator!(<S: BaseNum> Sub<$PointN<S> > for $PointN<S> { impl_operator!(<S: BaseNum> Sub<$PointN<S> > for $PointN<S> {
fn sub(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field - rhs.$field),+) } fn sub(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field - rhs.$field),+) }
}); });
impl_binary_operator!(<S: BaseNum> Mul<S> for $PointN<S> { impl_operator!(<S: BaseNum> Mul<S> for $PointN<S> {
fn mul(point, scalar) -> $PointN<S> { $PointN::new($(point.$field * scalar),+) } fn mul(point, scalar) -> $PointN<S> { $PointN::new($(point.$field * scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Div<S> for $PointN<S> { impl_operator!(<S: BaseNum> Div<S> for $PointN<S> {
fn div(point, scalar) -> $PointN<S> { $PointN::new($(point.$field / scalar),+) } fn div(point, scalar) -> $PointN<S> { $PointN::new($(point.$field / scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Rem<S> for $PointN<S> { impl_operator!(<S: BaseNum> Rem<S> for $PointN<S> {
fn rem(point, scalar) -> $PointN<S> { $PointN::new($(point.$field % scalar),+) } fn rem(point, scalar) -> $PointN<S> { $PointN::new($(point.$field % scalar),+) }
}); });

View file

@ -108,33 +108,25 @@ impl<S: BaseFloat> Quaternion<S> {
} }
} }
impl<S: BaseFloat> Neg for Quaternion<S> { impl_operator!(<S: BaseFloat> Neg for Quaternion<S> {
type Output = Quaternion<S>; fn neg(quat) -> Quaternion<S> {
Quaternion::from_sv(-quat.s, -quat.v)
}
});
#[inline] impl_operator!(<S: BaseFloat> Mul<S> for Quaternion<S> {
fn neg(self) -> Quaternion<S> { Quaternion::from_sv(-self.s, -self.v) }
}
impl<'a, S: BaseFloat> Neg for &'a Quaternion<S> {
type Output = Quaternion<S>;
#[inline]
fn neg(self) -> Quaternion<S> { Quaternion::from_sv(-self.s, -self.v) }
}
impl_binary_operator!(<S: BaseFloat> Mul<S> for Quaternion<S> {
fn mul(lhs, rhs) -> Quaternion<S> { fn mul(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs)
} }
}); });
impl_binary_operator!(<S: BaseFloat> Div<S> for Quaternion<S> { impl_operator!(<S: BaseFloat> Div<S> for Quaternion<S> {
fn div(lhs, rhs) -> Quaternion<S> { fn div(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs)
} }
}); });
impl_binary_operator!(<S: BaseFloat> Mul<Vector3<S> > for Quaternion<S> { impl_operator!(<S: BaseFloat> Mul<Vector3<S> > for Quaternion<S> {
fn mul(lhs, rhs) -> Vector3<S> {{ fn mul(lhs, rhs) -> Vector3<S> {{
let rhs = rhs.clone(); let rhs = rhs.clone();
let two: S = cast(2i8).unwrap(); let two: S = cast(2i8).unwrap();
@ -143,19 +135,19 @@ impl_binary_operator!(<S: BaseFloat> Mul<Vector3<S> > for Quaternion<S> {
}} }}
}); });
impl_binary_operator!(<S: BaseFloat> Add<Quaternion<S> > for Quaternion<S> { impl_operator!(<S: BaseFloat> Add<Quaternion<S> > for Quaternion<S> {
fn add(lhs, rhs) -> Quaternion<S> { fn add(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v)
} }
}); });
impl_binary_operator!(<S: BaseFloat> Sub<Quaternion<S> > for Quaternion<S> { impl_operator!(<S: BaseFloat> Sub<Quaternion<S> > for Quaternion<S> {
fn sub(lhs, rhs) -> Quaternion<S> { fn sub(lhs, rhs) -> Quaternion<S> {
Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v)
} }
}); });
impl_binary_operator!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> { impl_operator!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> {
fn mul(lhs, rhs) -> Quaternion<S> { fn mul(lhs, rhs) -> Quaternion<S> {
Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z,
lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y,

View file

@ -15,7 +15,7 @@
use angle::{Angle, Rad}; use angle::{Angle, Rad};
use approx::ApproxEq; use approx::ApproxEq;
use matrix::{Matrix, SquareMatrix}; use matrix::SquareMatrix;
use matrix::{Matrix2, Matrix3}; use matrix::{Matrix2, Matrix3};
use num::BaseFloat; use num::BaseFloat;
use point::{Point, Point2, Point3}; 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: /// // This is exactly equivalent to using the raw matrix itself:
/// let unit_y2: Matrix2<_> = rot.into(); /// 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); /// assert_eq!(unit_y2, unit_y);
/// ///
/// // Note that we can also concatenate rotations: /// // Note that we can also concatenate rotations:
@ -190,13 +190,13 @@ impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
} }
#[inline] #[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] #[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] #[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 // TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster // to be faster
@ -274,13 +274,13 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
} }
#[inline] #[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] #[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] #[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 // TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster // to be faster

View file

@ -189,17 +189,17 @@ impl<S: BaseFloat> Transform<Point3<S>> for AffineMatrix3<S> {
#[inline] #[inline]
fn transform_vector(&self, vec: Vector3<S>) -> Vector3<S> { 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] #[inline]
fn transform_point(&self, point: Point3<S>) -> Point3<S> { 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] #[inline]
fn concat(&self, other: &AffineMatrix3<S>) -> AffineMatrix3<S> { fn concat(&self, other: &AffineMatrix3<S>) -> AffineMatrix3<S> {
AffineMatrix3 { mat: self.mat.mul_m(&other.mat) } AffineMatrix3 { mat: self.mat * other.mat }
} }
#[inline] #[inline]

View file

@ -212,38 +212,38 @@ macro_rules! impl_vector {
} }
} }
impl_binary_operator!(<S: BaseNum> Add<S> for $VectorN<S> { impl_operator!(<S: BaseNum> Add<S> for $VectorN<S> {
fn add(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field + scalar),+) } fn add(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field + scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Add<$VectorN<S> > for $VectorN<S> { impl_operator!(<S: BaseNum> Add<$VectorN<S> > for $VectorN<S> {
fn add(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field + rhs.$field),+) } fn add(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field + rhs.$field),+) }
}); });
impl_binary_operator!(<S: BaseNum> Sub<S> for $VectorN<S> { impl_operator!(<S: BaseNum> Sub<S> for $VectorN<S> {
fn sub(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field - scalar),+) } fn sub(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field - scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Sub<$VectorN<S> > for $VectorN<S> { impl_operator!(<S: BaseNum> Sub<$VectorN<S> > for $VectorN<S> {
fn sub(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field - rhs.$field),+) } fn sub(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field - rhs.$field),+) }
}); });
impl_binary_operator!(<S: BaseNum> Mul<S> for $VectorN<S> { impl_operator!(<S: BaseNum> Mul<S> for $VectorN<S> {
fn mul(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field * scalar),+) } fn mul(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field * scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Mul<$VectorN<S> > for $VectorN<S> { impl_operator!(<S: BaseNum> Mul<$VectorN<S> > for $VectorN<S> {
fn mul(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field * rhs.$field),+) } fn mul(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field * rhs.$field),+) }
}); });
impl_binary_operator!(<S: BaseNum> Div<S> for $VectorN<S> { impl_operator!(<S: BaseNum> Div<S> for $VectorN<S> {
fn div(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field / scalar),+) } fn div(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field / scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Div<$VectorN<S> > for $VectorN<S> { impl_operator!(<S: BaseNum> Div<$VectorN<S> > for $VectorN<S> {
fn div(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field / rhs.$field),+) } fn div(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field / rhs.$field),+) }
}); });
impl_binary_operator!(<S: BaseNum> Rem<S> for $VectorN<S> { impl_operator!(<S: BaseNum> Rem<S> for $VectorN<S> {
fn rem(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field % scalar),+) } fn rem(vector, scalar) -> $VectorN<S> { $VectorN::new($(vector.$field % scalar),+) }
}); });
impl_binary_operator!(<S: BaseNum> Rem<$VectorN<S> > for $VectorN<S> { impl_operator!(<S: BaseNum> Rem<$VectorN<S> > for $VectorN<S> {
fn rem(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field % rhs.$field),+) } fn rem(lhs, rhs) -> $VectorN<S> { $VectorN::new($(lhs.$field % rhs.$field),+) }
}); });

View file

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