Impl ApproxEq for vectors, matrices and points

This commit is contained in:
Brendan Zabarauskas 2013-09-03 23:36:03 +10:00
parent b84e154898
commit 2b8e36d4a3
4 changed files with 118 additions and 27 deletions

View file

@ -103,27 +103,26 @@ macro_rules! array(
) )
) )
macro_rules! array_op( macro_rules! approx_eq(
(impl<$S:ident> ($Op:ident, $op:ident) for ($Self:ty, $Other:ty) -> $Result:ty) => ( (impl<$S:ident> $Self:ty) => (
impl<$S: Field> $Op<$Other, $Result> for $Self { impl<$S: Clone + ApproxEq<$S>> ApproxEq<$S> for $Self {
#[inline(always)] #[inline]
fn $op(&self, other: &$Other) -> $Result { fn approx_epsilon() -> $S {
self.bimap(other, |a, b| a.$op(b)) // TODO: fix this after static methods are fixed in rustc
fail!(~"Doesn't work!");
}
#[inline]
fn approx_eq(&self, other: &$Self) -> bool {
self.iter().zip(other.iter())
.all(|(a, b)| a.approx_eq(b))
}
#[inline]
fn approx_eq_eps(&self, other: &$Self, approx_epsilon: &$S) -> bool {
self.iter().zip(other.iter())
.all(|(a, b)| a.approx_eq_eps(b, approx_epsilon))
} }
} }
); )
(impl<$S:ident> ($Op:ident, $op:ident) for $Self:ty -> $Result:ty) => (
impl<$S: Field> $Op<$Result> for $Self {
#[inline(always)]
fn $op(&self) -> $Result {
self.map(|a| a.$op())
}
}
);
(impl<$S:ident> -$Self:ty -> $Result:ty) => (array_op!(impl<$S> (Neg, neg) for $Self -> $Result));
(impl<$S:ident> $Self:ty + $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Add, add) for ($Self, $Other) -> $Result));
(impl<$S:ident> $Self:ty - $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Sub, sub) for ($Self, $Other) -> $Result));
(impl<$S:ident> $Self:ty * $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Mul, mul) for ($Self, $Other) -> $Result));
(impl<$S:ident> $Self:ty / $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Div, div) for ($Self, $Other) -> $Result));
(impl<$S:ident> $Self:ty % $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Rem, rem) for ($Self, $Other) -> $Result));
) )

View file

