diff --git a/README.md b/README.md index 652144a..11125f9 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,13 @@ The library provides: - square matrices: `Mat2`, `Mat3`, `Mat4` - a quaternion type: `Quat` - rotation matrices: `Rot2`, `Rot3` -- rotations: `Euler`, `AxisAngle` - angle units: `Rad`, `Deg` - points: `Point2`, `Point3` - rays: `Ray2`, `Ray3` -- plane: `Plane` +- a plane: `Plane` - perspective projections: `Perspective`, `PerspectiveFov`, `Ortho` - a view frustum: `Frustrum` +- spatial transformations: `AffineMatrix3`, `Transform3D` - axis-aligned bounding boxes: `Aabb2`, `Aabb3` - oriented bounding boxes: `Obb2`, `Obb3` - collision primitives: `Sphere`, `Cylinder` diff --git a/src/cgmath/angle.rs b/src/cgmath/angle.rs index 9e23bfe..6fee689 100644 --- a/src/cgmath/angle.rs +++ b/src/cgmath/angle.rs @@ -21,6 +21,8 @@ pub use std::num::{asinh, acosh, atanh}; use std::fmt; use std::num::{Zero, zero, cast}; +use approx::ApproxEq; + #[deriving(Clone, Eq, Ord, Zero)] pub struct Rad { s: S } #[deriving(Clone, Eq, Ord, Zero)] pub struct Deg { s: S } @@ -126,7 +128,8 @@ pub trait Angle #[inline] pub fn bisect>(a: A, b: A) -> A { a.bisect(b) } -impl Rad { +impl> +Rad { #[inline] pub fn zero() -> Rad { zero() } #[inline] pub fn full_turn() -> Rad { Angle::full_turn() } #[inline] pub fn turn_div_2() -> Rad { Angle::turn_div_2() } @@ -135,7 +138,8 @@ impl Rad { #[inline] pub fn turn_div_6() -> Rad { Angle::turn_div_6() } } -impl Deg { +impl> +Deg { #[inline] pub fn zero() -> Deg { zero() } #[inline] pub fn full_turn() -> Deg { Angle::full_turn() } #[inline] pub fn turn_div_2() -> Deg { Angle::turn_div_2() } @@ -144,24 +148,28 @@ impl Deg { #[inline] pub fn turn_div_6() -> Deg { Angle::turn_div_6() } } -impl Equiv> for Rad { +impl> +Equiv> for Rad { fn equiv(&self, other: &Rad) -> bool { self.normalize() == other.normalize() } } -impl Equiv> for Deg { +impl> +Equiv> for Deg { fn equiv(&self, other: &Deg) -> bool { self.normalize() == other.normalize() } } -impl Angle for Rad { +impl> +Angle for Rad { #[inline] fn from>(theta: A) -> Rad { theta.to_rad() } #[inline] fn full_turn() -> Rad { rad(Real::two_pi()) } } -impl Angle for Deg { +impl> +Angle for Deg { #[inline] fn from>(theta: A) -> Deg { theta.to_deg() } #[inline] fn full_turn() -> Deg { deg(cast(360).unwrap()) } } @@ -183,38 +191,18 @@ impl Angle for Deg { impl ToStr for Rad { fn to_str(&self) -> ~str { format!("{} rad", self.s) } } impl ToStr for Deg { fn to_str(&self) -> ~str { format!("{}°", self.s) } } -impl ApproxEq for Rad { +impl> +ApproxEq for Rad { #[inline] - fn approx_epsilon() -> S { - // TODO: fix this after static methods are fixed in rustc - fail!(~"Doesn't work!"); - } - - #[inline] - fn approx_eq(&self, other: &Rad) -> bool { - self.s.approx_eq(&other.s) - } - - #[inline] - fn approx_eq_eps(&self, other: &Rad, approx_epsilon: &S) -> bool { - self.s.approx_eq_eps(&other.s, approx_epsilon) + fn approx_eq_eps(&self, other: &Rad, epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, epsilon) } } -impl ApproxEq for Deg { +impl> +ApproxEq for Deg { #[inline] - fn approx_epsilon() -> S { - // TODO: fix this after static methods are fixed in rustc - fail!(~"Doesn't work!"); - } - - #[inline] - fn approx_eq(&self, other: &Deg) -> bool { - self.s.approx_eq(&other.s) - } - - #[inline] - fn approx_eq_eps(&self, other: &Deg, approx_epsilon: &S) -> bool { - self.s.approx_eq_eps(&other.s, approx_epsilon) + fn approx_eq_eps(&self, other: &Deg, epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, epsilon) } } diff --git a/src/cgmath/approx.rs b/src/cgmath/approx.rs new file mode 100644 index 0000000..fa62e4f --- /dev/null +++ b/src/cgmath/approx.rs @@ -0,0 +1,77 @@ +// 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 std::num; + +use array::Array; +use matrix::{Mat2, Mat3, Mat4}; +use point::{Point2, Point3}; +use quaternion::Quat; +use vector::{Vec2, Vec3, Vec4}; + +pub trait ApproxEq { + fn approx_epsilon(_hack: Option) -> T { + num::cast(1.0e-5).unwrap() + } + + fn approx_eq(&self, other: &Self) -> bool { + let eps: T = ApproxEq::approx_epsilon(None::); + self.approx_eq_eps(other, &eps) + } + + fn approx_eq_eps(&self, other: &Self, epsilon: &T) -> bool; +} + + +macro_rules! approx_simple( + ($S:ident) => ( + impl ApproxEq<$S> for $S { + #[inline] + fn approx_eq_eps(&self, other: &$S, epsilon: &$S) -> bool { + num::abs(*self - *other) < *epsilon + } + } + ) +) + +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 Mat2) +approx_array!(impl Mat3) +approx_array!(impl Mat4) + +approx_array!(impl Quat) + +approx_array!(impl Vec2) +approx_array!(impl Vec3) +approx_array!(impl Vec4) + +approx_array!(impl Point2) +approx_array!(impl Point3) + diff --git a/src/cgmath/array.rs b/src/cgmath/array.rs index 0bae131..4460240 100644 --- a/src/cgmath/array.rs +++ b/src/cgmath/array.rs @@ -123,26 +123,3 @@ macro_rules! gen_each_mut( (_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)); }); ) -macro_rules! approx_eq( - (impl<$S:ident> $Self:ty) => ( - impl<$S: Clone + ApproxEq<$S>> ApproxEq<$S> for $Self { - #[inline] - fn approx_epsilon() -> $S { - // 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)) - } - } - ) -) diff --git a/src/cgmath/frustum.rs b/src/cgmath/frustum.rs index 4593f56..6de6a99 100644 --- a/src/cgmath/frustum.rs +++ b/src/cgmath/frustum.rs @@ -15,6 +15,7 @@ //! View frustum for visibility determination +use approx::ApproxEq; use matrix::{Matrix, Mat4}; use plane::Plane; use point::Point3; @@ -30,7 +31,8 @@ pub struct Frustum { far: Plane, } -impl Frustum { +impl> +Frustum { /// Constructs a frustum pub fn new(left: Plane, right: Plane, bottom: Plane, top: Plane, diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index 500e83e..726a805 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[pkgid="cgmath#0.1"]; +#[crate_id="cgmath#0.1"]; +#[crate_type = "lib"]; #[comment = "A mathematics library for computer graphics."]; #[license = "ASL2"]; -#[crate_type = "lib"]; #[feature(globs)]; #[feature(macro_rules)]; @@ -42,4 +42,5 @@ pub mod intersect; pub mod obb; pub mod sphere; +pub mod approx; pub mod ptr; diff --git a/src/cgmath/matrix.rs b/src/cgmath/matrix.rs index fd2be4f..421a561 100644 --- a/src/cgmath/matrix.rs +++ b/src/cgmath/matrix.rs @@ -18,6 +18,7 @@ use std::num::{Zero, zero, One, one, cast, sqrt}; use angle::{Rad, sin, cos, sin_cos}; +use approx::ApproxEq; use array::{Array, build}; use point::{Point, Point3}; use quaternion::{Quat, ToQuat}; @@ -36,9 +37,6 @@ pub struct Mat3 { x: Vec3, y: Vec3, z: Vec3 } #[deriving(Clone, Eq, Zero)] pub struct Mat4 { x: Vec4, y: Vec4, z: Vec4, w: Vec4 } -approx_eq!(impl Mat2) -approx_eq!(impl Mat3) -approx_eq!(impl Mat4) impl Mat2 { #[inline] @@ -114,7 +112,8 @@ impl Mat3 { } } -impl Mat3 { +impl> +Mat3 { pub fn look_at(dir: &Vec3, up: &Vec3) -> Mat3 { let dir = dir.normalize(); let side = dir.cross(&up.normalize()); @@ -223,7 +222,8 @@ impl Mat4 { } } -impl Mat4 { +impl> +Mat4 { pub fn look_at(eye: &Point3, center: &Point3, up: &Vec3) -> Mat4 { let f = center.sub_p(eye).normalize(); let s = f.cross(up).normalize(); @@ -246,7 +246,7 @@ array!(impl Mat4 -> [Vec4, ..4] _4) pub trait Matrix < - S: Float, Slice, + S: Float + ApproxEq, Slice, V: Clone + Vector + Array, VSlice > : Array @@ -362,7 +362,7 @@ impl Neg> for Mat2 { #[inline] fn neg(&self) -> Mat2 { b impl Neg> for Mat3 { #[inline] fn neg(&self) -> Mat3 { build(|i| self.i(i).neg()) } } impl Neg> for Mat4 { #[inline] fn neg(&self) -> Mat4 { build(|i| self.i(i).neg()) } } -impl +impl> Matrix, ..2], Vec2, [S, ..2]> for Mat2 { @@ -411,7 +411,7 @@ for Mat2 } } -impl +impl> Matrix, ..3], Vec3, [S, ..3]> for Mat3 { @@ -484,7 +484,7 @@ macro_rules! dot_mat4( (*$A.cr(3, $I)) * (*$B.cr($J, 3)) )) -impl +impl> Matrix, ..4], Vec4, [S, ..4]> for Mat4 { @@ -617,7 +617,8 @@ pub trait ToMat2 { fn to_mat2(&self) -> Mat2; } pub trait ToMat3 { fn to_mat3(&self) -> Mat3; } pub trait ToMat4 { fn to_mat4(&self) -> Mat4; } -impl ToMat3 for Mat2 { +impl> +ToMat3 for Mat2 { /// Clone the elements of a 2-dimensional matrix into the top corner of a /// 3-dimensional identity matrix. fn to_mat3(&self) -> Mat3 { @@ -627,7 +628,8 @@ impl ToMat3 for Mat2 { } } -impl ToMat4 for Mat2 { +impl> +ToMat4 for Mat2 { /// Clone the elements of a 2-dimensional matrix into the top corner of a /// 4-dimensional identity matrix. fn to_mat4(&self) -> Mat4 { @@ -638,7 +640,8 @@ impl ToMat4 for Mat2 { } } -impl ToMat4 for Mat3 { +impl> +ToMat4 for Mat3 { /// Clone the elements of a 3-dimensional matrix into the top corner of a /// 4-dimensional identity matrix. fn to_mat4(&self) -> Mat4 { @@ -649,7 +652,8 @@ impl ToMat4 for Mat3 { } } -impl ToQuat for Mat3 { +impl> +ToQuat for Mat3 { /// Convert the matrix to a quaternion fn to_quat(&self) -> Quat { // http://www.cs.ucr.edu/~vbz/resources/Quatut.pdf diff --git a/src/cgmath/plane.rs b/src/cgmath/plane.rs index 25d31c5..5b3f392 100644 --- a/src/cgmath/plane.rs +++ b/src/cgmath/plane.rs @@ -17,6 +17,7 @@ use std::cast::transmute; use std::fmt; use std::num::Zero; +use approx::ApproxEq; use intersect::Intersect; use point::{Point, Point3}; use ray::Ray3; @@ -45,7 +46,8 @@ pub struct Plane { d: S, } -impl Plane { +impl> +Plane { /// Construct a plane from a normal vector and a scalar distance pub fn new(n: Vec3, d: S) -> Plane { Plane { n: n, d: d } @@ -110,23 +112,12 @@ impl Intersect>> for (Plane, Plane, Plane) { } } -impl ApproxEq for Plane { +impl> +ApproxEq for Plane { #[inline] - fn approx_epsilon() -> S { - // TODO: fix this after static methods are fixed in rustc - fail!(~"Doesn't work!"); - } - - #[inline] - fn approx_eq(&self, other: &Plane) -> bool { - self.n.approx_eq(&other.n) && - self.d.approx_eq(&other.d) - } - - #[inline] - fn approx_eq_eps(&self, other: &Plane, approx_epsilon: &S) -> bool { - self.n.approx_eq_eps(&other.n, approx_epsilon) && - self.d.approx_eq_eps(&other.d, approx_epsilon) + fn approx_eq_eps(&self, other: &Plane, epsilon: &S) -> bool { + self.n.approx_eq_eps(&other.n, epsilon) && + self.d.approx_eq_eps(&other.d, epsilon) } } diff --git a/src/cgmath/point.rs b/src/cgmath/point.rs index 65b2adf..7f481d3 100644 --- a/src/cgmath/point.rs +++ b/src/cgmath/point.rs @@ -31,8 +31,6 @@ pub struct Point2 { x: S, y: S } #[deriving(Eq, Zero, Clone)] pub struct Point3 { x: S, y: S, z: S } -approx_eq!(impl Point2) -approx_eq!(impl Point3) impl Point2 { #[inline] diff --git a/src/cgmath/projection.rs b/src/cgmath/projection.rs index 3eb305f..3a541cc 100644 --- a/src/cgmath/projection.rs +++ b/src/cgmath/projection.rs @@ -16,6 +16,7 @@ use std::num::{zero, one, cast}; use angle::{Angle, tan, cot}; +use approx::ApproxEq; use frustum::Frustum; use matrix::{Mat4, ToMat4}; use plane::Plane; @@ -93,7 +94,8 @@ impl> PerspectiveFov { } } -impl> Projection for PerspectiveFov { +impl, A: Angle> +Projection for PerspectiveFov { fn to_frustum(&self) -> Frustum { // TODO: Could this be faster? Frustum::from_mat4(self.to_mat4()) @@ -149,7 +151,8 @@ pub struct Perspective { near: S, far: S, } -impl Projection for Perspective { +impl> +Projection for Perspective { fn to_frustum(&self) -> Frustum { // TODO: Could this be faster? Frustum::from_mat4(self.to_mat4()) @@ -199,7 +202,8 @@ pub struct Ortho { near: S, far: S, } -impl Projection for Ortho { +impl> +Projection for Ortho { fn to_frustum(&self) -> Frustum { Frustum { left: Plane::from_abcd( one::(), zero::(), zero::(), self.left.clone()), diff --git a/src/cgmath/quaternion.rs b/src/cgmath/quaternion.rs index 0e94329..8be7640 100644 --- a/src/cgmath/quaternion.rs +++ b/src/cgmath/quaternion.rs @@ -17,6 +17,7 @@ use std::fmt; use std::num::{zero, one, cast, sqrt}; use angle::{Angle, Rad, acos, cos, sin, sin_cos}; +use approx::ApproxEq; use array::{Array, build}; use matrix::{Mat3, ToMat3}; use vector::{Vec3, Vector, EuclideanVector}; @@ -26,13 +27,13 @@ use vector::{Vec3, Vector, EuclideanVector}; pub struct Quat { s: S, v: Vec3 } array!(impl Quat -> [S, ..4] _4) -approx_eq!(impl Quat) pub trait ToQuat { fn to_quat(&self) -> Quat; } -impl Quat { +impl> +Quat { /// Construct a new quaternion from one scalar component and three /// imaginary components #[inline] @@ -220,7 +221,8 @@ impl Quat { } } -impl Quat { +impl> +Quat { /// Spherical Linear Intoperlation /// /// Perform a spherical linear interpolation between the quaternion and @@ -265,7 +267,8 @@ impl Quat { } } -impl ToMat3 for Quat { +impl> +ToMat3 for Quat { /// Convert the quaternion to a 3 x 3 rotation matrix fn to_mat3(&self) -> Mat3 { let x2 = self.v.x + self.v.x; @@ -290,7 +293,8 @@ impl ToMat3 for Quat { } } -impl Neg> for Quat { +impl> +Neg> for Quat { #[inline] fn neg(&self) -> Quat { Quat::from_sv(-self.s, -self.v) diff --git a/src/cgmath/rotation.rs b/src/cgmath/rotation.rs index 7baed0c..9ad86d3 100644 --- a/src/cgmath/rotation.rs +++ b/src/cgmath/rotation.rs @@ -14,6 +14,7 @@ // limitations under the License. use angle::Rad; +use approx::ApproxEq; use array::Array; use matrix::Matrix; use matrix::{Mat2, ToMat2}; @@ -115,7 +116,8 @@ impl ToMat2 for Basis2 { fn to_mat2(&self) -> Mat2 { self.mat.clone() } } -impl Rotation, Point2> for Basis2 { +impl> +Rotation, Point2> for Basis2 { #[inline] fn identity() -> Basis2 { Basis2{ mat: Mat2::identity() } } @@ -139,25 +141,16 @@ impl Rotation, Point2> for Basis2 { fn invert_self(&mut self) { self.mat.invert_self(); } } -impl ApproxEq for Basis2 { +impl> +ApproxEq for Basis2 { #[inline] - fn approx_epsilon() -> S { - // TODO: fix this after static methods are fixed in rustc - fail!(~"Doesn't work!"); - } - - #[inline] - fn approx_eq(&self, other: &Basis2) -> bool { - self.mat.approx_eq(&other.mat) - } - - #[inline] - fn approx_eq_eps(&self, other: &Basis2, approx_epsilon: &S) -> bool { - self.mat.approx_eq_eps(&other.mat, approx_epsilon) + fn approx_eq_eps(&self, other: &Basis2, epsilon: &S) -> bool { + self.mat.approx_eq_eps(&other.mat, epsilon) } } -impl Rotation2 for Basis2 {} +impl> +Rotation2 for Basis2 {} /// A three-dimensional rotation matrix. /// @@ -170,7 +163,8 @@ pub struct Basis3 { priv mat: Mat3 } -impl Basis3 { +impl> +Basis3 { #[inline] pub fn look_at(dir: &Vec3, up: &Vec3) -> Basis3 { Basis3 { mat: Mat3::look_at(dir, up) } @@ -225,12 +219,14 @@ impl ToMat3 for Basis3 { fn to_mat3(&self) -> Mat3 { self.mat.clone() } } -impl ToQuat for Basis3 { +impl> +ToQuat for Basis3 { #[inline] fn to_quat(&self) -> Quat { self.mat.to_quat() } } -impl Rotation, Point3> for Basis3 { +impl> +Rotation, Point3> for Basis3 { #[inline] fn identity() -> Basis3 { Basis3{ mat: Mat3::identity() } } @@ -254,29 +250,21 @@ impl Rotation, Point3> for Basis3 { fn invert_self(&mut self) { self.mat.invert_self(); } } -impl ApproxEq for Basis3 { +impl> +ApproxEq for Basis3 { #[inline] - fn approx_epsilon() -> S { - // TODO: fix this after static methods are fixed in rustc - fail!(~"Doesn't work!"); - } - - #[inline] - fn approx_eq(&self, other: &Basis3) -> bool { - self.mat.approx_eq(&other.mat) - } - - #[inline] - fn approx_eq_eps(&self, other: &Basis3, approx_epsilon: &S) -> bool { - self.mat.approx_eq_eps(&other.mat, approx_epsilon) + fn approx_eq_eps(&self, other: &Basis3, epsilon: &S) -> bool { + self.mat.approx_eq_eps(&other.mat, epsilon) } } -impl Rotation3 for Basis3 {} +impl> +Rotation3 for Basis3 {} // Quaternion Rotation impls -impl ToBasis3 for Quat { +impl> +ToBasis3 for Quat { #[inline] fn to_rot3(&self) -> Basis3 { Basis3 { mat: self.to_mat3() } } } @@ -286,7 +274,8 @@ impl ToQuat for Quat { fn to_quat(&self) -> Quat { self.clone() } } -impl Rotation, Point3> for Quat { +impl> +Rotation, Point3> for Quat { #[inline] fn identity() -> Quat { Quat::identity() } @@ -306,4 +295,5 @@ impl Rotation, Point3> for Quat { fn invert_self(&mut self) { *self = self.invert() } } -impl Rotation3 for Quat {} +impl> +Rotation3 for Quat {} diff --git a/src/cgmath/transform.rs b/src/cgmath/transform.rs index 8e6fcef..eacfaf0 100644 --- a/src/cgmath/transform.rs +++ b/src/cgmath/transform.rs @@ -15,6 +15,7 @@ use std::{fmt,num}; +use approx::ApproxEq; use matrix::{Matrix, Mat4, ToMat4}; use point::{Point, Point3}; use ray::Ray; @@ -73,7 +74,7 @@ pub struct Decomposed { impl < - S: Float, + S: Float + ApproxEq, Slice, V: Vector, P: Point, @@ -129,7 +130,7 @@ pub trait Transform3 + ToMat4 {} -impl> +impl, R: Rotation3> ToMat4 for Decomposed, R> { fn to_mat4(&self) -> Mat4 { let mut m = self.rot.to_mat3().mul_s( self.scale.clone() ).to_mat4(); @@ -138,7 +139,7 @@ ToMat4 for Decomposed, R> { } } -impl> +impl, R: Rotation3> Transform3 for Decomposed,R> {} impl> @@ -155,7 +156,7 @@ pub struct AffineMatrix3 { mat: Mat4, } -impl +impl> Transform, Point3> for AffineMatrix3 { #[inline] fn identity() -> AffineMatrix3 { @@ -188,7 +189,7 @@ ToMat4 for AffineMatrix3 { #[inline] fn to_mat4(&self) -> Mat4 { self.mat.clone() } } -impl +impl> Transform3 for AffineMatrix3 {} @@ -201,4 +202,9 @@ impl Transform3D { pub fn new(scale: S, rot: Quat, disp: Vec3) -> Transform3D { Transform3D( Decomposed { scale: scale, rot: rot, disp: disp }) } + #[inline] + pub fn get<'a>(&'a self) -> &'a Decomposed,Quat> { + let &Transform3D(ref d) = self; + d + } } diff --git a/src/cgmath/vector.rs b/src/cgmath/vector.rs index 13aeeda..0860d0d 100644 --- a/src/cgmath/vector.rs +++ b/src/cgmath/vector.rs @@ -17,6 +17,7 @@ use std::fmt; use std::num::{Zero, zero, One, one, sqrt}; use angle::{Rad, atan2, acos}; +use approx::ApproxEq; use array::{Array, build}; /// A 2-dimensional vector. @@ -112,10 +113,6 @@ array!(impl Vec2 -> [S, ..2] _2) array!(impl Vec3 -> [S, ..3] _3) array!(impl Vec4 -> [S, ..4] _4) -approx_eq!(impl Vec2) -approx_eq!(impl Vec3) -approx_eq!(impl Vec4) - /// 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. @@ -215,7 +212,7 @@ impl Vec3 { /// 2-dimensional and 3-dimensional vectors. pub trait EuclideanVector < - S: Float, + S: Float + ApproxEq, Slice > : Vector @@ -286,21 +283,24 @@ pub trait EuclideanVector } } -impl EuclideanVector for Vec2 { +impl> +EuclideanVector for Vec2 { #[inline] fn angle(&self, other: &Vec2) -> Rad { atan2(self.perp_dot(other), self.dot(other)) } } -impl EuclideanVector for Vec3 { +impl> +EuclideanVector for Vec3 { #[inline] fn angle(&self, other: &Vec3) -> Rad { atan2(self.cross(other).length(), self.dot(other)) } } -impl EuclideanVector for Vec4 { +impl> +EuclideanVector for Vec4 { #[inline] fn angle(&self, other: &Vec4) -> Rad { acos(self.dot(other) / (self.length() * other.length())) diff --git a/src/tests/angle.rs b/src/tests/angle.rs index 19f7f60..f50e012 100644 --- a/src/tests/angle.rs +++ b/src/tests/angle.rs @@ -14,14 +14,15 @@ // limitations under the License. use cgmath::angle::*; +use cgmath::approx::ApproxEq; #[test] fn conv() { - assert_approx_eq!(deg(-5.0).to_rad().to_deg(), deg(-5.0)); - assert_approx_eq!(deg(30.0).to_rad().to_deg(), deg(30.0)); + assert!(deg(-5.0).to_rad().to_deg().approx_eq( °(-5.0) )); + assert!(deg(30.0).to_rad().to_deg().approx_eq( °(30.0) )); - assert_approx_eq!(rad(-5.0).to_deg().to_rad(), rad(-5.0)); - assert_approx_eq!(rad(30.0).to_deg().to_rad(), rad(30.0)); + assert!(rad(-5.0).to_deg().to_rad().approx_eq( &rad(-5.0) )); + assert!(rad(30.0).to_deg().to_rad().approx_eq( &rad(30.0) )); } #[test] diff --git a/src/tests/matrix.rs b/src/tests/matrix.rs index 82cfc71..8ba26cb 100644 --- a/src/tests/matrix.rs +++ b/src/tests/matrix.rs @@ -15,6 +15,7 @@ use cgmath::matrix::*; use cgmath::vector::*; +use cgmath::approx::ApproxEq; type float = f64; pub mod mat2 { @@ -287,11 +288,11 @@ fn test_invert() { // Mat4 assert!(Mat4::::identity().invert().unwrap().is_identity()); - assert_approx_eq!(mat4::C.invert().unwrap(), - Mat4::new( 5.0, -4.0, 1.0, 0.0, - -4.0, 8.0, -4.0, 0.0, - 4.0, -8.0, 4.0, 8.0, - -3.0, 4.0, 1.0, -8.0).mul_s(0.125)); + assert!(mat4::C.invert().unwrap().approx_eq(& + Mat4::new( 5.0, -4.0, 1.0, 0.0, + -4.0, 8.0, -4.0, 0.0, + 4.0, -8.0, 4.0, 8.0, + -3.0, 4.0, 1.0, -8.0).mul_s(0.125))); let mut mut_c = mat4::C; mut_c.invert_self(); assert_eq!(mut_c, mat4::C.invert().unwrap()); diff --git a/src/tests/point.rs b/src/tests/point.rs index b61954e..4b5f206 100644 --- a/src/tests/point.rs +++ b/src/tests/point.rs @@ -14,9 +14,10 @@ // limitations under the License. use cgmath::point::*; +use cgmath::approx::ApproxEq; #[test] fn test_homogeneous() { let p = Point3::new(1.0, 2.0, 3.0); - assert_approx_eq!(p, Point3::from_homogeneous( &p.to_homogeneous() )); + assert!(p.approx_eq( &Point3::from_homogeneous( &p.to_homogeneous() ) )); } diff --git a/src/tests/sphere.rs b/src/tests/sphere.rs index 2b76be2..a5a203e 100644 --- a/src/tests/sphere.rs +++ b/src/tests/sphere.rs @@ -2,6 +2,7 @@ use cgmath::sphere::*; use cgmath::point::*; use cgmath::vector::*; use cgmath::ray::*; +use cgmath::approx::ApproxEq; use cgmath::intersect::Intersect; use std::num; @@ -13,7 +14,7 @@ fn test_intersection() { let r2 = Ray::new(Point3::new(1f64, 0f64, 5f64), Vec3::new(0f64, 0f64, -5f64).normalize()); let r3 = Ray::new(Point3::new(2f64, 0f64, 5f64), Vec3::new(0f64, 0f64, -5f64).normalize()); assert_eq!((sphere,r0).intersection(), Some(Point3::new(0f64, 0f64, 1f64))); - assert_approx_eq!((sphere,r1).intersection().unwrap(), Point3::new(num::cos(1f64), 0f64, num::sin(1f64))); + assert!((sphere,r1).intersection().unwrap().approx_eq( &Point3::new(num::cos(1f64), 0f64, num::sin(1f64)) )); assert_eq!((sphere,r2).intersection(), Some(Point3::new(1f64, 0f64, 0f64))); assert_eq!((sphere,r3).intersection(), None); } diff --git a/src/tests/transform.rs b/src/tests/transform.rs index be81359..1ca465c 100644 --- a/src/tests/transform.rs +++ b/src/tests/transform.rs @@ -16,12 +16,13 @@ use cgmath::quaternion::*; use cgmath::transform::*; use cgmath::vector::*; +use cgmath::approx::ApproxEq; #[test] fn test_invert() { let v = Vec3::new(1.0, 2.0, 3.0); - let t = Transform3D::new( 1.5, Quat::new(0.5,0.5,0.5,0.5), Vec3::new(6.0,-7.0,8.0) ); - let ti = t.invert().expect("Expected successful inversion"); - let vt = t.transform_vec( &v ); - assert_approx_eq!(v, ti.transform_vec( &vt )); + let t = Transform3D::new(1.5, Quat::new(0.5,0.5,0.5,0.5), Vec3::new(6.0,-7.0,8.0)); + let ti = t.get().invert().expect("Expected successful inversion"); + let vt = t.get().transform_vec( &v ); + assert!(v.approx_eq( &ti.transform_vec( &vt ) )); } diff --git a/src/tests/vector.rs b/src/tests/vector.rs index 457b4c2..029308b 100644 --- a/src/tests/vector.rs +++ b/src/tests/vector.rs @@ -15,6 +15,7 @@ use cgmath::angle::*; use cgmath::vector::*; +use cgmath::approx::ApproxEq; #[test] fn test_from_value() { @@ -136,23 +137,23 @@ mod test_length { #[test] fn test_angle() { - assert_approx_eq!(Vec2::new(1.0, 0.0).angle(&Vec2::new(0.0, 1.0)), rad(Real::frac_pi_2())); - assert_approx_eq!(Vec2::new(10.0, 0.0).angle(&Vec2::new(0.0, 5.0)), rad(Real::frac_pi_2())); - assert_approx_eq!(Vec2::new(-1.0, 0.0).angle(&Vec2::new(0.0, 1.0)), -rad(Real::frac_pi_2())); + assert!(Vec2::new(1.0, 0.0).angle(&Vec2::new(0.0, 1.0)).approx_eq( &rad(Real::frac_pi_2()) )); + assert!(Vec2::new(10.0, 0.0).angle(&Vec2::new(0.0, 5.0)).approx_eq( &rad(Real::frac_pi_2()) )); + assert!(Vec2::new(-1.0, 0.0).angle(&Vec2::new(0.0, 1.0)).approx_eq( &-rad(Real::frac_pi_2()) )); - assert_approx_eq!(Vec3::new(1.0, 0.0, 1.0).angle(&Vec3::new(1.0, 1.0, 0.0)), rad(Real::frac_pi_3())); - assert_approx_eq!(Vec3::new(10.0, 0.0, 10.0).angle(&Vec3::new(5.0, 5.0, 0.0)), rad(Real::frac_pi_3())); - assert_approx_eq!(Vec3::new(-1.0, 0.0, -1.0).angle(&Vec3::new(1.0, -1.0, 0.0)), rad(2.0 * Real::frac_pi_3())); + assert!(Vec3::new(1.0, 0.0, 1.0).angle(&Vec3::new(1.0, 1.0, 0.0)).approx_eq( &rad(Real::frac_pi_3()) )); + assert!(Vec3::new(10.0, 0.0, 10.0).angle(&Vec3::new(5.0, 5.0, 0.0)).approx_eq( &rad(Real::frac_pi_3()) )); + assert!(Vec3::new(-1.0, 0.0, -1.0).angle(&Vec3::new(1.0, -1.0, 0.0)).approx_eq( &rad(2.0 * Real::frac_pi_3()) )); - assert_approx_eq!(Vec4::new(1.0, 0.0, 1.0, 0.0).angle(&Vec4::new(0.0, 1.0, 0.0, 1.0)), rad(Real::frac_pi_2())); - assert_approx_eq!(Vec4::new(10.0, 0.0, 10.0, 0.0).angle(&Vec4::new(0.0, 5.0, 0.0, 5.0)), rad(Real::frac_pi_2())); - assert_approx_eq!(Vec4::new(-1.0, 0.0, -1.0, 0.0).angle(&Vec4::new(0.0, 1.0, 0.0, 1.0)), rad(Real::frac_pi_2())); + assert!(Vec4::new(1.0, 0.0, 1.0, 0.0).angle(&Vec4::new(0.0, 1.0, 0.0, 1.0)).approx_eq( &rad(Real::frac_pi_2()) )); + assert!(Vec4::new(10.0, 0.0, 10.0, 0.0).angle(&Vec4::new(0.0, 5.0, 0.0, 5.0)).approx_eq( &rad(Real::frac_pi_2()) )); + assert!(Vec4::new(-1.0, 0.0, -1.0, 0.0).angle(&Vec4::new(0.0, 1.0, 0.0, 1.0)).approx_eq( &rad(Real::frac_pi_2()) )); } #[test] fn test_normalize() { // TODO: test normalize_to, normalize_sel.0, and normalize_self_to - assert_approx_eq!(Vec2::new(3.0, 4.0).normalize(), Vec2::new(3.0/5.0, 4.0/5.0)); - assert_approx_eq!(Vec3::new(2.0, 3.0, 6.0).normalize(), Vec3::new(2.0/7.0, 3.0/7.0, 6.0/7.0)); - assert_approx_eq!(Vec4::new(1.0, 2.0, 4.0, 10.0).normalize(), Vec4::new(1.0/11.0, 2.0/11.0, 4.0/11.0, 10.0/11.0)); + assert!(Vec2::new(3.0, 4.0).normalize().approx_eq( &Vec2::new(3.0/5.0, 4.0/5.0) )); + assert!(Vec3::new(2.0, 3.0, 6.0).normalize().approx_eq( &Vec3::new(2.0/7.0, 3.0/7.0, 6.0/7.0) )); + assert!(Vec4::new(1.0, 2.0, 4.0, 10.0).normalize().approx_eq( &Vec4::new(1.0/11.0, 2.0/11.0, 4.0/11.0, 10.0/11.0) )); }