Merge pull request #71 from cmr/master

Lots of docs.
This commit is contained in:
Corey Richardson 2014-05-25 14:58:57 -07:00
commit c54dc4fd61
16 changed files with 352 additions and 103 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@
/bench/
/test/
/doc/
*.swp

View file

@ -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<S, V, Slice>,
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::<S>() + one::<S>();
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::<S>()) &&
self.max().sub_p(p).iter().all(|x| *x > zero::<S>())
}
// 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<S> {
pub min: Point2<S>,
@ -101,6 +120,7 @@ impl<S: fmt::Show> fmt::Show for Aabb2<S> {
}
}
/// A three-dimensional AABB, aka a rectangular prism.
#[deriving(Clone, Eq)]
pub struct Aabb3<S> {
pub min: Point3<S>,

View file

@ -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<S> { pub s: S }
/// An angle, in degrees
#[deriving(Clone, Eq, Ord, Hash)] pub struct Deg<S> { pub s: S }
/// Create a new angle, in radians
#[inline] pub fn rad<S: Float>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: Float>(s: S) -> Deg<S> { Deg { s: s } }
pub trait ToRad<S: Float> { fn to_rad(&self) -> Rad<S>; }
pub trait ToDeg<S: Float> { fn to_deg(&self) -> Deg<S>; }
/// Represents types that can be converted to radians.
pub trait ToRad<S: Float> {
/// Convert this value to radians.
fn to_rad(&self) -> Rad<S>;
}
/// Represents types that can be converted to degrees.
pub trait ToDeg<S: Float> {
/// Convert this value to degrees.
fn to_deg(&self) -> Deg<S>;
}
impl<S: Float> ToRad<S> for Rad<S> { #[inline] fn to_rad(&self) -> Rad<S> { self.clone() } }
impl<S: Float> ToRad<S> for Deg<S> { #[inline] fn to_rad(&self) -> Rad<S> { rad(self.s.to_radians()) } }
@ -54,6 +67,7 @@ impl<S: Float> ScalarConv<S> for Deg<S> {
#[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<S>
+ ScalarConv<S>
{
/// Create a new angle from any other valid angle.
fn from<A: Angle<S>>(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)`.

View file

@ -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<T: Clone, Repr> {
/// 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]

View file

@ -22,7 +22,24 @@
#![feature(globs)]
#![feature(macro_rules)]
pub mod array;
//! Computer graphics-centric math.
//!
//! This crate provides useful mathematical primitives and operations on them.
//! 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;
mod array;
pub mod matrix;
pub mod quaternion;
pub mod vector;

View file

@ -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<P>
{

View file

@ -41,6 +41,7 @@ pub struct Matrix4<S> { pub x: Vector4<S>, pub y: Vector4<S>, pub z: Vector4<S>,
impl<S: Primitive> Matrix2<S> {
/// Create a new matrix, providing values for each index.
#[inline]
pub fn new(c0r0: S, c0r1: S,
c1r0: S, c1r1: S) -> Matrix2<S> {
@ -48,22 +49,27 @@ impl<S: Primitive> Matrix2<S> {
Vector2::new(c1r0, c1r1))
}
/// Create a new matrix, providing columns.
#[inline]
pub fn from_cols(c0: Vector2<S>, c1: Vector2<S>) -> Matrix2<S> {
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<S> {
Matrix2::new(value.clone(), zero(),
zero(), value.clone())
}
/// Create a zero matrix (all zeros).
#[inline]
pub fn zero() -> Matrix2<S> {
Matrix2::from_value(zero())
}
/// Create an identity matrix (diagonal matrix of ones).
#[inline]
pub fn identity() -> Matrix2<S> {
Matrix2::from_value(one())
@ -71,6 +77,8 @@ impl<S: Primitive> Matrix2<S> {
}
impl<S: PartOrdFloat<S>> Matrix2<S> {
/// Create a transformation matrix that will cause a vector to point at
/// `dir`, using `up` for orientation.
pub fn look_at(dir: &Vector2<S>, up: &Vector2<S>) -> Matrix2<S> {
//TODO: verify look_at 2D
Matrix2::from_cols(up.clone(), dir.clone()).transpose()
@ -87,6 +95,7 @@ impl<S: PartOrdFloat<S>> Matrix2<S> {
}
impl<S: Primitive> Matrix3<S> {
/// 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<S: Primitive> Matrix3<S> {
Vector3::new(c2r0, c2r1, c2r2))
}
/// Create a new matrix, providing columns.
#[inline]
pub fn from_cols(c0: Vector3<S>, c1: Vector3<S>, c2: Vector3<S>) -> Matrix3<S> {
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<S> {
Matrix3::new(value.clone(), zero(), zero(),
@ -108,11 +120,13 @@ impl<S: Primitive> Matrix3<S> {
zero(), zero(), value.clone())
}
/// Create a zero matrix (all zeros).
#[inline]
pub fn zero() -> Matrix3<S> {
Matrix3::from_value(zero())
}
/// Create an identity matrix (diagonal matrix of ones).
#[inline]
pub fn identity() -> Matrix3<S> {
Matrix3::from_value(one())
@ -121,6 +135,8 @@ impl<S: Primitive> Matrix3<S> {
impl<S: PartOrdFloat<S>>
Matrix3<S> {
/// Create a transformation matrix that will cause a vector to point at
/// `dir`, using `up` for orientation.
pub fn look_at(dir: &Vector3<S>, up: &Vector3<S>) -> Matrix3<S> {
let dir = dir.normalize();
let side = up.cross(&dir).normalize();
@ -194,6 +210,7 @@ Matrix3<S> {
}
impl<S: Primitive> Matrix4<S> {
/// 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<S: Primitive> Matrix4<S> {
Vector4::new(c3r0, c3r1, c3r2, c3r3))
}
/// Create a new matrix, providing columns.
#[inline]
pub fn from_cols(c0: Vector4<S>, c1: Vector4<S>, c2: Vector4<S>, c3: Vector4<S>) -> Matrix4<S> {
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<S> {
Matrix4::new(value.clone(), zero(), zero(), zero(),
@ -218,11 +238,13 @@ impl<S: Primitive> Matrix4<S> {
zero(), zero(), zero(), value.clone())
}
/// Create a zero matrix (all zeros).
#[inline]
pub fn zero() -> Matrix4<S> {
Matrix4::from_value(zero())
}
/// Create an identity matrix (diagonal matrix of ones).
#[inline]
pub fn identity() -> Matrix4<S> {
Matrix4::from_value(one())
@ -231,6 +253,8 @@ impl<S: Primitive> Matrix4<S> {
impl<S: PartOrdFloat<S>>
Matrix4<S> {
/// Create a transformation matrix that will cause a vector to point at
/// `dir`, using `up` for orientation.
pub fn look_at(eye: &Point3<S>, center: &Point3<S>, up: &Vector3<S>) -> Matrix4<S> {
let f = center.sub_p(eye).normalize();
let s = f.cross(up).normalize();
@ -257,12 +281,15 @@ pub trait Matrix
+ Zero + One
+ ApproxEq<S>
{
/// 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<Self>;
/// 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<S>
}
// Conversion traits
pub trait ToMatrix2<S: Primitive> { fn to_matrix2(&self) -> Matrix2<S>; }
pub trait ToMatrix3<S: Primitive> { fn to_matrix3(&self) -> Matrix3<S>; }
pub trait ToMatrix4<S: Primitive> { fn to_matrix4(&self) -> Matrix4<S>; }
/// Represents types which can be converted to a Matrix2
pub trait ToMatrix2<S: Primitive> {
/// Convert this value to a Matrix2
fn to_matrix2(&self) -> Matrix2<S>;
}
/// Represents types which can be converted to a Matrix3
pub trait ToMatrix3<S: Primitive> {
/// Convert this value to a Matrix3
fn to_matrix3(&self) -> Matrix3<S>;
}
/// Represents types which can be converted to a Matrix4
pub trait ToMatrix4<S: Primitive> {
/// Convert this value to a Matrix4
fn to_matrix4(&self) -> Matrix4<S>;
}
impl<S: PartOrdFloat<S>>
ToMatrix3<S> for Matrix2<S> {
/// 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<S> {
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<S> for Matrix2<S> {
impl<S: PartOrdFloat<S>>
ToMatrix4<S> for Matrix2<S> {
/// 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<S> {
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<S> for Matrix2<S> {
impl<S: PartOrdFloat<S>>
ToMatrix4<S> for Matrix3<S> {
/// 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<S> {
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(),

View file

@ -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;

View file

@ -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<S> {
@ -49,7 +49,9 @@ pub struct Plane<S> {
impl<S: PartOrdFloat<S>>
Plane<S> {
/// 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<S>, d: S) -> Plane<S> {
Plane { n: n, d: d }
}

View file

@ -69,25 +69,37 @@ pub trait Point
>
: Array<S, Slice>
{
/// Create a point at the origin.
#[inline] fn origin() -> Self{ build(|_i| zero::<S>()) }
/// 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::<S, Slice, V>(|i| self.i(i).mul(v.i(i))).comp_add()

View file

@ -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<S> { pub s: S, pub v: Vector3<S> }
array!(impl<S> Quaternion<S> -> [S, ..4] _4)
/// Represents types which can be expressed as a quaternion.
pub trait ToQuaternion<S: Float> {
/// Convert this value to a quaternion.
fn to_quaternion(&self) -> Quaternion<S>;
}
@ -93,7 +96,7 @@ Quaternion<S> {
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<S>) -> Quaternion<S> {
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<S> {
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<S>) {
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<S>) {
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<S>) {
*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>) -> 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<S> {
Quaternion::from_sv(self.s.clone(), -self.v.clone())
@ -158,17 +166,13 @@ Quaternion<S> {
self.magnitude2().sqrt()
}
/// The normalized quaternion
/// Normalize this quaternion, returning the new quaternion.
#[inline]
pub fn normalize(&self) -> Quaternion<S> {
self.mul_s(one::<S>() / 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<S>, amount: S) -> Quaternion<S> {
self.mul_s(one::<S>() - amount).add_q(&other.mul_s(amount)).normalize()
}
@ -178,18 +182,15 @@ impl<S: PartOrdFloat<S>>
Quaternion<S> {
/// 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/)

View file

@ -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<P,V>
{

View file

@ -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<S>
{
/// 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<P,V>) -> Ray<P,V> {
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<S>
+ ToBasis2<S>
{
// 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<S>) -> Self;
}
/// A three-dimensional rotation
/// A three-dimensional rotation.
pub trait Rotation3
<
S: Primitive
@ -97,7 +109,7 @@ pub trait Rotation3
+ ToBasis3<S>
+ ToQuaternion<S>
{
/// Create a rotation around a given axis.
/// Create a rotation using an angle around a given axis.
fn from_axis_angle(axis: &Vector3<S>, angle: Rad<S>) -> 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<S>, y: Rad<S>, z: Rad<S>) -> 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<S>) -> 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<S>) -> 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<S>) -> Self {
Rotation3::from_axis_angle( &Vector3::unit_z(), theta )
@ -139,11 +153,14 @@ pub struct Basis2<S> {
}
impl<S: Float> Basis2<S> {
/// Coerce to a `Matrix2`
#[inline]
pub fn as_matrix2<'a>(&'a self) -> &'a Matrix2<S> { &'a self.mat }
}
/// Represents types which can be converted to a rotation matrix.
pub trait ToBasis2<S: Float> {
/// Convert this type to a rotation matrix.
fn to_rot2(&self) -> Basis2<S>;
}
@ -171,7 +188,7 @@ Rotation<S, [S, ..2], Vector2<S>, Point2<S>> for Basis2<S> {
fn between_vectors(a: &Vector2<S>, b: &Vector2<S>) -> Basis2<S> {
Rotation2::from_angle( acos(a.dot(b)) )
}
#[inline]
fn rotate_vector(&self, vec: &Vector2<S>) -> Vector2<S> { self.mat.mul_v(vec) }
@ -218,16 +235,20 @@ pub struct Basis3<S> {
impl<S: PartOrdFloat<S>>
Basis3<S> {
/// Create a new rotation matrix from a quaternion.
#[inline]
pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
Basis3 { mat: quaternion.to_matrix3() }
}
/// Coerce to a `Matrix3`
#[inline]
pub fn as_matrix3<'a>(&'a self) -> &'a Matrix3<S> { &'a self.mat }
}
/// Represents types which can be converted to a rotation matrix.
pub trait ToBasis3<S: Float> {
/// Convert this type to a rotation matrix.
fn to_rot3(&self) -> Basis3<S>;
}
@ -262,7 +283,7 @@ Rotation<S, [S, ..3], Vector3<S>, Point3<S>> for Basis3<S> {
let q: Quaternion<S> = Rotation::between_vectors(a, b);
q.to_rot3()
}
#[inline]
fn rotate_vector(&self, vec: &Vector3<S>) -> Vector3<S> { self.mat.mul_v(vec) }

View file

@ -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<S,V,Slice>
>
{
/// 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<P,V>) -> Ray<P,V> {
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<Self>;
/// 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<S, [S, ..3], Vector3<S>, Point3<S>> for AffineMatrix3<S> {
fn look_at(eye: &Point3<S>, center: &Point3<S>, up: &Vector3<S>) -> AffineMatrix3<S> {
AffineMatrix3 { mat: Matrix4::look_at(eye, center, up) }
}
#[inline]
fn transform_vector(&self, vec: &Vector3<S>) -> Vector3<S> {
self.mat.mul_v( &vec.extend(num::zero()) ).truncate()
@ -202,7 +218,7 @@ Transform<S, [S, ..3], Vector3<S>, Point3<S>> for AffineMatrix3<S> {
#[inline]
fn invert(&self) -> Option<AffineMatrix3<S>> {
self.mat.invert().map(|m| AffineMatrix3{ mat: m })
}
}
}
impl<S: PartOrdPrim>

View file

@ -33,30 +33,51 @@ pub trait Vector
+ Neg<Self>
+ 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<S: PartOrdPrim, Slice, V: Vector<S, Slice>>(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<S> { $(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<S> Vector4<S> -> [S, ..4] _4)
/// Operations specific to numeric two-dimensional vectors.
impl<S: Primitive> Vector2<S> {
/// A unit vector in the `x` direction.
#[inline] pub fn unit_x() -> Vector2<S> { Vector2::new(one(), zero()) }
/// A unit vector in the `y` direction.
#[inline] pub fn unit_y() -> Vector2<S> { Vector2::new(zero(), one()) }
/// The perpendicular dot product of the vector and `other`.
@ -152,6 +177,8 @@ impl<S: Primitive> Vector2<S> {
(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<S> {
Vector3::new(self.x.clone(), self.y.clone(), z)
@ -160,8 +187,11 @@ impl<S: Primitive> Vector2<S> {
/// Operations specific to numeric three-dimensional vectors.
impl<S: Primitive> Vector3<S> {
/// A unit vector in the `x` direction.
#[inline] pub fn unit_x() -> Vector3<S> { Vector3::new(one(), zero(), zero()) }
/// A unit vector in the `y` direction.
#[inline] pub fn unit_y() -> Vector3<S> { Vector3::new(zero(), one(), zero()) }
/// A unit vector in the `w` direction.
#[inline] pub fn unit_z() -> Vector3<S> { Vector3::new(zero(), zero(), one()) }
/// Returns the cross product of the vector and `other`.
@ -179,27 +209,35 @@ impl<S: Primitive> Vector3<S> {
*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<S> {
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<S> {
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<S: Primitive> Vector4<S> {
/// A unit vector in the `x` direction.
#[inline] pub fn unit_x() -> Vector4<S> { Vector4::new(one(), zero(), zero(), zero()) }
/// A unit vector in the `y` direction.
#[inline] pub fn unit_y() -> Vector4<S> { Vector4::new(zero(), one(), zero(), zero()) }
/// A unit vector in the `z` direction.
#[inline] pub fn unit_z() -> Vector4<S> { Vector4::new(zero(), zero(), one(), zero()) }
/// A unit vector in the `w` direction.
#[inline] pub fn unit_w() -> Vector4<S> { Vector4::new(zero(), zero(), zero(), one()) }
/// Create a `Vector3`, dropping the `w` value.
#[inline]
pub fn truncate(&self)-> Vector3<S> {
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<S, Slice>
+ ApproxEq<S>
{
/// 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<S>;
/// Returns a vector with the same direction, but with a `length` (or

View file

@ -301,19 +301,16 @@ fn test_predicates() {
assert!(Matrix2::<f64>::identity().is_identity());
assert!(Matrix2::<f64>::identity().is_symmetric());
assert!(Matrix2::<f64>::identity().is_diagonal());
assert!(!Matrix2::<f64>::identity().is_rotated());
assert!(Matrix2::<f64>::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::<f64>::identity().is_identity());
assert!(Matrix3::<f64>::identity().is_symmetric());
assert!(Matrix3::<f64>::identity().is_diagonal());
assert!(!Matrix3::<f64>::identity().is_rotated());
assert!(Matrix3::<f64>::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::<f64>::identity().is_identity());
assert!(Matrix4::<f64>::identity().is_symmetric());
assert!(Matrix4::<f64>::identity().is_diagonal());
assert!(!Matrix4::<f64>::identity().is_rotated());
assert!(Matrix4::<f64>::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());