diff --git a/Makefile b/Makefile index 3b5ede3e..698ee0b8 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,13 @@ nalgebra_doc_path=doc all: mkdir -p $(nalgebra_lib_path) rustc src/lib.rs --out-dir $(nalgebra_lib_path) --opt-level 3 + rustc src/lib.rs --out-dir $(nalgebra_lib_path) --crate-type dylib --opt-level 3 test: mkdir -p $(nalgebra_lib_path) rustc --test src/lib.rs --opt-level 3 -o test~ && ./test~ rm test~ - # FIXME: - # rustdoc --test -L lib src/lib.rs + rustdoc --test -L lib src/lib.rs bench: rustc --test src/lib.rs --opt-level 3 -o bench~ && ./bench~ --bench diff --git a/src/lib.rs b/src/lib.rs index 04a8c2fe..4a102114 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ out-of-place modifications. * You can import the whole prelude using: -``` +```.ignore use nalgebra::na::*; ``` @@ -26,7 +26,7 @@ The preferred way to use **nalgebra** is to import types and traits explicitly, free-functions using the `na::` prefix: ```.rust -extern mod nalgebra; +extern crate nalgebra; use nalgebra::na::{Vec3, Rot3, Rotation}; use nalgebra::na; @@ -57,7 +57,7 @@ and keeps an optimized set of tools for computational graphics and physics. Thos For example, the following works: ```rust -extern mod nalgebra; +extern crate nalgebra; use nalgebra::na::{Vec3, Mat3}; use nalgebra::na; @@ -76,13 +76,15 @@ fn main() { You will need the last rust compiler from the master branch. If you encounter problems, make sure you have the last version before creating an issue. - git clone git://github.com/sebcrozet/nalgebra.git - cd nalgebra - make +```.ignore +git clone git://github.com/sebcrozet/nalgebra.git +cd nalgebra +make +``` You can build the documentation on the `doc` folder using: -``` +```.ignore make doc ``` @@ -107,9 +109,9 @@ Feel free to add your project to this list if you happen to use **nalgebra**! #[feature(macro_rules)]; #[doc(html_root_url = "http://www.rust-ci.org/sebcrozet/nalgebra/doc")]; -extern mod std; -extern mod extra; -extern mod serialize; +extern crate std; +extern crate extra; +extern crate serialize; pub mod na; mod structs; diff --git a/src/na.rs b/src/na.rs index e4fd655d..b81c3283 100644 --- a/src/na.rs +++ b/src/na.rs @@ -1,12 +1,14 @@ //! **nalgebra** prelude. use std::num::{Zero, One}; +use std::cmp; +pub use traits::{Less, Equal, Greater, NotComparable}; pub use traits::{ Absolute, AbsoluteRotate, ApproxEq, - RealVec, - RealVecExt, + FloatVec, + FloatVecExt, Basis, Cast, Col, @@ -25,6 +27,8 @@ pub use traits::{ Mean, Norm, Outer, + PartialOrd, + PartialOrdering, RMul, Rotate, Rotation, RotationMatrix, RotationWithTranslation, Row, @@ -48,6 +52,71 @@ pub use structs::{ Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6 }; +/// Change the input value to ensure it is on the range `[min, max]`. +#[inline(always)] +pub fn clamp(val: T, min: T, max: T) -> T { + if val > min { + if val < max { + val + } + else { + max + } + } + else { + min + } +} + +/// Same as `cmp::max`. +#[inline(always)] +pub fn max(a: T, b: T) -> T { + cmp::max(a, b) +} + +/// Same as `cmp::min`. +#[inline(always)] +pub fn min(a: T, b: T) -> T { + cmp::min(a, b) +} + +/// Returns the infimum of `a` and `b`. +#[inline(always)] +pub fn inf(a: &T, b: &T) -> T { + PartialOrd::inf(a, b) +} + +/// Returns the supremum of `a` and `b`. +#[inline(always)] +pub fn sup(a: &T, b: &T) -> T { + PartialOrd::sup(a, b) +} + +/// Compare `a` and `b` using a partial ordering relation. +#[inline(always)] +pub fn partial_cmp(a: &T, b: &T) -> PartialOrdering { + PartialOrd::partial_cmp(a, b) +} + +/// Return the minimum of `a` and `b` if they are comparable. +#[inline(always)] +pub fn partial_min<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> { + PartialOrd::partial_min(a, b) +} + +/// Return the maximum of `a` and `b` if they are comparable. +#[inline(always)] +pub fn partial_max<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> { + PartialOrd::partial_max(a, b) +} + +/// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to +/// `min` or `max`. +#[inline(always)] +pub fn partial_clamp<'a, T: PartialOrd>(value: &'a T, min: &'a T, max: &'a T) -> Option<&'a T> { + PartialOrd::partial_clamp(value, min, max) +} + // // // Constructors @@ -89,7 +158,7 @@ pub fn one() -> T { */ /// Computes a projection matrix given the frustrum near plane width, height, the field of /// view, and the distance to the clipping planes (`znear` and `zfar`). -pub fn perspective3d + Zero + One>(width: N, height: N, fov: N, znear: N, zfar: N) -> Mat4 { +pub fn perspective3d + Zero + One>(width: N, height: N, fov: N, znear: N, zfar: N) -> Mat4 { let aspect = width / height; let _1: N = one(); @@ -112,7 +181,7 @@ pub fn perspective3d + Zero + One>(width: N, height: N, fov: /// Gets the translation applicable by `m`. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Iso3}; /// use nalgebra::na; /// @@ -131,7 +200,7 @@ pub fn translation>(m: &M) -> V { /// Gets the inverse translation applicable by `m`. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Iso3}; /// use nalgebra::na; /// @@ -160,7 +229,7 @@ pub fn append_translation>(m: &M, v: &V) -> M { /// Applies a translation to a vector. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Iso3}; /// use nalgebra::na; /// @@ -181,7 +250,7 @@ pub fn translate>(m: &M, v: &V) -> V { /// Applies an inverse translation to a vector. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Iso3}; /// use nalgebra::na; /// @@ -205,7 +274,7 @@ pub fn inv_translate>(m: &M, v: &V) -> V { /// Gets the rotation applicable by `m`. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Rot3}; /// use nalgebra::na; /// @@ -224,7 +293,7 @@ pub fn rotation>(m: &M) -> V { /// Gets the inverse rotation applicable by `m`. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Rot3}; /// use nalgebra::na; /// @@ -243,7 +312,7 @@ pub fn inv_rotation>(m: &M) -> V { /// Applies the rotation `v` to a copy of `m`. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Rot3}; /// use nalgebra::na; /// @@ -264,7 +333,7 @@ pub fn append_rotation>(m: &M, v: &V) -> M { /// Pre-applies the rotation `v` to a copy of `m`. /// /// ```rust -/// extern mod nalgebra; +/// extern crate nalgebra; /// use nalgebra::na::{Vec3, Rot3}; /// use nalgebra::na; /// @@ -288,13 +357,13 @@ pub fn prepend_rotation>(m: &M, v: &V) -> M { /// Applies a rotation to a vector. /// /// ```rust -/// extern mod nalgebra; -/// use std::num::Real; +/// extern crate nalgebra; +/// use std::num::Float; /// use nalgebra::na::{Rot3, Vec3}; /// use nalgebra::na; /// /// fn main() { -/// let t = Rot3::new(Vec3::new(0.0, 0.0, 0.5 * Real::pi())); +/// let t = Rot3::new(Vec3::new(0.0, 0.0, 0.5 * Float::pi())); /// let v = Vec3::new(1.0, 0.0, 0.0); /// /// let tv = na::rotate(&t, &v); @@ -311,13 +380,13 @@ pub fn rotate>(m: &M, v: &V) -> V { /// Applies an inverse rotation to a vector. /// /// ```rust -/// extern mod nalgebra; -/// use std::num::Real; +/// extern crate nalgebra; +/// use std::num::Float; /// use nalgebra::na::{Rot3, Vec3}; /// use nalgebra::na; /// /// fn main() { -/// let t = Rot3::new(Vec3::new(0.0, 0.0, 0.5 * Real::pi())); +/// let t = Rot3::new(Vec3::new(0.0, 0.0, 0.5 * Float::pi())); /// let v = Vec3::new(1.0, 0.0, 0.0); /// /// let tv = na::inv_rotate(&t, &v); @@ -435,19 +504,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: Real>(v: &V) -> N { +pub fn norm, N: Float>(v: &V) -> N { Norm::norm(v) } /// Computes the squared L2 norm of a vector. #[inline(always)] -pub fn sqnorm, N: Real>(v: &V) -> N { +pub fn sqnorm, N: Float>(v: &V) -> N { Norm::sqnorm(v) } /// Gets the normalized version of a vector. #[inline(always)] -pub fn normalize, N: Real>(v: &V) -> V { +pub fn normalize, N: Float>(v: &V) -> V { Norm::normalize_cpy(v) } diff --git a/src/structs/dvec.rs b/src/structs/dvec.rs index 802cfa9d..d4e78b17 100644 --- a/src/structs/dvec.rs +++ b/src/structs/dvec.rs @@ -2,7 +2,7 @@ #[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait. -use std::num::{Zero, One, Real}; +use std::num::{Zero, One, Float}; use std::rand::Rand; use std::rand; use std::vec; @@ -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 except one which is equal /// to 1.0. @@ -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) diff --git a/src/structs/iso.rs b/src/structs/iso.rs index c69d93b2..8fecfb34 100644 --- a/src/structs/iso.rs +++ b/src/structs/iso.rs @@ -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 0762b685..98e6cd99 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 + Real + Real + Num + Clone> + impl + Float + Float + 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 + Real + Real + Clone> Rotation<$tav> for $t { + impl + Num + Float + Float + 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() } @@ -336,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/rot.rs b/src/structs/rot.rs index e7daa12f..bed3fd95 100644 --- a/src/structs/rot.rs +++ b/src/structs/rot.rs @@ -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 7b130aa2..40808458 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 + Real + Real + Num + Clone> + impl + Float + Float + Num + Clone> RotationMatrix<$tlv, $tav, $t> for $t { #[inline] fn to_rot_mat(&self) -> $t { diff --git a/src/structs/spec/vec.rs b/src/structs/spec/vec.rs index 38a16d08..5b747808 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 4530084c..a1572c48 100644 --- a/src/structs/spec/vec0.rs +++ b/src/structs/spec/vec0.rs @@ -1,5 +1,5 @@ use std::cast; -use std::num::{Zero, One, Real, Bounded}; +use std::num::{Zero, One, Float, Bounded}; use std::vec::{Items, MutItems}; use std::iter::{Iterator, FromIterator}; use traits::operations::ApproxEq; @@ -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() diff --git a/src/structs/vec.rs b/src/structs/vec.rs index c7884475..88cd1bb9 100644 --- a/src/structs/vec.rs +++ b/src/structs/vec.rs @@ -3,10 +3,11 @@ #[allow(missing_doc)]; // we allow missing to avoid having to document the vector components. use std::cast; -use std::num::{Zero, One, Real, Bounded}; +use std::cmp; +use std::num::{Zero, One, Float, Bounded}; use std::vec::{Items, MutItems}; use std::iter::{Iterator, FromIterator}; -use traits::operations::ApproxEq; +use traits::operations::{ApproxEq, PartialOrd, PartialOrdering, Less, Equal, Greater, NotComparable}; use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm, Translation, Translate}; @@ -38,7 +39,6 @@ sub_redispatch_impl!(Vec1, Vec1SubRhs) cast_redispatch_impl!(Vec1, Vec1Cast) new_impl!(Vec1, x) ord_impl!(Vec1, x) -orderable_impl!(Vec1, x) vec_axis_impl!(Vec1, x) vec_cast_impl!(Vec1, Vec1Cast, x) indexable_impl!(Vec1, 1) @@ -137,7 +137,6 @@ sub_redispatch_impl!(Vec2, Vec2SubRhs) cast_redispatch_impl!(Vec2, Vec2Cast) new_impl!(Vec2, x, y) ord_impl!(Vec2, x, y) -orderable_impl!(Vec2, x, y) vec_axis_impl!(Vec2, x, y) vec_cast_impl!(Vec2, Vec2Cast, x, y) indexable_impl!(Vec2, 2) @@ -238,7 +237,6 @@ sub_redispatch_impl!(Vec3, Vec3SubRhs) cast_redispatch_impl!(Vec3, Vec3Cast) new_impl!(Vec3, x, y, z) ord_impl!(Vec3, x, y, z) -orderable_impl!(Vec3, x, y, z) vec_axis_impl!(Vec3, x, y, z) vec_cast_impl!(Vec3, Vec3Cast, x, y, z) indexable_impl!(Vec3, 3) @@ -345,7 +343,6 @@ sub_redispatch_impl!(Vec4, Vec4SubRhs) cast_redispatch_impl!(Vec4, Vec4Cast) new_impl!(Vec4, x, y, z, w) ord_impl!(Vec4, x, y, z, w) -orderable_impl!(Vec4, x, y, z, w) vec_axis_impl!(Vec4, x, y, z, w) vec_cast_impl!(Vec4, Vec4Cast, x, y, z, w) indexable_impl!(Vec4, 4) @@ -450,7 +447,6 @@ sub_redispatch_impl!(Vec5, Vec5SubRhs) cast_redispatch_impl!(Vec5, Vec5Cast) new_impl!(Vec5, x, y, z, w, a) ord_impl!(Vec5, x, y, z, w, a) -orderable_impl!(Vec5, x, y, z, w, a) vec_axis_impl!(Vec5, x, y, z, w, a) vec_cast_impl!(Vec5, Vec5Cast, x, y, z, w, a) indexable_impl!(Vec5, 5) @@ -557,7 +553,6 @@ sub_redispatch_impl!(Vec6, Vec6SubRhs) cast_redispatch_impl!(Vec6, Vec6Cast) new_impl!(Vec6, x, y, z, w, a, b) ord_impl!(Vec6, x, y, z, w, a, b) -orderable_impl!(Vec6, x, y, z, w, a, b) vec_axis_impl!(Vec6, x, y, z, w, a, b) vec_cast_impl!(Vec6, Vec6Cast, x, y, z, w, a, b) indexable_impl!(Vec6, 6) diff --git a/src/structs/vec_macros.rs b/src/structs/vec_macros.rs index 9c105265..11eac72b 100644 --- a/src/structs/vec_macros.rs +++ b/src/structs/vec_macros.rs @@ -36,47 +36,52 @@ macro_rules! at_fast_impl( macro_rules! ord_impl( ($t: ident, $comp0: ident $(,$compN: ident)*) => ( - impl Ord for $t { + impl PartialOrd for $t { #[inline] - fn lt(&self, other: &$t) -> bool { - self.$comp0 < other.$comp0 $(&& self.$compN < other.$compN)* + fn inf(a: &$t, b: &$t) -> $t { + $t::new(cmp::min(a.$comp0.clone(), b.$comp0.clone()) + $(, cmp::min(a.$compN.clone(), b.$compN.clone()))*) } #[inline] - fn le(&self, other: &$t) -> bool { - self.$comp0 <= other.$comp0 $(&& self.$compN <= other.$compN)* + fn sup(a: &$t, b: &$t) -> $t { + $t::new(cmp::max(a.$comp0.clone(), b.$comp0.clone()) + $(, cmp::max(a.$compN.clone(), b.$compN.clone()))*) } #[inline] - fn gt(&self, other: &$t) -> bool { - self.$comp0 > other.$comp0 $(&& self.$compN > other.$compN)* - } + #[allow(unused_mut)] // otherwise there will be a warning for is_eq or Vec1. + fn partial_cmp(a: &$t, b: &$t) -> PartialOrdering { + let is_lt = a.$comp0 < b.$comp0; + let mut is_eq = a.$comp0 == b.$comp0; - #[inline] - fn ge(&self, other: &$t) -> bool { - self.$comp0 >= other.$comp0 $(&& self.$compN >= other.$compN)* - } - } - ) -) + if is_lt { // < + $( + if a.$compN > b.$compN { + return NotComparable + } + )* -macro_rules! orderable_impl( - ($t: ident, $comp0: ident $(,$compN: ident)*) => ( - impl Orderable for $t { - #[inline] - fn max(&self, other: &$t) -> $t { - $t::new(self.$comp0.max(&other.$comp0) $(, self.$compN.max(&other.$compN))*) - } + Less + } + else { // >= + $( + if a.$compN < b.$compN { + return NotComparable + } + else if a.$compN > b.$compN { + is_eq = false; + } - #[inline] - fn min(&self, other: &$t) -> $t { - $t::new(self.$comp0.min(&other.$comp0) $(, self.$compN.min(&other.$compN))*) - } + )* - #[inline] - fn clamp(&self, min: &$t, max: &$t) -> $t { - $t::new(self.$comp0.clamp(&min.$comp0, &max.$comp0) - $(, self.$compN.clamp(&min.$comp0, &max.$comp0))*) + if is_eq { + Equal + } + else { + Greater + } + } } } ) @@ -223,7 +228,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) { @@ -433,7 +438,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) diff --git a/src/tests/mat.rs b/src/tests/mat.rs index c654696b..f34a004c 100644 --- a/src/tests/mat.rs +++ b/src/tests/mat.rs @@ -1,4 +1,4 @@ -use std::num::{Real, abs}; +use std::num::{Float, abs}; use std::rand::random; use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable}; use na; @@ -87,7 +87,7 @@ fn test_inv_mat6() { fn test_rotation2() { for _ in range(0, 10000) { let randmat: na::Rot2 = na::one(); - let ang = Vec1::new(abs::(random()) % Real::pi()); + let ang = Vec1::new(abs::(random()) % Float::pi()); assert!(na::approx_eq(&na::rotation(&na::append_rotation(&randmat, &ang)), &ang)); } @@ -105,7 +105,7 @@ fn test_inv_rotation3() { for _ in range(0, 10000) { let randmat: Rot3 = na::one(); let dir: Vec3 = random(); - let ang = na::normalize(&dir) * (abs::(random()) % Real::pi()); + let ang = na::normalize(&dir) * (abs::(random()) % Float::pi()); let rot = na::append_rotation(&randmat, &ang); assert!(na::approx_eq(&(na::transpose(&rot) * rot), &na::one())); diff --git a/src/tests/vec.rs b/src/tests/vec.rs index fca0cbe4..ea78040b 100644 --- a/src/tests/vec.rs +++ b/src/tests/vec.rs @@ -292,23 +292,19 @@ fn test_ord_vec3() { assert!(Vec3::new(1.5, 0.5, 0.5) != Vec3::new(0.5, 0.5, 0.5)); // comparable - assert!(Vec3::new(0.5, 0.3, 0.3) < Vec3::new(1.0, 2.0, 1.0)); - assert!(Vec3::new(0.5, 0.3, 0.3) <= Vec3::new(1.0, 2.0, 1.0)); - assert!(Vec3::new(2.0, 4.0, 2.0) > Vec3::new(1.0, 2.0, 1.0)); - assert!(Vec3::new(2.0, 4.0, 2.0) >= Vec3::new(1.0, 2.0, 1.0)); + assert!(na::partial_cmp(&Vec3::new(0.5, 0.3, 0.3), &Vec3::new(1.0, 2.0, 1.0)).is_le()); + assert!(na::partial_cmp(&Vec3::new(0.5, 0.3, 0.3), &Vec3::new(1.0, 2.0, 1.0)).is_lt()); + assert!(na::partial_cmp(&Vec3::new(2.0, 4.0, 2.0), &Vec3::new(1.0, 2.0, 1.0)).is_ge()); + assert!(na::partial_cmp(&Vec3::new(2.0, 4.0, 2.0), &Vec3::new(1.0, 2.0, 1.0)).is_gt()); // not comparable - assert!(!(Vec3::new(0.0, 3.0, 0.0) < Vec3::new(1.0, 2.0, 1.0))); - assert!(!(Vec3::new(0.0, 3.0, 0.0) > Vec3::new(1.0, 2.0, 1.0))); - assert!(!(Vec3::new(0.0, 3.0, 0.0) <= Vec3::new(1.0, 2.0, 1.0))); - assert!(!(Vec3::new(0.0, 3.0, 0.0) >= Vec3::new(1.0, 2.0, 1.0))); + assert!(na::partial_cmp(&Vec3::new(0.0, 3.0, 0.0), &Vec3::new(1.0, 2.0, 1.0)).is_not_comparable()); } #[test] fn test_min_max_vec3() { - assert_eq!(Vec3::new(1, 2, 3).max(&Vec3::new(3, 2, 1)), Vec3::new(3, 2, 3)); - assert_eq!(Vec3::new(1, 2, 3).min(&Vec3::new(3, 2, 1)), Vec3::new(1, 2, 1)); - assert_eq!(Vec3::new(0, 2, 4).clamp(&Vec3::new(1, 1, 1), &Vec3::new(3, 3, 3)), Vec3::new(1, 2, 3)); + assert_eq!(na::sup(&Vec3::new(1, 2, 3), &Vec3::new(3, 2, 1)), Vec3::new(3, 2, 3)); + assert_eq!(na::inf(&Vec3::new(1, 2, 3), &Vec3::new(3, 2, 1)), Vec3::new(1, 2, 1)); } #[test] diff --git a/src/traits/geometry.rs b/src/traits/geometry.rs index 91fdf4b3..14b4df58 100644 --- a/src/traits/geometry.rs +++ b/src/traits/geometry.rs @@ -153,9 +153,9 @@ pub trait RotationMatrix + Rotation> : Rotation { pub trait AbsoluteRotate { /// This is the same as: /// - /// ~~~ + /// ```.ignore /// self.rotation_matrix().absolute().rmul(v) - /// ~~~ + /// ``` fn absolute_rotate(&self, v: &V) -> V; } @@ -208,9 +208,9 @@ pub trait Dot { * computing intermediate vectors. * The following equation must be verified: * - * ~~~ + * ```.ignore * a.sub_dot(b, c) == (a - b).dot(c) - * ~~~ + * ``` * */ #[inline] @@ -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 6f25caed..f192a654 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -4,11 +4,12 @@ pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneou Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous, Transform, Transformation, Translate, Translation, UniformSphereSample}; -pub use self::structure::{RealVec, RealVecExt, Basis, Cast, Col, Dim, Indexable, +pub use self::structure::{FloatVec, FloatVecExt, Basis, Cast, Col, Dim, Indexable, Iterable, IterableMut, Mat, Row, Vec, VecExt}; -pub use self::operations::{Absolute, ApproxEq, Cov, Inv, LMul, Mean, Outer, RMul, ScalarAdd, - ScalarSub, Transpose}; +pub use self::operations::{Absolute, ApproxEq, Cov, Inv, LMul, Mean, Outer, PartialOrd, RMul, + ScalarAdd, ScalarSub, Transpose}; +pub use self::operations::{PartialOrdering, Less, Equal, Greater, NotComparable}; pub mod geometry; pub mod structure; diff --git a/src/traits/operations.rs b/src/traits/operations.rs index 015ff4be..7f090281 100644 --- a/src/traits/operations.rs +++ b/src/traits/operations.rs @@ -1,5 +1,129 @@ //! Low level operations on vectors and matrices. +use std::cmp; + + +/// Result of a partial ordering. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, Show)] +pub enum PartialOrdering { + /// Result of a strict comparison. + Less, + /// Equality relationship. + Equal, + /// Result of a strict comparison. + Greater, + /// Result of a comparison between two objects that are not comparable. + NotComparable +} + +impl PartialOrdering { + /// Returns `true` if `self` is equal to `Equal`. + pub fn is_eq(&self) -> bool { + *self == Equal + } + + /// Returns `true` if `self` is equal to `Less`. + pub fn is_lt(&self) -> bool { + *self == Less + } + + /// Returns `true` if `self` is equal to `Less` or `Equal`. + pub fn is_le(&self) -> bool { + *self == Less || *self == Equal + } + + /// Returns `true` if `self` is equal to `Greater`. + pub fn is_gt(&self) -> bool { + *self == Greater + } + + /// Returns `true` if `self` is equal to `Greater` or `Equal`. + pub fn is_ge(&self) -> bool { + *self == Greater || *self == Equal + } + + /// Returns `true` if `self` is equal to `NotComparable`. + pub fn is_not_comparable(&self) -> bool { + *self == NotComparable + } + + /// Creates a `PartialOrdering` from an `Ordering`. + pub fn from_ordering(ord: Ordering) -> PartialOrdering { + match ord { + cmp::Less => Less, + cmp::Equal => Equal, + cmp::Greater => Greater + } + } + + /// Converts this `PartialOrdering` to an `Ordering`. + /// + /// Returns `None` if `self` is `NotComparable`. + pub fn to_ordering(self) -> Option { + match self { + Less => Some(cmp::Less), + Equal => Some(cmp::Equal), + Greater => Some(cmp::Greater), + NotComparable => None + } + } +} + +/// Pointwise ordering operations. +pub trait PartialOrd { + /// Returns the infimum of `a` and `b`. + fn inf(a: &Self, b: &Self) -> Self; + + /// Returns the supremum of `a` and `b`. + fn sup(a: &Self, b: &Self) -> Self; + + /// Compare `a` and `b` using a partial ordering relation. + fn partial_cmp(a: &Self, b: &Self) -> PartialOrdering; + + /// Return the minimum of `a` and `b` if they are comparable. + #[inline] + fn partial_min<'a>(a: &'a Self, b: &'a Self) -> Option<&'a Self> { + match PartialOrd::partial_cmp(a, b) { + Less | Equal => Some(a), + Greater => Some(b), + NotComparable => None + } + } + + /// Return the maximum of `a` and `b` if they are comparable. + #[inline] + fn partial_max<'a>(a: &'a Self, b: &'a Self) -> Option<&'a Self> { + match PartialOrd::partial_cmp(a, b) { + Greater | Equal => Some(a), + Less => Some(b), + NotComparable => None + } + } + + /// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to + /// `min` or `max`. + #[inline] + fn partial_clamp<'a>(value: &'a Self, min: &'a Self, max: &'a Self) -> Option<&'a Self> { + let v_min = PartialOrd::partial_cmp(value, min); + let v_max = PartialOrd::partial_cmp(value, max); + + if v_min.is_not_comparable() || v_max.is_not_comparable() { + None + } + else { + if v_min.is_lt() { + Some(min) + } + else if v_max.is_gt() { + Some(max) + } + else { + Some(value) + } + } + } +} + /// Trait for testing approximate equality pub trait ApproxEq { /// Default epsilon for approximation. diff --git a/src/traits/structure.rs b/src/traits/structure.rs index 7f14c1eb..360e9748 100644 --- a/src/traits/structure.rs +++ b/src/traits/structure.rs @@ -27,31 +27,31 @@ pub trait Vec: Dim + Sub + Add + Neg + Zero + E + Div + Dot { } -/// Trait of vector with components implementing the `Real` trait. -pub trait RealVec: Vec + Norm { +/// Trait of vector with components implementing the `Float` trait. +pub trait FloatVec: Vec + Norm { } /// Trait grouping uncommon, low-level and borderline (from the mathematical point of view) /// operations on vectors. pub trait VecExt: Vec + Indexable + Iterable + - UniformSphereSample + ScalarAdd + ScalarSub + Bounded + Orderable + UniformSphereSample + ScalarAdd + ScalarSub + Bounded { } /// Trait grouping uncommon, low-level and borderline (from the mathematical point of view) /// operations on vectors. -pub trait RealVecExt: RealVec + VecExt + Basis + Round { } +pub trait FloatVecExt: FloatVec + VecExt + Basis + Round { } impl + Add + Neg + Zero + Eq + Mul + Div + Dot> Vec for V { } -impl + Norm> RealVec for V { } +impl + Norm> FloatVec for V { } impl + Indexable + Iterable + - UniformSphereSample + ScalarAdd + ScalarSub + Bounded + Orderable> + UniformSphereSample + ScalarAdd + ScalarSub + Bounded> VecExt for V { } -impl + VecExt + Basis + Round> RealVecExt for V { } +impl + VecExt + Basis + Round> FloatVecExt for V { } // FIXME: return an iterator instead /// Traits of objects which can form a basis (typically vectors).