Add the ApproxEq trait.

It is no longer part of std::num
This commit is contained in:
Sébastien Crozet 2014-01-09 20:48:30 +01:00
parent 31904cad6f
commit f5b0b76d8d
19 changed files with 171 additions and 129 deletions

View File

@ -4,8 +4,9 @@ use std::num::{Zero, One};
pub use traits::{ pub use traits::{
Absolute, Absolute,
AbsoluteRotate, AbsoluteRotate,
AlgebraicVec, ApproxEq,
AlgebraicVecExt, RealVec,
RealVecExt,
Basis, Basis,
Cast, Cast,
Col, Col,
@ -431,19 +432,19 @@ pub fn sub_dot<V: Dot<N>, N>(a: &V, b: &V, c: &V) -> N {
/// Computes the L2 norm of a vector. /// Computes the L2 norm of a vector.
#[inline(always)] #[inline(always)]
pub fn norm<V: Norm<N>, N: Algebraic>(v: &V) -> N { pub fn norm<V: Norm<N>, N: Real>(v: &V) -> N {
Norm::norm(v) Norm::norm(v)
} }
/// Computes the squared L2 norm of a vector. /// Computes the squared L2 norm of a vector.
#[inline(always)] #[inline(always)]
pub fn sqnorm<V: Norm<N>, N: Algebraic>(v: &V) -> N { pub fn sqnorm<V: Norm<N>, N: Real>(v: &V) -> N {
Norm::sqnorm(v) Norm::sqnorm(v)
} }
/// Gets the normalized version of a vector. /// Gets the normalized version of a vector.
#[inline(always)] #[inline(always)]
pub fn normalize<V: Norm<N>, N: Algebraic>(v: &V) -> V { pub fn normalize<V: Norm<N>, N: Real>(v: &V) -> V {
Norm::normalize_cpy(v) Norm::normalize_cpy(v)
} }
@ -508,6 +509,21 @@ pub fn sample_sphere<V: UniformSphereSample>(f: |V| -> ()) {
// //
// //
/*
* AproxEq<N>
*/
/// Tests approximate equality.
#[inline(always)]
pub fn approx_eq<T: ApproxEq<N>, N>(a: &T, b: &T) -> bool {
ApproxEq::approx_eq(a, b)
}
/// Tests approximate equality using a custom epsilon.
#[inline(always)]
pub fn approx_eq_eps<T: ApproxEq<N>, N>(a: &T, b: &T, eps: &N) -> bool {
ApproxEq::approx_eq_eps(a, b, eps)
}
/* /*
* Absolute<A> * Absolute<A>

View File

@ -6,7 +6,7 @@ use std::rand::Rand;
use std::rand; use std::rand;
use std::num::{One, Zero}; use std::num::{One, Zero};
use std::vec; use std::vec;
use std::cmp::ApproxEq; use traits::operations::ApproxEq;
use std::util; use std::util;
use structs::dvec::{DVec, DVecMulRhs}; use structs::dvec::{DVec, DVecMulRhs};
use traits::operations::{Inv, Transpose, Mean, Cov}; use traits::operations::{Inv, Transpose, Mean, Cov};
@ -499,25 +499,22 @@ impl<N: Clone + Num + Cast<f32> + DMatDivRhs<N, DMat<N>> + ToStr > Cov<DMat<N>>
impl<N: ApproxEq<N>> ApproxEq<N> for DMat<N> { impl<N: ApproxEq<N>> ApproxEq<N> for DMat<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<DMat<N>>) -> N {
fail!("This function cannot work due to a compiler bug.") ApproxEq::approx_epsilon(None::<N>)
// let res: N = ApproxEq::<N>::approx_epsilon();
// res
} }
#[inline] #[inline]
fn approx_eq(&self, other: &DMat<N>) -> bool { fn approx_eq(a: &DMat<N>, b: &DMat<N>) -> bool {
let mut zip = self.mij.iter().zip(other.mij.iter()); let mut zip = a.mij.iter().zip(b.mij.iter());
zip.all(|(a, b)| a.approx_eq(b)) zip.all(|(a, b)| ApproxEq::approx_eq(a, b))
} }
#[inline] #[inline]
fn approx_eq_eps(&self, other: &DMat<N>, epsilon: &N) -> bool { fn approx_eq_eps(a: &DMat<N>, b: &DMat<N>, epsilon: &N) -> bool {
let mut zip = self.mij.iter().zip(other.mij.iter()); let mut zip = a.mij.iter().zip(b.mij.iter());
zip.all(|(a, b)| a.approx_eq_eps(b, epsilon)) zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon))
} }
} }

View File

@ -2,12 +2,12 @@
#[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait. #[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait.
use std::num::{Zero, One, Algebraic}; use std::num::{Zero, One, Real};
use std::rand::Rand; use std::rand::Rand;
use std::rand; use std::rand;
use std::vec; use std::vec;
use std::vec::{VecIterator, VecMutIterator}; use std::vec::{VecIterator, VecMutIterator};
use std::cmp::ApproxEq; use traits::operations::ApproxEq;
use std::iter::FromIterator; use std::iter::FromIterator;
use traits::geometry::{Dot, Norm}; use traits::geometry::{Dot, Norm};
use traits::structure::{Iterable, IterableMut}; use traits::structure::{Iterable, IterableMut};
@ -177,7 +177,7 @@ impl<N> FromIterator<N> for DVec<N> {
} }
} }
impl<N: Clone + Num + Algebraic + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N> { impl<N: Clone + Num + Real + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N> {
/// Computes the canonical basis for the given dimension. A canonical basis is a set of /// Computes the canonical basis for the given dimension. A canonical basis is a set of
/// vectors, mutually orthogonal, with all its component equal to 0.0 exept one which is equal /// vectors, mutually orthogonal, with all its component equal to 0.0 exept one which is equal
/// to 1.0. /// to 1.0.
@ -220,7 +220,7 @@ impl<N: Clone + Num + Algebraic + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N>
elt = elt - v * Dot::dot(&elt, v) elt = elt - v * Dot::dot(&elt, v)
}; };
if !Norm::sqnorm(&elt).approx_eq(&Zero::zero()) { if !ApproxEq::approx_eq(&Norm::sqnorm(&elt), &Zero::zero()) {
res.push(Norm::normalize_cpy(&elt)); res.push(Norm::normalize_cpy(&elt));
} }
} }
@ -284,7 +284,7 @@ impl<N: Num + Clone> Dot<N> for DVec<N> {
} }
} }
impl<N: Num + Algebraic + Clone> Norm<N> for DVec<N> { impl<N: Num + Real + Clone> Norm<N> for DVec<N> {
#[inline] #[inline]
fn sqnorm(v: &DVec<N>) -> N { fn sqnorm(v: &DVec<N>) -> N {
Dot::dot(v, v) Dot::dot(v, v)
@ -318,25 +318,22 @@ impl<N: Num + Algebraic + Clone> Norm<N> for DVec<N> {
impl<N: ApproxEq<N>> ApproxEq<N> for DVec<N> { impl<N: ApproxEq<N>> ApproxEq<N> for DVec<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<DVec<N>>) -> N {
fail!("Fix me.") ApproxEq::approx_epsilon(None::<N>)
// let res: N = ApproxEq::<N>::approx_epsilon();
// res
} }
#[inline] #[inline]
fn approx_eq(&self, other: &DVec<N>) -> bool { fn approx_eq(a: &DVec<N>, b: &DVec<N>) -> bool {
let mut zip = self.at.iter().zip(other.at.iter()); let mut zip = a.at.iter().zip(b.at.iter());
zip.all(|(a, b)| a.approx_eq(b)) zip.all(|(a, b)| ApproxEq::approx_eq(a, b))
} }
#[inline] #[inline]
fn approx_eq_eps(&self, other: &DVec<N>, epsilon: &N) -> bool { fn approx_eq_eps(a: &DVec<N>, b: &DVec<N>, epsilon: &N) -> bool {
let mut zip = self.at.iter().zip(other.at.iter()); let mut zip = a.at.iter().zip(b.at.iter());
zip.all(|(a, b)| a.approx_eq_eps(b, epsilon)) zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon))
} }
} }

View File

@ -6,7 +6,7 @@ use std::num::{Zero, One};
use std::rand::{Rand, Rng}; use std::rand::{Rand, Rng};
use structs::mat::{Mat3, Mat4, Mat5}; use structs::mat::{Mat3, Mat4, Mat5};
use traits::structure::{Cast, Dim, Col}; use traits::structure::{Cast, Dim, Col};
use traits::operations::{Inv}; use traits::operations::{Inv, ApproxEq};
use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation, use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation,
Translate, Translation, ToHomogeneous}; Translate, Translation, ToHomogeneous};
@ -51,7 +51,7 @@ pub struct Iso4<N> {
translation: Vec4<N> translation: Vec4<N>
} }
impl<N: Clone + Num + Algebraic> Iso3<N> { impl<N: Clone + Num + Real> Iso3<N> {
/// Reorient and translate this transformation such that its local `x` axis points to a given /// Reorient and translate this transformation such that its local `x` axis points to a given
/// direction. Note that the usually known `look_at` function does the same thing but with the /// direction. Note that the usually known `look_at` function does the same thing but with the
/// `z` axis. See `look_at_z` for that. /// `z` axis. See `look_at_z` for that.

View File

@ -2,7 +2,7 @@
macro_rules! iso_impl( macro_rules! iso_impl(
($t: ident, $submat: ident, $subvec: ident, $subrotvec: ident) => ( ($t: ident, $submat: ident, $subvec: ident, $subrotvec: ident) => (
impl<N: Clone + Trigonometric + Algebraic + Num> $t<N> { impl<N: Clone + Real + Real + Num> $t<N> {
/// Creates a new isometry from a rotation matrix and a vector. /// Creates a new isometry from a rotation matrix and a vector.
#[inline] #[inline]
pub fn new(translation: $subvec<N>, rotation: $subrotvec<N>) -> $t<N> { pub fn new(translation: $subvec<N>, rotation: $subrotvec<N>) -> $t<N> {
@ -26,7 +26,7 @@ macro_rules! iso_impl(
macro_rules! rotation_matrix_impl( macro_rules! rotation_matrix_impl(
($t: ident, $trot: ident, $tlv: ident, $tav: ident) => ( ($t: ident, $trot: ident, $tlv: ident, $tav: ident) => (
impl<N: Cast<f32> + Algebraic + Trigonometric + Num + Clone> impl<N: Cast<f32> + Real + Real + Num + Clone>
RotationMatrix<$tlv<N>, $tav<N>, $trot<N>> for $t<N> { RotationMatrix<$tlv<N>, $tav<N>, $trot<N>> for $t<N> {
#[inline] #[inline]
fn to_rot_mat(&self) -> $trot<N> { fn to_rot_mat(&self) -> $trot<N> {
@ -50,7 +50,7 @@ macro_rules! dim_impl(
macro_rules! one_impl( macro_rules! one_impl(
($t: ident) => ( ($t: ident) => (
impl<N: Trigonometric + Algebraic + Num + Clone> One for $t<N> { impl<N: Real + Real + Num + Clone> One for $t<N> {
#[inline] #[inline]
fn one() -> $t<N> { fn one() -> $t<N> {
$t::new_with_rotmat(Zero::zero(), One::one()) $t::new_with_rotmat(Zero::zero(), One::one())
@ -61,7 +61,7 @@ macro_rules! one_impl(
macro_rules! iso_mul_iso_impl( macro_rules! iso_mul_iso_impl(
($t: ident, $tmul: ident) => ( ($t: ident, $tmul: ident) => (
impl<N: Num + Trigonometric + Algebraic + Clone> $tmul<N, $t<N>> for $t<N> { impl<N: Num + Real + Real + Clone> $tmul<N, $t<N>> for $t<N> {
#[inline] #[inline]
fn binop(left: &$t<N>, right: &$t<N>) -> $t<N> { fn binop(left: &$t<N>, right: &$t<N>) -> $t<N> {
$t::new_with_rotmat( $t::new_with_rotmat(
@ -96,7 +96,7 @@ macro_rules! vec_mul_iso_impl(
macro_rules! translation_impl( macro_rules! translation_impl(
($t: ident, $tv: ident) => ( ($t: ident, $tv: ident) => (
impl<N: Trigonometric + Num + Algebraic + Clone> Translation<$tv<N>> for $t<N> { impl<N: Real + Num + Real + Clone> Translation<$tv<N>> for $t<N> {
#[inline] #[inline]
fn translation(&self) -> $tv<N> { fn translation(&self) -> $tv<N> {
self.translation.clone() self.translation.clone()
@ -153,7 +153,7 @@ macro_rules! translate_impl(
macro_rules! rotation_impl( macro_rules! rotation_impl(
($t: ident, $trot: ident, $tav: ident) => ( ($t: ident, $trot: ident, $tav: ident) => (
impl<N: Cast<f32> + Num + Trigonometric + Algebraic + Clone> Rotation<$tav<N>> for $t<N> { impl<N: Cast<f32> + Num + Real + Real + Clone> Rotation<$tav<N>> for $t<N> {
#[inline] #[inline]
fn rotation(&self) -> $tav<N> { fn rotation(&self) -> $tav<N> {
self.rotation.rotation() self.rotation.rotation()
@ -220,7 +220,7 @@ macro_rules! rotate_impl(
macro_rules! transformation_impl( macro_rules! transformation_impl(
($t: ident) => ( ($t: ident) => (
impl<N: Num + Trigonometric + Algebraic + Clone> Transformation<$t<N>> for $t<N> { impl<N: Num + Real + Real + Clone> Transformation<$t<N>> for $t<N> {
fn transformation(&self) -> $t<N> { fn transformation(&self) -> $t<N> {
self.clone() self.clone()
} }
@ -315,21 +315,20 @@ macro_rules! approx_eq_impl(
($t: ident) => ( ($t: ident) => (
impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> { impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<$t<N>>) -> N {
fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") ApproxEq::approx_epsilon(None::<N>)
// ApproxEq::<N>::approx_epsilon()
} }
#[inline] #[inline]
fn approx_eq(&self, other: &$t<N>) -> bool { fn approx_eq(a: &$t<N>, b: &$t<N>) -> bool {
self.rotation.approx_eq(&other.rotation) && ApproxEq::approx_eq(&a.rotation, &b.rotation) &&
self.translation.approx_eq(&other.translation) ApproxEq::approx_eq(&a.translation, &b.translation)
} }
#[inline] #[inline]
fn approx_eq_eps(&self, other: &$t<N>, epsilon: &N) -> bool { fn approx_eq_eps(a: &$t<N>, b: &$t<N>, epsilon: &N) -> bool {
self.rotation.approx_eq_eps(&other.rotation, epsilon) && ApproxEq::approx_eq_eps(&a.rotation, &b.rotation, epsilon) &&
self.translation.approx_eq_eps(&other.translation, epsilon) ApproxEq::approx_eq_eps(&a.translation, &b.translation, epsilon)
} }
} }
) )
@ -337,7 +336,7 @@ macro_rules! approx_eq_impl(
macro_rules! rand_impl( macro_rules! rand_impl(
($t: ident) => ( ($t: ident) => (
impl<N: Rand + Clone + Trigonometric + Algebraic + Num> Rand for $t<N> { impl<N: Rand + Clone + Real + Real + Num> Rand for $t<N> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> $t<N> { fn rand<R: Rng>(rng: &mut R) -> $t<N> {
$t::new(rng.gen(), rng.gen()) $t::new(rng.gen(), rng.gen())

View File

@ -4,7 +4,7 @@
use std::cast; use std::cast;
use std::num::{One, Zero}; use std::num::{One, Zero};
use std::cmp::ApproxEq; use traits::operations::ApproxEq;
use std::vec::{VecIterator, VecMutIterator}; use std::vec::{VecIterator, VecMutIterator};
use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Vec1MulRhs, Vec4MulRhs, use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Vec1MulRhs, Vec4MulRhs,
Vec5MulRhs, Vec6MulRhs}; Vec5MulRhs, Vec6MulRhs};

View File

@ -449,23 +449,22 @@ macro_rules! approx_eq_impl(
($t: ident) => ( ($t: ident) => (
impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> { impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<$t<N>>) -> N {
fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") ApproxEq::approx_epsilon(None::<N>)
// ApproxEq::<N>::approx_epsilon()
} }
#[inline] #[inline]
fn approx_eq(&self, other: &$t<N>) -> bool { fn approx_eq(a: &$t<N>, b: &$t<N>) -> bool {
let mut zip = self.iter().zip(other.iter()); let mut zip = a.iter().zip(b.iter());
zip.all(|(a, b)| a.approx_eq(b)) zip.all(|(a, b)| ApproxEq::approx_eq(a, b))
} }
#[inline] #[inline]
fn approx_eq_eps(&self, other: &$t<N>, epsilon: &N) -> bool { fn approx_eq_eps(a: &$t<N>, b: &$t<N>, epsilon: &N) -> bool {
let mut zip = self.iter().zip(other.iter()); let mut zip = a.iter().zip(b.iter());
zip.all(|(a, b)| a.approx_eq_eps(b, epsilon)) zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon))
} }
} }
) )

View File

@ -7,7 +7,7 @@ use std::rand::{Rand, Rng};
use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Transform, ToHomogeneous, use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Transform, ToHomogeneous,
Norm, Cross}; Norm, Cross};
use traits::structure::{Cast, Dim, Row, Col}; use traits::structure::{Cast, Dim, Row, Col};
use traits::operations::{Absolute, Inv, Transpose}; use traits::operations::{Absolute, Inv, Transpose, ApproxEq};
use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs}; use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs};
use structs::mat::{Mat2, Mat3, Mat4, Mat5}; use structs::mat::{Mat2, Mat3, Mat4, Mat5};
@ -20,7 +20,7 @@ pub struct Rot2<N> {
priv submat: Mat2<N> priv submat: Mat2<N>
} }
impl<N: Clone + Trigonometric + Neg<N>> Rot2<N> { impl<N: Clone + Real + Neg<N>> Rot2<N> {
/// Builds a 2 dimensional rotation matrix from an angle in radian. /// Builds a 2 dimensional rotation matrix from an angle in radian.
pub fn new(angle: Vec1<N>) -> Rot2<N> { pub fn new(angle: Vec1<N>) -> Rot2<N> {
let (sia, coa) = angle.x.sin_cos(); let (sia, coa) = angle.x.sin_cos();
@ -31,7 +31,7 @@ impl<N: Clone + Trigonometric + Neg<N>> Rot2<N> {
} }
} }
impl<N: Trigonometric + Num + Clone> impl<N: Real + Num + Clone>
Rotation<Vec1<N>> for Rot2<N> { Rotation<Vec1<N>> for Rot2<N> {
#[inline] #[inline]
fn rotation(&self) -> Vec1<N> { fn rotation(&self) -> Vec1<N> {
@ -69,7 +69,7 @@ Rotation<Vec1<N>> for Rot2<N> {
} }
} }
impl<N: Clone + Rand + Trigonometric + Neg<N>> Rand for Rot2<N> { impl<N: Clone + Rand + Real + Neg<N>> Rand for Rot2<N> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Rot2<N> { fn rand<R: Rng>(rng: &mut R) -> Rot2<N> {
Rot2::new(rng.gen()) Rot2::new(rng.gen())
@ -99,7 +99,7 @@ pub struct Rot3<N> {
} }
impl<N: Clone + Trigonometric + Num + Algebraic> Rot3<N> { impl<N: Clone + Real + Num + Real> Rot3<N> {
/// Builds a 3 dimensional rotation matrix from an axis and an angle. /// Builds a 3 dimensional rotation matrix from an axis and an angle.
/// ///
/// # Arguments /// # Arguments
@ -140,7 +140,7 @@ impl<N: Clone + Trigonometric + Num + Algebraic> Rot3<N> {
} }
} }
impl<N: Clone + Num + Algebraic> Rot3<N> { impl<N: Clone + Num + Real> Rot3<N> {
/// Reorient this matrix such that its local `x` axis points to a given point. Note that the /// Reorient this matrix such that its local `x` axis points to a given point. Note that the
/// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z` /// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z`
/// for that. /// for that.
@ -180,7 +180,7 @@ impl<N: Clone + Num + Algebraic> Rot3<N> {
} }
} }
impl<N: Clone + Trigonometric + Num + Algebraic + Cast<f32>> impl<N: Clone + Real + Num + Real + Cast<f32>>
Rotation<Vec3<N>> for Rot3<N> { Rotation<Vec3<N>> for Rot3<N> {
#[inline] #[inline]
fn rotation(&self) -> Vec3<N> { fn rotation(&self) -> Vec3<N> {
@ -245,7 +245,7 @@ Rotation<Vec3<N>> for Rot3<N> {
} }
} }
impl<N: Clone + Rand + Trigonometric + Num + Algebraic> impl<N: Clone + Rand + Real + Num + Real>
Rand for Rot3<N> { Rand for Rot3<N> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Rot3<N> { fn rand<R: Rng>(rng: &mut R) -> Rot3<N> {
@ -309,7 +309,7 @@ impl<N: Signed> AbsoluteRotate<Vec4<N>> for Rot4<N> {
} }
} }
impl<N: Trigonometric + Num + Clone> impl<N: Real + Num + Clone>
Rotation<Vec4<N>> for Rot4<N> { Rotation<Vec4<N>> for Rot4<N> {
#[inline] #[inline]
fn rotation(&self) -> Vec4<N> { fn rotation(&self) -> Vec4<N> {

View File

@ -56,7 +56,7 @@ macro_rules! dim_impl(
macro_rules! rotation_matrix_impl( macro_rules! rotation_matrix_impl(
($t: ident, $tlv: ident, $tav: ident) => ( ($t: ident, $tlv: ident, $tav: ident) => (
impl<N: Cast<f32> + Algebraic + Trigonometric + Num + Clone> impl<N: Cast<f32> + Real + Real + Num + Clone>
RotationMatrix<$tlv<N>, $tav<N>, $t<N>> for $t<N> { RotationMatrix<$tlv<N>, $tav<N>, $t<N>> for $t<N> {
#[inline] #[inline]
fn to_rot_mat(&self) -> $t<N> { fn to_rot_mat(&self) -> $t<N> {
@ -201,19 +201,18 @@ macro_rules! approx_eq_impl(
($t: ident) => ( ($t: ident) => (
impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> { impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<$t<N>>) -> N {
// ApproxEq::<N>::approx_epsilon() ApproxEq::approx_epsilon(None::<N>)
fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.")
} }
#[inline] #[inline]
fn approx_eq(&self, other: &$t<N>) -> bool { fn approx_eq(a: &$t<N>, b: &$t<N>) -> bool {
self.submat.approx_eq(&other.submat) ApproxEq::approx_eq(&a.submat, &b.submat)
} }
#[inline] #[inline]
fn approx_eq_eps(&self, other: &$t<N>, epsilon: &N) -> bool { fn approx_eq_eps(a: &$t<N>, b: &$t<N>, epsilon: &N) -> bool {
self.submat.approx_eq_eps(&other.submat, epsilon) ApproxEq::approx_eq_eps(&a.submat, &b.submat, epsilon)
} }
} }
) )

View File

@ -91,7 +91,7 @@ impl<N: Clone + One + Zero + Neg<N>> Basis for Vec2<N> {
} }
} }
impl<N: Clone + Ord + Algebraic + Signed> Basis for Vec3<N> { impl<N: Clone + Ord + Real + Signed> Basis for Vec3<N> {
#[inline(always)] #[inline(always)]
fn canonical_basis(f: |Vec3<N>| -> bool) { fn canonical_basis(f: |Vec3<N>| -> bool) {
if !f(Vec3::new(One::one(), Zero::zero(), Zero::zero())) { return }; if !f(Vec3::new(One::one(), Zero::zero(), Zero::zero())) { return };

View File

@ -1,8 +1,8 @@
use std::cast; use std::cast;
use std::num::{Zero, One, Algebraic, Bounded}; use std::num::{Zero, One, Real, Bounded};
use std::vec::{VecIterator, VecMutIterator}; use std::vec::{VecIterator, VecMutIterator};
use std::iter::{Iterator, FromIterator}; use std::iter::{Iterator, FromIterator};
use std::cmp::ApproxEq; use traits::operations::ApproxEq;
use traits::structure::{Iterable, IterableMut, Indexable, Basis, Dim}; use traits::structure::{Iterable, IterableMut, Indexable, Basis, Dim};
use traits::geometry::{Translation, Dot, Norm}; use traits::geometry::{Translation, Dot, Norm};
use structs::vec; use structs::vec;
@ -159,7 +159,7 @@ impl<N: Clone + Add<N, N> + Neg<N>> Translation<vec::Vec0<N>> for vec::Vec0<N> {
} }
} }
impl<N: Clone + Num + Algebraic> Norm<N> for vec::Vec0<N> { impl<N: Clone + Num + Real> Norm<N> for vec::Vec0<N> {
#[inline] #[inline]
fn sqnorm(_: &vec::Vec0<N>) -> N { fn sqnorm(_: &vec::Vec0<N>) -> N {
Zero::zero() Zero::zero()
@ -183,18 +183,17 @@ impl<N: Clone + Num + Algebraic> Norm<N> for vec::Vec0<N> {
impl<N: ApproxEq<N>> ApproxEq<N> for vec::Vec0<N> { impl<N: ApproxEq<N>> ApproxEq<N> for vec::Vec0<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<vec::Vec0<N>>) -> N {
fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") ApproxEq::approx_epsilon(None::<N>)
// ApproxEq::<N>::approx_epsilon()
} }
#[inline] #[inline]
fn approx_eq(&self, _: &vec::Vec0<N>) -> bool { fn approx_eq(_: &vec::Vec0<N>, _: &vec::Vec0<N>) -> bool {
true true
} }
#[inline] #[inline]
fn approx_eq_eps(&self, _: &vec::Vec0<N>, _: &N) -> bool { fn approx_eq_eps(_: &vec::Vec0<N>, _: &vec::Vec0<N>, _: &N) -> bool {
true true
} }
} }

View File

@ -3,10 +3,10 @@
#[allow(missing_doc)]; // we allow missing to avoid having to document the vector components. #[allow(missing_doc)]; // we allow missing to avoid having to document the vector components.
use std::cast; use std::cast;
use std::num::{Zero, One, Algebraic, Bounded}; use std::num::{Zero, One, Real, Bounded};
use std::vec::{VecIterator, VecMutIterator}; use std::vec::{VecIterator, VecMutIterator};
use std::iter::{Iterator, FromIterator}; use std::iter::{Iterator, FromIterator};
use std::cmp::ApproxEq; use traits::operations::ApproxEq;
use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm, use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm,
Translation, Translate}; Translation, Translate};

View File

@ -223,7 +223,7 @@ macro_rules! container_impl(
macro_rules! basis_impl( macro_rules! basis_impl(
($t: ident, $trhs: ident, $dim: expr) => ( ($t: ident, $trhs: ident, $dim: expr) => (
impl<N: Clone + Num + Algebraic + ApproxEq<N> + $trhs<N, $t<N>>> Basis for $t<N> { impl<N: Clone + Num + Real + ApproxEq<N> + $trhs<N, $t<N>>> Basis for $t<N> {
#[inline] #[inline]
fn canonical_basis(f: |$t<N>| -> bool) { fn canonical_basis(f: |$t<N>| -> bool) {
for i in range(0u, $dim) { for i in range(0u, $dim) {
@ -262,7 +262,7 @@ macro_rules! basis_impl(
elt = elt - v * Dot::dot(&elt, v) elt = elt - v * Dot::dot(&elt, v)
}; };
if !Norm::sqnorm(&elt).approx_eq(&Zero::zero()) { if !ApproxEq::approx_eq(&Norm::sqnorm(&elt), &Zero::zero()) {
let new_element = Norm::normalize_cpy(&elt); let new_element = Norm::normalize_cpy(&elt);
if !f(new_element.clone()) { return }; if !f(new_element.clone()) { return };
@ -433,7 +433,7 @@ macro_rules! translation_impl(
macro_rules! norm_impl( macro_rules! norm_impl(
($t: ident, $comp0: ident $(,$compN: ident)*) => ( ($t: ident, $comp0: ident $(,$compN: ident)*) => (
impl<N: Clone + Num + Algebraic> Norm<N> for $t<N> { impl<N: Clone + Num + Real> Norm<N> for $t<N> {
#[inline] #[inline]
fn sqnorm(v: &$t<N>) -> N { fn sqnorm(v: &$t<N>) -> N {
Dot::dot(v, v) Dot::dot(v, v)
@ -496,19 +496,20 @@ macro_rules! approx_eq_impl(
($t: ident, $comp0: ident $(,$compN: ident)*) => ( ($t: ident, $comp0: ident $(,$compN: ident)*) => (
impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> { impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> {
#[inline] #[inline]
fn approx_epsilon() -> N { fn approx_epsilon(_: Option<$t<N>>) -> N {
fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") ApproxEq::approx_epsilon(None::<N>)
// ApproxEq::<N>::approx_epsilon()
} }
#[inline] #[inline]
fn approx_eq(&self, other: &$t<N>) -> bool { fn approx_eq(a: &$t<N>, b: &$t<N>) -> bool {
self.$comp0.approx_eq(&other.$comp0) $(&& self.$compN.approx_eq(&other.$compN))* ApproxEq::approx_eq(&a.$comp0, &b.$comp0)
$(&& ApproxEq::approx_eq(&a.$compN, &b.$compN))*
} }
#[inline] #[inline]
fn approx_eq_eps(&self, other: &$t<N>, eps: &N) -> bool { fn approx_eq_eps(a: &$t<N>, b: &$t<N>, eps: &N) -> bool {
self.$comp0.approx_eq_eps(&other.$comp0, eps) $(&& self.$compN.approx_eq_eps(&other.$compN, eps))* ApproxEq::approx_eq_eps(&a.$comp0, &b.$comp0, eps)
$(&& ApproxEq::approx_eq_eps(&a.$compN, &b.$compN, eps))*
} }
} }
) )

View File

@ -1,6 +1,5 @@
use std::num::{Real, abs}; use std::num::{Real, abs};
use std::rand::random; use std::rand::random;
use std::cmp::ApproxEq;
use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable}; use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable};
use na; use na;
@ -9,7 +8,7 @@ macro_rules! test_inv_mat_impl(
10000.times(|| { 10000.times(|| {
let randmat : $t = random(); let randmat : $t = random();
assert!((na::inv(&randmat).unwrap() * randmat).approx_eq(&na::one())); assert!(na::approx_eq(&(na::inv(&randmat).unwrap() * randmat), &na::one()));
}) })
); );
) )
@ -90,7 +89,7 @@ fn test_rotation2() {
let randmat: na::Rot2<f64> = na::one(); let randmat: na::Rot2<f64> = na::one();
let ang = Vec1::new(abs::<f64>(random()) % Real::pi()); let ang = Vec1::new(abs::<f64>(random()) % Real::pi());
assert!(na::rotation(&na::append_rotation(&randmat, &ang)).approx_eq(&ang)); assert!(na::approx_eq(&na::rotation(&na::append_rotation(&randmat, &ang)), &ang));
}) })
} }
@ -109,7 +108,7 @@ fn test_inv_rotation3() {
let ang = na::normalize(&dir) * (abs::<f64>(random()) % Real::pi()); let ang = na::normalize(&dir) * (abs::<f64>(random()) % Real::pi());
let rot = na::append_rotation(&randmat, &ang); let rot = na::append_rotation(&randmat, &ang);
assert!((na::transpose(&rot) * rot).approx_eq(&na::one())); assert!(na::approx_eq(&(na::transpose(&rot) * rot), &na::one()));
}) })
} }
@ -125,7 +124,7 @@ fn test_mean_dmat() {
] ]
); );
assert!(na::mean(&mat).approx_eq(&DVec::from_vec(3, [4.0f64, 5.0, 6.0]))); assert!(na::approx_eq(&na::mean(&mat), &DVec::from_vec(3, [4.0f64, 5.0, 6.0])));
} }
#[test] #[test]
@ -152,7 +151,7 @@ fn test_cov_dmat() {
] ]
); );
assert!(na::cov(&mat).approx_eq(&expected)); assert!(na::approx_eq(&na::cov(&mat), &expected));
} }
#[test] #[test]

View File

@ -1,5 +1,4 @@
use std::rand::{random}; use std::rand::{random};
use std::cmp::ApproxEq;
use na::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6}; use na::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
use na::{Mat3, Iterable, IterableMut}; // FIXME: get rid of that use na::{Mat3, Iterable, IterableMut}; // FIXME: get rid of that
use na; use na;
@ -28,7 +27,7 @@ macro_rules! test_commut_dot_impl(
let v1 : $t = random(); let v1 : $t = random();
let v2 : $t = random(); let v2 : $t = random();
assert!(na::dot(&v1, &v2).approx_eq(&na::dot(&v2, &v1))); assert!(na::approx_eq(&na::dot(&v1, &v2), &na::dot(&v2, &v1)));
}) })
); );
) )
@ -39,10 +38,10 @@ macro_rules! test_scalar_op_impl(
let v1 : $t = random(); let v1 : $t = random();
let n : $n = random(); let n : $n = random();
assert!(((v1 * n) / n).approx_eq(&v1)); assert!(na::approx_eq(&((v1 * n) / n), &v1));
assert!(((v1 / n) * n).approx_eq(&v1)); assert!(na::approx_eq(&((v1 / n) * n), &v1));
assert!(((v1 - n) + n).approx_eq(&v1)); assert!(na::approx_eq(&((v1 - n) + n), &v1));
assert!(((v1 + n) - n).approx_eq(&v1)); assert!(na::approx_eq(&((v1 + n) - n), &v1));
let mut v1 : $t = random(); let mut v1 : $t = random();
let v0 : $t = v1.clone(); let v0 : $t = v1.clone();
@ -51,7 +50,7 @@ macro_rules! test_scalar_op_impl(
v1 = v1 * n; v1 = v1 * n;
v1 = v1 / n; v1 = v1 / n;
assert!(v1.approx_eq(&v0)); assert!(na::approx_eq(&v1, &v0));
}) })
); );
) )
@ -61,12 +60,12 @@ macro_rules! test_basis_impl(
10000.times(|| { 10000.times(|| {
na::canonical_basis(|e1: $t| { na::canonical_basis(|e1: $t| {
na::canonical_basis(|e2: $t| { na::canonical_basis(|e2: $t| {
assert!(e1 == e2 || na::dot(&e1, &e2).approx_eq(&na::zero())); assert!(e1 == e2 || na::approx_eq(&na::dot(&e1, &e2), &na::zero()));
true true
}); });
assert!(na::norm(&e1).approx_eq(&na::one())); assert!(na::approx_eq(&na::norm(&e1), &na::one()));
true true
}) })
@ -82,12 +81,12 @@ macro_rules! test_subspace_basis_impl(
na::orthonormal_subspace_basis(&v1, |e1| { na::orthonormal_subspace_basis(&v1, |e1| {
// check vectors are orthogonal to v1 // check vectors are orthogonal to v1
assert!(na::dot(&v1, &e1).approx_eq(&na::zero())); assert!(na::approx_eq(&na::dot(&v1, &e1), &na::zero()));
// check vectors form an orthonormal basis // check vectors form an orthonormal basis
assert!(na::norm(&e1).approx_eq(&na::one())); assert!(na::approx_eq(&na::norm(&e1), &na::one()));
// check vectors form an ortogonal basis // check vectors form an ortogonal basis
na::orthonormal_subspace_basis(&v1, |e2| { na::orthonormal_subspace_basis(&v1, |e2| {
assert!(e1 == e2 || na::dot(&e1, &e2).approx_eq(&na::zero())); assert!(e1 == e2 || na::approx_eq(&na::dot(&e1, &e2), &na::zero()));
true true
}); });
@ -105,8 +104,8 @@ fn test_cross_vec3() {
let v2 : Vec3<f64> = random(); let v2 : Vec3<f64> = random();
let v3 : Vec3<f64> = na::cross(&v1, &v2); let v3 : Vec3<f64> = na::cross(&v1, &v2);
assert!(na::dot(&v3, &v2).approx_eq(&na::zero())); assert!(na::approx_eq(&na::dot(&v3, &v2), &na::zero()));
assert!(na::dot(&v3, &v1).approx_eq(&na::zero())); assert!(na::approx_eq(&na::dot(&v3, &v1), &na::zero()));
}) })
} }

View File

@ -218,7 +218,7 @@ pub trait Dot<N> {
} }
/// Traits of objects having an euclidian norm. /// Traits of objects having an euclidian norm.
pub trait Norm<N: Algebraic> { pub trait Norm<N: Real> {
/// Computes the norm of `self`. /// Computes the norm of `self`.
#[inline] #[inline]
fn norm(v: &Self) -> N { fn norm(v: &Self) -> N {

View File

@ -4,11 +4,11 @@ pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneou
Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous, Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous,
Transform, Transformation, Translate, Translation, UniformSphereSample}; Transform, Transformation, Translate, Translation, UniformSphereSample};
pub use self::structure::{AlgebraicVec, AlgebraicVecExt, Basis, Cast, Col, Dim, Indexable, pub use self::structure::{RealVec, RealVecExt, Basis, Cast, Col, Dim, Indexable,
Iterable, IterableMut, Mat, Row, Vec, VecExt}; Iterable, IterableMut, Mat, Row, Vec, VecExt};
pub use self::operations::{Absolute, Cov, Inv, LMul, Mean, Outer, RMul, ScalarAdd, ScalarSub, pub use self::operations::{Absolute, ApproxEq, Cov, Inv, LMul, Mean, Outer, RMul, ScalarAdd,
Transpose}; ScalarSub, Transpose};
pub mod geometry; pub mod geometry;
pub mod structure; pub mod structure;

View File

@ -1,5 +1,42 @@
//! Low level operations on vectors and matrices. //! Low level operations on vectors and matrices.
/// Trait for testing approximate equality
pub trait ApproxEq<Eps> {
/// Default epsilon for approximation.
fn approx_epsilon(unused_self: Option<Self>) -> Eps;
/// Tests approximate equality using a custom epsilon.
fn approx_eq_eps(a: &Self, other: &Self, epsilon: &Eps) -> bool;
/// Tests approximate equality.
fn approx_eq(a: &Self, b: &Self) -> bool {
ApproxEq::approx_eq_eps(a, b, &ApproxEq::approx_epsilon(None::<Self>))
}
}
impl ApproxEq<f32> for f32 {
#[inline]
fn approx_epsilon(_: Option<f32>) -> f32 {
1.0e-6
}
#[inline]
fn approx_eq_eps(a: &f32, b: &f32, epsilon: &f32) -> bool {
(*a - *b).abs() < *epsilon
}
}
impl ApproxEq<f64> for f64 {
#[inline]
fn approx_epsilon(_: Option<f64>) -> f64 {
1.0e-6
}
#[inline]
fn approx_eq_eps(a: &f64, b: &f64, approx_epsilon: &f64) -> bool {
(*a - *b).abs() < *approx_epsilon
}
}
/// Trait of objects having an absolute value. /// Trait of objects having an absolute value.
/// This is useful if the object does not have the same type as its absolute value. /// This is useful if the object does not have the same type as its absolute value.

View File

@ -27,8 +27,8 @@ pub trait Vec<N>: Dim + Sub<Self, Self> + Add<Self, Self> + Neg<Self> + Zero + E
+ Div<N, Self> + Dot<N> { + Div<N, Self> + Dot<N> {
} }
/// Trait of vector with components implementing the `Algebraic` trait. /// Trait of vector with components implementing the `Real` trait.
pub trait AlgebraicVec<N: Algebraic>: Vec<N> + Norm<N> { pub trait RealVec<N: Real>: Vec<N> + Norm<N> {
} }
/// Trait grouping uncommon, low-level and borderline (from the mathematical point of view) /// Trait grouping uncommon, low-level and borderline (from the mathematical point of view)
@ -39,19 +39,19 @@ pub trait VecExt<N>: Vec<N> + Indexable<uint, N> + Iterable<N> +
/// Trait grouping uncommon, low-level and borderline (from the mathematical point of view) /// Trait grouping uncommon, low-level and borderline (from the mathematical point of view)
/// operations on vectors. /// operations on vectors.
pub trait AlgebraicVecExt<N: Algebraic>: AlgebraicVec<N> + VecExt<N> + Basis + Round { } pub trait RealVecExt<N: Real>: RealVec<N> + VecExt<N> + Basis + Round { }
impl<N, V: Dim + Sub<V, V> + Add<V, V> + Neg<V> + Zero + Eq + Mul<N, V> + Div<N, V> + Dot<N>> impl<N, V: Dim + Sub<V, V> + Add<V, V> + Neg<V> + Zero + Eq + Mul<N, V> + Div<N, V> + Dot<N>>
Vec<N> for V { } Vec<N> for V { }
impl<N: Algebraic, V: Vec<N> + Norm<N>> AlgebraicVec<N> for V { } impl<N: Real, V: Vec<N> + Norm<N>> RealVec<N> for V { }
impl<N, impl<N,
V: Vec<N> + Indexable<uint, N> + Iterable<N> + V: Vec<N> + Indexable<uint, N> + Iterable<N> +
UniformSphereSample + ScalarAdd<N> + ScalarSub<N> + Bounded + Orderable> UniformSphereSample + ScalarAdd<N> + ScalarSub<N> + Bounded + Orderable>
VecExt<N> for V { } VecExt<N> for V { }
impl<N: Algebraic, V: AlgebraicVec<N> + VecExt<N> + Basis + Round> AlgebraicVecExt<N> for V { } impl<N: Real, V: RealVec<N> + VecExt<N> + Basis + Round> RealVecExt<N> for V { }
// FIXME: return an iterator instead // FIXME: return an iterator instead
/// Traits of objects which can form a basis (typically vectors). /// Traits of objects which can form a basis (typically vectors).