From f5b0b76d8dcb0087d08a1b15f4e6e553dbd59dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 9 Jan 2014 20:48:30 +0100 Subject: [PATCH] Add the ApproxEq trait. It is no longer part of std::num --- src/na.rs | 26 +++++++++++++++++++++----- src/structs/dmat.rs | 21 +++++++++------------ src/structs/dvec.rs | 29 +++++++++++++---------------- src/structs/iso.rs | 4 ++-- src/structs/iso_macros.rs | 33 ++++++++++++++++----------------- src/structs/mat.rs | 2 +- src/structs/mat_macros.rs | 17 ++++++++--------- src/structs/rot.rs | 18 +++++++++--------- src/structs/rot_macros.rs | 15 +++++++-------- src/structs/spec/vec.rs | 2 +- src/structs/spec/vec0.rs | 15 +++++++-------- src/structs/vec.rs | 4 ++-- src/structs/vec_macros.rs | 21 +++++++++++---------- src/tests/mat.rs | 11 +++++------ src/tests/vec.rs | 27 +++++++++++++-------------- src/traits/geometry.rs | 2 +- src/traits/mod.rs | 6 +++--- src/traits/operations.rs | 37 +++++++++++++++++++++++++++++++++++++ src/traits/structure.rs | 10 +++++----- 19 files changed, 171 insertions(+), 129 deletions(-) diff --git a/src/na.rs b/src/na.rs index b6b56643..504fd983 100644 --- a/src/na.rs +++ b/src/na.rs @@ -4,8 +4,9 @@ use std::num::{Zero, One}; pub use traits::{ Absolute, AbsoluteRotate, - AlgebraicVec, - AlgebraicVecExt, + ApproxEq, + RealVec, + RealVecExt, Basis, Cast, Col, @@ -431,19 +432,19 @@ pub fn sub_dot, N>(a: &V, b: &V, c: &V) -> N { /// Computes the L2 norm of a vector. #[inline(always)] -pub fn norm, N: Algebraic>(v: &V) -> N { +pub fn norm, N: Real>(v: &V) -> N { Norm::norm(v) } /// Computes the squared L2 norm of a vector. #[inline(always)] -pub fn sqnorm, N: Algebraic>(v: &V) -> N { +pub fn sqnorm, N: Real>(v: &V) -> N { Norm::sqnorm(v) } /// Gets the normalized version of a vector. #[inline(always)] -pub fn normalize, N: Algebraic>(v: &V) -> V { +pub fn normalize, N: Real>(v: &V) -> V { Norm::normalize_cpy(v) } @@ -508,6 +509,21 @@ pub fn sample_sphere(f: |V| -> ()) { // // +/* + * AproxEq + */ +/// Tests approximate equality. +#[inline(always)] +pub fn approx_eq, 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, N>(a: &T, b: &T, eps: &N) -> bool { + ApproxEq::approx_eq_eps(a, b, eps) +} + /* * Absolute diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index 586a3886..bca8a2b9 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -6,7 +6,7 @@ use std::rand::Rand; use std::rand; use std::num::{One, Zero}; use std::vec; -use std::cmp::ApproxEq; +use traits::operations::ApproxEq; use std::util; use structs::dvec::{DVec, DVecMulRhs}; use traits::operations::{Inv, Transpose, Mean, Cov}; @@ -499,25 +499,22 @@ impl + DMatDivRhs> + ToStr > Cov> impl> ApproxEq for DMat { #[inline] - fn approx_epsilon() -> N { - fail!("This function cannot work due to a compiler bug.") - // let res: N = ApproxEq::::approx_epsilon(); - - // res + fn approx_epsilon(_: Option>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, other: &DMat) -> bool { - let mut zip = self.mij.iter().zip(other.mij.iter()); + fn approx_eq(a: &DMat, b: &DMat) -> bool { + 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] - fn approx_eq_eps(&self, other: &DMat, epsilon: &N) -> bool { - let mut zip = self.mij.iter().zip(other.mij.iter()); + fn approx_eq_eps(a: &DMat, b: &DMat, epsilon: &N) -> bool { + 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)) } } diff --git a/src/structs/dvec.rs b/src/structs/dvec.rs index 935980e3..a2711c2f 100644 --- a/src/structs/dvec.rs +++ b/src/structs/dvec.rs @@ -2,12 +2,12 @@ #[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; use std::vec; use std::vec::{VecIterator, VecMutIterator}; -use std::cmp::ApproxEq; +use traits::operations::ApproxEq; use std::iter::FromIterator; use traits::geometry::{Dot, Norm}; use traits::structure::{Iterable, IterableMut}; @@ -177,7 +177,7 @@ impl FromIterator for DVec { } } -impl + DVecMulRhs>> DVec { +impl + DVecMulRhs>> DVec { /// 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 /// to 1.0. @@ -220,7 +220,7 @@ impl + DVecMulRhs>> DVec 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)); } } @@ -284,7 +284,7 @@ impl Dot for DVec { } } -impl Norm for DVec { +impl Norm for DVec { #[inline] fn sqnorm(v: &DVec) -> N { Dot::dot(v, v) @@ -318,25 +318,22 @@ impl Norm for DVec { impl> ApproxEq for DVec { #[inline] - fn approx_epsilon() -> N { - fail!("Fix me.") - // let res: N = ApproxEq::::approx_epsilon(); - - // res + fn approx_epsilon(_: Option>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, other: &DVec) -> bool { - let mut zip = self.at.iter().zip(other.at.iter()); + fn approx_eq(a: &DVec, b: &DVec) -> bool { + 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] - fn approx_eq_eps(&self, other: &DVec, epsilon: &N) -> bool { - let mut zip = self.at.iter().zip(other.at.iter()); + fn approx_eq_eps(a: &DVec, b: &DVec, epsilon: &N) -> bool { + 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)) } } diff --git a/src/structs/iso.rs b/src/structs/iso.rs index c73cbd25..c69d93b2 100644 --- a/src/structs/iso.rs +++ b/src/structs/iso.rs @@ -6,7 +6,7 @@ use std::num::{Zero, One}; use std::rand::{Rand, Rng}; use structs::mat::{Mat3, Mat4, Mat5}; use traits::structure::{Cast, Dim, Col}; -use traits::operations::{Inv}; +use traits::operations::{Inv, ApproxEq}; use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation, Translate, Translation, ToHomogeneous}; @@ -51,7 +51,7 @@ pub struct Iso4 { translation: Vec4 } -impl Iso3 { +impl Iso3 { /// 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 /// `z` axis. See `look_at_z` for that. diff --git a/src/structs/iso_macros.rs b/src/structs/iso_macros.rs index bdf0cb2b..149290d6 100644 --- a/src/structs/iso_macros.rs +++ b/src/structs/iso_macros.rs @@ -2,7 +2,7 @@ macro_rules! iso_impl( ($t: ident, $submat: ident, $subvec: ident, $subrotvec: ident) => ( - impl $t { + impl $t { /// Creates a new isometry from a rotation matrix and a vector. #[inline] pub fn new(translation: $subvec, rotation: $subrotvec) -> $t { @@ -26,7 +26,7 @@ macro_rules! iso_impl( macro_rules! rotation_matrix_impl( ($t: ident, $trot: ident, $tlv: ident, $tav: ident) => ( - impl + Algebraic + Trigonometric + Num + Clone> + impl + Real + Real + Num + Clone> RotationMatrix<$tlv, $tav, $trot> for $t { #[inline] fn to_rot_mat(&self) -> $trot { @@ -50,7 +50,7 @@ macro_rules! dim_impl( macro_rules! one_impl( ($t: ident) => ( - impl One for $t { + impl One for $t { #[inline] fn one() -> $t { $t::new_with_rotmat(Zero::zero(), One::one()) @@ -61,7 +61,7 @@ macro_rules! one_impl( macro_rules! iso_mul_iso_impl( ($t: ident, $tmul: ident) => ( - impl $tmul> for $t { + impl $tmul> for $t { #[inline] fn binop(left: &$t, right: &$t) -> $t { $t::new_with_rotmat( @@ -96,7 +96,7 @@ macro_rules! vec_mul_iso_impl( macro_rules! translation_impl( ($t: ident, $tv: ident) => ( - impl Translation<$tv> for $t { + impl Translation<$tv> for $t { #[inline] fn translation(&self) -> $tv { self.translation.clone() @@ -153,7 +153,7 @@ macro_rules! translate_impl( macro_rules! rotation_impl( ($t: ident, $trot: ident, $tav: ident) => ( - impl + Num + Trigonometric + Algebraic + Clone> Rotation<$tav> for $t { + impl + Num + Real + Real + Clone> Rotation<$tav> for $t { #[inline] fn rotation(&self) -> $tav { self.rotation.rotation() @@ -220,7 +220,7 @@ macro_rules! rotate_impl( macro_rules! transformation_impl( ($t: ident) => ( - impl Transformation<$t> for $t { + impl Transformation<$t> for $t { fn transformation(&self) -> $t { self.clone() } @@ -315,21 +315,20 @@ macro_rules! approx_eq_impl( ($t: ident) => ( impl> ApproxEq for $t { #[inline] - fn approx_epsilon() -> N { - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") - // ApproxEq::::approx_epsilon() + fn approx_epsilon(_: Option<$t>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, other: &$t) -> bool { - self.rotation.approx_eq(&other.rotation) && - self.translation.approx_eq(&other.translation) + fn approx_eq(a: &$t, b: &$t) -> bool { + ApproxEq::approx_eq(&a.rotation, &b.rotation) && + ApproxEq::approx_eq(&a.translation, &b.translation) } #[inline] - fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { - self.rotation.approx_eq_eps(&other.rotation, epsilon) && - self.translation.approx_eq_eps(&other.translation, epsilon) + fn approx_eq_eps(a: &$t, b: &$t, epsilon: &N) -> bool { + ApproxEq::approx_eq_eps(&a.rotation, &b.rotation, epsilon) && + ApproxEq::approx_eq_eps(&a.translation, &b.translation, epsilon) } } ) @@ -337,7 +336,7 @@ macro_rules! approx_eq_impl( macro_rules! rand_impl( ($t: ident) => ( - impl Rand for $t { + impl Rand for $t { #[inline] fn rand(rng: &mut R) -> $t { $t::new(rng.gen(), rng.gen()) diff --git a/src/structs/mat.rs b/src/structs/mat.rs index baf2c1c5..6bafa927 100644 --- a/src/structs/mat.rs +++ b/src/structs/mat.rs @@ -4,7 +4,7 @@ use std::cast; use std::num::{One, Zero}; -use std::cmp::ApproxEq; +use traits::operations::ApproxEq; use std::vec::{VecIterator, VecMutIterator}; use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Vec1MulRhs, Vec4MulRhs, Vec5MulRhs, Vec6MulRhs}; diff --git a/src/structs/mat_macros.rs b/src/structs/mat_macros.rs index 61b745af..8abf00c5 100644 --- a/src/structs/mat_macros.rs +++ b/src/structs/mat_macros.rs @@ -449,23 +449,22 @@ macro_rules! approx_eq_impl( ($t: ident) => ( impl> ApproxEq for $t { #[inline] - fn approx_epsilon() -> N { - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") - // ApproxEq::::approx_epsilon() + fn approx_epsilon(_: Option<$t>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, other: &$t) -> bool { - let mut zip = self.iter().zip(other.iter()); + fn approx_eq(a: &$t, b: &$t) -> bool { + 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] - fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { - let mut zip = self.iter().zip(other.iter()); + fn approx_eq_eps(a: &$t, b: &$t, epsilon: &N) -> bool { + 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)) } } ) diff --git a/src/structs/rot.rs b/src/structs/rot.rs index e0684884..e7daa12f 100644 --- a/src/structs/rot.rs +++ b/src/structs/rot.rs @@ -7,7 +7,7 @@ use std::rand::{Rand, Rng}; use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Transform, ToHomogeneous, Norm, Cross}; 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::mat::{Mat2, Mat3, Mat4, Mat5}; @@ -20,7 +20,7 @@ pub struct Rot2 { priv submat: Mat2 } -impl> Rot2 { +impl> Rot2 { /// Builds a 2 dimensional rotation matrix from an angle in radian. pub fn new(angle: Vec1) -> Rot2 { let (sia, coa) = angle.x.sin_cos(); @@ -31,7 +31,7 @@ impl> Rot2 { } } -impl +impl Rotation> for Rot2 { #[inline] fn rotation(&self) -> Vec1 { @@ -69,7 +69,7 @@ Rotation> for Rot2 { } } -impl> Rand for Rot2 { +impl> Rand for Rot2 { #[inline] fn rand(rng: &mut R) -> Rot2 { Rot2::new(rng.gen()) @@ -99,7 +99,7 @@ pub struct Rot3 { } -impl Rot3 { +impl Rot3 { /// Builds a 3 dimensional rotation matrix from an axis and an angle. /// /// # Arguments @@ -140,7 +140,7 @@ impl Rot3 { } } -impl Rot3 { +impl Rot3 { /// 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` /// for that. @@ -180,7 +180,7 @@ impl Rot3 { } } -impl> +impl> Rotation> for Rot3 { #[inline] fn rotation(&self) -> Vec3 { @@ -245,7 +245,7 @@ Rotation> for Rot3 { } } -impl +impl Rand for Rot3 { #[inline] fn rand(rng: &mut R) -> Rot3 { @@ -309,7 +309,7 @@ impl AbsoluteRotate> for Rot4 { } } -impl +impl Rotation> for Rot4 { #[inline] fn rotation(&self) -> Vec4 { diff --git a/src/structs/rot_macros.rs b/src/structs/rot_macros.rs index 03353be2..b0d341f0 100644 --- a/src/structs/rot_macros.rs +++ b/src/structs/rot_macros.rs @@ -56,7 +56,7 @@ macro_rules! dim_impl( macro_rules! rotation_matrix_impl( ($t: ident, $tlv: ident, $tav: ident) => ( - impl + Algebraic + Trigonometric + Num + Clone> + impl + Real + Real + Num + Clone> RotationMatrix<$tlv, $tav, $t> for $t { #[inline] fn to_rot_mat(&self) -> $t { @@ -201,19 +201,18 @@ macro_rules! approx_eq_impl( ($t: ident) => ( impl> ApproxEq for $t { #[inline] - fn approx_epsilon() -> N { - // ApproxEq::::approx_epsilon() - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") + fn approx_epsilon(_: Option<$t>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, other: &$t) -> bool { - self.submat.approx_eq(&other.submat) + fn approx_eq(a: &$t, b: &$t) -> bool { + ApproxEq::approx_eq(&a.submat, &b.submat) } #[inline] - fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { - self.submat.approx_eq_eps(&other.submat, epsilon) + fn approx_eq_eps(a: &$t, b: &$t, epsilon: &N) -> bool { + ApproxEq::approx_eq_eps(&a.submat, &b.submat, epsilon) } } ) diff --git a/src/structs/spec/vec.rs b/src/structs/spec/vec.rs index 394d1570..38a16d08 100644 --- a/src/structs/spec/vec.rs +++ b/src/structs/spec/vec.rs @@ -91,7 +91,7 @@ impl> Basis for Vec2 { } } -impl Basis for Vec3 { +impl Basis for Vec3 { #[inline(always)] fn canonical_basis(f: |Vec3| -> bool) { if !f(Vec3::new(One::one(), Zero::zero(), Zero::zero())) { return }; diff --git a/src/structs/spec/vec0.rs b/src/structs/spec/vec0.rs index 01d2af76..384d7f64 100644 --- a/src/structs/spec/vec0.rs +++ b/src/structs/spec/vec0.rs @@ -1,8 +1,8 @@ use std::cast; -use std::num::{Zero, One, Algebraic, Bounded}; +use std::num::{Zero, One, Real, Bounded}; use std::vec::{VecIterator, VecMutIterator}; use std::iter::{Iterator, FromIterator}; -use std::cmp::ApproxEq; +use traits::operations::ApproxEq; use traits::structure::{Iterable, IterableMut, Indexable, Basis, Dim}; use traits::geometry::{Translation, Dot, Norm}; use structs::vec; @@ -159,7 +159,7 @@ impl + Neg> Translation> for vec::Vec0 { } } -impl Norm for vec::Vec0 { +impl Norm for vec::Vec0 { #[inline] fn sqnorm(_: &vec::Vec0) -> N { Zero::zero() @@ -183,18 +183,17 @@ impl Norm for vec::Vec0 { impl> ApproxEq for vec::Vec0 { #[inline] - fn approx_epsilon() -> N { - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") - // ApproxEq::::approx_epsilon() + fn approx_epsilon(_: Option>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, _: &vec::Vec0) -> bool { + fn approx_eq(_: &vec::Vec0, _: &vec::Vec0) -> bool { true } #[inline] - fn approx_eq_eps(&self, _: &vec::Vec0, _: &N) -> bool { + fn approx_eq_eps(_: &vec::Vec0, _: &vec::Vec0, _: &N) -> bool { true } } diff --git a/src/structs/vec.rs b/src/structs/vec.rs index 79d9fcd1..d0c3e54a 100644 --- a/src/structs/vec.rs +++ b/src/structs/vec.rs @@ -3,10 +3,10 @@ #[allow(missing_doc)]; // we allow missing to avoid having to document the vector components. use std::cast; -use std::num::{Zero, One, Algebraic, Bounded}; +use std::num::{Zero, One, Real, Bounded}; use std::vec::{VecIterator, VecMutIterator}; use std::iter::{Iterator, FromIterator}; -use std::cmp::ApproxEq; +use traits::operations::ApproxEq; use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm, Translation, Translate}; diff --git a/src/structs/vec_macros.rs b/src/structs/vec_macros.rs index fb15ddea..cb0004eb 100644 --- a/src/structs/vec_macros.rs +++ b/src/structs/vec_macros.rs @@ -223,7 +223,7 @@ macro_rules! container_impl( macro_rules! basis_impl( ($t: ident, $trhs: ident, $dim: expr) => ( - impl + $trhs>> Basis for $t { + impl + $trhs>> Basis for $t { #[inline] fn canonical_basis(f: |$t| -> bool) { for i in range(0u, $dim) { @@ -262,7 +262,7 @@ macro_rules! basis_impl( 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); if !f(new_element.clone()) { return }; @@ -433,7 +433,7 @@ macro_rules! translation_impl( macro_rules! norm_impl( ($t: ident, $comp0: ident $(,$compN: ident)*) => ( - impl Norm for $t { + impl Norm for $t { #[inline] fn sqnorm(v: &$t) -> N { Dot::dot(v, v) @@ -496,19 +496,20 @@ macro_rules! approx_eq_impl( ($t: ident, $comp0: ident $(,$compN: ident)*) => ( impl> ApproxEq for $t { #[inline] - fn approx_epsilon() -> N { - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") - // ApproxEq::::approx_epsilon() + fn approx_epsilon(_: Option<$t>) -> N { + ApproxEq::approx_epsilon(None::) } #[inline] - fn approx_eq(&self, other: &$t) -> bool { - self.$comp0.approx_eq(&other.$comp0) $(&& self.$compN.approx_eq(&other.$compN))* + fn approx_eq(a: &$t, b: &$t) -> bool { + ApproxEq::approx_eq(&a.$comp0, &b.$comp0) + $(&& ApproxEq::approx_eq(&a.$compN, &b.$compN))* } #[inline] - fn approx_eq_eps(&self, other: &$t, eps: &N) -> bool { - self.$comp0.approx_eq_eps(&other.$comp0, eps) $(&& self.$compN.approx_eq_eps(&other.$compN, eps))* + fn approx_eq_eps(a: &$t, b: &$t, eps: &N) -> bool { + ApproxEq::approx_eq_eps(&a.$comp0, &b.$comp0, eps) + $(&& ApproxEq::approx_eq_eps(&a.$compN, &b.$compN, eps))* } } ) diff --git a/src/tests/mat.rs b/src/tests/mat.rs index b190a884..ff423aa0 100644 --- a/src/tests/mat.rs +++ b/src/tests/mat.rs @@ -1,6 +1,5 @@ use std::num::{Real, abs}; use std::rand::random; -use std::cmp::ApproxEq; use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable}; use na; @@ -9,7 +8,7 @@ macro_rules! test_inv_mat_impl( 10000.times(|| { 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 = na::one(); let ang = Vec1::new(abs::(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::(random()) % Real::pi()); 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] @@ -152,7 +151,7 @@ fn test_cov_dmat() { ] ); - assert!(na::cov(&mat).approx_eq(&expected)); + assert!(na::approx_eq(&na::cov(&mat), &expected)); } #[test] diff --git a/src/tests/vec.rs b/src/tests/vec.rs index bcd74f65..a8829f4d 100644 --- a/src/tests/vec.rs +++ b/src/tests/vec.rs @@ -1,5 +1,4 @@ use std::rand::{random}; -use std::cmp::ApproxEq; use na::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6}; use na::{Mat3, Iterable, IterableMut}; // FIXME: get rid of that use na; @@ -28,7 +27,7 @@ macro_rules! test_commut_dot_impl( let v1 : $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 n : $n = random(); - assert!(((v1 * n) / n).approx_eq(&v1)); - assert!(((v1 / n) * n).approx_eq(&v1)); - assert!(((v1 - n) + n).approx_eq(&v1)); - assert!(((v1 + n) - n).approx_eq(&v1)); + assert!(na::approx_eq(&((v1 * n) / n), &v1)); + assert!(na::approx_eq(&((v1 / n) * n), &v1)); + assert!(na::approx_eq(&((v1 - n) + n), &v1)); + assert!(na::approx_eq(&((v1 + n) - n), &v1)); let mut v1 : $t = random(); let v0 : $t = v1.clone(); @@ -51,7 +50,7 @@ macro_rules! test_scalar_op_impl( 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(|| { na::canonical_basis(|e1: $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 }); - assert!(na::norm(&e1).approx_eq(&na::one())); + assert!(na::approx_eq(&na::norm(&e1), &na::one())); true }) @@ -82,12 +81,12 @@ macro_rules! test_subspace_basis_impl( na::orthonormal_subspace_basis(&v1, |e1| { // 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 - assert!(na::norm(&e1).approx_eq(&na::one())); + assert!(na::approx_eq(&na::norm(&e1), &na::one())); // check vectors form an ortogonal basis 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 }); @@ -105,8 +104,8 @@ fn test_cross_vec3() { let v2 : Vec3 = random(); let v3 : Vec3 = na::cross(&v1, &v2); - assert!(na::dot(&v3, &v2).approx_eq(&na::zero())); - assert!(na::dot(&v3, &v1).approx_eq(&na::zero())); + assert!(na::approx_eq(&na::dot(&v3, &v2), &na::zero())); + assert!(na::approx_eq(&na::dot(&v3, &v1), &na::zero())); }) } diff --git a/src/traits/geometry.rs b/src/traits/geometry.rs index 1bf295e0..333f1afd 100644 --- a/src/traits/geometry.rs +++ b/src/traits/geometry.rs @@ -218,7 +218,7 @@ pub trait Dot { } /// Traits of objects having an euclidian norm. -pub trait Norm { +pub trait Norm { /// Computes the norm of `self`. #[inline] fn norm(v: &Self) -> N { diff --git a/src/traits/mod.rs b/src/traits/mod.rs index b41c4fa5..6f25caed 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -4,11 +4,11 @@ pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneou Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous, 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}; -pub use self::operations::{Absolute, Cov, Inv, LMul, Mean, Outer, RMul, ScalarAdd, ScalarSub, - Transpose}; +pub use self::operations::{Absolute, ApproxEq, Cov, Inv, LMul, Mean, Outer, RMul, ScalarAdd, + ScalarSub, Transpose}; pub mod geometry; pub mod structure; diff --git a/src/traits/operations.rs b/src/traits/operations.rs index 1593ee2b..d4cfc25f 100644 --- a/src/traits/operations.rs +++ b/src/traits/operations.rs @@ -1,5 +1,42 @@ //! Low level operations on vectors and matrices. +/// Trait for testing approximate equality +pub trait ApproxEq { + /// Default epsilon for approximation. + fn approx_epsilon(unused_self: Option) -> 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::)) + } +} + +impl ApproxEq for f32 { + #[inline] + fn approx_epsilon(_: Option) -> f32 { + 1.0e-6 + } + + #[inline] + fn approx_eq_eps(a: &f32, b: &f32, epsilon: &f32) -> bool { + (*a - *b).abs() < *epsilon + } +} + +impl ApproxEq for f64 { + #[inline] + fn approx_epsilon(_: Option) -> 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. /// This is useful if the object does not have the same type as its absolute value. diff --git a/src/traits/structure.rs b/src/traits/structure.rs index 1c35c4a6..deed3c9a 100644 --- a/src/traits/structure.rs +++ b/src/traits/structure.rs @@ -27,8 +27,8 @@ pub trait Vec: Dim + Sub + Add + Neg + Zero + E + Div + Dot { } -/// Trait of vector with components implementing the `Algebraic` trait. -pub trait AlgebraicVec: Vec + Norm { +/// Trait of vector with components implementing the `Real` trait. +pub trait RealVec: Vec + Norm { } /// Trait grouping uncommon, low-level and borderline (from the mathematical point of view) @@ -39,19 +39,19 @@ pub trait VecExt: Vec + Indexable + Iterable + /// Trait grouping uncommon, low-level and borderline (from the mathematical point of view) /// operations on vectors. -pub trait AlgebraicVecExt: AlgebraicVec + VecExt + Basis + Round { } +pub trait RealVecExt: RealVec + VecExt + Basis + Round { } impl + Add + Neg + Zero + Eq + Mul + Div + Dot> Vec for V { } -impl + Norm> AlgebraicVec for V { } +impl + Norm> RealVec for V { } impl + Indexable + Iterable + UniformSphereSample + ScalarAdd + ScalarSub + Bounded + Orderable> VecExt for V { } -impl + VecExt + Basis + Round> AlgebraicVecExt for V { } +impl + VecExt + Basis + Round> RealVecExt for V { } // FIXME: return an iterator instead /// Traits of objects which can form a basis (typically vectors).