commit
c54dc4fd61
16 changed files with 352 additions and 103 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
|||
/bench/
|
||||
/test/
|
||||
/doc/
|
||||
*.swp
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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)`.
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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/)
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue