From 5b1d1a0f011e2e9e7ce3993e6a11c4b90be72501 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sat, 24 May 2014 18:22:23 -0700 Subject: [PATCH 01/12] Document Array --- src/cgmath/array.rs | 49 ++++++++++++++++++++++++++++++++++----------- src/cgmath/lib.rs | 5 ++++- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/cgmath/array.rs b/src/cgmath/array.rs index 9ae7dc6..4f0417d 100644 --- a/src/cgmath/array.rs +++ b/src/cgmath/array.rs @@ -17,30 +17,55 @@ use std::slice::{Items, MutItems}; -pub trait Array -< - T: Clone, - Slice -> -{ +/// An array containing elements of type `T` represented with `Repr` +/// +/// This trait abstracts over [T, ..N], and is manually implemented for arrays +/// of length 2, 3, and 4. +pub trait Array { + /// Get a shared reference to the `i`th value. fn i<'a>(&'a self, i: uint) -> &'a T; + + /// Get a mutable reference to the `i`th value. fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut T; - fn as_slice<'a>(&'a self) -> &'a Slice; - fn as_mut_slice<'a>(&'a mut self) -> &'a mut Slice; - fn from_slice(slice: Slice) -> Self; + + /// Get a shared reference to this array's data as `Repr`. + fn as_slice<'a>(&'a self) -> &'a Repr; + + /// Get a mutable reference to this array's data as `Repr`. + fn as_mut_slice<'a>(&'a mut self) -> &'a mut Repr; + + /// Construct a new Array from its representation. + fn from_repr(repr: Repr) -> Self; + + /// Create a new `Array` using a closure to generate the elements. The + /// closure is passed the index of the element it should produce. fn build(builder: |i: uint| -> T) -> Self; + + /// Iterate over the elements of this `Array`, yielding shared references + /// to items. fn iter<'a>(&'a self) -> Items<'a, T>; + + /// Iterate over the elements of this `Array`, yielding mutable references + /// to items. fn mut_iter<'a>(&'a mut self) -> MutItems<'a, T>; - /// Swap two elements of the type in place. #[inline] + /// Swap the elements at indices `a` and `b` in-place. fn swap(&mut self, a: uint, b: uint) { let tmp = self.i(a).clone(); *self.mut_i(a) = self.i(b).clone(); *self.mut_i(b) = tmp; } + /// Fold over this array, creating the same type as the type of the + /// elements. Use `.iter().fold(...)` for a more flexible fold. The first + /// element passed to the fold is the accumulator. It starts as the first + /// value in the array. fn fold(&self, f: |&T, &T| -> T) -> T; + + /// Iterate over this array, yielding mutable references to items. The + /// closure is passed the index of the element the reference is pointing + /// at. fn each_mut(&mut self, f: |i: uint, x: &mut T|); } @@ -68,13 +93,13 @@ macro_rules! array( } #[inline] - fn from_slice(slice: [$T,..$n]) -> $Self { + fn from_repr(slice: [$T,..$n]) -> $Self { unsafe { ::std::mem::transmute(slice) } } #[inline] fn build(builder: |i: uint| -> $T) -> $Self { - Array::from_slice(gen_builder!($_n)) + Array::from_repr(gen_builder!($_n)) } #[inline] diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index f0353e0..cd3b847 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -22,7 +22,10 @@ #![feature(globs)] #![feature(macro_rules)] -pub mod array; +pub use array::Array; + +mod array; + pub mod matrix; pub mod quaternion; pub mod vector; From fd2138bd88109cb5affdaeb92a0703d2ebf546a7 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 01:01:02 -0700 Subject: [PATCH 02/12] 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()); From ed9e5d092985e631dad32c2428ebe2a2c0cbb708 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 01:29:19 -0700 Subject: [PATCH 03/12] Cleanup Quaternion docs --- src/cgmath/quaternion.rs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/cgmath/quaternion.rs b/src/cgmath/quaternion.rs index e793eb5..4d71623 100644 --- a/src/cgmath/quaternion.rs +++ b/src/cgmath/quaternion.rs @@ -25,13 +25,16 @@ use rotation::{Rotation, Rotation3, Basis3, ToBasis3}; use vector::{Vector3, Vector, EuclideanVector}; use partial_ord::PartOrdFloat; -/// A quaternion in scalar/vector form +/// A [quaternion](https://en.wikipedia.org/wiki/Quaternion) in scalar/vector +/// form. #[deriving(Clone, Eq)] pub struct Quaternion { pub s: S, pub v: Vector3 } array!(impl Quaternion -> [S, ..4] _4) +/// Represents types which can be expressed as a quaternion. pub trait ToQuaternion { + /// Convert this value to a quaternion. fn to_quaternion(&self) -> Quaternion; } @@ -93,7 +96,7 @@ Quaternion { build(|i| self.i(i).add(other.i(i))) } - /// The the result of multipliplying the quaternion by `other` + /// The result of multipliplying the quaternion by `other` pub fn mul_q(&self, other: &Quaternion) -> Quaternion { Quaternion::new(self.s * other.s - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z, self.s * other.v.x + self.v.x * other.s + self.v.y * other.v.z - self.v.z * other.v.y, @@ -101,38 +104,43 @@ Quaternion { self.s * other.v.z + self.v.z * other.s + self.v.x * other.v.y - self.v.y * other.v.x) } + /// Multiply this quaternion by a scalar, in-place. #[inline] pub fn mul_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.mul(&s)) } + /// Divide this quaternion by a scalar, in-place. #[inline] pub fn div_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.div(&s)) } + /// Add this quaternion by another, in-place. #[inline] pub fn add_self_q(&mut self, other: &Quaternion) { self.each_mut(|i, x| *x = x.add(other.i(i))); } + /// Subtract another quaternion from this one, in-place. #[inline] pub fn sub_self_q(&mut self, other: &Quaternion) { self.each_mut(|i, x| *x = x.sub(other.i(i))); } + /// Multiply this quaternion by another, in-place. #[inline] pub fn mul_self_q(&mut self, other: &Quaternion) { *self = self.mul_q(other); } - /// The dot product of the quaternion and `other` + /// The dot product of the quaternion and `other`. #[inline] pub fn dot(&self, other: &Quaternion) -> S { self.s * other.s + self.v.dot(&other.v) } - /// The conjugate of the quaternion + /// The conjugate of the quaternion. #[inline] pub fn conjugate(&self) -> Quaternion { Quaternion::from_sv(self.s.clone(), -self.v.clone()) @@ -158,17 +166,13 @@ Quaternion { self.magnitude2().sqrt() } - /// The normalized quaternion + /// Normalize this quaternion, returning the new quaternion. #[inline] pub fn normalize(&self) -> Quaternion { self.mul_s(one::() / self.magnitude()) } - /// Normalised linear interpolation - /// - /// # Return value - /// - /// The intoperlated quaternion + /// Do a normalized linear interpolation with `other`, by `amount`. pub fn nlerp(&self, other: &Quaternion, amount: S) -> Quaternion { self.mul_s(one::() - amount).add_q(&other.mul_s(amount)).normalize() } @@ -178,18 +182,15 @@ impl> Quaternion { /// Spherical Linear Intoperlation /// - /// Perform a spherical linear interpolation between the quaternion and + /// Return the spherical linear interpolation between the quaternion and /// `other`. Both quaternions should be normalized first. /// - /// # Return value - /// - /// The intoperlated quaternion - /// /// # Performance notes /// - /// The `acos` operation used in `slerp` is an expensive operation, so unless - /// your quarternions a far away from each other it's generally more advisable - /// to use `nlerp` when you know your rotations are going to be small. + /// The `acos` operation used in `slerp` is an expensive operation, so + /// unless your quarternions are far away from each other it's generally + /// more advisable to use `nlerp` when you know your rotations are going + /// to be small. /// /// - [Understanding Slerp, Then Not Using It] /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/) From d6c0d1d65dcb2a61ffddccc68d968c7980964337 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 02:43:51 -0700 Subject: [PATCH 04/12] Minor doc cleanup for Vector --- src/cgmath/vector.rs | 50 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/cgmath/vector.rs b/src/cgmath/vector.rs index 1a22e16..95b689a 100644 --- a/src/cgmath/vector.rs +++ b/src/cgmath/vector.rs @@ -33,30 +33,51 @@ pub trait Vector + Neg + Zero + One { + /// Add a scalar to this vector, returning a new vector. #[inline] fn add_s(&self, s: S) -> Self { build(|i| self.i(i).add(&s)) } + /// Subtract a scalar from this vector, returning a new vector. #[inline] fn sub_s(&self, s: S) -> Self { build(|i| self.i(i).sub(&s)) } + /// Multiply this vector by a scalar, returning a new vector. #[inline] fn mul_s(&self, s: S) -> Self { build(|i| self.i(i).mul(&s)) } + /// Divide this vector by a scalar, returning a new vector. #[inline] fn div_s(&self, s: S) -> Self { build(|i| self.i(i).div(&s)) } + /// Take the remainder of this vector by a scalar, returning a new vector. #[inline] fn rem_s(&self, s: S) -> Self { build(|i| self.i(i).rem(&s)) } + /// Add this vector to another, returning a new vector. #[inline] fn add_v(&self, other: &Self) -> Self { build(|i| self.i(i).add(other.i(i))) } + /// Subtract another vector from this one, returning a new vector. #[inline] fn sub_v(&self, other: &Self) -> Self { build(|i| self.i(i).sub(other.i(i))) } + /// Multiply this vector by another, returning a new vector. #[inline] fn mul_v(&self, other: &Self) -> Self { build(|i| self.i(i).mul(other.i(i))) } + /// Divide this vector by another, returning a new vector. #[inline] fn div_v(&self, other: &Self) -> Self { build(|i| self.i(i).div(other.i(i))) } + /// Take the remainder of this vector by another, returning a new scalar. #[inline] fn rem_v(&self, other: &Self) -> Self { build(|i| self.i(i).rem(other.i(i))) } + /// Negate this vector in-place. #[inline] fn neg_self(&mut self) { self.each_mut(|_, x| *x = x.neg()) } + /// Add a scalar to this vector in-place. #[inline] fn add_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.add(&s)) } + /// Subtract a scalar from this vector, in-place. #[inline] fn sub_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.sub(&s)) } + /// Multiply this vector by a scalar, in-place. #[inline] fn mul_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.mul(&s)) } + /// Divide this vector by a scalar, in-place. #[inline] fn div_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.div(&s)) } + /// Take the remainder of this vector by a scalar, in-place. #[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.rem(&s)) } + /// Add another vector to this one, in-place. #[inline] fn add_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.add(other.i(i))) } + /// Subtract another vector from this one, in-place. #[inline] fn sub_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.sub(other.i(i))) } + /// Multiply this matrix by another, in-place. #[inline] fn mul_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.mul(other.i(i))) } + /// Divide this matrix by anothor, in-place. #[inline] fn div_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.div(other.i(i))) } + /// Take the remainder of this vector by another, in-place. #[inline] fn rem_self_v(&mut self, other: &Self) { self.each_mut(|i, x| *x = x.rem(other.i(i))) } /// The sum of each component of the vector. @@ -75,6 +96,7 @@ pub trait Vector #[inline] fn comp_max(&self) -> S { self.fold(|a, b| if *a > *b { *a } else {*b }) } } +/// Dot product of two vectors. #[inline] pub fn dot>(a: V, b: V) -> S { a.dot(&b) } // Utility macro for generating associated functions for the vectors @@ -84,12 +106,13 @@ macro_rules! vec( pub struct $Self { $(pub $field: S),+ } impl<$S: Primitive> $Self<$S> { + /// Construct a new vector, using the provided values. #[inline] pub fn new($($field: $S),+) -> $Self<$S> { $Self { $($field: $field),+ } } - /// Construct a vector from a single value. + /// Construct a vector from a single value, replicating it. #[inline] pub fn from_value(value: $S) -> $Self<$S> { $Self { $($field: value.clone()),+ } @@ -143,7 +166,9 @@ array!(impl Vector4 -> [S, ..4] _4) /// Operations specific to numeric two-dimensional vectors. impl Vector2 { + /// A unit vector in the `x` direction. #[inline] pub fn unit_x() -> Vector2 { Vector2::new(one(), zero()) } + /// A unit vector in the `y` direction. #[inline] pub fn unit_y() -> Vector2 { Vector2::new(zero(), one()) } /// The perpendicular dot product of the vector and `other`. @@ -152,6 +177,8 @@ impl Vector2 { (self.x * other.y) - (self.y * other.x) } + /// Create a `Vector3`, using the `x` and `y` values from this vector, and the + /// provided `z`. #[inline] pub fn extend(&self, z: S)-> Vector3 { Vector3::new(self.x.clone(), self.y.clone(), z) @@ -160,8 +187,11 @@ impl Vector2 { /// Operations specific to numeric three-dimensional vectors. impl Vector3 { + /// A unit vector in the `x` direction. #[inline] pub fn unit_x() -> Vector3 { Vector3::new(one(), zero(), zero()) } + /// A unit vector in the `y` direction. #[inline] pub fn unit_y() -> Vector3 { Vector3::new(zero(), one(), zero()) } + /// A unit vector in the `w` direction. #[inline] pub fn unit_z() -> Vector3 { Vector3::new(zero(), zero(), one()) } /// Returns the cross product of the vector and `other`. @@ -179,27 +209,35 @@ impl Vector3 { *self = self.cross(other) } + /// Create a `Vector4`, using the `x`, `y` and `z` values from this vector, and the + /// provided `w`. #[inline] pub fn extend(&self, w: S)-> Vector4 { Vector4::new(self.x.clone(), self.y.clone(), self.z.clone(), w) } + /// Create a `Vector2`, dropping the `z` value. #[inline] pub fn truncate(&self)-> Vector2 { - Vector2::new(self.x.clone(), self.y.clone()) //ignore Z + Vector2::new(self.x.clone(), self.y.clone()) } } /// Operations specific to numeric four-dimensional vectors. impl Vector4 { + /// A unit vector in the `x` direction. #[inline] pub fn unit_x() -> Vector4 { Vector4::new(one(), zero(), zero(), zero()) } + /// A unit vector in the `y` direction. #[inline] pub fn unit_y() -> Vector4 { Vector4::new(zero(), one(), zero(), zero()) } + /// A unit vector in the `z` direction. #[inline] pub fn unit_z() -> Vector4 { Vector4::new(zero(), zero(), one(), zero()) } + /// A unit vector in the `w` direction. #[inline] pub fn unit_w() -> Vector4 { Vector4::new(zero(), zero(), zero(), one()) } + /// Create a `Vector3`, dropping the `w` value. #[inline] pub fn truncate(&self)-> Vector3 { - Vector3::new(self.x.clone(), self.y.clone(), self.z.clone()) //ignore W + Vector3::new(self.x.clone(), self.y.clone(), self.z.clone()) } } @@ -213,8 +251,8 @@ pub trait EuclideanVector : Vector + ApproxEq { - /// Returns `true` if the vector is perpendicular (at right angles to) - /// the other vector. + /// Returns `true` if the vector is perpendicular (at right angles) to the + /// other vector. fn is_perpendicular(&self, other: &Self) -> bool { self.dot(other).approx_eq(&zero()) } @@ -233,7 +271,7 @@ pub trait EuclideanVector self.dot(self).sqrt() } - /// The angle between the vector and `other`. + /// The angle between the vector and `other`, in radians. fn angle(&self, other: &Self) -> Rad; /// Returns a vector with the same direction, but with a `length` (or From 8fa0f67333913cfe839867f3fa89a85430b7ca72 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 03:00:52 -0700 Subject: [PATCH 05/12] Add some docs for Angle --- src/cgmath/angle.rs | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/cgmath/angle.rs b/src/cgmath/angle.rs index bdba0e1..9327cfb 100644 --- a/src/cgmath/angle.rs +++ b/src/cgmath/angle.rs @@ -20,14 +20,27 @@ use std::num::{One, one, Zero, zero, cast}; use approx::ApproxEq; +/// An angle, in radians #[deriving(Clone, Eq, Ord, Hash)] pub struct Rad { pub s: S } +/// An angle, in degrees #[deriving(Clone, Eq, Ord, Hash)] pub struct Deg { pub s: S } +/// Create a new angle, in radians #[inline] pub fn rad(s: S) -> Rad { Rad { s: s } } +/// Create a new angle, in degrees #[inline] pub fn deg(s: S) -> Deg { Deg { s: s } } -pub trait ToRad { fn to_rad(&self) -> Rad; } -pub trait ToDeg { fn to_deg(&self) -> Deg; } +/// Represents types that can be converted to radians. +pub trait ToRad { + /// Convert this value to radians. + fn to_rad(&self) -> Rad; +} + +/// Represents types that can be converted to degrees. +pub trait ToDeg { + /// Convert this value to degrees. + fn to_deg(&self) -> Deg; +} impl ToRad for Rad { #[inline] fn to_rad(&self) -> Rad { self.clone() } } impl ToRad for Deg { #[inline] fn to_rad(&self) -> Rad { rad(self.s.to_radians()) } } @@ -54,6 +67,7 @@ impl ScalarConv for Deg { #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s } } +/// Operations on angles. pub trait Angle < S: Float @@ -66,22 +80,38 @@ pub trait Angle + ToDeg + ScalarConv { + /// Create a new angle from any other valid angle. fn from>(theta: A) -> Self; + /// Negate this angle, in-place. #[inline] fn neg_self(&mut self) { *self = -*self } + /// Add this angle with another, returning the new angle. #[inline] fn add_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() + *other.s()) } + /// Subtract another angle from this one, returning the new angle. #[inline] fn sub_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() - *other.s()) } + /// Divide this angle by another, returning the ratio. #[inline] fn div_a(&self, other: Self) -> S { *self.s() / *other.s() } + /// Take the remainder of this angle with another. #[inline] fn rem_a(&self, other: Self) -> S { *self.s() % *other.s() } + + /// Multiply this angle by a scalar, returning the new angle. #[inline] fn mul_s(&self, s: S) -> Self { ScalarConv::from(*self.s() * s) } + /// Divide this angle by a scalar, returing the new angle. #[inline] fn div_s(&self, s: S) -> Self { ScalarConv::from(*self.s() / s) } + /// Take the remainder of this angle by a scalar, returning the new angle. #[inline] fn rem_s(&self, s: S) -> Self { ScalarConv::from(*self.s() % s) } + /// Add this angle with another, in-place. #[inline] fn add_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() + *other.s() } + /// Subtract another angle from this one, in-place. #[inline] fn sub_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() - *other.s() } + + /// Multiply this angle by a scalar, in-place. #[inline] fn mul_self_s(&mut self, s: S) { *self.mut_s() = *self.s() * s } + /// Divide this angle by a scalar, in-place. #[inline] fn div_self_s(&mut self, s: S) { *self.mut_s() = *self.s() / s } + /// Take the remainder of this angle by a scalar, in-place. #[inline] fn rem_self_s(&mut self, s: S) { *self.mut_s() = *self.s() % s } /// Return the angle, normalized to the range `[0, full_turn)`. From c9573ad511d85c9a28aadfead2767f9978cb6d38 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 03:04:44 -0700 Subject: [PATCH 06/12] Touch up the Plane docs --- src/cgmath/plane.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cgmath/plane.rs b/src/cgmath/plane.rs index eb3b5fa..adf9cd0 100644 --- a/src/cgmath/plane.rs +++ b/src/cgmath/plane.rs @@ -26,7 +26,7 @@ use vector::{Vector, EuclideanVector}; use partial_ord::PartOrdFloat; -/// A 3-dimensional plane formed from the equation: `a*x + b*y + c*z - d = 0`. +/// A 3-dimensional plane formed from the equation: `A*x + B*y + C*z - D = 0`. /// /// # Fields /// @@ -38,8 +38,8 @@ use partial_ord::PartOrdFloat; /// /// # Notes /// -/// The `a*x + b*y + c*z - d = 0` form is preferred over the other common -/// alternative, `a*x + b*y + c*z + d = 0`, because it tends to avoid +/// The `A*x + B*y + C*z - D = 0` form is preferred over the other common +/// alternative, `A*x + B*y + C*z + D = 0`, because it tends to avoid /// superfluous negations (see _Real Time Collision Detection_, p. 55). #[deriving(Clone, Eq)] pub struct Plane { @@ -49,7 +49,9 @@ pub struct Plane { impl> Plane { - /// Construct a plane from a normal vector and a scalar distance + /// Construct a plane from a normal vector and a scalar distance. The + /// plane will be perpendicular to `n`, and `d` units offset from the + /// origin. pub fn new(n: Vector3, d: S) -> Plane { Plane { n: n, d: d } } From 982887038000fa2a15ecff055e40477acf85d0f0 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 03:09:33 -0700 Subject: [PATCH 07/12] Document Point --- src/cgmath/point.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cgmath/point.rs b/src/cgmath/point.rs index f54e6f7..32635f0 100644 --- a/src/cgmath/point.rs +++ b/src/cgmath/point.rs @@ -69,25 +69,37 @@ pub trait Point > : Array { + /// Create a point at the origin. #[inline] fn origin() -> Self{ build(|_i| zero::()) } + /// Create a point from a vector. #[inline] fn from_vec(v: &V) -> Self { build(|i| v.i(i).clone()) } + /// Convert a point to a vector. #[inline] fn to_vec(&self) -> V { build(|i| self.i(i).clone()) } + /// Multiply each component by a scalar, returning the new point. #[inline] fn mul_s(&self, s: S) -> Self { build(|i| self.i(i).mul(&s)) } + /// Divide each component by a scalar, returning the new point. #[inline] fn div_s(&self, s: S) -> Self { build(|i| self.i(i).div(&s)) } + /// Subtract a scalar from each component, returning the new point. #[inline] fn rem_s(&self, s: S) -> Self { build(|i| self.i(i).rem(&s)) } + /// Add a vector to this point, returning the new point. #[inline] fn add_v(&self, other: &V) -> Self { build(|i| self.i(i).add(other.i(i))) } + /// Subtract another point from this one, returning a new vector. #[inline] fn sub_p(&self, other: &Self) -> V { build(|i| self.i(i).sub(other.i(i))) } + /// Multiply each component by a scalar, in-place. #[inline] fn mul_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.mul(&s)) } + /// Divide each component by a scalar, in-place. #[inline] fn div_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.div(&s)) } + /// Take the remainder of each component by a scalar, in-place. #[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.rem(&s)) } + /// Add a vector to this point, in-place. #[inline] fn add_self_v(&mut self, other: &V) { self.each_mut(|i, x| *x = x.add(other.i(i))) } - /// This is a weird one, but its useful for plane calculations + /// This is a weird one, but its useful for plane calculations. #[inline] fn dot(&self, v: &V) -> S { build::(|i| self.i(i).mul(v.i(i))).comp_add() From 7416e5ce14cece94d6fac8b07bbb6af7c639e2f3 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 03:17:57 -0700 Subject: [PATCH 08/12] Touch up Ray docs --- src/cgmath/line.rs | 2 +- src/cgmath/ray.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cgmath/line.rs b/src/cgmath/line.rs index 92c82a0..5359b42 100644 --- a/src/cgmath/line.rs +++ b/src/cgmath/line.rs @@ -22,7 +22,7 @@ use vector::{Vector, Vector2}; use partial_ord::PartOrdFloat; use intersect::Intersect; -/// A generic directed line segment +/// A generic directed line segment from `origin` to `dest`. #[deriving(Clone, Eq)] pub struct Line

{ diff --git a/src/cgmath/ray.rs b/src/cgmath/ray.rs index 3431ab4..69cb118 100644 --- a/src/cgmath/ray.rs +++ b/src/cgmath/ray.rs @@ -16,7 +16,8 @@ use point::{Point, Point2, Point3}; use vector::{Vector, Vector2, Vector3}; -/// A generic ray +/// A generic ray starting at `origin` and extending infinitely in +/// `direction`. #[deriving(Clone, Eq)] pub struct Ray { From 27488b0dbc2cbb100142944fd95e86037f0dfe81 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 04:10:44 -0700 Subject: [PATCH 09/12] Touch up docs for Rotation --- src/cgmath/lib.rs | 1 + src/cgmath/rotation.rs | 45 +++++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index cd3b847..fe816a4 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -22,6 +22,7 @@ #![feature(globs)] #![feature(macro_rules)] +//! Computer graphics-centric math. pub use array::Array; mod array; diff --git a/src/cgmath/rotation.rs b/src/cgmath/rotation.rs index 85ac745..5fe8b47 100644 --- a/src/cgmath/rotation.rs +++ b/src/cgmath/rotation.rs @@ -25,7 +25,8 @@ use ray::Ray; use vector::{Vector, Vector2, Vector3}; use partial_ord::{PartOrdPrim, PartOrdFloat}; -/// A trait for generic rotation +/// A trait for a generic rotation. A rotation is a transformation that +/// creates a circular motion, and preserves at least one point in the space. pub trait Rotation < S: PartOrdPrim, @@ -36,22 +37,27 @@ pub trait Rotation : Eq + ApproxEq { + /// Create the identity transform (causes no transformation). fn identity() -> Self; /// Create a rotation to a given direction with an 'up' vector fn look_at(dir: &V, up: &V) -> Self; - + /// Create a shortest rotation to transform vector 'a' into 'b'. /// Both given vectors are assumed to have unit length. fn between_vectors(a: &V, b: &V) -> Self; + /// Rotate a vector using this rotation. fn rotate_vector(&self, vec: &V) -> V; + /// Rotate a point using this rotation, by converting it to its + /// representation as a vector. #[inline] fn rotate_point(&self, point: &P) -> P { Point::from_vec( &self.rotate_vector( &point.to_vec() ) ) } + /// Rotate a ray using this rotation. #[inline] fn rotate_ray(&self, ray: &Ray) -> Ray { Ray::new( //FIXME: use clone derived from Array @@ -59,21 +65,27 @@ pub trait Rotation self.rotate_vector(&ray.direction) ) } + /// Create a new rotation which combines both this rotation, and another. fn concat(&self, other: &Self) -> Self; + + /// Create a new rotation which "un-does" this rotation. That is, + /// `r.concat(r.invert())` is the identity. fn invert(&self) -> Self; + /// Modify this rotation in-place by combining it with another. #[inline] fn concat_self(&mut self, other: &Self) { *self = self.concat(other); } - + + /// Invert this rotation in-place. #[inline] fn invert_self(&mut self) { *self = self.invert(); } } -/// A two-dimensional rotation +/// A two-dimensional rotation. pub trait Rotation2 < S @@ -82,12 +94,12 @@ pub trait Rotation2 + ToMatrix2 + ToBasis2 { - // Create a rotation by a given angle. Thus is a redundant case of both - // from_axis_angle() and from_euler() for 2D space. + /// Create a rotation by a given angle. Thus is a redundant case of both + /// from_axis_angle() and from_euler() for 2D space. fn from_angle(theta: Rad) -> Self; } -/// A three-dimensional rotation +/// A three-dimensional rotation. pub trait Rotation3 < S: Primitive @@ -97,7 +109,7 @@ pub trait Rotation3 + ToBasis3 + ToQuaternion { - /// Create a rotation around a given axis. + /// Create a rotation using an angle around a given axis. fn from_axis_angle(axis: &Vector3, angle: Rad) -> Self; /// Create a rotation from a set of euler angles. @@ -109,17 +121,19 @@ pub trait Rotation3 /// - `z`: the angular rotation around the `z` axis (roll). fn from_euler(x: Rad, y: Rad, z: Rad) -> Self; - /// Create a rotation matrix from a rotation around the `x` axis (pitch). + /// Create a rotation from an angle around the `x` axis (pitch). #[inline] fn from_angle_x(theta: Rad) -> Self { Rotation3::from_axis_angle( &Vector3::unit_x(), theta ) } + /// Create a rotation from an angle around the `y` axis (yaw). #[inline] fn from_angle_y(theta: Rad) -> Self { Rotation3::from_axis_angle( &Vector3::unit_y(), theta ) } + /// Create a rotation from an angle around the `z` axis (roll). #[inline] fn from_angle_z(theta: Rad) -> Self { Rotation3::from_axis_angle( &Vector3::unit_z(), theta ) @@ -139,11 +153,14 @@ pub struct Basis2 { } impl Basis2 { + /// Coerce to a `Matrix2` #[inline] pub fn as_matrix2<'a>(&'a self) -> &'a Matrix2 { &'a self.mat } } +/// Represents types which can be converted to a rotation matrix. pub trait ToBasis2 { + /// Convert this type to a rotation matrix. fn to_rot2(&self) -> Basis2; } @@ -171,7 +188,7 @@ Rotation, Point2> for Basis2 { fn between_vectors(a: &Vector2, b: &Vector2) -> Basis2 { Rotation2::from_angle( acos(a.dot(b)) ) } - + #[inline] fn rotate_vector(&self, vec: &Vector2) -> Vector2 { self.mat.mul_v(vec) } @@ -218,16 +235,20 @@ pub struct Basis3 { impl> Basis3 { + /// Create a new rotation matrix from a quaternion. #[inline] pub fn from_quaternion(quaternion: &Quaternion) -> Basis3 { Basis3 { mat: quaternion.to_matrix3() } } - + + /// Coerce to a `Matrix3` #[inline] pub fn as_matrix3<'a>(&'a self) -> &'a Matrix3 { &'a self.mat } } +/// Represents types which can be converted to a rotation matrix. pub trait ToBasis3 { + /// Convert this type to a rotation matrix. fn to_rot3(&self) -> Basis3; } @@ -262,7 +283,7 @@ Rotation, Point3> for Basis3 { let q: Quaternion = Rotation::between_vectors(a, b); q.to_rot3() } - + #[inline] fn rotate_vector(&self, vec: &Vector3) -> Vector3 { self.mat.mul_v(vec) } From bf2cdfade3793a87272200bc7a0b1689f84fabda Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 04:17:26 -0700 Subject: [PATCH 10/12] Document Transform --- src/cgmath/transform.rs | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/cgmath/transform.rs b/src/cgmath/transform.rs index 57e3bbe..e7df504 100644 --- a/src/cgmath/transform.rs +++ b/src/cgmath/transform.rs @@ -26,7 +26,9 @@ use quaternion::Quaternion; use vector::{Vector, Vector3}; use partial_ord::{PartOrdPrim, PartOrdFloat}; -/// A trait of affine transformation, that can be applied to points or vectors +/// A trait representing an [affine +/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that +/// can be applied to points or vectors. An affine transformation is one which pub trait Transform < S: PartOrdPrim, @@ -35,36 +37,50 @@ pub trait Transform P: Point > { + /// Create an identity transformation. That is, a transformation which + /// does nothing. fn identity() -> Self; + + /// Create a transformation that rotates a vector to look at `center` from + /// `eye`, using `up` for orientation. fn look_at(eye: &P, center: &P, up: &V) -> Self; + /// Transform a vector using this transform. fn transform_vector(&self, vec: &V) -> V; + + /// Transform a point using this transform. fn transform_point(&self, point: &P) -> P; + /// Transform a ray using this transform. #[inline] fn transform_ray(&self, ray: &Ray) -> Ray { Ray::new( self.transform_point(&ray.origin), self.transform_vector(&ray.direction) ) } + /// Transform a vector as a point using this transform. #[inline] - fn transform_as_point(&self, vec: &V)-> V { + fn transform_as_point(&self, vec: &V) -> V { self.transform_point( &Point::from_vec(vec) ).to_vec() } + /// Combine this transform with another, yielding a new transformation + /// which has the effects of both. fn concat(&self, other: &Self) -> Self; + + /// Create a transform that "un-does" this one. fn invert(&self) -> Option; + /// Combine this transform with another, in-place. #[inline] fn concat_self(&mut self, other: &Self) { *self = self.concat(other); } + /// Invert this transform in-place, failing if the transformation is not + /// invertible. #[inline] - fn invert_self(&mut self)-> bool { - match self.invert() { - Some(t) => {*self = t; true}, - None => false, - } + fn invert_self(&mut self) { + *self = self.invert().unwrap() } } @@ -183,7 +199,7 @@ Transform, Point3> for AffineMatrix3 { fn look_at(eye: &Point3, center: &Point3, up: &Vector3) -> AffineMatrix3 { AffineMatrix3 { mat: Matrix4::look_at(eye, center, up) } } - + #[inline] fn transform_vector(&self, vec: &Vector3) -> Vector3 { self.mat.mul_v( &vec.extend(num::zero()) ).truncate() @@ -202,7 +218,7 @@ Transform, Point3> for AffineMatrix3 { #[inline] fn invert(&self) -> Option> { self.mat.invert().map(|m| AffineMatrix3{ mat: m }) - } + } } impl From 322a5d0c3873bb21b67dcc7dc3da8152193dfeeb Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 13:52:01 -0700 Subject: [PATCH 11/12] AABB docs --- src/cgmath/aabb.rs | 28 ++++++++++++++++++++++++---- src/cgmath/lib.rs | 4 ++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/cgmath/aabb.rs b/src/cgmath/aabb.rs index abb46ed..fb2b063 100644 --- a/src/cgmath/aabb.rs +++ b/src/cgmath/aabb.rs @@ -14,6 +14,11 @@ // limitations under the License. //! Axis-aligned bounding boxes +//! +//! An AABB is a geometric object which encompasses a set of points and is not +//! rotated. It is either a rectangle or a rectangular prism (depending on the +//! dimension) where the slope of every line is either 0 or undefined. These +//! are useful for very cheap collision detection. use point::{Point, Point2, Point3}; use vector::{Vector, Vector2, Vector3}; @@ -30,39 +35,52 @@ pub trait Aabb P: Point, Slice > { + /// Create a new AABB using two points as opposing corners. fn new(p1: P, p2: P) -> Self; + + /// Return a shared reference to the point nearest to (-inf, -inf). fn min<'a>(&'a self) -> &'a P; + + /// Return a shared reference to the point nearest to (inf, inf). fn max<'a>(&'a self) -> &'a P; + + /// Return the dimensions of this AABB. #[inline] fn dim(&self) -> V { self.max().sub_p(self.min()) } + + /// Return the volume this AABB encloses. #[inline] fn volume(&self) -> S { self.dim().comp_mul() } + + /// Return the center point of this AABB. #[inline] fn center(&self) -> P { let two = one::() + one::(); self.min().add_v(&self.dim().div_s(two)) } - // Tests whether a point is cointained in the box, inclusive for min corner - // and exclusive for the max corner. + /// Tests whether a point is cointained in the box, inclusive for min corner + /// and exclusive for the max corner. #[inline] fn contains(&self, p: &P) -> bool { p.sub_p(self.min()).iter().all(|x| *x >= zero::()) && self.max().sub_p(p).iter().all(|x| *x > zero::()) } - // Returns a new AABB that is grown to include the given point. + /// Returns a new AABB that is grown to include the given point. fn grow(&self, p: &P) -> Self { let min : P = build(|i| self.min().i(i).min(*p.i(i))); let max : P = build(|i| self.max().i(i).max(*p.i(i))); Aabb::new(min, max) } - // Returns a new AABB that has its points translated by the given vector. + /// Add a vector to every point in the AABB, returning a new AABB. fn add_v(&self, v: &V) -> Self { Aabb::new(self.min().add_v(v), self.max().add_v(v)) } + /// Multiply every point in the AABB by a scalar, returning a new AABB. fn mul_s(&self, s: S) -> Self { Aabb::new(self.min().mul_s(s.clone()), self.max().mul_s(s.clone())) } + /// Multiply every point in the AABB by a vector, returning a new AABB. fn mul_v(&self, v: &V) -> Self { let min : P = Point::from_vec(&self.min().to_vec().mul_v(v)); let max : P = Point::from_vec(&self.max().to_vec().mul_v(v)); @@ -70,6 +88,7 @@ pub trait Aabb } } +/// A two-dimensional AABB, aka a rectangle. #[deriving(Clone, Eq)] pub struct Aabb2 { pub min: Point2, @@ -101,6 +120,7 @@ impl fmt::Show for Aabb2 { } } +/// A three-dimensional AABB, aka a rectangular prism. #[deriving(Clone, Eq)] pub struct Aabb3 { pub min: Point3, diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index fe816a4..98d85ac 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -23,6 +23,10 @@ #![feature(macro_rules)] //! Computer graphics-centric math. +//! +//! This crate provides useful mathematical primitives and operations on them. +//! It is organized into one module per primitive. + pub use array::Array; mod array; From ad970b94ec9fdcc373aa6ddd70404442c33a1d32 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Sun, 25 May 2014 14:35:46 -0700 Subject: [PATCH 12/12] Expand crate documentation --- src/cgmath/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index 98d85ac..e0a18a0 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -25,7 +25,16 @@ //! Computer graphics-centric math. //! //! This crate provides useful mathematical primitives and operations on them. -//! It is organized into one module per primitive. +//! It is organized into one module per primitive. The core structures are +//! vectors and matrices. A strongly-typed interface is provided, to prevent +//! mixing units or violating mathematical invariants. +//! +//! Transformations are not usually done directly on matrices, but go through +//! transformation objects that can be converted to matrices. Rotations go +//! through the `Basis` types, which are guaranteed to be orthogonal matrices. +//! Despite this, one can directly create a limited rotation matrix using the +//! `look_at`, `from_angle`, `from_euler`, and `from_axis_angle` methods. +//! These are provided for convenience. pub use array::Array;