From fd2138bd88109cb5affdaeb92a0703d2ebf546a7 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 01:01:02 -0700 Subject: [PATCH] Document Matrix And remove `is_rotated` --- .gitignore | 1 + src/cgmath/matrix.rs | 117 ++++++++++++++++++++++++++++++-------- src/cgmath/partial_ord.rs | 3 + src/test/matrix.rs | 9 --- 4 files changed, 98 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 95053da..d76d080 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /bench/ /test/ /doc/ +*.swp diff --git a/src/cgmath/matrix.rs b/src/cgmath/matrix.rs index 0fe6a65..2e7d4d7 100644 --- a/src/cgmath/matrix.rs +++ b/src/cgmath/matrix.rs @@ -41,6 +41,7 @@ pub struct Matrix4 { pub x: Vector4, pub y: Vector4, pub z: Vector4, impl Matrix2 { + /// Create a new matrix, providing values for each index. #[inline] pub fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2 { @@ -48,22 +49,27 @@ impl Matrix2 { Vector2::new(c1r0, c1r1)) } + /// Create a new matrix, providing columns. #[inline] pub fn from_cols(c0: Vector2, c1: Vector2) -> Matrix2 { Matrix2 { x: c0, y: c1 } } + /// Create a new diagonal matrix, providing a single value to use for each + /// non-zero index. #[inline] pub fn from_value(value: S) -> Matrix2 { Matrix2::new(value.clone(), zero(), zero(), value.clone()) } + /// Create a zero matrix (all zeros). #[inline] pub fn zero() -> Matrix2 { Matrix2::from_value(zero()) } + /// Create an identity matrix (diagonal matrix of ones). #[inline] pub fn identity() -> Matrix2 { Matrix2::from_value(one()) @@ -71,6 +77,8 @@ impl Matrix2 { } impl> Matrix2 { + /// Create a transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. pub fn look_at(dir: &Vector2, up: &Vector2) -> Matrix2 { //TODO: verify look_at 2D Matrix2::from_cols(up.clone(), dir.clone()).transpose() @@ -87,6 +95,7 @@ impl> Matrix2 { } impl Matrix3 { + /// Create a new matrix, providing values for each index. #[inline] pub fn new(c0r0:S, c0r1:S, c0r2:S, c1r0:S, c1r1:S, c1r2:S, @@ -96,11 +105,14 @@ impl Matrix3 { Vector3::new(c2r0, c2r1, c2r2)) } + /// Create a new matrix, providing columns. #[inline] pub fn from_cols(c0: Vector3, c1: Vector3, c2: Vector3) -> Matrix3 { Matrix3 { x: c0, y: c1, z: c2 } } + /// Create a new diagonal matrix, providing a single value to use for each + /// non-zero index. #[inline] pub fn from_value(value: S) -> Matrix3 { Matrix3::new(value.clone(), zero(), zero(), @@ -108,11 +120,13 @@ impl Matrix3 { zero(), zero(), value.clone()) } + /// Create a zero matrix (all zeros). #[inline] pub fn zero() -> Matrix3 { Matrix3::from_value(zero()) } + /// Create an identity matrix (diagonal matrix of ones). #[inline] pub fn identity() -> Matrix3 { Matrix3::from_value(one()) @@ -121,6 +135,8 @@ impl Matrix3 { impl> Matrix3 { + /// Create a transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. pub fn look_at(dir: &Vector3, up: &Vector3) -> Matrix3 { let dir = dir.normalize(); let side = up.cross(&dir).normalize(); @@ -194,6 +210,7 @@ Matrix3 { } impl Matrix4 { + /// Create a new matrix, providing values for each index. #[inline] pub fn new(c0r0: S, c0r1: S, c0r2: S, c0r3: S, c1r0: S, c1r1: S, c1r2: S, c1r3: S, @@ -205,11 +222,14 @@ impl Matrix4 { Vector4::new(c3r0, c3r1, c3r2, c3r3)) } + /// Create a new matrix, providing columns. #[inline] pub fn from_cols(c0: Vector4, c1: Vector4, c2: Vector4, c3: Vector4) -> Matrix4 { Matrix4 { x: c0, y: c1, z: c2, w: c3 } } + /// Create a new diagonal matrix, providing a single value to use for each + /// non-zero index. #[inline] pub fn from_value(value: S) -> Matrix4 { Matrix4::new(value.clone(), zero(), zero(), zero(), @@ -218,11 +238,13 @@ impl Matrix4 { zero(), zero(), zero(), value.clone()) } + /// Create a zero matrix (all zeros). #[inline] pub fn zero() -> Matrix4 { Matrix4::from_value(zero()) } + /// Create an identity matrix (diagonal matrix of ones). #[inline] pub fn identity() -> Matrix4 { Matrix4::from_value(one()) @@ -231,6 +253,8 @@ impl Matrix4 { impl> Matrix4 { + /// Create a transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. pub fn look_at(eye: &Point3, center: &Point3, up: &Vector3) -> Matrix4 { let f = center.sub_p(eye).normalize(); let s = f.cross(up).normalize(); @@ -257,12 +281,15 @@ pub trait Matrix + Zero + One + ApproxEq { + /// Get a shared reference to a column of this matrix. #[inline] fn c<'a>(&'a self, c: uint) -> &'a V { self.i(c) } + /// Get a mutable reference to a column of this matrix. #[inline] fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut V { self.mut_i(c) } + /// Swap two columns of this matrix. #[inline] fn swap_c(&mut self, a: uint, b: uint) { let tmp = self.c(a).clone(); @@ -270,24 +297,32 @@ pub trait Matrix *self.mut_c(b) = tmp; } + /// Get a row from this matrix. + /// + /// Since matrixes in cgmath are stored column-major, this cannot return a + /// reference. It creates a new copy of the row instead. #[inline] fn r(&self, r: uint) -> V { build(|i| self.i(i).i(r).clone()) } + /// Swap two rows of this matrix. #[inline] fn swap_r(&mut self, a: uint, b: uint) { self.each_mut(|_, c| c.swap(a, b)) } + /// Return a shared reference to the element at column `c` and row `r`. #[inline] fn cr<'a>(&'a self, c: uint, r: uint) -> &'a S { self.i(c).i(r) } + /// Return a mutable reference to the element at column `c` and row `r`. #[inline] fn mut_cr<'a>(&'a mut self, c: uint, r: uint) -> &'a mut S { self.mut_i(c).mut_i(r) } + /// Swap the values at index `a` and `b` #[inline] fn swap_cr(&mut self, a: (uint, uint), b: (uint, uint)) { let (ca, ra) = a; @@ -297,67 +332,88 @@ pub trait Matrix *self.mut_cr(cb, rb) = tmp; } - // fn swap_cr(&mut self, (ca, ra): (uint, uint), (cb, rb): (uint, uint)) { - // let tmp = self.cr(ca, ra).clone(); - // *self.mut_cr(ca, ra) = self.cr(cb, rb).clone(); - // *self.mut_cr(cb, rb) = tmp; - // } - + /// Negate this matrix in-place (multiply by scalar -1). #[inline] fn neg_self(&mut self) { self.each_mut(|_, x| *x = x.neg()) } - #[inline] fn mul_s(&self, s: S) -> Self { build(|i| self.i(i).mul_s(s.clone())) } - #[inline] fn div_s(&self, s: S) -> Self { build(|i| self.i(i).div_s(s.clone())) } - #[inline] fn rem_s(&self, s: S) -> Self { build(|i| self.i(i).rem_s(s.clone())) } + /// Multiply this matrix by a scalar, returning the new matrix. + #[inline] fn mul_s(&self, s: S) -> Self { build(|i| self.c(i).mul_s(s.clone())) } + /// Divide this matrix by a scalar, returning the new matrix. + #[inline] fn div_s(&self, s: S) -> Self { build(|i| self.c(i).div_s(s.clone())) } + /// Take the remainder of this matrix by a scalar, returning the new + /// matrix. + #[inline] fn rem_s(&self, s: S) -> Self { build(|i| self.c(i).rem_s(s.clone())) } + /// Add this matrix with another matrix, returning the new metrix. #[inline] fn add_m(&self, other: &Self) -> Self { build(|i| self.i(i).add_v(other.i(i))) } + /// Subtract another matrix from this matrix, returning the new matrix. #[inline] fn sub_m(&self, other: &Self) -> Self { build(|i| self.i(i).sub_v(other.i(i))) } + /// Multiplay a vector by this matrix, returning a new vector. #[inline] fn mul_v(&self, v: &V) -> V { build(|i| self.r(i).dot(v)) } + /// Multiply this matrix by another matrix, returning the new matrix. fn mul_m(&self, other: &Self) -> Self; + /// Multiply this matrix by a scalar, in-place. #[inline] fn mul_self_s(&mut self, s: S) { self.each_mut(|_, c| *c = c.mul_s(s.clone())) } + /// Divide this matrix by a scalar, in-place. #[inline] fn div_self_s(&mut self, s: S) { self.each_mut(|_, c| *c = c.div_s(s.clone())) } + /// Take the remainder of this matrix, in-place. #[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, c| *c = c.rem_s(s.clone())) } + /// Add this matrix with another matrix, in-place. #[inline] fn add_self_m(&mut self, other: &Self) { self.each_mut(|i, c| *c = c.add_v(other.c(i))) } + /// Subtract another matrix from this matrix, in-place. #[inline] fn sub_self_m(&mut self, other: &Self) { self.each_mut(|i, c| *c = c.sub_v(other.c(i))) } + /// Multiply this matrix by another matrix, in-place. #[inline] fn mul_self_m(&mut self, other: &Self) { *self = self.mul_m(other); } + /// Transpose this matrix, returning a new matrix. fn transpose(&self) -> Self; + /// Transpose this matrix in-place. fn transpose_self(&mut self); + /// Take the determinant of this matrix. fn determinant(&self) -> S; + /// Return a vector containing the diagonal of this matrix. #[inline] fn diagonal(&self) -> V { build(|i| self.cr(i, i).clone()) } + /// Return the trace of this matrix. That is, the sum of the diagonal. #[inline] fn trace(&self) -> S { self.diagonal().comp_add() } + /// Invert this matrix, returning a new matrix. `m.mul_m(m.invert())` is + /// the identity matrix. Returns `None` if this matrix is not invertible + /// (has a determinant of zero). fn invert(&self) -> Option; + /// Invert this matrix in-place. #[inline] fn invert_self(&mut self) { *self = self.invert().expect("Attempted to invert a matrix with zero determinant."); } + /// Test if this matrix is invertible. #[inline] fn is_invertible(&self) -> bool { !self.determinant().approx_eq(&zero()) } + /// Test if this matrix is the identity matrix. That is, it is diagonal + /// and every element in the diagonal is one. #[inline] fn is_identity(&self) -> bool { self.approx_eq(&one()) } - #[inline] - fn is_rotated(&self) -> bool { - !self.approx_eq(&one()) - } - + /// Test if this is a diagonal matrix. That is, every element outside of + /// the diagonal is 0. fn is_diagonal(&self) -> bool; + + /// Test if this matrix is symmetric. That is, it is equal to its + /// transpose. fn is_symmetric(&self) -> bool; } @@ -636,14 +692,29 @@ for Matrix4 } // Conversion traits -pub trait ToMatrix2 { fn to_matrix2(&self) -> Matrix2; } -pub trait ToMatrix3 { fn to_matrix3(&self) -> Matrix3; } -pub trait ToMatrix4 { fn to_matrix4(&self) -> Matrix4; } + +/// Represents types which can be converted to a Matrix2 +pub trait ToMatrix2 { + /// Convert this value to a Matrix2 + fn to_matrix2(&self) -> Matrix2; +} + +/// Represents types which can be converted to a Matrix3 +pub trait ToMatrix3 { + /// Convert this value to a Matrix3 + fn to_matrix3(&self) -> Matrix3; +} + +/// Represents types which can be converted to a Matrix4 +pub trait ToMatrix4 { + /// Convert this value to a Matrix4 + fn to_matrix4(&self) -> Matrix4; +} impl> ToMatrix3 for Matrix2 { - /// Clone the elements of a 2-dimensional matrix into the top corner of a - /// 3-dimensional identity matrix. + /// Clone the elements of a 2-dimensional matrix into the top-left corner + /// of a 3-dimensional identity matrix. fn to_matrix3(&self) -> Matrix3 { Matrix3::new(self.cr(0, 0).clone(), self.cr(0, 1).clone(), zero(), self.cr(1, 0).clone(), self.cr(1, 1).clone(), zero(), @@ -653,8 +724,8 @@ ToMatrix3 for Matrix2 { impl> ToMatrix4 for Matrix2 { - /// Clone the elements of a 2-dimensional matrix into the top corner of a - /// 4-dimensional identity matrix. + /// Clone the elements of a 2-dimensional matrix into the top-left corner + /// of a 4-dimensional identity matrix. fn to_matrix4(&self) -> Matrix4 { Matrix4::new(self.cr(0, 0).clone(), self.cr(0, 1).clone(), zero(), zero(), self.cr(1, 0).clone(), self.cr(1, 1).clone(), zero(), zero(), @@ -665,8 +736,8 @@ ToMatrix4 for Matrix2 { impl> ToMatrix4 for Matrix3 { - /// Clone the elements of a 3-dimensional matrix into the top corner of a - /// 4-dimensional identity matrix. + /// Clone the elements of a 3-dimensional matrix into the top-left corner + /// of a 4-dimensional identity matrix. fn to_matrix4(&self) -> Matrix4 { Matrix4::new(self.cr(0, 0).clone(), self.cr(0, 1).clone(), self.cr(0, 2).clone(), zero(), self.cr(1, 0).clone(), self.cr(1, 1).clone(), self.cr(1, 2).clone(), zero(), diff --git a/src/cgmath/partial_ord.rs b/src/cgmath/partial_ord.rs index 5a04524..1040d76 100644 --- a/src/cgmath/partial_ord.rs +++ b/src/cgmath/partial_ord.rs @@ -16,6 +16,9 @@ use approx::ApproxEq; use std::cmp; +/// A trait providing a [partial order][po] over a primitive type. +/// +/// [po]: http://mathworld.wolfram.com/PartialOrder.html pub trait PartOrdPrim : Primitive { fn min(&self, b: Self) -> Self; fn max(&self, b: Self) -> Self; diff --git a/src/test/matrix.rs b/src/test/matrix.rs index 1dc3a92..8b036a4 100644 --- a/src/test/matrix.rs +++ b/src/test/matrix.rs @@ -301,19 +301,16 @@ fn test_predicates() { assert!(Matrix2::::identity().is_identity()); assert!(Matrix2::::identity().is_symmetric()); assert!(Matrix2::::identity().is_diagonal()); - assert!(!Matrix2::::identity().is_rotated()); assert!(Matrix2::::identity().is_invertible()); assert!(!matrix2::A.is_identity()); assert!(!matrix2::A.is_symmetric()); assert!(!matrix2::A.is_diagonal()); - assert!(matrix2::A.is_rotated()); assert!(matrix2::A.is_invertible()); assert!(!matrix2::C.is_identity()); assert!(matrix2::C.is_symmetric()); assert!(!matrix2::C.is_diagonal()); - assert!(matrix2::C.is_rotated()); assert!(matrix2::C.is_invertible()); assert!(Matrix2::from_value(6.0).is_diagonal()); @@ -323,19 +320,16 @@ fn test_predicates() { assert!(Matrix3::::identity().is_identity()); assert!(Matrix3::::identity().is_symmetric()); assert!(Matrix3::::identity().is_diagonal()); - assert!(!Matrix3::::identity().is_rotated()); assert!(Matrix3::::identity().is_invertible()); assert!(!matrix3::A.is_identity()); assert!(!matrix3::A.is_symmetric()); assert!(!matrix3::A.is_diagonal()); - assert!(matrix3::A.is_rotated()); assert!(!matrix3::A.is_invertible()); assert!(!matrix3::D.is_identity()); assert!(matrix3::D.is_symmetric()); assert!(!matrix3::D.is_diagonal()); - assert!(matrix3::D.is_rotated()); assert!(matrix3::D.is_invertible()); assert!(Matrix3::from_value(6.0).is_diagonal()); @@ -345,19 +339,16 @@ fn test_predicates() { assert!(Matrix4::::identity().is_identity()); assert!(Matrix4::::identity().is_symmetric()); assert!(Matrix4::::identity().is_diagonal()); - assert!(!Matrix4::::identity().is_rotated()); assert!(Matrix4::::identity().is_invertible()); assert!(!matrix4::A.is_identity()); assert!(!matrix4::A.is_symmetric()); assert!(!matrix4::A.is_diagonal()); - assert!(matrix4::A.is_rotated()); assert!(!matrix4::A.is_invertible()); assert!(!matrix4::D.is_identity()); assert!(matrix4::D.is_symmetric()); assert!(!matrix4::D.is_diagonal()); - assert!(matrix4::D.is_rotated()); assert!(matrix4::D.is_invertible()); assert!(Matrix4::from_value(6.0).is_diagonal());