@ -34,6 +34,10 @@ pub struct Mat3<S> { x: Vec3<S>, y: Vec3<S>, z: Vec3<S> }
#[deriving(Clone, Eq, Zero)] #[deriving(Clone, Eq, Zero)]
pub struct Mat4<S> { x: Vec4<S>, y: Vec4<S>, z: Vec4<S>, w: Vec4<S> } pub struct Mat4<S> { x: Vec4<S>, y: Vec4<S>, z: Vec4<S>, w: Vec4<S> }
approx_eq!(impl<S> Mat2<S>)
approx_eq!(impl<S> Mat3<S>)
approx_eq!(impl<S> Mat4<S>)
// Conversion traits // Conversion traits
pub trait ToMat2<S: Clone + Num> { fn to_mat2(&self) -> Mat2<S>; } pub trait ToMat2<S: Clone + Num> { fn to_mat2(&self) -> Mat2<S>; }
pub trait ToMat3<S: Clone + Num> { fn to_mat3(&self) -> Mat3<S>; } pub trait ToMat3<S: Clone + Num> { fn to_mat3(&self) -> Mat3<S>; }
@ -175,6 +179,7 @@ pub trait Matrix
: Array<V, Slice> : Array<V, Slice>
+ Neg<Self> + Neg<Self>
+ Zero + One + Zero + One
+ ApproxEq<S>
{ {
#[inline] #[inline]
fn c<'a>(&'a self, c: uint) -> &'a V { self.i(c) } fn c<'a>(&'a self, c: uint) -> &'a V { self.i(c) }
@ -237,13 +242,21 @@ pub trait Matrix
#[inline] #[inline]
fn is_invertible(&self) -> bool { fn is_invertible(&self) -> bool {
!self.determinant().approx_eq(&zero::<S>()) !self.determinant().approx_eq(&zero())
} }
// pub fn is_identity(&self) -> bool; #[inline]
// pub fn is_diagonal(&self) -> bool; fn is_identity(&self) -> bool {
// pub fn is_rotated(&self) -> bool; self.approx_eq(&one())
// pub fn is_symmetric(&self) -> bool; }
#[inline]
fn is_rotated(&self) -> bool {
!self.approx_eq(&one())
}
fn is_diagonal(&self) -> bool;
fn is_symmetric(&self) -> bool;
} }
impl<S: Clone + Float> Neg<Mat2<S>> for Mat2<S> { #[inline] fn neg(&self) -> Mat2<S> { self.map(|c| c.neg()) } } impl<S: Clone + Float> Neg<Mat2<S>> for Mat2<S> { #[inline] fn neg(&self) -> Mat2<S> { self.map(|c| c.neg()) } }
@ -280,6 +293,7 @@ for Mat2<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 invert(&self) -> Option<Mat2<S>> { fn invert(&self) -> Option<Mat2<S>> {
let det = self.determinant(); let det = self.determinant();
if det.approx_eq(&zero()) { if det.approx_eq(&zero()) {
@ -289,6 +303,19 @@ for Mat2<S>
-self.cr(1, 0) / det, self.cr(0, 0) / det)) -self.cr(1, 0) / det, self.cr(0, 0) / det))
} }
} }
#[inline]
fn is_diagonal(&self) -> bool {
self.cr(0, 1).approx_eq(&zero()) &&
self.cr(1, 0).approx_eq(&zero())
}
#[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))
}
} }
impl<S: Clone + Float> impl<S: Clone + Float>
@ -336,6 +363,28 @@ for Mat3<S>
self.c(0).cross(self.c(1)).div_s(det.clone())).transpose()) self.c(0).cross(self.c(1)).div_s(det.clone())).transpose())
} }
} }
fn is_diagonal(&self) -> bool {
self.cr(0, 1).approx_eq(&zero()) &&
self.cr(0, 2).approx_eq(&zero()) &&
self.cr(1, 0).approx_eq(&zero()) &&
self.cr(1, 2).approx_eq(&zero()) &&
self.cr(2, 0).approx_eq(&zero()) &&
self.cr(2, 1).approx_eq(&zero())
}
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(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))
}
} }
impl<S: Clone + Float> impl<S: Clone + Float>
@ -357,7 +406,6 @@ for Mat4<S>
self.cr(0, 3).clone(), self.cr(1, 3).clone(), self.cr(2, 3).clone(), self.cr(3, 3).clone()) self.cr(0, 3).clone(), self.cr(1, 3).clone(), self.cr(2, 3).clone(), self.cr(3, 3).clone())
} }
#[inline]
fn transpose_self(&mut self) { fn transpose_self(&mut self) {
self.swap_cr((0, 1), (1, 0)); self.swap_cr((0, 1), (1, 0));
self.swap_cr((0, 2), (2, 0)); self.swap_cr((0, 2), (2, 0));
@ -435,6 +483,42 @@ for Mat4<S>
None None
} }
} }
fn is_diagonal(&self) -> bool {
self.cr(0, 1).approx_eq(&zero()) &&
self.cr(0, 2).approx_eq(&zero()) &&
self.cr(0, 3).approx_eq(&zero()) &&
self.cr(1, 0).approx_eq(&zero()) &&
self.cr(1, 2).approx_eq(&zero()) &&
self.cr(1, 3).approx_eq(&zero()) &&
self.cr(2, 0).approx_eq(&zero()) &&
self.cr(2, 1).approx_eq(&zero()) &&
self.cr(2, 3).approx_eq(&zero()) &&
self.cr(3, 0).approx_eq(&zero()) &&
self.cr(3, 1).approx_eq(&zero()) &&
self.cr(3, 2).approx_eq(&zero())
}
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(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(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<S:Clone + Float> ToQuat<S> for Mat3<S> { impl<S:Clone + Float> ToQuat<S> for Mat3<S> {

View file

@ -30,6 +30,9 @@ struct Point2<S> { x: S, y: S }
#[deriving(Eq, Zero, Clone)] #[deriving(Eq, Zero, Clone)]
struct Point3<S> { x: S, y: S, z: S } struct Point3<S> { x: S, y: S, z: S }
approx_eq!(impl<S> Point2<S>)
approx_eq!(impl<S> Point3<S>)
impl<S: Num> Point2<S> { impl<S: Num> Point2<S> {
#[inline] #[inline]
pub fn new(x: S, y: S) -> Point2<S> { pub fn new(x: S, y: S) -> Point2<S> {

View file

@ -35,6 +35,10 @@ pub trait ToVec2<S: Clone + Num> { fn to_vec2(&self) -> Vec2<S>; }
pub trait ToVec3<S: Clone + Num> { fn to_vec3(&self) -> Vec3<S>; } pub trait ToVec3<S: Clone + Num> { fn to_vec3(&self) -> Vec3<S>; }
pub trait ToVec4<S: Clone + Num> { fn to_vec4(&self) -> Vec4<S>; } pub trait ToVec4<S: Clone + Num> { fn to_vec4(&self) -> Vec4<S>; }
approx_eq!(impl<S> Vec2<S>)
approx_eq!(impl<S> Vec3<S>)
approx_eq!(impl<S> Vec4<S>)
// Utility macro for generating associated functions for the vectors // Utility macro for generating associated functions for the vectors
macro_rules! vec( macro_rules! vec(
(impl $Self:ident <$S:ident> { $($field:ident),+ }) => ( (impl $Self:ident <$S:ident> { $($field:ident),+ }) => (
@ -166,6 +170,7 @@ pub trait EuclideanVector
Slice Slice
> >
: Vector<S, Slice> : Vector<S, Slice>
+ ApproxEq<S>
{ {
/// Returns `true` if the vector is perpendicular (at right angles to) /// Returns `true` if the vector is perpendicular (at right angles to)
/// the other vector. /// the other vector.