From 3559ab2e352d104150aa9466aac865e5a41a3998 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 27 May 2014 18:59:03 -0700 Subject: [PATCH] Simplify type signatures and make function implementations more strait-forward This results in more code duplication, but the resulting type signatures are much simpler and the implementations are far easier to understand. It should be easier for llvm to optimise things too, seeing as closures are not used. --- src/cgmath/aabb.rs | 67 ++-- src/cgmath/approx.rs | 38 +-- src/cgmath/array.rs | 170 ++++------ src/cgmath/frustum.rs | 3 +- src/cgmath/lib.rs | 4 - src/cgmath/line.rs | 12 +- src/cgmath/matrix.rs | 659 +++++++++++++++++++++++++++++---------- src/cgmath/point.rs | 296 ++++++++++++++++-- src/cgmath/ptr.rs | 38 --- src/cgmath/quaternion.rs | 69 ++-- src/cgmath/ray.rs | 2 +- src/cgmath/rotation.rs | 46 +-- src/cgmath/transform.rs | 28 +- src/cgmath/vector.rs | 187 +++++++---- 14 files changed, 1057 insertions(+), 562 deletions(-) delete mode 100644 src/cgmath/ptr.rs diff --git a/src/cgmath/aabb.rs b/src/cgmath/aabb.rs index 68bd905..60a555c 100644 --- a/src/cgmath/aabb.rs +++ b/src/cgmath/aabb.rs @@ -22,19 +22,11 @@ use point::{Point, Point2, Point3}; use vector::{Vector, Vector2, Vector3}; -use array::build; use num::BaseNum; use std::fmt; use std::num::{zero, one}; -use std::iter::Iterator; -pub trait Aabb -< - S: BaseNum, - V: Vector, - P: Point, - Slice -> { +pub trait Aabb, P: Point> { /// Create a new AABB using two points as opposing corners. fn new(p1: P, p2: P) -> Self; @@ -45,28 +37,29 @@ pub trait Aabb fn max<'a>(&'a self) -> &'a P; /// Return the dimensions of this AABB. - #[inline] fn dim(&self) -> V { self.max().sub_p(self.min()) } + #[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() } + #[inline] + fn volume(&self) -> S { self.dim().comp_mul() } /// Return the center point of this AABB. - #[inline] fn center(&self) -> P { + #[inline] + fn center(&self) -> P { let two = one::() + one::(); self.min().add_v(&self.dim().div_s(two)) } /// Tests whether a point is cointained in the box, inclusive for min corner /// and exclusive for the max corner. - #[inline] fn contains(&self, p: &P) -> bool { - p.sub_p(self.min()).iter().all(|x| *x >= zero::()) && - self.max().sub_p(p).iter().all(|x| *x > zero::()) - } + #[inline] + fn contains(&self, p: &P) -> bool; /// 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).partial_min(*p.i(i))); - let max : P = build(|i| self.max().i(i).partial_max(*p.i(i))); + let min = self.min().min(p); + let max = self.max().max(p); Aabb::new(min, max) } @@ -108,10 +101,23 @@ impl Aabb2 { } } -impl Aabb, Point2, [S, ..2]> for Aabb2 { +impl Aabb, Point2> for Aabb2 { + #[inline] fn new(p1: Point2, p2: Point2) -> Aabb2 { Aabb2::new(p1, p2) } - #[inline] fn min<'a>(&'a self) -> &'a Point2 { &self.min } - #[inline] fn max<'a>(&'a self) -> &'a Point2 { &self.max } + + #[inline] + fn min<'a>(&'a self) -> &'a Point2 { &self.min } + + #[inline] + fn max<'a>(&'a self) -> &'a Point2 { &self.max } + + #[inline] + fn contains(&self, p: &Point2) -> bool { + let v_min = p.sub_p(self.min()); + let v_max = self.max().sub_p(p); + v_min.x >= zero() && v_min.y >= zero() && + v_max.x > zero() && v_max.y > zero() + } } impl fmt::Show for Aabb2 { @@ -142,10 +148,23 @@ impl Aabb3 { } } -impl Aabb, Point3, [S, ..3]> for Aabb3 { +impl Aabb, Point3> for Aabb3 { + #[inline] fn new(p1: Point3, p2: Point3) -> Aabb3 { Aabb3::new(p1, p2) } - #[inline] fn min<'a>(&'a self) -> &'a Point3 { &self.min } - #[inline] fn max<'a>(&'a self) -> &'a Point3 { &self.max } + + #[inline] + fn min<'a>(&'a self) -> &'a Point3 { &self.min } + + #[inline] + fn max<'a>(&'a self) -> &'a Point3 { &self.max } + + #[inline] + fn contains(&self, p: &Point3) -> bool { + let v_min = p.sub_p(self.min()); + let v_max = self.max().sub_p(p); + v_min.x >= zero() && v_min.y >= zero() && v_min.z >= zero() && + v_max.x > zero() && v_max.y > zero() && v_max.z > zero() + } } impl fmt::Show for Aabb3 { diff --git a/src/cgmath/approx.rs b/src/cgmath/approx.rs index 3827c80..dced6dd 100644 --- a/src/cgmath/approx.rs +++ b/src/cgmath/approx.rs @@ -15,12 +15,6 @@ use std::num; -use array::Array; -use matrix::{Matrix2, Matrix3, Matrix4}; -use point::{Point2, Point3}; -use quaternion::Quaternion; -use vector::{Vector2, Vector3, Vector4}; - pub trait ApproxEq { fn approx_epsilon(_hack: Option) -> T { num::cast(1.0e-5).unwrap() @@ -35,7 +29,7 @@ pub trait ApproxEq { } -macro_rules! approx_simple( +macro_rules! approx_float( ($S:ident) => ( impl ApproxEq<$S> for $S { #[inline] @@ -46,31 +40,5 @@ macro_rules! approx_simple( ) ) -approx_simple!(f32) -approx_simple!(f64) - - -macro_rules! approx_array( - (impl<$S:ident> $Self:ty) => ( - impl<$S: Float + Clone + ApproxEq<$S>> ApproxEq<$S> for $Self { - #[inline] - fn approx_eq_eps(&self, other: &$Self, epsilon: &$S) -> bool { - self.iter().zip(other.iter()) - .all(|(a, b)| a.approx_eq_eps(b, epsilon)) - } - } - ) -) - -approx_array!(impl Matrix2) -approx_array!(impl Matrix3) -approx_array!(impl Matrix4) - -approx_array!(impl Quaternion) - -approx_array!(impl Vector2) -approx_array!(impl Vector3) -approx_array!(impl Vector4) - -approx_array!(impl Point2) -approx_array!(impl Point3) +approx_float!(f32) +approx_float!(f64) diff --git a/src/cgmath/array.rs b/src/cgmath/array.rs index 4f0417d..ea1a2d2 100644 --- a/src/cgmath/array.rs +++ b/src/cgmath/array.rs @@ -13,138 +13,84 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![macro_escape] +use std::mem; +use std::ptr; -use std::slice::{Items, MutItems}; +/// An array containing elements of type `Element` +pub trait Array1 { + /// Get the pointer to the first element of the array. + fn ptr<'a>(&'a self) -> &'a Element; + + /// Get a mutable pointer to the first element of the array. + fn mut_ptr<'a>(&'a mut self) -> &'a mut Element; -/// An array containing elements of type `T` represented with `Repr` -/// -/// This trait abstracts over [T, ..N], and is manually implemented for arrays -/// of length 2, 3, and 4. -pub trait Array { /// Get a shared reference to the `i`th value. - fn i<'a>(&'a self, i: uint) -> &'a T; + fn i(&self, i: uint) -> Element; /// Get a mutable reference to the `i`th value. - fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut T; - - /// 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>; + fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut Element; #[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; + fn swap_i(&mut self, a: uint, b: uint) { + // Yeah, ok borrow checker – I know what I'm doing here + unsafe { ptr::swap(self.mut_i(a), self.mut_i(b)) }; } - /// 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|); + /// Replace an element in the array. + #[inline] + fn replace_i(&mut self, i: uint, src: Element) -> Element { + mem::replace(self.mut_i(i), src) + } } -macro_rules! array( - (impl<$S:ident> $Self:ty -> [$T:ty, ..$n:expr] $_n:ident) => ( - impl<$S: Clone> Array<$T, [$T,..$n]> for $Self { - #[inline] - fn i<'a>(&'a self, i: uint) -> &'a $T { - &'a self.as_slice()[i] - } +/// A column-major array +pub trait Array2, Row: Array1, Element: Copy> { + /// Get the pointer to the first element of the array. + fn ptr<'a>(&'a self) -> &'a Element; - #[inline] - fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut $T { - &'a mut self.as_mut_slice()[i] - } + /// Get a mutable pointer to the first element of the array. + fn mut_ptr<'a>(&'a mut self) -> &'a mut Element; - #[inline] - fn as_slice<'a>(&'a self) -> &'a [$T,..$n] { - unsafe { ::std::mem::transmute(self) } - } + /// Get a shared reference to a column of this array. + fn c<'a>(&'a self, c: uint) -> &'a Column; - #[inline] - fn as_mut_slice<'a>(&'a mut self) -> &'a mut [$T,..$n] { - unsafe { ::std::mem::transmute(self) } - } + /// Get a mutable reference to a column of this array. + fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut Column; - #[inline] - fn from_repr(slice: [$T,..$n]) -> $Self { - unsafe { ::std::mem::transmute(slice) } - } + /// Swap two columns of this array. + #[inline] + fn swap_c(&mut self, a: uint, b: uint) { + unsafe { ptr::swap(self.mut_c(a), self.mut_c(b)) }; + } - #[inline] - fn build(builder: |i: uint| -> $T) -> $Self { - Array::from_repr(gen_builder!($_n)) - } + /// Replace a column in the array. + #[inline] + fn replace_c(&mut self, c: uint, src: Column) -> Column { + mem::replace(self.mut_c(c), src) + } - #[inline] - fn iter<'a>(&'a self) -> ::std::slice::Items<'a, $T> { - self.as_slice().iter() - } + /// Get a row from this array by-value. + fn r(&self, r: uint) -> Row; - #[inline] - fn mut_iter<'a>(&'a mut self) -> ::std::slice::MutItems<'a, $T> { - self.as_mut_slice().mut_iter() - } + /// Swap two rows of this array. + fn swap_r(&mut self, a: uint, b: uint); - #[inline] - fn fold(&self, f: |&$T, &$T| -> $T) -> $T { - gen_fold!($_n) - } + /// Return a shared reference to the element at column `c` and row `r`. + #[inline] + fn cr(&self, c: uint, r: uint) -> Element { self.c(c).i(r) } - #[inline] - fn each_mut(&mut self, f: |i: uint, x: &mut $T|) { - gen_each_mut!($_n) - } - } - ) -) + /// 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 Element { + self.mut_c(c).mut_i(r) + } -#[inline] -pub fn build>(builder: |i: uint| -> T) -> A { - Array::build(builder) + /// Swap the values at index `a` and `b` + #[inline] + fn swap_cr(&mut self, a: (uint, uint), b: (uint, uint)) { + let (ac, ar) = a; + let (bc, br) = b; + unsafe { ptr::swap(self.mut_cr(ac, ar), self.mut_cr(bc, br)) }; + } } - -macro_rules! gen_builder( - (_2) => ({ [builder(0), builder(1)] }); - (_3) => ({ [builder(0), builder(1), builder(2)] }); - (_4) => ({ [builder(0), builder(1), builder(2), builder(3)] }); -) - -macro_rules! gen_fold( - (_2) => ({ f(self.i(0), self.i(1)) }); - (_3) => ({ let tmp = f(self.i(0), self.i(1)); f(&tmp, self.i(2)) }); - (_4) => ({ let tmp1 = f(self.i(0), self.i(1)); let tmp2 = f(&tmp1, self.i(2)); f(&tmp2, self.i(3)) }); -) - -macro_rules! gen_each_mut( - (_2) => ({ f(0, self.mut_i(0)); f(1, self.mut_i(1)); }); - (_3) => ({ f(0, self.mut_i(0)); f(1, self.mut_i(1)); f(2, self.mut_i(2)); }); - (_4) => ({ f(0, self.mut_i(0)); f(1, self.mut_i(1)); f(2, self.mut_i(2)); f(3, self.mut_i(3)); }); -) - diff --git a/src/cgmath/frustum.rs b/src/cgmath/frustum.rs index a14f99b..2456c0c 100644 --- a/src/cgmath/frustum.rs +++ b/src/cgmath/frustum.rs @@ -15,7 +15,8 @@ //! View frustum for visibility determination -use matrix::{Matrix, Matrix4}; +use array::Array2; +use matrix::Matrix4; use num::BaseFloat; use plane::Plane; use point::Point3; diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index 00a222b..308c920 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -36,8 +36,6 @@ //! `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; @@ -63,5 +61,3 @@ pub mod sphere; pub mod approx; pub mod num; -pub mod ptr; - diff --git a/src/cgmath/line.rs b/src/cgmath/line.rs index 72771f5..de4a365 100644 --- a/src/cgmath/line.rs +++ b/src/cgmath/line.rs @@ -24,20 +24,12 @@ use intersect::Intersect; /// A generic directed line segment from `origin` to `dest`. #[deriving(Clone, Eq)] -pub struct Line

-{ +pub struct Line

{ pub origin: P, pub dest: P, } -impl -< - S: BaseNum, - Slice, - V: Vector, - P: Point -> Line

-{ +impl, P: Point> Line

{ pub fn new(origin: P, dest: P) -> Line

{ Line { origin:origin, dest:dest } } diff --git a/src/cgmath/matrix.rs b/src/cgmath/matrix.rs index e5620ed..7fa08e3 100644 --- a/src/cgmath/matrix.rs +++ b/src/cgmath/matrix.rs @@ -16,11 +16,12 @@ //! Column major, square matrix types and traits. use std::fmt; +use std::mem; use std::num::{Zero, zero, One, one, cast}; use angle::{Rad, sin, cos, sin_cos}; use approx::ApproxEq; -use array::{Array, build}; +use array::{Array1, Array2}; use num::{BaseFloat, BaseNum}; use point::{Point, Point3}; use quaternion::{Quaternion, ToQuaternion}; @@ -267,107 +268,47 @@ Matrix4 { } } -array!(impl Matrix2 -> [Vector2, ..2] _2) -array!(impl Matrix3 -> [Vector3, ..3] _3) -array!(impl Matrix4 -> [Vector4, ..4] _4) - -pub trait Matrix -< - S: BaseFloat, Slice, - V: Clone + Vector + Array, VSlice -> -: Array -+ Neg -+ Zero + One -+ ApproxEq -{ - /// Get a shared reference to a column of this matrix. - #[inline] - fn c<'a>(&'a self, c: uint) -> &'a V { self.i(c) } - - /// Get a mutable reference to a column of this matrix. - #[inline] - fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut V { self.mut_i(c) } - - /// Swap two columns of this matrix. - #[inline] - fn swap_c(&mut self, a: uint, b: uint) { - let tmp = self.c(a).clone(); - *self.mut_c(a) = self.c(b).clone(); - *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; - let (cb, rb) = b; - 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()) } - +pub trait Matrix>: Array2 + + Neg + + Zero + One + + ApproxEq { /// 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())) } + fn mul_s(&self, s: S) -> Self; /// 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())) } + fn div_s(&self, s: S) -> Self; /// 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())) } + fn rem_s(&self, s: S) -> Self; /// 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))) } + fn add_m(&self, m: &Self) -> Self; /// 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))) } + fn sub_m(&self, m: &Self) -> Self; /// 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)) } + fn mul_v(&self, v: &V) -> V; /// Multiply this matrix by another matrix, returning the new matrix. - fn mul_m(&self, other: &Self) -> Self; + fn mul_m(&self, m: &Self) -> Self; + + /// Negate this matrix in-place (multiply by scalar -1). + fn neg_self(&mut 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())) } + fn mul_self_s(&mut self, s: S); /// 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())) } + fn div_self_s(&mut self, s: S); /// 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())) } + fn rem_self_s(&mut self, s: S); /// 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))) } + fn add_self_m(&mut self, m: &Self); /// 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))) } + fn sub_self_m(&mut self, m: &Self); /// Multiply this matrix by another matrix, in-place. - #[inline] fn mul_self_m(&mut self, other: &Self) { *self = self.mul_m(other); } + #[inline] + fn mul_self_m(&mut self, m: &Self) { *self = self.mul_m(m); } /// Transpose this matrix, returning a new matrix. fn transpose(&self) -> Self; @@ -377,8 +318,7 @@ pub trait 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()) } + fn diagonal(&self) -> V; /// Return the trace of this matrix. That is, the sum of the diagonal. #[inline] @@ -397,16 +337,12 @@ pub trait Matrix /// Test if this matrix is invertible. #[inline] - fn is_invertible(&self) -> bool { - !self.determinant().approx_eq(&zero()) - } + 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()) - } + fn is_identity(&self) -> bool { self.approx_eq(&one()) } /// Test if this is a diagonal matrix. That is, every element outside of /// the diagonal is 0. @@ -425,9 +361,9 @@ impl Sub, Matrix2> for Matrix2 { #[inline] fn sub impl Sub, Matrix3> for Matrix3 { #[inline] fn sub(&self, other: &Matrix3) -> Matrix3 { self.sub_m(other) } } impl Sub, Matrix4> for Matrix4 { #[inline] fn sub(&self, other: &Matrix4) -> Matrix4 { self.sub_m(other) } } -impl Neg> for Matrix2 { #[inline] fn neg(&self) -> Matrix2 { build(|i| self.i(i).neg()) } } -impl Neg> for Matrix3 { #[inline] fn neg(&self) -> Matrix3 { build(|i| self.i(i).neg()) } } -impl Neg> for Matrix4 { #[inline] fn neg(&self) -> Matrix4 { build(|i| self.i(i).neg()) } } +impl Neg> for Matrix2 { #[inline] fn neg(&self) -> Matrix2 { Matrix2::from_cols(self.c(0).neg(), self.c(1).neg()) } } +impl Neg> for Matrix3 { #[inline] fn neg(&self) -> Matrix3 { Matrix3::from_cols(self.c(0).neg(), self.c(1).neg(), self.c(2).neg()) } } +impl Neg> for Matrix4 { #[inline] fn neg(&self) -> Matrix4 { Matrix4::from_cols(self.c(0).neg(), self.c(1).neg(), self.c(2).neg(), self.c(3).neg()) } } impl Zero for Matrix2 { #[inline] fn zero() -> Matrix2 { Matrix2::zero() } #[inline] fn is_zero(&self) -> bool { *self == zero() } } impl Zero for Matrix3 { #[inline] fn zero() -> Matrix3 { Matrix3::zero() } #[inline] fn is_zero(&self) -> bool { *self == zero() } } @@ -441,15 +377,186 @@ impl One for Matrix2 { #[inline] fn one() -> Matrix2 { Matri impl One for Matrix3 { #[inline] fn one() -> Matrix3 { Matrix3::identity() } } impl One for Matrix4 { #[inline] fn one() -> Matrix4 { Matrix4::identity() } } -impl -Matrix, ..2], Vector2, [S, ..2]> -for Matrix2 -{ +impl Array2, Vector2, S> for Matrix2 { + #[inline] + fn ptr<'a>(&'a self) -> &'a S { &self.x.x } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.x.x } + + #[inline] + fn c<'a>(&'a self, c: uint) -> &'a Vector2 { + let slice: &'a [Vector2, ..2] = unsafe { mem::transmute(self) }; + &'a slice[c] + } + + #[inline] + fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut Vector2 { + let slice: &'a mut [Vector2, ..2] = unsafe { mem::transmute(self) }; + &'a mut slice[c] + } + + #[inline] + fn r(&self, r: uint) -> Vector2 { + Vector2::new(self.cr(0, r), + self.cr(1, r)) + } + + #[inline] + fn swap_r(&mut self, a: uint, b: uint) { + self.mut_c(0).swap_i(a, b); + self.mut_c(1).swap_i(a, b); + } +} + +impl Array2, Vector3, S> for Matrix3 { + #[inline] + fn ptr<'a>(&'a self) -> &'a S { &self.x.x } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.x.x } + + #[inline] + fn c<'a>(&'a self, c: uint) -> &'a Vector3 { + let slice: &'a [Vector3, ..3] = unsafe { mem::transmute(self) }; + &'a slice[c] + } + + #[inline] + fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut Vector3 { + let slice: &'a mut [Vector3, ..3] = unsafe { mem::transmute(self) }; + &'a mut slice[c] + } + + #[inline] + fn r(&self, r: uint) -> Vector3 { + Vector3::new(self.cr(0, r), + self.cr(1, r), + self.cr(2, r)) + } + + #[inline] + fn swap_r(&mut self, a: uint, b: uint) { + self.mut_c(0).swap_i(a, b); + self.mut_c(1).swap_i(a, b); + self.mut_c(2).swap_i(a, b); + } +} + +impl Array2, Vector4, S> for Matrix4 { + #[inline] + fn ptr<'a>(&'a self) -> &'a S { &self.x.x } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.x.x } + + #[inline] + fn c<'a>(&'a self, c: uint) -> &'a Vector4 { + let slice: &'a [Vector4, ..4] = unsafe { mem::transmute(self) }; + &'a slice[c] + } + + #[inline] + fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut Vector4 { + let slice: &'a mut [Vector4, ..4] = unsafe { mem::transmute(self) }; + &'a mut slice[c] + } + + #[inline] + fn r(&self, r: uint) -> Vector4 { + Vector4::new(self.cr(0, r), + self.cr(1, r), + self.cr(2, r), + self.cr(3, r)) + } + + #[inline] + fn swap_r(&mut self, a: uint, b: uint) { + self.mut_c(0).swap_i(a, b); + self.mut_c(1).swap_i(a, b); + self.mut_c(2).swap_i(a, b); + self.mut_c(3).swap_i(a, b); + } +} + +impl Matrix> for Matrix2 { + #[inline] + fn mul_s(&self, s: S) -> Matrix2 { + Matrix2::from_cols(self.c(0).mul_s(s), + self.c(1).mul_s(s)) + } + + #[inline] + fn div_s(&self, s: S) -> Matrix2 { + Matrix2::from_cols(self.c(0).div_s(s), + self.c(1).div_s(s)) + } + + #[inline] + fn rem_s(&self, s: S) -> Matrix2 { + Matrix2::from_cols(self.c(0).rem_s(s), + self.c(1).rem_s(s)) + } + + #[inline] + fn add_m(&self, m: &Matrix2) -> Matrix2 { + Matrix2::from_cols(self.c(0).add_v(m.c(0)), + self.c(1).add_v(m.c(1))) + } + + #[inline] + fn sub_m(&self, m: &Matrix2) -> Matrix2 { + Matrix2::from_cols(self.c(0).sub_v(m.c(0)), + self.c(1).sub_v(m.c(1))) + } + + #[inline] + fn mul_v(&self, v: &Vector2) -> Vector2 { + Vector2::new(self.r(0).dot(v), + self.r(1).dot(v)) + } + fn mul_m(&self, other: &Matrix2) -> Matrix2 { Matrix2::new(self.r(0).dot(other.c(0)), self.r(1).dot(other.c(0)), self.r(0).dot(other.c(1)), self.r(1).dot(other.c(1))) } + #[inline] + fn neg_self(&mut self) { + self.mut_c(0).neg_self(); + self.mut_c(1).neg_self(); + } + + #[inline] + fn mul_self_s(&mut self, s: S) { + self.mut_c(0).mul_self_s(s); + self.mut_c(1).mul_self_s(s); + } + + #[inline] + fn div_self_s(&mut self, s: S) { + self.mut_c(0).div_self_s(s); + self.mut_c(1).div_self_s(s); + } + + #[inline] + fn rem_self_s(&mut self, s: S) { + self.mut_c(0).rem_self_s(s); + self.mut_c(1).rem_self_s(s); + } + + #[inline] + fn add_self_m(&mut self, m: &Matrix2) { + self.mut_c(0).add_self_v(m.c(0)); + self.mut_c(1).add_self_v(m.c(1)); + } + + #[inline] + fn sub_self_m(&mut self, m: &Matrix2) { + self.mut_c(0).sub_self_v(m.c(0)); + self.mut_c(1).sub_self_v(m.c(1)); + } + fn transpose(&self) -> Matrix2 { Matrix2::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(0, 1).clone(), self.cr(1, 1).clone()) @@ -462,7 +569,13 @@ for Matrix2 #[inline] fn determinant(&self) -> S { - *self.cr(0, 0) * *self.cr(1, 1) - *self.cr(1, 0) * *self.cr(0, 1) + self.cr(0, 0) * self.cr(1, 1) - self.cr(1, 0) * self.cr(0, 1) + } + + #[inline] + fn diagonal(&self) -> Vector2 { + Vector2::new(self.cr(0, 0), + self.cr(1, 1)) } #[inline] @@ -471,8 +584,8 @@ for Matrix2 if det.approx_eq(&zero()) { None } else { - Some(Matrix2::new( *self.cr(1, 1) / det, -*self.cr(0, 1) / det, - -*self.cr(1, 0) / det, *self.cr(0, 0) / det)) + Some(Matrix2::new( self.cr(1, 1) / det, -self.cr(0, 1) / det, + -self.cr(1, 0) / det, self.cr(0, 0) / det)) } } @@ -485,21 +598,102 @@ for Matrix2 #[inline] fn is_symmetric(&self) -> bool { - self.cr(0, 1).approx_eq(self.cr(1, 0)) && - self.cr(1, 0).approx_eq(self.cr(0, 1)) + self.cr(0, 1).approx_eq(&self.cr(1, 0)) && + self.cr(1, 0).approx_eq(&self.cr(0, 1)) } } -impl -Matrix, ..3], Vector3, [S, ..3]> -for Matrix3 -{ +impl Matrix> for Matrix3 { + #[inline] + fn mul_s(&self, s: S) -> Matrix3 { + Matrix3::from_cols(self.c(0).mul_s(s), + self.c(1).mul_s(s), + self.c(2).mul_s(s)) + } + + #[inline] + fn div_s(&self, s: S) -> Matrix3 { + Matrix3::from_cols(self.c(0).div_s(s), + self.c(1).div_s(s), + self.c(2).div_s(s)) + } + + #[inline] + fn rem_s(&self, s: S) -> Matrix3 { + Matrix3::from_cols(self.c(0).rem_s(s), + self.c(1).rem_s(s), + self.c(2).rem_s(s)) + } + + #[inline] + fn add_m(&self, m: &Matrix3) -> Matrix3 { + Matrix3::from_cols(self.c(0).add_v(m.c(0)), + self.c(1).add_v(m.c(1)), + self.c(2).add_v(m.c(2))) + } + + #[inline] + fn sub_m(&self, m: &Matrix3) -> Matrix3 { + Matrix3::from_cols(self.c(0).sub_v(m.c(0)), + self.c(1).sub_v(m.c(1)), + self.c(2).sub_v(m.c(2))) + } + + #[inline] + fn mul_v(&self, v: &Vector3) -> Vector3 { + Vector3::new(self.r(0).dot(v), + self.r(1).dot(v), + self.r(2).dot(v)) + } + fn mul_m(&self, other: &Matrix3) -> Matrix3 { Matrix3::new(self.r(0).dot(other.c(0)),self.r(1).dot(other.c(0)),self.r(2).dot(other.c(0)), self.r(0).dot(other.c(1)),self.r(1).dot(other.c(1)),self.r(2).dot(other.c(1)), self.r(0).dot(other.c(2)),self.r(1).dot(other.c(2)),self.r(2).dot(other.c(2))) } + #[inline] + fn neg_self(&mut self) { + self.mut_c(0).neg_self(); + self.mut_c(1).neg_self(); + self.mut_c(2).neg_self(); + } + + #[inline] + fn mul_self_s(&mut self, s: S) { + self.mut_c(0).mul_self_s(s); + self.mut_c(1).mul_self_s(s); + self.mut_c(2).mul_self_s(s); + } + + #[inline] + fn div_self_s(&mut self, s: S) { + self.mut_c(0).div_self_s(s); + self.mut_c(1).div_self_s(s); + self.mut_c(2).div_self_s(s); + } + + #[inline] + fn rem_self_s(&mut self, s: S) { + self.mut_c(0).rem_self_s(s); + self.mut_c(1).rem_self_s(s); + self.mut_c(2).rem_self_s(s); + } + + #[inline] + fn add_self_m(&mut self, m: &Matrix3) { + self.mut_c(0).add_self_v(m.c(0)); + self.mut_c(1).add_self_v(m.c(1)); + self.mut_c(2).add_self_v(m.c(2)); + } + + #[inline] + fn sub_self_m(&mut self, m: &Matrix3) { + self.mut_c(0).sub_self_v(m.c(0)); + self.mut_c(1).sub_self_v(m.c(1)); + self.mut_c(2).sub_self_v(m.c(2)); + } + fn transpose(&self) -> Matrix3 { Matrix3::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(2, 0).clone(), self.cr(0, 1).clone(), self.cr(1, 1).clone(), self.cr(2, 1).clone(), @@ -514,9 +708,16 @@ for Matrix3 } fn determinant(&self) -> S { - *self.cr(0, 0) * (*self.cr(1, 1) * *self.cr(2, 2) - *self.cr(2, 1) * *self.cr(1, 2)) - - *self.cr(1, 0) * (*self.cr(0, 1) * *self.cr(2, 2) - *self.cr(2, 1) * *self.cr(0, 2)) + - *self.cr(2, 0) * (*self.cr(0, 1) * *self.cr(1, 2) - *self.cr(1, 1) * *self.cr(0, 2)) + self.cr(0, 0) * (self.cr(1, 1) * self.cr(2, 2) - self.cr(2, 1) * self.cr(1, 2)) - + self.cr(1, 0) * (self.cr(0, 1) * self.cr(2, 2) - self.cr(2, 1) * self.cr(0, 2)) + + self.cr(2, 0) * (self.cr(0, 1) * self.cr(1, 2) - self.cr(1, 1) * self.cr(0, 2)) + } + + #[inline] + fn diagonal(&self) -> Vector3 { + Vector3::new(self.cr(0, 0), + self.cr(1, 1), + self.cr(2, 2)) } fn invert(&self) -> Option> { @@ -540,14 +741,14 @@ for Matrix3 } fn is_symmetric(&self) -> bool { - self.cr(0, 1).approx_eq(self.cr(1, 0)) && - self.cr(0, 2).approx_eq(self.cr(2, 0)) && + self.cr(0, 1).approx_eq(&self.cr(1, 0)) && + self.cr(0, 2).approx_eq(&self.cr(2, 0)) && - self.cr(1, 0).approx_eq(self.cr(0, 1)) && - self.cr(1, 2).approx_eq(self.cr(2, 1)) && + self.cr(1, 0).approx_eq(&self.cr(0, 1)) && + self.cr(1, 2).approx_eq(&self.cr(2, 1)) && - self.cr(2, 0).approx_eq(self.cr(0, 2)) && - self.cr(2, 1).approx_eq(self.cr(1, 2)) + self.cr(2, 0).approx_eq(&self.cr(0, 2)) && + self.cr(2, 1).approx_eq(&self.cr(1, 2)) } } @@ -557,16 +758,61 @@ for Matrix3 // around ~4 times. macro_rules! dot_matrix4( ($A:expr, $B:expr, $I:expr, $J:expr) => ( - (*$A.cr(0, $I)) * (*$B.cr($J, 0)) + - (*$A.cr(1, $I)) * (*$B.cr($J, 1)) + - (*$A.cr(2, $I)) * (*$B.cr($J, 2)) + - (*$A.cr(3, $I)) * (*$B.cr($J, 3)) + ($A.cr(0, $I)) * ($B.cr($J, 0)) + + ($A.cr(1, $I)) * ($B.cr($J, 1)) + + ($A.cr(2, $I)) * ($B.cr($J, 2)) + + ($A.cr(3, $I)) * ($B.cr($J, 3)) )) -impl -Matrix, ..4], Vector4, [S, ..4]> -for Matrix4 -{ +impl Matrix> for Matrix4 { + #[inline] + fn mul_s(&self, s: S) -> Matrix4 { + Matrix4::from_cols(self.c(0).mul_s(s), + self.c(1).mul_s(s), + self.c(2).mul_s(s), + self.c(3).mul_s(s)) + } + + #[inline] + fn div_s(&self, s: S) -> Matrix4 { + Matrix4::from_cols(self.c(0).div_s(s), + self.c(1).div_s(s), + self.c(2).div_s(s), + self.c(3).div_s(s)) + } + + #[inline] + fn rem_s(&self, s: S) -> Matrix4 { + Matrix4::from_cols(self.c(0).rem_s(s), + self.c(1).rem_s(s), + self.c(2).rem_s(s), + self.c(3).rem_s(s)) + } + + #[inline] + fn add_m(&self, m: &Matrix4) -> Matrix4 { + Matrix4::from_cols(self.c(0).add_v(m.c(0)), + self.c(1).add_v(m.c(1)), + self.c(2).add_v(m.c(2)), + self.c(3).add_v(m.c(3))) + } + + #[inline] + fn sub_m(&self, m: &Matrix4) -> Matrix4 { + Matrix4::from_cols(self.c(0).sub_v(m.c(0)), + self.c(1).sub_v(m.c(1)), + self.c(2).sub_v(m.c(2)), + self.c(3).sub_v(m.c(3))) + } + + #[inline] + fn mul_v(&self, v: &Vector4) -> Vector4 { + Vector4::new(self.r(0).dot(v), + self.r(1).dot(v), + self.r(2).dot(v), + self.r(3).dot(v)) + } + fn mul_m(&self, other: &Matrix4) -> Matrix4 { Matrix4::new(dot_matrix4!(self, other, 0, 0), dot_matrix4!(self, other, 1, 0), dot_matrix4!(self, other, 2, 0), dot_matrix4!(self, other, 3, 0), dot_matrix4!(self, other, 0, 1), dot_matrix4!(self, other, 1, 1), dot_matrix4!(self, other, 2, 1), dot_matrix4!(self, other, 3, 1), @@ -574,6 +820,54 @@ for Matrix4 dot_matrix4!(self, other, 0, 3), dot_matrix4!(self, other, 1, 3), dot_matrix4!(self, other, 2, 3), dot_matrix4!(self, other, 3, 3)) } + #[inline] + fn neg_self(&mut self) { + self.mut_c(0).neg_self(); + self.mut_c(1).neg_self(); + self.mut_c(2).neg_self(); + self.mut_c(3).neg_self(); + } + + #[inline] + fn mul_self_s(&mut self, s: S) { + self.mut_c(0).mul_self_s(s); + self.mut_c(1).mul_self_s(s); + self.mut_c(2).mul_self_s(s); + self.mut_c(3).mul_self_s(s); + } + + #[inline] + fn div_self_s(&mut self, s: S) { + self.mut_c(0).div_self_s(s); + self.mut_c(1).div_self_s(s); + self.mut_c(2).div_self_s(s); + self.mut_c(3).div_self_s(s); + } + + #[inline] + fn rem_self_s(&mut self, s: S) { + self.mut_c(0).rem_self_s(s); + self.mut_c(1).rem_self_s(s); + self.mut_c(2).rem_self_s(s); + self.mut_c(3).rem_self_s(s); + } + + #[inline] + fn add_self_m(&mut self, m: &Matrix4) { + self.mut_c(0).add_self_v(m.c(0)); + self.mut_c(1).add_self_v(m.c(1)); + self.mut_c(2).add_self_v(m.c(2)); + self.mut_c(3).add_self_v(m.c(3)); + } + + #[inline] + fn sub_self_m(&mut self, m: &Matrix4) { + self.mut_c(0).sub_self_v(m.c(0)); + self.mut_c(1).sub_self_v(m.c(1)); + self.mut_c(2).sub_self_v(m.c(2)); + self.mut_c(3).sub_self_v(m.c(3)); + } + fn transpose(&self) -> Matrix4 { Matrix4::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(2, 0).clone(), self.cr(3, 0).clone(), self.cr(0, 1).clone(), self.cr(1, 1).clone(), self.cr(2, 1).clone(), self.cr(3, 1).clone(), @@ -604,10 +898,18 @@ for Matrix4 self.cr(0, 2).clone(), self.cr(1, 2).clone(), self.cr(2, 2).clone(), self.cr(0, 3).clone(), self.cr(1, 3).clone(), self.cr(2, 3).clone()); - *self.cr(0, 0) * m0.determinant() - - *self.cr(1, 0) * m1.determinant() + - *self.cr(2, 0) * m2.determinant() - - *self.cr(3, 0) * m3.determinant() + self.cr(0, 0) * m0.determinant() - + self.cr(1, 0) * m1.determinant() + + self.cr(2, 0) * m2.determinant() - + self.cr(3, 0) * m3.determinant() + } + + #[inline] + fn diagonal(&self) -> Vector4 { + Vector4::new(self.cr(0, 0), + self.cr(1, 1), + self.cr(2, 2), + self.cr(3, 3)) } fn invert(&self) -> Option> { @@ -673,21 +975,48 @@ for Matrix4 } fn is_symmetric(&self) -> bool { - self.cr(0, 1).approx_eq(self.cr(1, 0)) && - self.cr(0, 2).approx_eq(self.cr(2, 0)) && - self.cr(0, 3).approx_eq(self.cr(3, 0)) && + self.cr(0, 1).approx_eq(&self.cr(1, 0)) && + self.cr(0, 2).approx_eq(&self.cr(2, 0)) && + self.cr(0, 3).approx_eq(&self.cr(3, 0)) && - self.cr(1, 0).approx_eq(self.cr(0, 1)) && - self.cr(1, 2).approx_eq(self.cr(2, 1)) && - self.cr(1, 3).approx_eq(self.cr(3, 1)) && + self.cr(1, 0).approx_eq(&self.cr(0, 1)) && + self.cr(1, 2).approx_eq(&self.cr(2, 1)) && + self.cr(1, 3).approx_eq(&self.cr(3, 1)) && - self.cr(2, 0).approx_eq(self.cr(0, 2)) && - self.cr(2, 1).approx_eq(self.cr(1, 2)) && - self.cr(2, 3).approx_eq(self.cr(3, 2)) && + self.cr(2, 0).approx_eq(&self.cr(0, 2)) && + self.cr(2, 1).approx_eq(&self.cr(1, 2)) && + self.cr(2, 3).approx_eq(&self.cr(3, 2)) && - self.cr(3, 0).approx_eq(self.cr(0, 3)) && - self.cr(3, 1).approx_eq(self.cr(1, 3)) && - self.cr(3, 2).approx_eq(self.cr(2, 3)) + self.cr(3, 0).approx_eq(&self.cr(0, 3)) && + self.cr(3, 1).approx_eq(&self.cr(1, 3)) && + self.cr(3, 2).approx_eq(&self.cr(2, 3)) + } +} + +impl ApproxEq for Matrix2 { + #[inline] + fn approx_eq_eps(&self, other: &Matrix2, epsilon: &S) -> bool { + self.c(0).approx_eq_eps(other.c(0), epsilon) && + self.c(1).approx_eq_eps(other.c(1), epsilon) + } +} + +impl ApproxEq for Matrix3 { + #[inline] + fn approx_eq_eps(&self, other: &Matrix3, epsilon: &S) -> bool { + self.c(0).approx_eq_eps(other.c(0), epsilon) && + self.c(1).approx_eq_eps(other.c(1), epsilon) && + self.c(2).approx_eq_eps(other.c(2), epsilon) + } +} + +impl ApproxEq for Matrix4 { + #[inline] + fn approx_eq_eps(&self, other: &Matrix4, epsilon: &S) -> bool { + self.c(0).approx_eq_eps(other.c(0), epsilon) && + self.c(1).approx_eq_eps(other.c(1), epsilon) && + self.c(2).approx_eq_eps(other.c(2), epsilon) && + self.c(3).approx_eq_eps(other.c(3), epsilon) } } @@ -711,8 +1040,7 @@ pub trait ToMatrix4 { fn to_matrix4(&self) -> Matrix4; } -impl -ToMatrix3 for Matrix2 { +impl ToMatrix3 for Matrix2 { /// Clone the elements of a 2-dimensional matrix into the top-left corner /// of a 3-dimensional identity matrix. fn to_matrix3(&self) -> Matrix3 { @@ -722,8 +1050,7 @@ ToMatrix3 for Matrix2 { } } -impl -ToMatrix4 for Matrix2 { +impl ToMatrix4 for Matrix2 { /// Clone the elements of a 2-dimensional matrix into the top-left corner /// of a 4-dimensional identity matrix. fn to_matrix4(&self) -> Matrix4 { @@ -734,8 +1061,7 @@ ToMatrix4 for Matrix2 { } } -impl -ToMatrix4 for Matrix3 { +impl ToMatrix4 for Matrix3 { /// Clone the elements of a 3-dimensional matrix into the top-left corner /// of a 4-dimensional identity matrix. fn to_matrix4(&self) -> Matrix4 { @@ -746,8 +1072,7 @@ ToMatrix4 for Matrix3 { } } -impl -ToQuaternion for Matrix3 { +impl ToQuaternion for Matrix3 { /// Convert the matrix to a quaternion fn to_quaternion(&self) -> Quaternion { // http://www.cs.ucr.edu/~vbz/resources/quatut.pdf @@ -758,43 +1083,43 @@ ToQuaternion for Matrix3 { let s = (one::() + trace).sqrt(); let w = half * s; let s = half / s; - let x = (*self.cr(1, 2) - *self.cr(2, 1)) * s; - let y = (*self.cr(2, 0) - *self.cr(0, 2)) * s; - let z = (*self.cr(0, 1) - *self.cr(1, 0)) * s; + let x = (self.cr(1, 2) - self.cr(2, 1)) * s; + let y = (self.cr(2, 0) - self.cr(0, 2)) * s; + let z = (self.cr(0, 1) - self.cr(1, 0)) * s; Quaternion::new(w, x, y, z) } - () if (*self.cr(0, 0) > *self.cr(1, 1)) && (*self.cr(0, 0) > *self.cr(2, 2)) => { - let s = (half + (*self.cr(0, 0) - *self.cr(1, 1) - *self.cr(2, 2))).sqrt(); + () if (self.cr(0, 0) > self.cr(1, 1)) && (self.cr(0, 0) > self.cr(2, 2)) => { + let s = (half + (self.cr(0, 0) - self.cr(1, 1) - self.cr(2, 2))).sqrt(); let w = half * s; let s = half / s; - let x = (*self.cr(0, 1) - *self.cr(1, 0)) * s; - let y = (*self.cr(2, 0) - *self.cr(0, 2)) * s; - let z = (*self.cr(1, 2) - *self.cr(2, 1)) * s; + let x = (self.cr(0, 1) - self.cr(1, 0)) * s; + let y = (self.cr(2, 0) - self.cr(0, 2)) * s; + let z = (self.cr(1, 2) - self.cr(2, 1)) * s; Quaternion::new(w, x, y, z) } - () if *self.cr(1, 1) > *self.cr(2, 2) => { - let s = (half + (*self.cr(1, 1) - *self.cr(0, 0) - *self.cr(2, 2))).sqrt(); + () if self.cr(1, 1) > self.cr(2, 2) => { + let s = (half + (self.cr(1, 1) - self.cr(0, 0) - self.cr(2, 2))).sqrt(); let w = half * s; let s = half / s; - let x = (*self.cr(0, 1) - *self.cr(1, 0)) * s; - let y = (*self.cr(1, 2) - *self.cr(2, 1)) * s; - let z = (*self.cr(2, 0) - *self.cr(0, 2)) * s; + let x = (self.cr(0, 1) - self.cr(1, 0)) * s; + let y = (self.cr(1, 2) - self.cr(2, 1)) * s; + let z = (self.cr(2, 0) - self.cr(0, 2)) * s; Quaternion::new(w, x, y, z) } () => { - let s = (half + (*self.cr(2, 2) - *self.cr(0, 0) - *self.cr(1, 1))).sqrt(); + let s = (half + (self.cr(2, 2) - self.cr(0, 0) - self.cr(1, 1))).sqrt(); let w = half * s; let s = half / s; - let x = (*self.cr(2, 0) - *self.cr(0, 2)) * s; - let y = (*self.cr(1, 2) - *self.cr(2, 1)) * s; - let z = (*self.cr(0, 1) - *self.cr(1, 0)) * s; + let x = (self.cr(2, 0) - self.cr(0, 2)) * s; + let y = (self.cr(1, 2) - self.cr(2, 1)) * s; + let z = (self.cr(0, 1) - self.cr(1, 0)) * s; Quaternion::new(w, x, y, z) } } } } -impl fmt::Show for Matrix2 { +impl fmt::Show for Matrix2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[[{}, {}], [{}, {}]]", self.cr(0, 0), self.cr(0, 1), @@ -802,7 +1127,7 @@ impl fmt::Show for Matrix2 { } } -impl fmt::Show for Matrix3 { +impl fmt::Show for Matrix3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[[{}, {}, {}], [{}, {}, {}], [{}, {}, {}]]", self.cr(0, 0), self.cr(0, 1), self.cr(0, 2), @@ -811,7 +1136,7 @@ impl fmt::Show for Matrix3 { } } -impl fmt::Show for Matrix4 { +impl fmt::Show for Matrix4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[[{}, {}, {}, {}], [{}, {}, {}, {}], [{}, {}, {}, {}], [{}, {}, {}, {}]]", self.cr(0, 0), self.cr(0, 1), self.cr(0, 2), self.cr(0, 3), diff --git a/src/cgmath/point.rs b/src/cgmath/point.rs index 8769859..e0416fa 100644 --- a/src/cgmath/point.rs +++ b/src/cgmath/point.rs @@ -18,10 +18,12 @@ //! not have a fixed position. use std::fmt; +use std::mem; use std::num::{one, zero}; -use array::*; -use num::BaseNum; +use approx::ApproxEq; +use array::Array1; +use num::{BaseNum, BaseFloat}; use vector::*; /// A point in 2-dimensional space. @@ -61,56 +63,294 @@ impl Point3 { } /// Specifies the numeric operations for point types. -pub trait Point -< - S: BaseNum, - V: Vector, - Slice -> -: Array -{ +pub trait Point>: Array1 + Clone { /// Create a point at the origin. - #[inline] fn origin() -> Self{ build(|_i| zero::()) } + fn origin() -> Self; /// Create a point from a vector. - #[inline] fn from_vec(v: &V) -> Self { build(|i| v.i(i).clone()) } + fn from_vec(v: &V) -> Self; /// Convert a point to a vector. - #[inline] fn to_vec(&self) -> V { build(|i| self.i(i).clone()) } + fn to_vec(&self) -> V; /// 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)) } + fn mul_s(&self, s: S) -> Self; /// 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)) } + fn div_s(&self, s: S) -> Self; /// 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)) } + fn rem_s(&self, s: S) -> Self; /// 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))) } + fn add_v(&self, v: &V) -> Self; /// 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))) } + fn sub_p(&self, p: &Self) -> V; /// 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)) } + fn mul_self_s(&mut self, s: 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)) } + fn div_self_s(&mut self, s: 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)) } + fn rem_self_s(&mut self, s: 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))) } + fn add_self_v(&mut self, v: &V); /// This is a weird one, but its useful for plane calculations. + fn dot(&self, v: &V) -> S; + + fn min(&self, p: &Self) -> Self; + + fn max(&self, p: &Self) -> Self; +} + +impl Array1 for Point2 { #[inline] - fn dot(&self, v: &V) -> S { - build::(|i| self.i(i).mul(v.i(i))).comp_add() + fn ptr<'a>(&'a self) -> &'a S { &self.x } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.x } + + #[inline] + fn i(&self, i: uint) -> S { + let slice: &[S, ..2] = unsafe { mem::transmute(self) }; + slice[i] + } + + #[inline] + fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut S { + let slice: &'a mut [S, ..2] = unsafe { mem::transmute(self) }; + &'a mut slice[i] } } -array!(impl Point2 -> [S, ..2] _2) -array!(impl Point3 -> [S, ..3] _3) +impl Point> for Point2 { + #[inline] + fn origin() -> Point2 { + Point2::new(zero(), zero()) + } -impl Point, [S, ..2]> for Point2 {} -impl Point, [S, ..3]> for Point3 {} + #[inline] + fn from_vec(v: &Vector2) -> Point2 { + Point2::new(v.x, v.y) + } + + #[inline] + fn to_vec(&self) -> Vector2 { + Vector2::new(self.x, + self.y) + } + + #[inline] + fn mul_s(&self, s: S) -> Point2 { + Point2::new(self.x * s, + self.y * s) + } + + #[inline] + fn div_s(&self, s: S) -> Point2 { + Point2::new(self.x / s, + self.y / s) + } + + #[inline] + fn rem_s(&self, s: S) -> Point2 { + Point2::new(self.x % s, + self.y % s) + } + + #[inline] + fn add_v(&self, v: &Vector2) -> Point2 { + Point2::new(self.x + v.x, + self.y + v.y) + } + + #[inline] + fn sub_p(&self, p: &Point2) -> Vector2 { + Vector2::new(self.x - p.x, + self.y - p.y) + } + + #[inline] + fn mul_self_s(&mut self, s: S) { + self.x = self.x * s; + self.y = self.y * s; + } + + #[inline] + fn div_self_s(&mut self, s: S) { + self.x = self.x / s; + self.y = self.y / s; + } + + #[inline] + fn rem_self_s(&mut self, s: S) { + self.x = self.x % s; + self.y = self.y % s; + } + + #[inline] + fn add_self_v(&mut self, v: &Vector2) { + self.x = self.x + v.x; + self.y = self.y + v.y; + } + + #[inline] + fn dot(&self, v: &Vector2) -> S { + self.x * v.x + + self.y * v.y + } + + #[inline] + fn min(&self, p: &Point2) -> Point2 { + Point2::new(self.x.partial_min(p.x), + self.y.partial_min(p.y)) + } + + #[inline] + fn max(&self, p: &Point2) -> Point2 { + Point2::new(self.x.partial_max(p.x), + self.y.partial_max(p.y)) + } +} + +impl ApproxEq for Point2 { + #[inline] + fn approx_eq_eps(&self, other: &Point2, epsilon: &S) -> bool { + self.x.approx_eq_eps(&other.x, epsilon) && + self.y.approx_eq_eps(&other.y, epsilon) + } +} + +impl Array1 for Point3 { + #[inline] + fn ptr<'a>(&'a self) -> &'a S { &self.x } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.x } + + #[inline] + fn i(&self, i: uint) -> S { + let slice: &[S, ..3] = unsafe { mem::transmute(self) }; + slice[i] + } + + #[inline] + fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut S { + let slice: &'a mut [S, ..3] = unsafe { mem::transmute(self) }; + &'a mut slice[i] + } +} + +impl Point> for Point3 { + #[inline] + fn origin() -> Point3 { + Point3::new(zero(), zero(), zero()) + } + + #[inline] + fn from_vec(v: &Vector3) -> Point3 { + Point3::new(v.x, v.y, v.z) + } + + #[inline] + fn to_vec(&self) -> Vector3 { + Vector3::new(self.x, + self.y, + self.z) + } + + #[inline] + fn mul_s(&self, s: S) -> Point3 { + Point3::new(self.x * s, + self.y * s, + self.z * s) + } + + #[inline] + fn div_s(&self, s: S) -> Point3 { + Point3::new(self.x / s, + self.y / s, + self.z / s) + } + + #[inline] + fn rem_s(&self, s: S) -> Point3 { + Point3::new(self.x % s, + self.y % s, + self.z % s) + } + + #[inline] + fn add_v(&self, v: &Vector3) -> Point3 { + Point3::new(self.x + v.x, + self.y + v.y, + self.z + v.z) + } + + #[inline] + fn sub_p(&self, p: &Point3) -> Vector3 { + Vector3::new(self.x - p.x, + self.y - p.y, + self.z - p.z) + } + + #[inline] + fn mul_self_s(&mut self, s: S) { + self.x = self.x * s; + self.y = self.y * s; + self.z = self.z * s; + } + + #[inline] + fn div_self_s(&mut self, s: S) { + self.x = self.x / s; + self.y = self.y / s; + self.z = self.z / s; + } + + #[inline] + fn rem_self_s(&mut self, s: S) { + self.x = self.x % s; + self.y = self.y % s; + self.z = self.z % s; + } + + #[inline] + fn add_self_v(&mut self, v: &Vector3) { + self.x = self.x + v.x; + self.y = self.y + v.y; + self.z = self.z + v.z; + } + + #[inline] + fn dot(&self, v: &Vector3) -> S { + self.x * v.x + + self.y * v.y + + self.z * v.z + } + + #[inline] + fn min(&self, p: &Point3) -> Point3 { + Point3::new(self.x.partial_min(p.x), + self.y.partial_min(p.y), + self.z.partial_min(p.z)) + } + + #[inline] + fn max(&self, p: &Point3) -> Point3 { + Point3::new(self.x.partial_max(p.x), + self.y.partial_max(p.y), + self.z.partial_max(p.z)) + } +} + +impl ApproxEq for Point3 { + #[inline] + fn approx_eq_eps(&self, other: &Point3, epsilon: &S) -> bool { + self.x.approx_eq_eps(&other.x, epsilon) && + self.y.approx_eq_eps(&other.y, epsilon) && + self.z.approx_eq_eps(&other.z, epsilon) + } +} impl fmt::Show for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/cgmath/ptr.rs b/src/cgmath/ptr.rs deleted file mode 100644 index d3565e1..0000000 --- a/src/cgmath/ptr.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2013 The CGMath Developers. For a full listing of the authors, -// refer to the AUTHORS file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use array::Array; -use matrix::{Matrix2, Matrix3, Matrix4}; -use point::{Point2, Point3}; -use vector::{Vector2, Vector3, Vector4}; - -pub trait Ptr { - fn ptr<'a>(&'a self) -> &'a T; -} - -impl Ptr for Vector2 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } } -impl Ptr for Vector3 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } } -impl Ptr for Vector4 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } } - -impl Ptr for Point2 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } } -impl Ptr for Point3 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0) } } - -impl Ptr for Matrix2 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0).i(0) } } -impl Ptr for Matrix3 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0).i(0) } } -impl Ptr for Matrix4 { #[inline] fn ptr<'a>(&'a self) -> &'a S { self.i(0).i(0) } } - -impl<'a, T, P: Ptr> Ptr for &'a [P] { - #[inline] fn ptr<'a>(&'a self) -> &'a T { self[0].ptr() } -} diff --git a/src/cgmath/quaternion.rs b/src/cgmath/quaternion.rs index 9783859..2a5fd8e 100644 --- a/src/cgmath/quaternion.rs +++ b/src/cgmath/quaternion.rs @@ -14,13 +14,15 @@ // limitations under the License. use std::fmt; +use std::mem; use std::num::{zero, one, cast}; use angle::{Angle, Rad, acos, sin, sin_cos}; -use array::{Array, build}; +use approx::ApproxEq; +use array::Array1; use matrix::{Matrix3, ToMatrix3, ToMatrix4, Matrix4}; use num::BaseFloat; -use point::{Point3}; +use point::Point3; use rotation::{Rotation, Rotation3, Basis3, ToBasis3}; use vector::{Vector3, Vector, EuclideanVector}; @@ -29,14 +31,32 @@ use vector::{Vector3, Vector, EuclideanVector}; #[deriving(Clone, Eq)] pub struct Quaternion { pub s: S, pub v: Vector3 } -array!(impl Quaternion -> [S, ..4] _4) - /// Represents types which can be expressed as a quaternion. pub trait ToQuaternion { /// Convert this value to a quaternion. fn to_quaternion(&self) -> Quaternion; } +impl Array1 for Quaternion { + #[inline] + fn ptr<'a>(&'a self) -> &'a S { &self.s } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.s } + + #[inline] + fn i(&self, i: uint) -> S { + let slice: &[S, ..4] = unsafe { mem::transmute(self) }; + slice[i] + } + + #[inline] + fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut S { + let slice: &'a mut [S, ..4] = unsafe { mem::transmute(self) }; + &'a mut slice[i] + } +} + impl Quaternion { /// Construct a new quaternion from one scalar component and three /// imaginary components @@ -85,13 +105,13 @@ impl Quaternion { /// The sum of this quaternion and `other` #[inline] pub fn add_q(&self, other: &Quaternion) -> Quaternion { - build(|i| self.i(i).add(other.i(i))) + Quaternion::from_sv(self.s + other.s, self.v + other.v) } /// The difference between this quaternion and `other` #[inline] pub fn sub_q(&self, other: &Quaternion) -> Quaternion { - build(|i| self.i(i).add(other.i(i))) + Quaternion::from_sv(self.s - other.s, self.v - other.v) } /// The result of multipliplying the quaternion by `other` @@ -105,37 +125,42 @@ impl Quaternion { /// 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)) + self.s = self.s * s; + self.v.mul_self_s(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)) + self.s = self.s / s; + self.v.div_self_s(s); } /// Add this quaternion by another, in-place. #[inline] - pub fn add_self_q(&mut self, other: &Quaternion) { - self.each_mut(|i, x| *x = x.add(other.i(i))); + pub fn add_self_q(&mut self, q: &Quaternion) { + self.s = self.s + q.s; + self.v.add_self_v(&q.v); } /// Subtract another quaternion from this one, in-place. #[inline] - pub fn sub_self_q(&mut self, other: &Quaternion) { - self.each_mut(|i, x| *x = x.sub(other.i(i))); + pub fn sub_self_q(&mut self, q: &Quaternion) { + self.s = self.s - q.s; + self.v.sub_self_v(&q.v); } /// Multiply this quaternion by another, in-place. #[inline] - pub fn mul_self_q(&mut self, other: &Quaternion) { - *self = self.mul_q(other); + pub fn mul_self_q(&mut self, q: &Quaternion) { + self.s = self.s * q.s; + self.v.mul_self_v(&q.v); } - /// The dot product of the quaternion and `other`. + /// The dot product of the quaternion and `q`. #[inline] - pub fn dot(&self, other: &Quaternion) -> S { - self.s * other.s + self.v.dot(&other.v) + pub fn dot(&self, q: &Quaternion) -> S { + self.s * q.s + self.v.dot(&q.v) } /// The conjugate of the quaternion. @@ -176,6 +201,14 @@ impl Quaternion { } } +impl ApproxEq for Quaternion { + #[inline] + fn approx_eq_eps(&self, other: &Quaternion, epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, epsilon) && + self.v.approx_eq_eps(&other.v, epsilon) + } +} + impl Quaternion { /// Spherical Linear Intoperlation /// @@ -305,7 +338,7 @@ impl ToQuaternion for Quaternion { fn to_quaternion(&self) -> Quaternion { self.clone() } } -impl Rotation, Point3> for Quaternion { +impl Rotation, Point3> for Quaternion { #[inline] fn identity() -> Quaternion { Quaternion::identity() } diff --git a/src/cgmath/ray.rs b/src/cgmath/ray.rs index 9e1d028..75bdcd8 100644 --- a/src/cgmath/ray.rs +++ b/src/cgmath/ray.rs @@ -25,7 +25,7 @@ pub struct Ray { pub direction: V, } -impl, P: Point> Ray { +impl, P: Point> Ray { pub fn new(origin: P, direction: V) -> Ray { Ray { origin: origin, direction: direction } } diff --git a/src/cgmath/rotation.rs b/src/cgmath/rotation.rs index b80f0ca..9fe930e 100644 --- a/src/cgmath/rotation.rs +++ b/src/cgmath/rotation.rs @@ -15,7 +15,6 @@ use angle::{Rad, acos}; use approx::ApproxEq; -use array::Array; use matrix::Matrix; use matrix::{Matrix2, ToMatrix2}; use matrix::{Matrix3, ToMatrix3}; @@ -27,16 +26,7 @@ use vector::{Vector, Vector2, Vector3}; /// 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: BaseNum, - Slice, - V: Vector, - P: Point -> -: Eq -+ ApproxEq -{ +pub trait Rotation, P: Point>: Eq + ApproxEq { /// Create the identity transform (causes no transformation). fn identity() -> Self; @@ -59,10 +49,8 @@ pub trait Rotation /// Rotate a ray using this rotation. #[inline] - fn rotate_ray(&self, ray: &Ray) -> Ray { - Ray::new( //FIXME: use clone derived from Array - Array::build(|i| ray.origin.i(i).clone()), - self.rotate_vector(&ray.direction) ) + fn rotate_ray(&self, ray: &Ray) -> Ray { + Ray::new(ray.origin.clone(), self.rotate_vector(&ray.direction)) } /// Create a new rotation which combines both this rotation, and another. @@ -86,29 +74,19 @@ pub trait Rotation } /// A two-dimensional rotation. -pub trait Rotation2 -< - S -> -: Rotation, Point2> -+ ToMatrix2 -+ ToBasis2 -{ +pub trait Rotation2: Rotation, Point2> + + ToMatrix2 + + ToBasis2 { /// Create a rotation by a given angle. Thus is a redundant case of both /// from_axis_angle() and from_euler() for 2D space. fn from_angle(theta: Rad) -> Self; } /// A three-dimensional rotation. -pub trait Rotation3 -< - S: BaseNum -> -: Rotation, Point3> -+ ToMatrix3 -+ ToBasis3 -+ ToQuaternion -{ +pub trait Rotation3: Rotation, Point3> + + ToMatrix3 + + ToBasis3 + + ToQuaternion{ /// Create a rotation using an angle around a given axis. fn from_axis_angle(axis: &Vector3, angle: Rad) -> Self; @@ -174,7 +152,7 @@ impl ToMatrix2 for Basis2 { fn to_matrix2(&self) -> Matrix2 { self.mat.clone() } } -impl Rotation, Point2> for Basis2 { +impl Rotation, Point2> for Basis2 { #[inline] fn identity() -> Basis2 { Basis2{ mat: Matrix2::identity() } } @@ -263,7 +241,7 @@ impl ToQuaternion for Basis3 { fn to_quaternion(&self) -> Quaternion { self.mat.to_quaternion() } } -impl Rotation, Point3> for Basis3 { +impl Rotation, Point3> for Basis3 { #[inline] fn identity() -> Basis3 { Basis3{ mat: Matrix3::identity() } } diff --git a/src/cgmath/transform.rs b/src/cgmath/transform.rs index 7c91d81..fe5a543 100644 --- a/src/cgmath/transform.rs +++ b/src/cgmath/transform.rs @@ -29,14 +29,7 @@ use vector::{Vector, Vector3}; /// 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: BaseNum, - Slice, - V: Vector, - P: Point -> -{ +pub trait Transform, P: Point> { /// Create an identity transformation. That is, a transformation which /// does nothing. fn identity() -> Self; @@ -92,15 +85,7 @@ pub struct Decomposed { pub disp: V, } -impl -< - S: BaseFloat, - Slice, - V: Vector, - P: Point, - R: Rotation -> -Transform for Decomposed { +impl, P: Point, R: Rotation> Transform for Decomposed { #[inline] fn identity() -> Decomposed { Decomposed { @@ -157,10 +142,7 @@ Transform for Decomposed { } } -pub trait Transform3 -: Transform, Point3> -+ ToMatrix4 -{} +pub trait Transform3: Transform, Point3>+ ToMatrix4 {} impl> ToMatrix4 for Decomposed, R> { fn to_matrix4(&self) -> Matrix4 { @@ -185,7 +167,7 @@ pub struct AffineMatrix3 { pub mat: Matrix4, } -impl Transform, Point3> for AffineMatrix3 { +impl Transform, Point3> for AffineMatrix3 { #[inline] fn identity() -> AffineMatrix3 { AffineMatrix3 { mat: Matrix4::identity() } @@ -226,7 +208,7 @@ impl Transform3 for AffineMatrix3 {} /// A transformation in three dimensions consisting of a rotation, /// displacement vector and scale amount. -pub struct Transform3D( Decomposed,Quaternion> ); +pub struct Transform3D(Decomposed,Quaternion>); impl Transform3D { #[inline] diff --git a/src/cgmath/vector.rs b/src/cgmath/vector.rs index 14dfb7e..4193dde 100644 --- a/src/cgmath/vector.rs +++ b/src/cgmath/vector.rs @@ -14,90 +14,85 @@ // limitations under the License. use std::fmt; +use std::mem; use std::num::{Zero, zero, One, one}; use angle::{Rad, atan2, acos}; use approx::ApproxEq; -use array::{Array, build}; -use num::{BaseNum, BaseFloat, PartialOrd}; +use array::Array1; +use num::{BaseNum, BaseFloat}; /// A trait that specifies a range of numeric operations for vectors. Not all /// of these make sense from a linear algebra point of view, but are included /// for pragmatic reasons. -pub trait Vector -< - S: BaseNum, - Slice -> -: Array -+ Neg -+ Zero + One -{ +pub trait Vector: Array1 + + Neg + + Zero + + One { /// Add a scalar to this vector, returning a new vector. - #[inline] fn add_s(&self, s: S) -> Self { build(|i| self.i(i).add(&s)) } + fn add_s(&self, s: S) -> Self; /// 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)) } + fn sub_s(&self, s: S) -> Self; /// 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)) } + fn mul_s(&self, s: S) -> Self; /// 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)) } + fn div_s(&self, s: S) -> Self; /// 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)) } + fn rem_s(&self, s: S) -> Self; /// 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))) } + fn add_v(&self, v: &Self) -> Self; /// 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))) } + fn sub_v(&self, v: &Self) -> Self; /// 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))) } + fn mul_v(&self, v: &Self) -> Self; /// 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))) } + fn div_v(&self, v: &Self) -> Self; /// 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))) } + fn rem_v(&self, v: &Self) -> Self; /// Negate this vector in-place. - #[inline] fn neg_self(&mut self) { self.each_mut(|_, x| *x = x.neg()) } + fn neg_self(&mut self); /// 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)) } + fn add_self_s(&mut self, s: 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)) } + fn sub_self_s(&mut self, s: 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)) } + fn mul_self_s(&mut self, s: 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)) } + fn div_self_s(&mut self, s: 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)) } + fn rem_self_s(&mut self, s: 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))) } + fn add_self_v(&mut self, v: &Self); /// 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))) } + fn sub_self_v(&mut self, v: &Self); /// 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))) } + fn mul_self_v(&mut self, v: &Self); /// 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))) } + fn div_self_v(&mut self, v: &Self); /// 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))) } + fn rem_self_v(&mut self, v: &Self); /// The sum of each component of the vector. - #[inline] fn comp_add(&self) -> S { self.fold(|a, b| a.add(b)) } - + fn comp_add(&self) -> S; /// The product of each component of the vector. - #[inline] fn comp_mul(&self) -> S { self.fold(|a, b| a.mul(b)) } + fn comp_mul(&self) -> S; /// Vector dot product. - #[inline] fn dot(&self, other: &Self) -> S { self.mul_v(other).comp_add() } + #[inline] + fn dot(&self, v: &Self) -> S { self.mul_v(v).comp_add() } /// The minimum component of the vector. - #[inline] fn comp_min(&self) -> S { self.fold(|a, b| a.partial_min(*b)) } - + fn comp_min(&self) -> S; /// The maximum component of the vector. - #[inline] fn comp_max(&self) -> S { self.fold(|a, b| a.partial_max(*b)) } + fn comp_max(&self) -> S; } /// Dot product of two vectors. -#[inline] pub fn dot>(a: V, b: V) -> S { a.dot(&b) } +#[inline] pub fn dot>(a: V, b: V) -> S { a.dot(&b) } // Utility macro for generating associated functions for the vectors macro_rules! vec( @@ -105,19 +100,23 @@ macro_rules! vec( #[deriving(Eq, TotalEq, Clone, Hash)] pub struct $Self { $(pub $field: S),+ } - impl<$S: BaseNum> $Self<$S> { + impl<$S> $Self<$S> { /// Construct a new vector, using the provided values. #[inline] pub fn new($($field: $S),+) -> $Self<$S> { $Self { $($field: $field),+ } } + } + impl<$S: Clone> $Self<$S> { /// Construct a vector from a single value, replicating it. #[inline] pub fn from_value(value: $S) -> $Self<$S> { $Self { $($field: value.clone()),+ } } + } + impl<$S: BaseNum> $Self<$S> { /// The additive identity of the vector. #[inline] pub fn zero() -> $Self<$S> { $Self::from_value(zero()) } @@ -127,12 +126,65 @@ macro_rules! vec( pub fn ident() -> $Self<$S> { $Self::from_value(one()) } } + impl Array1 for $Self { + #[inline] + fn ptr<'a>(&'a self) -> &'a S { &self.x } + + #[inline] + fn mut_ptr<'a>(&'a mut self) -> &'a mut S { &mut self.x } + + #[inline] + fn i(&self, i: uint) -> S { + let slice: &[S, ..$n] = unsafe { mem::transmute(self) }; + slice[i] + } + + #[inline] + fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut S { + let slice: &'a mut [S, ..$n] = unsafe { mem::transmute(self) }; + &'a mut slice[i] + } + } + + impl Vector for $Self { + #[inline] fn add_s(&self, s: S) -> $Self { $Self::new($(self.$field + s),+) } + #[inline] fn sub_s(&self, s: S) -> $Self { $Self::new($(self.$field - s),+) } + #[inline] fn mul_s(&self, s: S) -> $Self { $Self::new($(self.$field * s),+) } + #[inline] fn div_s(&self, s: S) -> $Self { $Self::new($(self.$field / s),+) } + #[inline] fn rem_s(&self, s: S) -> $Self { $Self::new($(self.$field % s),+) } + + #[inline] fn add_v(&self, v: &$Self) -> $Self { $Self::new($(self.$field + v.$field),+) } + #[inline] fn sub_v(&self, v: &$Self) -> $Self { $Self::new($(self.$field - v.$field),+) } + #[inline] fn mul_v(&self, v: &$Self) -> $Self { $Self::new($(self.$field * v.$field),+) } + #[inline] fn div_v(&self, v: &$Self) -> $Self { $Self::new($(self.$field / v.$field),+) } + #[inline] fn rem_v(&self, v: &$Self) -> $Self { $Self::new($(self.$field % v.$field),+) } + + #[inline] fn neg_self(&mut self) { $(self.$field = -self.$field;)+ } + + #[inline] fn add_self_s(&mut self, s: S) { $(self.$field = self.$field + s;)+ } + #[inline] fn sub_self_s(&mut self, s: S) { $(self.$field = self.$field - s;)+ } + #[inline] fn mul_self_s(&mut self, s: S) { $(self.$field = self.$field * s;)+ } + #[inline] fn div_self_s(&mut self, s: S) { $(self.$field = self.$field / s;)+ } + #[inline] fn rem_self_s(&mut self, s: S) { $(self.$field = self.$field % s;)+ } + + #[inline] fn add_self_v(&mut self, v: &$Self) { $(self.$field = self.$field + v.$field;)+ } + #[inline] fn sub_self_v(&mut self, v: &$Self) { $(self.$field = self.$field - v.$field;)+ } + #[inline] fn mul_self_v(&mut self, v: &$Self) { $(self.$field = self.$field * v.$field;)+ } + #[inline] fn div_self_v(&mut self, v: &$Self) { $(self.$field = self.$field / v.$field;)+ } + #[inline] fn rem_self_v(&mut self, v: &$Self) { $(self.$field = self.$field % v.$field;)+ } + + #[inline] fn comp_add(&self) -> S { fold!(&add, { $(self.$field),+ }) } + #[inline] fn comp_mul(&self) -> S { fold!(&mul, { $(self.$field),+ }) } + #[inline] fn comp_min(&self) -> S { fold!(partial_min, { $(self.$field),+ }) } + #[inline] fn comp_max(&self) -> S { fold!(partial_max, { $(self.$field),+ }) } + } + impl Add<$Self, $Self> for $Self { - #[inline] fn add(&self, other: &$Self) -> $Self { self.add_v(other) } + #[inline] fn add(&self, v: &$Self) -> $Self { self.add_v(v) } } impl Sub<$Self, $Self> for $Self { - #[inline] fn sub(&self, other: &$Self) -> $Self { self.sub_v(other) } + #[inline] fn sub(&self, v: &$Self) -> $Self { self.sub_v(v) } } impl Zero for $Self { @@ -141,29 +193,39 @@ macro_rules! vec( } impl Neg<$Self> for $Self { - #[inline] fn neg(&self) -> $Self { build(|i| self.i(i).neg()) } + #[inline] fn neg(&self) -> $Self { $Self::new($(-self.$field),+) } } impl Mul<$Self, $Self> for $Self { - #[inline] fn mul(&self, other: &$Self) -> $Self { self.mul_v(other) } + #[inline] fn mul(&self, v: &$Self) -> $Self { self.mul_v(v) } } impl One for $Self { #[inline] fn one() -> $Self { $Self::from_value(one()) } } - impl Vector for $Self {} + impl ApproxEq for $Self { + #[inline] + fn approx_eq_eps(&self, other: &$Self, epsilon: &S) -> bool { + $(self.$field.approx_eq_eps(&other.$field, epsilon))&&+ + } + } ) ) +macro_rules! fold { + (&$method:ident, { $x:expr, $y:expr }) => { $x.$method(&$y) }; + (&$method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method(&$y).$method(&$z) }; + (&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method(&$y).$method(&$z).$method(&$w) }; + ($method:ident, { $x:expr, $y:expr }) => { $x.$method($y) }; + ($method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method($y).$method($z) }; + ($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method($y).$method($z).$method($w) }; +} + vec!(Vector2 { x, y }, 2) vec!(Vector3 { x, y, z }, 3) vec!(Vector4 { x, y, z, w }, 4) -array!(impl Vector2 -> [S, ..2] _2) -array!(impl Vector3 -> [S, ..3] _3) -array!(impl Vector4 -> [S, ..4] _4) - /// Operations specific to numeric two-dimensional vectors. impl Vector2 { /// A unit vector in the `x` direction. @@ -243,14 +305,8 @@ impl Vector4 { /// Specifies geometric operations for vectors. This is only implemented for /// 2-dimensional and 3-dimensional vectors. -pub trait EuclideanVector -< - S: BaseFloat, - Slice -> -: Vector -+ ApproxEq -{ +pub trait EuclideanVector: Vector + + ApproxEq { /// Returns `true` if the vector is perpendicular (at right angles) to the /// other vector. fn is_perpendicular(&self, other: &Self) -> bool { @@ -316,43 +372,40 @@ pub trait EuclideanVector } } -impl -EuclideanVector for Vector2 { +impl EuclideanVector for Vector2 { #[inline] fn angle(&self, other: &Vector2) -> Rad { atan2(self.perp_dot(other), self.dot(other)) } } -impl -EuclideanVector for Vector3 { +impl EuclideanVector for Vector3 { #[inline] fn angle(&self, other: &Vector3) -> Rad { atan2(self.cross(other).length(), self.dot(other)) } } -impl -EuclideanVector for Vector4 { +impl EuclideanVector for Vector4 { #[inline] fn angle(&self, other: &Vector4) -> Rad { acos(self.dot(other) / (self.length() * other.length())) } } -impl fmt::Show for Vector2 { +impl fmt::Show for Vector2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}, {}]", self.x, self.y) } } -impl fmt::Show for Vector3 { +impl fmt::Show for Vector3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}, {}, {}]", self.x, self.y, self.z) } } -impl fmt::Show for Vector4 { +impl fmt::Show for Vector4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w) }