diff --git a/CHANGELOG.md b/CHANGELOG.md index 207acdc6..ab56eaa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ documented here. This project adheres to [Semantic Versioning](http://semver.org/). ## [0.9.0] - WIP -## Modified +### Modified * Renamed: - `::from_col_vector` -> `::from_column_vector` - `::from_col_iter` -> `::from_column_iter` @@ -13,9 +13,38 @@ This project adheres to [Semantic Versioning](http://semver.org/). - `.set_col` -> `.set_column` - `::canonical_basis_with_dim` -> `::canonical_basis_with_dimension` - `::from_elem` -> `::from_element` + - `DiagMut` -> `DiagonalMut` + - `UnitQuaternion::new` becomes `UnitQuaternion::from_scaled_axis` or + `UnitQuaternion::from_axisangle`. The new `::new` method now requires a + not-normalized quaternion. + +Methods names starting with `new_with_` now start with `from_`. This is more +idiomatic in Rust. + +The `Norm` trait now uses an associated type instead of a type parameter. +Other similar trait changes are to be expected in the future, e.g., for the +`Diagonal` trait. + +Methods marked `unsafe` for reasons unrelated to memory safety are no +longer unsafe. Instead, their name end with `_unchecked`. In particular: + * `Rotation3::new_with_matrix` -> `Rotation3::new_with_matrix_unchecked` + * `PerspectiveMatrix3::new_with_matrix` -> `PerspectiveMatrix3::new_with_matrix_unchecked` + * `OrthographicMatrix3::new_with_matrix` -> `OrthographicMatrix3::new_with_matrix_unchecked` + +### Added + - A `Unit` type that wraps normalized values. In particular, + `UnitQuaternion` is now an alias for `Unit>`. + - `.ln()`, `.exp()` and `.powf(..)` for quaternions and unit quaternions. + - `::from_parts(...)` to build a quaternion from its scalar and vector + parts. + - The `Norm` trait now has a `try_normalize()` that returns `None` if the + norm is too small. + - The `BaseFloat` and `FloatVector` traits now inherit from `ApproxEq` as + well. It is clear that performing computations with floats requires + approximate equality. ## [0.8.0] -## Modified +### Modified * Almost everything (types, methods, and traits) now use full names instead of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are abvious. Note however that: diff --git a/Cargo.toml b/Cargo.toml index f1d6f68e..253be7f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.8.2" +version = "0.9.0" authors = [ "Sébastien Crozet " ] # FIXME: add the contributors. description = "Linear algebra library for computer physics, computer graphics and general low-dimensional linear algebra for Rust." @@ -24,6 +24,7 @@ generic_sizes = [ "generic-array", "typenum" ] rustc-serialize = "0.3.*" rand = "0.3.*" num = "0.1.*" +# algebra = "*" [dependencies.generic-array] optional = true diff --git a/README.md b/README.md index bf0c8391..a5fca593 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,16 @@ -[![Build Status](https://travis-ci.org/sebcrozet/nalgebra.svg?branch=master)](https://travis-ci.org/sebcrozet/nalgebra) +

+ + crates.io + + + Build status + +

+

+ + Documentation | Forum + +

nalgebra ======== @@ -9,8 +21,6 @@ nalgebra * Real time computer graphics. * Real time computer physics. -An on-line version of this documentation is available [here](http://nalgebra.org/doc/nalgebra). - ## Using **nalgebra** All the functionality of **nalgebra** is grouped in one place: the root module `nalgebra::`. This module re-exports everything and includes free functions for all traits methods performing diff --git a/benches/construction.rs b/benches/construction.rs index 8afef416..cc4179d0 100644 --- a/benches/construction.rs +++ b/benches/construction.rs @@ -11,9 +11,9 @@ use na::{UnitQuaternion, Rotation2, Rotation3, Vector1, Vector3}; #[path="common/macros.rs"] mod macros; -bench_construction!(_bench_quaternion_from_axisangle, UnitQuaternion::new, axisangle: Vector3); +bench_construction!(_bench_quaternion_from_axisangle, UnitQuaternion::from_scaled_axis, axisangle: Vector3); bench_construction!(_bench_rot2_from_axisangle, Rotation2::new, axisangle: Vector1); bench_construction!(_bench_rot3_from_axisangle, Rotation3::new, axisangle: Vector3); -bench_construction!(_bench_quaternion_from_euler_angles, UnitQuaternion::new_with_euler_angles, roll: f32, pitch: f32, yaw: f32); -bench_construction!(_bench_rot3_from_euler_angles, Rotation3::new_with_euler_angles, roll: f32, pitch: f32, yaw: f32); +bench_construction!(_bench_quaternion_from_euler_angles, UnitQuaternion::from_euler_angles, roll: f32, pitch: f32, yaw: f32); +bench_construction!(_bench_rot3_from_euler_angles, Rotation3::from_euler_angles, roll: f32, pitch: f32, yaw: f32); diff --git a/benches/vec.rs b/benches/vec.rs index 6bdd0392..4681dc1f 100644 --- a/benches/vec.rs +++ b/benches/vec.rs @@ -63,6 +63,13 @@ bench_unop!(_bench_vec4_normalize, Vector4, normalize); #[cfg(feature = "generic_sizes")] mod bench_vecn { + extern crate test; + extern crate rand; + extern crate nalgebra as na; + + use rand::{IsaacRng, Rng}; + use test::Bencher; + use std::ops::{Add, Sub, Mul, Div}; use typenum::{U2, U3, U4}; use na::VectorN; diff --git a/src/lib.rs b/src/lib.rs index 564ec7b6..df41c059 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,7 +154,8 @@ pub use structs::{ Point1, Point2, Point3, Point4, Point5, Point6, Perspective3, PerspectiveMatrix3, Orthographic3, OrthographicMatrix3, - Quaternion, UnitQuaternion + Quaternion, UnitQuaternion, + Unit }; pub use linalg::{ @@ -173,7 +174,7 @@ mod macros; // mod chol; /// Change the input value to ensure it is on the range `[min, max]`. -#[inline(always)] +#[inline] pub fn clamp(val: T, min: T, max: T) -> T { if val > min { if val < max { @@ -189,74 +190,74 @@ pub fn clamp(val: T, min: T, max: T) -> T { } /// Same as `cmp::max`. -#[inline(always)] +#[inline] pub fn max(a: T, b: T) -> T { cmp::max(a, b) } /// Same as `cmp::min`. -#[inline(always)] +#[inline] pub fn min(a: T, b: T) -> T { cmp::min(a, b) } /// Returns the infimum of `a` and `b`. -#[inline(always)] +#[inline] pub fn inf(a: &T, b: &T) -> T { PartialOrder::inf(a, b) } /// Returns the supremum of `a` and `b`. -#[inline(always)] +#[inline] pub fn sup(a: &T, b: &T) -> T { PartialOrder::sup(a, b) } /// Compare `a` and `b` using a partial ordering relation. -#[inline(always)] +#[inline] pub fn partial_cmp(a: &T, b: &T) -> PartialOrdering { PartialOrder::partial_cmp(a, b) } /// Returns `true` iff `a` and `b` are comparable and `a < b`. -#[inline(always)] +#[inline] pub fn partial_lt(a: &T, b: &T) -> bool { PartialOrder::partial_lt(a, b) } /// Returns `true` iff `a` and `b` are comparable and `a <= b`. -#[inline(always)] +#[inline] pub fn partial_le(a: &T, b: &T) -> bool { PartialOrder::partial_le(a, b) } /// Returns `true` iff `a` and `b` are comparable and `a > b`. -#[inline(always)] +#[inline] pub fn partial_gt(a: &T, b: &T) -> bool { PartialOrder::partial_gt(a, b) } /// Returns `true` iff `a` and `b` are comparable and `a >= b`. -#[inline(always)] +#[inline] pub fn partial_ge(a: &T, b: &T) -> bool { PartialOrder::partial_ge(a, b) } /// Return the minimum of `a` and `b` if they are comparable. -#[inline(always)] +#[inline] pub fn partial_min<'a, T: PartialOrder>(a: &'a T, b: &'a T) -> Option<&'a T> { PartialOrder::partial_min(a, b) } /// Return the maximum of `a` and `b` if they are comparable. -#[inline(always)] +#[inline] pub fn partial_max<'a, T: PartialOrder>(a: &'a T, b: &'a T) -> Option<&'a T> { PartialOrder::partial_max(a, b) } /// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to /// `min` or `max`. -#[inline(always)] +#[inline] pub fn partial_clamp<'a, T: PartialOrder>(value: &'a T, min: &'a T, max: &'a T) -> Option<&'a T> { PartialOrder::partial_clamp(value, min, max) } @@ -270,7 +271,7 @@ pub fn partial_clamp<'a, T: PartialOrder>(value: &'a T, min: &'a T, max: &'a T) /// Create a special identity object. /// /// Same as `Identity::new()`. -#[inline(always)] +#[inline] pub fn identity() -> Identity { Identity::new() } @@ -278,13 +279,13 @@ pub fn identity() -> Identity { /// Create a zero-valued value. /// /// This is the same as `std::num::zero()`. -#[inline(always)] +#[inline] pub fn zero() -> T { Zero::zero() } /// Tests is a value is iqual to zero. -#[inline(always)] +#[inline] pub fn is_zero(val: &T) -> bool { val.is_zero() } @@ -292,7 +293,7 @@ pub fn is_zero(val: &T) -> bool { /// Create a one-valued value. /// /// This is the same as `std::num::one()`. -#[inline(always)] +#[inline] pub fn one() -> T { One::one() } @@ -304,7 +305,7 @@ pub fn one() -> T { // /// Returns the trivial origin of an affine space. -#[inline(always)] +#[inline] pub fn origin() -> P { Origin::origin() } @@ -312,26 +313,23 @@ pub fn origin() -> P { /// Returns the center of two points. #[inline] pub fn center>(a: &P, b: &P) -> P - where

::Vector: Norm -{ - let _2 = one::() + one(); - (*a + b.to_vector()) / _2 + where

::Vector: Norm { + (*a + b.to_vector()) / ::cast(2.0) } /* * FloatPoint */ /// Returns the distance between two points. -#[inline(always)] -pub fn distance>(a: &P, b: &P) -> N where

::Vector: Norm { +#[inline] +pub fn distance>(a: &P, b: &P) -> N where

::Vector: Norm { a.distance(b) } /// Returns the squared distance between two points. -#[inline(always)] +#[inline] pub fn distance_squared>(a: &P, b: &P) -> N - where

::Vector: Norm -{ + where

::Vector: Norm { a.distance_squared(b) } @@ -352,7 +350,7 @@ pub fn distance_squared>(a: &P, b: &P) -> N /// assert!(trans == Vector3::new(1.0, 1.0, 1.0)); /// } /// ``` -#[inline(always)] +#[inline] pub fn translation>(m: &M) -> V { m.translation() } @@ -370,13 +368,13 @@ pub fn translation>(m: &M) -> V { /// assert!(itrans == Vector3::new(-1.0, -1.0, -1.0)); /// } /// ``` -#[inline(always)] +#[inline] pub fn inverse_translation>(m: &M) -> V { m.inverse_translation() } /// Applies the translation `v` to a copy of `m`. -#[inline(always)] +#[inline] pub fn append_translation>(m: &M, v: &V) -> M { Translation::append_translation(m, v) } @@ -400,7 +398,7 @@ pub fn append_translation>(m: &M, v: &V) -> M { /// assert!(tp == Point3::new(3.0, 3.0, 3.0)) /// } /// ``` -#[inline(always)] +#[inline] pub fn translate>(m: &M, p: &P) -> P { m.translate(p) } @@ -419,7 +417,7 @@ pub fn translate>(m: &M, p: &P) -> P { /// /// assert!(na::approx_eq(&tp, &Point3::new(1.0, 1.0, 1.0))) /// } -#[inline(always)] +#[inline] pub fn inverse_translate>(m: &M, p: &P) -> P { m.inverse_translate(p) } @@ -440,7 +438,7 @@ pub fn inverse_translate>(m: &M, p: &P) -> P { /// assert!(na::approx_eq(&na::rotation(&t), &Vector3::new(1.0, 1.0, 1.0))); /// } /// ``` -#[inline(always)] +#[inline] pub fn rotation>(m: &M) -> V { m.rotation() } @@ -458,7 +456,7 @@ pub fn rotation>(m: &M) -> V { /// assert!(na::approx_eq(&na::inverse_rotation(&t), &Vector3::new(-1.0, -1.0, -1.0))); /// } /// ``` -#[inline(always)] +#[inline] pub fn inverse_rotation>(m: &M) -> V { m.inverse_rotation() } @@ -478,7 +476,7 @@ pub fn inverse_rotation>(m: &M) -> V { /// assert!(na::approx_eq(&na::rotation(&rt), &Vector3::new(1.0, 1.0, 1.0))) /// } /// ``` -#[inline(always)] +#[inline] pub fn append_rotation>(m: &M, v: &V) -> M { Rotation::append_rotation(m, v) } @@ -498,7 +496,7 @@ pub fn append_rotation>(m: &M, v: &V) -> M { /// assert!(na::approx_eq(&na::rotation(&rt), &Vector3::new(1.0, 1.0, 1.0))) /// } /// ``` -#[inline(always)] +#[inline] pub fn prepend_rotation>(m: &M, v: &V) -> M { Rotation::prepend_rotation(m, v) } @@ -522,7 +520,7 @@ pub fn prepend_rotation>(m: &M, v: &V) -> M { /// assert!(na::approx_eq(&tv, &Vector3::new(0.0, 1.0, 0.0))) /// } /// ``` -#[inline(always)] +#[inline] pub fn rotate>(m: &M, v: &V) -> V { m.rotate(v) } @@ -543,7 +541,7 @@ pub fn rotate>(m: &M, v: &V) -> V { /// assert!(na::approx_eq(&tv, &Vector3::new(0.0, -1.0, 0.0))) /// } /// ``` -#[inline(always)] +#[inline] pub fn inverse_rotate>(m: &M, v: &V) -> V { m.inverse_rotate(v) } @@ -553,7 +551,7 @@ pub fn inverse_rotate>(m: &M, v: &V) -> V { */ /// Rotates a copy of `m` by `amount` using `center` as the pivot point. -#[inline(always)] +#[inline] pub fn append_rotation_wrt_point + Copy, AV, M: RotationWithTranslation>( @@ -564,7 +562,7 @@ pub fn append_rotation_wrt_point + Copy, } /// Rotates a copy of `m` by `amount` using `m.translation()` as the pivot point. -#[inline(always)] +#[inline] pub fn append_rotation_wrt_center + Copy, AV, M: RotationWithTranslation>( @@ -577,13 +575,13 @@ pub fn append_rotation_wrt_center + Copy, * RotationTo */ /// Computes the angle of the rotation needed to transfom `a` to `b`. -#[inline(always)] +#[inline] pub fn angle_between(a: &V, b: &V) -> V::AngleType { a.angle_to(b) } /// Computes the rotation needed to transform `a` to `b`. -#[inline(always)] +#[inline] pub fn rotation_between(a: &V, b: &V) -> V::DeltaRotationType { a.rotation_to(b) } @@ -593,7 +591,7 @@ pub fn rotation_between(a: &V, b: &V) -> V::DeltaRotationType { */ /// Builds a rotation matrix from `r`. -#[inline(always)] +#[inline] pub fn to_rotation_matrix(r: &R) -> M where R: RotationMatrix, M: SquareMatrix + Rotation + Copy, @@ -608,7 +606,7 @@ pub fn to_rotation_matrix(r: &R) -> M */ /// Applies a rotation using the absolute values of its components. -#[inline(always)] +#[inline] pub fn absolute_rotate>(m: &M, v: &V) -> V { m.absolute_rotate(v) } @@ -618,19 +616,19 @@ pub fn absolute_rotate>(m: &M, v: &V) -> V { */ /// Gets the transformation applicable by `m`. -#[inline(always)] +#[inline] pub fn transformation>(m: &M) -> T { m.transformation() } /// Gets the inverse transformation applicable by `m`. -#[inline(always)] +#[inline] pub fn inverse_transformation>(m: &M) -> T { m.inverse_transformation() } /// Gets a transformed copy of `m`. -#[inline(always)] +#[inline] pub fn append_transformation>(m: &M, t: &T) -> M { Transformation::append_transformation(m, t) } @@ -640,13 +638,13 @@ pub fn append_transformation>(m: &M, t: &T) -> M { */ /// Applies a transformation to a vector. -#[inline(always)] +#[inline] pub fn transform>(m: &M, v: &V) -> V { m.transform(v) } /// Applies an inverse transformation to a vector. -#[inline(always)] +#[inline] pub fn inverse_transform>(m: &M, v: &V) -> V { m.inverse_transform(v) } @@ -656,7 +654,7 @@ pub fn inverse_transform>(m: &M, v: &V) -> V { */ /// Computes the dot product of two vectors. -#[inline(always)] +#[inline] pub fn dot, N>(a: &V, b: &V) -> N { Dot::dot(a, b) } @@ -666,28 +664,34 @@ pub fn dot, N>(a: &V, b: &V) -> N { */ /// Computes the L2 norm of a vector. -#[inline(always)] -pub fn norm, N: BaseFloat>(v: &V) -> N { +#[inline] +pub fn norm(v: &V) -> V::NormType { Norm::norm(v) } /// Computes the squared L2 norm of a vector. -#[inline(always)] -pub fn norm_squared, N: BaseFloat>(v: &V) -> N { +#[inline] +pub fn norm_squared(v: &V) -> V::NormType { Norm::norm_squared(v) } /// Gets the normalized version of a vector. -#[inline(always)] -pub fn normalize, N: BaseFloat>(v: &V) -> V { +#[inline] +pub fn normalize(v: &V) -> V { Norm::normalize(v) } +/// Gets the normalized version of a vector or `None` if its norm is smaller than `min_norm`. +#[inline] +pub fn try_normalize(v: &V, min_norm: V::NormType) -> Option { + Norm::try_normalize(v, min_norm) +} + /* * Determinant */ /// Computes the determinant of a square matrix. -#[inline(always)] +#[inline] pub fn determinant, N>(m: &M) -> N { Determinant::determinant(m) } @@ -697,7 +701,7 @@ pub fn determinant, N>(m: &M) -> N { */ /// Computes the cross product of two vectors. -#[inline(always)] +#[inline] pub fn cross(a: &LV, b: &LV) -> LV::CrossProductType { Cross::cross(a, b) } @@ -708,7 +712,7 @@ pub fn cross(a: &LV, b: &LV) -> LV::CrossProductType { /// Given a vector, computes the matrix which, when multiplied by another vector, computes a cross /// product. -#[inline(always)] +#[inline] pub fn cross_matrix, M>(v: &V) -> M { CrossMatrix::cross_matrix(v) } @@ -718,7 +722,7 @@ pub fn cross_matrix, M>(v: &V) -> M { */ /// Converts a matrix or vector to homogeneous coordinates. -#[inline(always)] +#[inline] pub fn to_homogeneous, Res>(m: &M) -> Res { ToHomogeneous::to_homogeneous(m) } @@ -730,7 +734,7 @@ pub fn to_homogeneous, Res>(m: &M) -> Res { /// Converts a matrix or vector from homogeneous coordinates. /// /// w-normalization is appied. -#[inline(always)] +#[inline] pub fn from_homogeneous>(m: &M) -> Res { FromHomogeneous::from(m) } @@ -742,7 +746,7 @@ pub fn from_homogeneous>(m: &M) -> Res { /// Samples the unit sphere living on the dimension as the samples types. /// /// The number of sampling point is implementation-specific. It is always uniform. -#[inline(always)] +#[inline] pub fn sample_sphere(f: F) { UniformSphereSample::sample(f) } @@ -757,13 +761,13 @@ pub fn sample_sphere(f: F) { * AproxEq */ /// Tests approximate equality. -#[inline(always)] +#[inline] pub fn approx_eq, N>(a: &T, b: &T) -> bool { ApproxEq::approx_eq(a, b) } /// Tests approximate equality using a custom epsilon. -#[inline(always)] +#[inline] pub fn approx_eq_eps, N>(a: &T, b: &T, eps: &N) -> bool { ApproxEq::approx_eq_eps(a, b, eps) } @@ -774,7 +778,7 @@ pub fn approx_eq_eps, N>(a: &T, b: &T, eps: &N) -> bool { */ /// Computes a component-wise absolute value. -#[inline(always)] +#[inline] pub fn abs, Res>(m: &M) -> Res { Absolute::abs(m) } @@ -784,7 +788,7 @@ pub fn abs, Res>(m: &M) -> Res { */ /// Gets an inverted copy of a matrix. -#[inline(always)] +#[inline] pub fn inverse(m: &M) -> Option { Inverse::inverse(m) } @@ -794,7 +798,7 @@ pub fn inverse(m: &M) -> Option { */ /// Gets a transposed copy of a matrix. -#[inline(always)] +#[inline] pub fn transpose(m: &M) -> M { Transpose::transpose(m) } @@ -804,7 +808,7 @@ pub fn transpose(m: &M) -> M { */ /// Computes the outer product of two vectors. -#[inline(always)] +#[inline] pub fn outer(a: &V, b: &V) -> V::OuterProductType { Outer::outer(a, b) } @@ -814,7 +818,7 @@ pub fn outer(a: &V, b: &V) -> V::OuterProductType { */ /// Computes the covariance of a set of observations. -#[inline(always)] +#[inline] pub fn covariance, Res>(observations: &M) -> Res { Covariance::covariance(observations) } @@ -824,7 +828,7 @@ pub fn covariance, Res>(observations: &M) -> Res { */ /// Computes the mean of a set of observations. -#[inline(always)] +#[inline] pub fn mean>(observations: &M) -> N { Mean::mean(observations) } @@ -833,7 +837,7 @@ pub fn mean>(observations: &M) -> N { * EigenQR */ /// Computes the eigenvalues and eigenvectors of a square matrix usin the QR algorithm. -#[inline(always)] +#[inline] pub fn eigen_qr(m: &M, eps: &N, niter: usize) -> (M, V) where V: Mul, M: EigenQR { @@ -850,7 +854,7 @@ pub fn eigen_qr(m: &M, eps: &N, niter: usize) -> (M, V) * Eye */ /// Construct the identity matrix for a given dimension -#[inline(always)] +#[inline] pub fn new_identity(dimension: usize) -> M { Eye::new_identity(dimension) } @@ -862,7 +866,7 @@ pub fn new_identity(dimension: usize) -> M { /// Create an object by repeating a value. /// /// Same as `Identity::new()`. -#[inline(always)] +#[inline] pub fn repeat>(val: N) -> T { Repeat::repeat(val) } @@ -872,13 +876,13 @@ pub fn repeat>(val: N) -> T { */ /// Computes the canonical basis for a given dimension. -#[inline(always)] +#[inline] pub fn canonical_basis bool>(f: F) { Basis::canonical_basis(f) } /// Computes the basis of the orthonormal subspace of a given vector. -#[inline(always)] +#[inline] pub fn orthonormal_subspace_basis bool>(v: &V, f: F) { Basis::orthonormal_subspace_basis(v, f) } @@ -901,7 +905,7 @@ pub fn canonical_basis_element(i: usize) -> Option { * Diagonal */ /// Gets the diagonal of a square matrix. -#[inline(always)] +#[inline] pub fn diagonal, V>(m: &M) -> V { m.diagonal() } @@ -912,13 +916,13 @@ pub fn diagonal, V>(m: &M) -> V { /// Gets the dimension an object lives in. /// /// Same as `Dimension::dimension::(None::)`. -#[inline(always)] +#[inline] pub fn dimension() -> usize { Dimension::dimension(None::) } /// Gets the indexable range of an object. -#[inline(always)] +#[inline] pub fn shape, I>(v: &V) -> I { v.shape() } @@ -940,7 +944,7 @@ pub fn shape, I>(v: &V) -> I { /// range of an i32 when a cast from i64 to i32 is done). /// * A cast does not affect the dimension of an algebraic object. Note that this prevents an /// isometric transform to be cast to a raw matrix. Use `to_homogeneous` for that special purpose. -#[inline(always)] +#[inline] pub fn cast>(t: T) -> U { Cast::from(t) } diff --git a/src/linalg/decompositions.rs b/src/linalg/decompositions.rs index 112923b9..9a6751fd 100644 --- a/src/linalg/decompositions.rs +++ b/src/linalg/decompositions.rs @@ -1,5 +1,5 @@ use traits::operations::{Transpose, ApproxEq}; -use traits::structure::{ColumnSlice, Eye, Indexable, Diagonal, SquareMatrix, BaseFloat, Cast}; +use traits::structure::{ColumnSlice, Eye, Indexable, SquareMatrix, BaseFloat, Cast}; use traits::geometry::Norm; use std::cmp; use std::ops::{Mul, Add, Sub}; @@ -40,7 +40,7 @@ pub fn householder_matrix(dimension: usize, start: usize, vector: V) -> /// * `m` - matrix to decompose pub fn qr(m: &M) -> (M, M) where N: BaseFloat, - V: Indexable + Norm, + V: Indexable + Norm, M: Copy + Eye + ColumnSlice + Transpose + Indexable<(usize, usize), N> + Mul { let (rows, cols) = m.shape(); @@ -75,7 +75,7 @@ pub fn qr(m: &M) -> (M, M) pub fn eigen_qr(m: &M, eps: &N, niter: usize) -> (M, V) where N: BaseFloat, V: Mul, - VS: Indexable + Norm, + VS: Indexable + Norm, M: Indexable<(usize, usize), N> + SquareMatrix + Add + Sub + ColumnSlice + ApproxEq + Copy { @@ -264,12 +264,12 @@ pub fn eigen_qr(m: &M, eps: &N, niter: usize) -> (M, V) pub fn cholesky(m: &M) -> Result where N: BaseFloat, V: Mul, - VS: Indexable + Norm, + VS: Indexable + Norm, M: Indexable<(usize, usize), N> + SquareMatrix + Add + Sub + ColumnSlice + ApproxEq + Copy { - let mut out = m.clone().transpose(); + let mut out = m.transpose(); if !ApproxEq::approx_eq(&out, &m) { return Err("Cholesky: Input matrix is not symmetric"); @@ -302,7 +302,7 @@ pub fn cholesky(m: &M) -> Result } } - return Ok(out); + Ok(out) } /// Hessenberg @@ -316,11 +316,11 @@ pub fn cholesky(m: &M) -> Result /// * Second return value `h` - Matrix m in Hessenberg form pub fn hessenberg(m: &M) -> (M, M) where N: BaseFloat, - V: Indexable + Norm, + V: Indexable + Norm, M: Copy + Eye + ColumnSlice + Transpose + Indexable<(usize, usize), N> + Mul { - let mut h = m.clone(); + let mut h = *m; let (rows, cols) = h.shape(); let mut q : M = Eye::new_identity(cols); @@ -347,5 +347,5 @@ pub fn hessenberg(m: &M) -> (M, M) } } - return (q, h); + (q, h) } diff --git a/src/structs/common_macros.rs b/src/structs/common_macros.rs new file mode 100644 index 00000000..ac5438ad --- /dev/null +++ b/src/structs/common_macros.rs @@ -0,0 +1,351 @@ +#![macro_use] + +macro_rules! pointwise_mul( + ($t: ident, $($compN: ident),+) => ( + impl> Mul<$t> for $t { + type Output = $t; + + #[inline] + fn mul(self, right: $t) -> $t { + $t::new($(self.$compN * right.$compN),+) + } + } + + impl> MulAssign<$t> for $t { + #[inline] + fn mul_assign(&mut self, right: $t) { + $( self.$compN *= right.$compN; )+ + } + } + ) +); + +macro_rules! pointwise_div( + ($t: ident, $($compN: ident),+) => ( + impl> Div<$t> for $t { + type Output = $t; + + #[inline] + fn div(self, right: $t) -> $t { + $t::new($(self.$compN / right.$compN),+) + } + } + + impl> DivAssign<$t> for $t { + #[inline] + fn div_assign(&mut self, right: $t) { + $( self.$compN /= right.$compN; )+ + } + } + ) +); + +macro_rules! pointwise_add( + ($t: ident, $($compN: ident),+) => ( + impl> Add<$t> for $t { + type Output = $t; + + #[inline] + fn add(self, right: $t) -> $t { + $t::new($(self.$compN + right.$compN),+) + } + } + + impl> AddAssign<$t> for $t { + #[inline] + fn add_assign(&mut self, right: $t) { + $( self.$compN += right.$compN; )+ + } + } + ) +); + + +macro_rules! pointwise_sub( + ($t: ident, $($compN: ident),+) => ( + impl> Sub<$t> for $t { + type Output = $t; + + #[inline] + fn sub(self, right: $t) -> $t { + $t::new($(self.$compN - right.$compN),+) + } + } + + + impl> SubAssign<$t> for $t { + #[inline] + fn sub_assign(&mut self, right: $t) { + $( self.$compN -= right.$compN; )+ + } + } + ) +); + + +macro_rules! pointwise_scalar_mul( + ($t: ident, $($compN: ident),+) => ( + impl> Mul for $t { + type Output = $t; + + #[inline] + fn mul(self, right: N) -> $t { + $t::new($(self.$compN * right),+) + } + } + + impl> MulAssign for $t { + #[inline] + fn mul_assign(&mut self, right: N) { + $( self.$compN *= right; )+ + } + } + + impl Mul<$t> for f32 { + type Output = $t; + + #[inline] + fn mul(self, right: $t) -> $t { + $t::new($(self * right.$compN),+) + } + } + + impl Mul<$t> for f64 { + type Output = $t; + + #[inline] + fn mul(self, right: $t) -> $t { + $t::new($(self * right.$compN),+) + } + } + ) +); + + +macro_rules! pointwise_scalar_div( + ($t: ident, $($compN: ident),+) => ( + impl> Div for $t { + type Output = $t; + + #[inline] + fn div(self, right: N) -> $t { + $t::new($(self.$compN / right),+) + } + } + + impl> DivAssign for $t { + #[inline] + fn div_assign(&mut self, right: N) { + $( self.$compN /= right; )+ + } + } + ) +); + + +macro_rules! pointwise_scalar_add( + ($t: ident, $($compN: ident),+) => ( + impl> Add for $t { + type Output = $t; + + #[inline] + fn add(self, right: N) -> $t { + $t::new($(self.$compN + right),+) + } + } + + impl> AddAssign for $t { + #[inline] + fn add_assign(&mut self, right: N) { + $( self.$compN += right; )+ + } + } + + impl Add<$t> for f32 { + type Output = $t; + + #[inline] + fn add(self, right: $t) -> $t { + $t::new($(self + right.$compN),+) + } + } + + impl Add<$t> for f64 { + type Output = $t; + + #[inline] + fn add(self, right: $t) -> $t { + $t::new($(self + right.$compN),+) + } + } + ) +); + +macro_rules! pointwise_scalar_sub( + ($t: ident, $($compN: ident),+) => ( + impl> Sub for $t { + type Output = $t; + + #[inline] + fn sub(self, right: N) -> $t { + $t::new($(self.$compN - right),+) + } + } + + impl> SubAssign for $t { + #[inline] + fn sub_assign(&mut self, right: N) { + $( self.$compN -= right; )+ + } + } + + impl Sub<$t> for f32 { + type Output = $t; + + #[inline] + fn sub(self, right: $t) -> $t { + $t::new($(self - right.$compN),+) + } + } + + impl Sub<$t> for f64 { + type Output = $t; + + #[inline] + fn sub(self, right: $t) -> $t { + $t::new($(self - right.$compN),+) + } + } + ) +); + +macro_rules! componentwise_neg( + ($t: ident, $($compN: ident),+) => ( + impl + Copy> Neg for $t { + type Output = $t; + + #[inline] + fn neg(self) -> $t { + $t::new($(-self.$compN ),+) + } + } + ) +); + +macro_rules! componentwise_repeat( + ($t: ident, $($compN: ident),+) => ( + impl Repeat for $t { + fn repeat(val: N) -> $t { + $t { + $($compN: val ),+ + } + } + } + ) +); + +macro_rules! componentwise_absolute( + ($t: ident, $($compN: ident),+) => ( + impl> Absolute<$t> for $t { + #[inline] + fn abs(m: &$t) -> $t { + $t::new($(::abs(&m.$compN) ),+) + } + } + ) +); + +macro_rules! componentwise_zero( + ($t: ident, $($compN: ident),+ ) => ( + impl Zero for $t { + #[inline] + fn zero() -> $t { + $t { + $($compN: ::zero() ),+ + } + } + + #[inline] + fn is_zero(&self) -> bool { + $(::is_zero(&self.$compN) )&&+ + } + } + ) +); + +macro_rules! componentwise_one( + ($t: ident, $($compN: ident),+ ) => ( + impl One for $t { + #[inline] + fn one() -> $t { + $t { + $($compN: ::one() ),+ + } + } + } + ) +); + +// Implements Arbitrary by setting each components to Arbitrary::arbitrary. +macro_rules! componentwise_arbitrary( + ($t: ident, $($compN: ident),+ ) => ( + #[cfg(feature="arbitrary")] + impl Arbitrary for $t { + #[inline] + fn arbitrary(g: &mut G) -> $t { + $t { $($compN: Arbitrary::arbitrary(g),)* } + } + } + ) +); + +// Implements Rand by setting each components to Rand::rand. +macro_rules! componentwise_rand( + ($t: ident, $($compN: ident),+ ) => ( + impl Rand for $t { + #[inline] + fn rand(rng: &mut R) -> $t { + $t { $($compN: Rand::rand(rng), )* } + } + } + ) +); + +macro_rules! component_basis_element( + ($t: ident, $($compN: ident),+ ) => ( + /* + * + * Element of the canonical basis. + * + */ + impl $t { + $( + /// Create the element of the canonical basis having this component set to one and + /// all the others set to zero. + #[inline] + pub fn $compN() -> $t { + let mut res: $t = ::zero(); + + res.$compN = ::one(); + + res + } + )+ + } + ) +); + +// A function to create a new element from its component values. +macro_rules! component_new( + ($t: ident, $($compN: ident),+) => ( + impl $t { + /// Creation from component values. + #[inline] + pub fn new($($compN: N ),+) -> $t { + $t { + $($compN: $compN ),+ + } + } + } + ); +); diff --git a/src/structs/dmatrix.rs b/src/structs/dmatrix.rs index b0e47f6d..81bd9962 100644 --- a/src/structs/dmatrix.rs +++ b/src/structs/dmatrix.rs @@ -9,7 +9,8 @@ use rand::{self, Rand}; use num::{Zero, One}; use structs::dvector::{DVector, DVector1, DVector2, DVector3, DVector4, DVector5, DVector6}; use traits::operations::{ApproxEq, Inverse, Transpose, Mean, Covariance}; -use traits::structure::{Cast, Column, ColumnSlice, Row, RowSlice, Diagonal, DiagMut, Eye, Indexable, Shape, BaseNum}; +use traits::structure::{Cast, Column, ColumnSlice, Row, RowSlice, Diagonal, DiagonalMut, Eye, + Indexable, Shape, BaseNum}; #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -109,7 +110,7 @@ impl DMatrix { impl DMatrix { /// Builds a matrix filled with the results of a function applied to each of its component coordinates. - #[inline(always)] + #[inline] pub fn from_fn N>(nrows: usize, ncols: usize, mut f: F) -> DMatrix { DMatrix { nrows: nrows, @@ -133,7 +134,7 @@ dmat_impl!(DMatrix, DVector); pub struct DMatrix1 { nrows: usize, ncols: usize, - mij: [N; 1 * 1], + mij: [N; 1], } small_dmat_impl!(DMatrix1, DVector1, 1, 0); diff --git a/src/structs/dmatrix_macros.rs b/src/structs/dmatrix_macros.rs index 96868f7c..80e99761 100644 --- a/src/structs/dmatrix_macros.rs +++ b/src/structs/dmatrix_macros.rs @@ -84,9 +84,8 @@ macro_rules! dmat_impl( fn new_identity(dimension: usize) -> $dmatrix { let mut res = $dmatrix::new_zeros(dimension, dimension); - for i in 0..dimension { - let _1: N = ::one(); - res[(i, i)] = _1; + for i in 0 .. dimension { + res[(i, i)] = ::one::(); } res @@ -94,7 +93,7 @@ macro_rules! dmat_impl( } impl $dmatrix { - #[inline(always)] + #[inline] fn offset(&self, i: usize, j: usize) -> usize { i + j * self.nrows } @@ -774,9 +773,8 @@ macro_rules! dmat_impl( // We can init from slice thanks to the matrix being column-major. let start = self.offset(row_start, column_id); let stop = self.offset(row_end, column_id); - let slice = $dvector::from_slice(row_end - row_start, &self.mij[start .. stop]); - slice + $dvector::from_slice(row_end - row_start, &self.mij[start .. stop]) } } @@ -824,12 +822,12 @@ macro_rules! dmat_impl( let mut slice : $dvector = unsafe { $dvector::new_uninitialized(column_end - column_start) }; - let mut slice_idx = 0; + for column_id in column_start .. column_end { unsafe { + let slice_idx = column_id - column_start; slice.unsafe_set(slice_idx, self.unsafe_at((row_id, column_id))); } - slice_idx += 1; } slice @@ -860,7 +858,7 @@ macro_rules! dmat_impl( } } - impl DiagMut<$dvector> for $dmatrix { + impl DiagonalMut<$dvector> for $dmatrix { #[inline] fn set_diagonal(&mut self, diagonal: &$dvector) { let smallest_dim = cmp::min(self.nrows, self.ncols); @@ -1140,7 +1138,7 @@ macro_rules! small_dmat_from_impl( } /// Builds a matrix using an initialization function. - #[inline(always)] + #[inline] pub fn from_fn N>(nrows: usize, ncols: usize, mut f: F) -> $dmatrix { assert!(nrows <= $dimension); assert!(ncols <= $dimension); diff --git a/src/structs/dvector.rs b/src/structs/dvector.rs index d90370bd..62761272 100644 --- a/src/structs/dvector.rs +++ b/src/structs/dvector.rs @@ -56,9 +56,9 @@ impl DVector { impl DVector { /// Builds a vector filled with the results of a function applied to each of its component coordinates. - #[inline(always)] - pub fn from_fn N>(dimension: usize, mut f: F) -> DVector { - DVector { at: (0 .. dimension).map(|i| f(i)).collect() } + #[inline] + pub fn from_fn N>(dimension: usize, f: F) -> DVector { + DVector { at: (0 .. dimension).map(f).collect() } } /// The vector length. diff --git a/src/structs/dvector_macros.rs b/src/structs/dvector_macros.rs index eee85cd6..12c685b6 100644 --- a/src/structs/dvector_macros.rs +++ b/src/structs/dvector_macros.rs @@ -191,7 +191,7 @@ macro_rules! small_dvec_from_impl ( impl $dvector { /// Builds a vector filled with the result of a function. - #[inline(always)] + #[inline] pub fn from_fn N>(dimension: usize, mut f: F) -> $dvector { assert!(dimension <= $dimension); diff --git a/src/structs/isometry.rs b/src/structs/isometry.rs index 9d43961d..7b9ceb8e 100644 --- a/src/structs/isometry.rs +++ b/src/structs/isometry.rs @@ -44,7 +44,7 @@ pub struct Isometry3 { pub translation: Vector3 } -impl Isometry3 { +impl Isometry3 { /// Creates an isometry that corresponds to the local frame of an observer standing at the /// point `eye` and looking toward `target`. /// @@ -59,7 +59,7 @@ impl Isometry3 { #[inline] pub fn new_observer_frame(eye: &Point3, target: &Point3, up: &Vector3) -> Isometry3 { let new_rotation_matrix = Rotation3::new_observer_frame(&(*target - *eye), up); - Isometry3::new_with_rotation_matrix(eye.as_vector().clone(), new_rotation_matrix) + Isometry3::from_rotation_matrix(eye.to_vector(), new_rotation_matrix) } /// Builds a right-handed look-at view matrix. @@ -74,10 +74,10 @@ impl Isometry3 { /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] pub fn look_at_rh(eye: &Point3, target: &Point3, up: &Vector3) -> Isometry3 { - let rotation = Rotation3::look_at_rh(&(*target - *eye), up); - let trans = rotation * (-*eye); + let rotation = Rotation3::look_at_rh(&(*target - *eye), up); + let trans = rotation * (-*eye); - Isometry3::new_with_rotation_matrix(trans.to_vector(), rotation) + Isometry3::from_rotation_matrix(trans.to_vector(), rotation) } /// Builds a left-handed look-at view matrix. @@ -92,53 +92,15 @@ impl Isometry3 { /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] pub fn look_at_lh(eye: &Point3, target: &Point3, up: &Vector3) -> Isometry3 { - let rotation = Rotation3::look_at_lh(&(*target - *eye), up); - let trans = rotation * (-*eye); + let rotation = Rotation3::look_at_lh(&(*target - *eye), up); + let trans = rotation * (-*eye); - Isometry3::new_with_rotation_matrix(trans.to_vector(), rotation) + Isometry3::from_rotation_matrix(trans.to_vector(), rotation) } } -isometry_impl!(Isometry2, Rotation2, Vector2, Vector1); -rotation_matrix_impl!(Isometry2, Rotation2, Vector2, Vector1); -rotation_impl!(Isometry2, Rotation2, Vector1); +isometry_impl!(Isometry2, Rotation2, Vector2, Vector1, Point2, Matrix3); dim_impl!(Isometry2, 2); -one_impl!(Isometry2); -absolute_rotate_impl!(Isometry2, Vector2); -rand_impl!(Isometry2); -approx_eq_impl!(Isometry2); -to_homogeneous_impl!(Isometry2, Matrix3); -inverse_impl!(Isometry2); -transform_impl!(Isometry2, Point2); -transformation_impl!(Isometry2); -rotate_impl!(Isometry2, Vector2); -translation_impl!(Isometry2, Vector2); -translate_impl!(Isometry2, Point2); -isometry_mul_isometry_impl!(Isometry2); -isometry_mul_rotation_impl!(Isometry2, Rotation2); -isometry_mul_point_impl!(Isometry2, Point2); -isometry_mul_vec_impl!(Isometry2, Vector2); -arbitrary_isometry_impl!(Isometry2); -isometry_display_impl!(Isometry2); -isometry_impl!(Isometry3, Rotation3, Vector3, Vector3); -rotation_matrix_impl!(Isometry3, Rotation3, Vector3, Vector3); -rotation_impl!(Isometry3, Rotation3, Vector3); +isometry_impl!(Isometry3, Rotation3, Vector3, Vector3, Point3, Matrix4); dim_impl!(Isometry3, 3); -one_impl!(Isometry3); -absolute_rotate_impl!(Isometry3, Vector3); -rand_impl!(Isometry3); -approx_eq_impl!(Isometry3); -to_homogeneous_impl!(Isometry3, Matrix4); -inverse_impl!(Isometry3); -transform_impl!(Isometry3, Point3); -transformation_impl!(Isometry3); -rotate_impl!(Isometry3, Vector3); -translation_impl!(Isometry3, Vector3); -translate_impl!(Isometry3, Point3); -isometry_mul_isometry_impl!(Isometry3); -isometry_mul_rotation_impl!(Isometry3, Rotation3); -isometry_mul_point_impl!(Isometry3, Point3); -isometry_mul_vec_impl!(Isometry3, Vector3); -arbitrary_isometry_impl!(Isometry3); -isometry_display_impl!(Isometry3); diff --git a/src/structs/isometry_macros.rs b/src/structs/isometry_macros.rs index 8d9742be..14cfb5fd 100644 --- a/src/structs/isometry_macros.rs +++ b/src/structs/isometry_macros.rs @@ -1,74 +1,69 @@ #![macro_use] macro_rules! isometry_impl( - ($t: ident, $submatrix: ident, $subvector: ident, $subrotvector: ident) => ( + ($t: ident, $rotmatrix: ident, $vector: ident, $rotvector: ident, $point: ident, + $homogeneous: ident) => ( impl $t { /// Creates a new isometry from an axis-angle rotation, and a vector. #[inline] - pub fn new(translation: $subvector, rotation: $subrotvector) -> $t { + pub fn new(translation: $vector, rotation: $rotvector) -> $t { $t { - rotation: $submatrix::new(rotation), + rotation: $rotmatrix::new(rotation), translation: translation } } /// Creates a new isometry from a rotation matrix and a vector. #[inline] - pub fn new_with_rotation_matrix(translation: $subvector, rotation: $submatrix) -> $t { + pub fn from_rotation_matrix(translation: $vector, rotation: $rotmatrix) -> $t { $t { rotation: rotation, translation: translation } } } - ) -); -macro_rules! rotation_matrix_impl( - ($t: ident, $trotation: ident, $tlv: ident, $tav: ident) => ( + + /* + * + * RotationMatrix + * + */ impl + BaseFloat> - RotationMatrix, $tav> for $t { - type Output = $trotation; + RotationMatrix, $rotvector> for $t { + type Output = $rotmatrix; #[inline] - fn to_rotation_matrix(&self) -> $trotation { + fn to_rotation_matrix(&self) -> $rotmatrix { self.rotation } } - ) -); -macro_rules! dim_impl( - ($t: ident, $dimension: expr) => ( - impl Dimension for $t { - #[inline] - fn dimension(_: Option<$t>) -> usize { - $dimension - } - } - ) -); - -macro_rules! one_impl( - ($t: ident) => ( + /* + * + * One + * + */ impl One for $t { #[inline] fn one() -> $t { - $t::new_with_rotation_matrix(::zero(), ::one()) + $t::from_rotation_matrix(::zero(), ::one()) } } - ) -); -macro_rules! isometry_mul_isometry_impl( - ($t: ident) => ( + + /* + * + * Isometry × Isometry + * + */ impl Mul<$t> for $t { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { - $t::new_with_rotation_matrix( + $t::from_rotation_matrix( self.translation + self.rotation * right.translation, self.rotation * right.rotation) } @@ -81,192 +76,208 @@ macro_rules! isometry_mul_isometry_impl( self.rotation *= right.rotation; } } - ) -); -macro_rules! isometry_mul_rotation_impl( - ($t: ident, $rotation: ident) => ( - impl Mul<$rotation> for $t { + + /* + * + * Isometry × Rotation + * + */ + impl Mul<$rotmatrix> for $t { type Output = $t; #[inline] - fn mul(self, right: $rotation) -> $t { - $t::new_with_rotation_matrix(self.translation, self.rotation * right) + fn mul(self, right: $rotmatrix) -> $t { + $t::from_rotation_matrix(self.translation, self.rotation * right) } } - impl Mul<$t> for $rotation { + impl Mul<$t> for $rotmatrix { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { - $t::new_with_rotation_matrix( + $t::from_rotation_matrix( self * right.translation, self * right.rotation) } } - impl MulAssign<$rotation> for $t { + impl MulAssign<$rotmatrix> for $t { #[inline] - fn mul_assign(&mut self, right: $rotation) { + fn mul_assign(&mut self, right: $rotmatrix) { self.rotation *= right } } - ) -); -macro_rules! isometry_mul_point_impl( - ($t: ident, $tv: ident) => ( - impl Mul<$tv> for $t { - type Output = $tv; + + /* + * + * Isometry × Point + * + */ + impl Mul<$point> for $t { + type Output = $point; #[inline] - fn mul(self, right: $tv) -> $tv { + fn mul(self, right: $point) -> $point { self.rotation * right + self.translation } } - ) -); -macro_rules! isometry_mul_vec_impl( - ($t: ident, $tv: ident) => ( - impl Mul<$tv> for $t { - type Output = $tv; + + /* + * + * Isometry × Vector + * + */ + impl Mul<$vector> for $t { + type Output = $vector; #[inline] - fn mul(self, right: $tv) -> $tv { + fn mul(self, right: $vector) -> $vector { self.rotation * right } } - ) -); -macro_rules! translation_impl( - ($t: ident, $tv: ident) => ( - impl Translation<$tv> for $t { + + /* + * + * Translation + * + */ + impl Translation<$vector> for $t { #[inline] - fn translation(&self) -> $tv { + fn translation(&self) -> $vector { self.translation } #[inline] - fn inverse_translation(&self) -> $tv { + fn inverse_translation(&self) -> $vector { -self.translation } #[inline] - fn append_translation_mut(&mut self, t: &$tv) { + fn append_translation_mut(&mut self, t: &$vector) { self.translation = *t + self.translation } #[inline] - fn append_translation(&self, t: &$tv) -> $t { - $t::new_with_rotation_matrix(*t + self.translation, self.rotation) + fn append_translation(&self, t: &$vector) -> $t { + $t::from_rotation_matrix(*t + self.translation, self.rotation) } #[inline] - fn prepend_translation_mut(&mut self, t: &$tv) { + fn prepend_translation_mut(&mut self, t: &$vector) { self.translation = self.translation + self.rotation * *t } #[inline] - fn prepend_translation(&self, t: &$tv) -> $t { - $t::new_with_rotation_matrix(self.translation + self.rotation * *t, self.rotation) + fn prepend_translation(&self, t: &$vector) -> $t { + $t::from_rotation_matrix(self.translation + self.rotation * *t, self.rotation) } #[inline] - fn set_translation(&mut self, t: $tv) { + fn set_translation(&mut self, t: $vector) { self.translation = t } } - ) -); -macro_rules! translate_impl( - ($t: ident, $tv: ident) => ( - impl + Sub> Translate<$tv> for $t { + + /* + * + * Translate + * + */ + impl + Sub> Translate<$point> for $t { #[inline] - fn translate(&self, v: &$tv) -> $tv { + fn translate(&self, v: &$point) -> $point { *v + self.translation } #[inline] - fn inverse_translate(&self, v: &$tv) -> $tv { + fn inverse_translate(&self, v: &$point) -> $point { *v - self.translation } } - ) -); -macro_rules! rotation_impl( - ($t: ident, $trotation: ident, $tav: ident) => ( - impl + BaseFloat> Rotation<$tav> for $t { + + /* + * + * Rotation + * + */ + impl + BaseFloat> Rotation<$rotvector> for $t { #[inline] - fn rotation(&self) -> $tav { + fn rotation(&self) -> $rotvector { self.rotation.rotation() } #[inline] - fn inverse_rotation(&self) -> $tav { + fn inverse_rotation(&self) -> $rotvector { self.rotation.inverse_rotation() } #[inline] - fn append_rotation_mut(&mut self, rotation: &$tav) { - let delta = $trotation::new(*rotation); + fn append_rotation_mut(&mut self, rotation: &$rotvector) { + let delta = $rotmatrix::new(*rotation); self.rotation = delta * self.rotation; self.translation = delta * self.translation; } #[inline] - fn append_rotation(&self, rotation: &$tav) -> $t { - let delta = $trotation::new(*rotation); + fn append_rotation(&self, rotation: &$rotvector) -> $t { + let delta = $rotmatrix::new(*rotation); - $t::new_with_rotation_matrix(delta * self.translation, delta * self.rotation) + $t::from_rotation_matrix(delta * self.translation, delta * self.rotation) } #[inline] - fn prepend_rotation_mut(&mut self, rotation: &$tav) { - let delta = $trotation::new(*rotation); + fn prepend_rotation_mut(&mut self, rotation: &$rotvector) { + let delta = $rotmatrix::new(*rotation); self.rotation = self.rotation * delta; } #[inline] - fn prepend_rotation(&self, rotation: &$tav) -> $t { - let delta = $trotation::new(*rotation); + fn prepend_rotation(&self, rotation: &$rotvector) -> $t { + let delta = $rotmatrix::new(*rotation); - $t::new_with_rotation_matrix(self.translation, self.rotation * delta) + $t::from_rotation_matrix(self.translation, self.rotation * delta) } #[inline] - fn set_rotation(&mut self, rotation: $tav) { + fn set_rotation(&mut self, rotation: $rotvector) { // FIXME: should the translation be changed too? self.rotation.set_rotation(rotation) } } - ) -); -macro_rules! rotate_impl( - ($t: ident, $tv: ident) => ( - impl Rotate<$tv> for $t { + + /* + * + * Rotate + * + */ + impl Rotate<$vector> for $t { #[inline] - fn rotate(&self, v: &$tv) -> $tv { + fn rotate(&self, v: &$vector) -> $vector { self.rotation.rotate(v) } #[inline] - fn inverse_rotate(&self, v: &$tv) -> $tv { + fn inverse_rotate(&self, v: &$vector) -> $vector { self.rotation.inverse_rotate(v) } } - ) -); -macro_rules! transformation_impl( - ($t: ident) => ( + + /* + * + * Transformation + * + */ impl Transformation<$t> for $t { fn transformation(&self) -> $t { *self @@ -297,27 +308,31 @@ macro_rules! transformation_impl( *self = t } } - ) -); -macro_rules! transform_impl( - ($t: ident, $tp: ident) => ( - impl Transform<$tp> for $t { + + /* + * + * Transform + * + */ + impl Transform<$point> for $t { #[inline] - fn transform(&self, p: &$tp) -> $tp { + fn transform(&self, p: &$point) -> $point { self.rotation.transform(p) + self.translation } #[inline] - fn inverse_transform(&self, p: &$tp) -> $tp { + fn inverse_transform(&self, p: &$point) -> $point { self.rotation.inverse_transform(&(*p - self.translation)) } } - ) -); -macro_rules! inverse_impl( - ($t: ident) => ( + + /* + * + * Inverse + * + */ impl> Inverse for $t { #[inline] fn inverse_mut(&mut self) -> bool { @@ -335,28 +350,32 @@ macro_rules! inverse_impl( Some(res) } } - ) -); -macro_rules! to_homogeneous_impl( - ($t: ident, $th: ident) => ( - impl ToHomogeneous<$th> for $t { - fn to_homogeneous(&self) -> $th { + + /* + * + * ToHomogeneous + * + */ + impl ToHomogeneous<$homogeneous> for $t { + fn to_homogeneous(&self) -> $homogeneous { let mut res = self.rotation.to_homogeneous(); // copy the translation - let dimension = Dimension::dimension(None::<$th>); + let dimension = Dimension::dimension(None::<$homogeneous>); res.set_column(dimension - 1, self.translation.as_point().to_homogeneous().to_vector()); res } } - ) -); -macro_rules! approx_eq_impl( - ($t: ident) => ( + + /* + * + * ApproxEq + * + */ impl> ApproxEq for $t { #[inline] fn approx_epsilon(_: Option<$t>) -> N { @@ -380,47 +399,55 @@ macro_rules! approx_eq_impl( ApproxEq::approx_eq_ulps(&self.translation, &other.translation, ulps) } } - ) -); -macro_rules! rand_impl( - ($t: ident) => ( + + /* + * + * Rand + * + */ impl Rand for $t { #[inline] fn rand(rng: &mut R) -> $t { $t::new(rng.gen(), rng.gen()) } } - ) -); -macro_rules! absolute_rotate_impl( - ($t: ident, $tv: ident) => ( - impl AbsoluteRotate<$tv> for $t { + + /* + * + * AbsoluteRotate + * + */ + impl AbsoluteRotate<$vector> for $t { #[inline] - fn absolute_rotate(&self, v: &$tv) -> $tv { + fn absolute_rotate(&self, v: &$vector) -> $vector { self.rotation.absolute_rotate(v) } } - ) -); -macro_rules! arbitrary_isometry_impl( - ($t: ident) => ( + + /* + * + * Arbitrary + * + */ #[cfg(feature="arbitrary")] impl Arbitrary for $t { fn arbitrary(g: &mut G) -> $t { - $t::new_with_rotation_matrix( + $t::from_rotation_matrix( Arbitrary::arbitrary(g), Arbitrary::arbitrary(g) ) } } - ) -); -macro_rules! isometry_display_impl( - ($t: ident) => ( + + /* + * + * Display + * + */ impl fmt::Display for $t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(writeln!(f, "Isometry {{")); @@ -441,3 +468,14 @@ macro_rules! isometry_display_impl( } ) ); + +macro_rules! dim_impl( + ($t: ident, $dimension: expr) => ( + impl Dimension for $t { + #[inline] + fn dimension(_: Option<$t>) -> usize { + $dimension + } + } + ) +); diff --git a/src/structs/matrix.rs b/src/structs/matrix.rs index e52f64e0..7e07c663 100644 --- a/src/structs/matrix.rs +++ b/src/structs/matrix.rs @@ -14,7 +14,7 @@ use structs::point::{Point1, Point4, Point5, Point6}; use structs::dvector::{DVector1, DVector2, DVector3, DVector4, DVector5, DVector6}; use traits::structure::{Cast, Row, Column, Iterable, IterableMut, Dimension, Indexable, Eye, ColumnSlice, - RowSlice, Diagonal, DiagMut, Shape, BaseFloat, BaseNum, Repeat}; + RowSlice, Diagonal, DiagonalMut, Shape, BaseFloat, BaseNum, Repeat}; use traits::operations::{Absolute, Transpose, Inverse, Outer, EigenQR, Mean}; use traits::geometry::{ToHomogeneous, FromHomogeneous, Origin}; use linalg; @@ -50,45 +50,20 @@ pub struct Matrix1 { eye_impl!(Matrix1, 1, m11); -mat_impl!(Matrix1, m11); -repeat_impl!(Matrix1, m11); -conversion_impl!(Matrix1, 1); -mat_cast_impl!(Matrix1, m11); -add_impl!(Matrix1, m11); -sub_impl!(Matrix1, m11); -scalar_add_impl!(Matrix1, m11); -scalar_sub_impl!(Matrix1, m11); -scalar_mul_impl!(Matrix1, m11); -scalar_div_impl!(Matrix1, m11); -absolute_impl!(Matrix1, m11); -zero_impl!(Matrix1, m11); +matrix_impl!(Matrix1, 1, Vector1, DVector1, m11); one_impl!(Matrix1, ::one); -iterable_impl!(Matrix1, 1); -iterable_mut_impl!(Matrix1, 1); -at_fast_impl!(Matrix1, 1); dim_impl!(Matrix1, 1); -indexable_impl!(Matrix1, 1); -index_impl!(Matrix1, 1); mat_mul_mat_impl!(Matrix1, 1); mat_mul_vec_impl!(Matrix1, Vector1, 1, ::zero); vec_mul_mat_impl!(Matrix1, Vector1, 1, ::zero); mat_mul_point_impl!(Matrix1, Point1, 1, Origin::origin); point_mul_mat_impl!(Matrix1, Point1, 1, Origin::origin); // (specialized); inverse_impl!(Matrix1, 1); -transpose_impl!(Matrix1, 1); -approx_eq_impl!(Matrix1); -row_impl!(Matrix1, Vector1, 1); -column_impl!(Matrix1, Vector1, 1); -column_slice_impl!(Matrix1, Vector1, DVector1, 1); -row_slice_impl!(Matrix1, Vector1, DVector1, 1); -diag_impl!(Matrix1, Vector1, 1); to_homogeneous_impl!(Matrix1, Matrix2, 1, 2); from_homogeneous_impl!(Matrix1, Matrix2, 1, 2); -outer_impl!(Vector1, Matrix1); eigen_qr_impl!(Matrix1, Vector1); -arbitrary_impl!(Matrix1, m11); -rand_impl!(Matrix1, m11); -mean_impl!(Matrix1, Vector1, 1); +componentwise_arbitrary!(Matrix1, m11); +componentwise_rand!(Matrix1, m11); mat_display_impl!(Matrix1, 1); /// Square matrix of dimension 2. @@ -101,49 +76,20 @@ pub struct Matrix2 { eye_impl!(Matrix2, 2, m11, m22); -mat_impl!(Matrix2, m11, m12, - m21, m22); -repeat_impl!(Matrix2, m11, m12, - m21, m22); -conversion_impl!(Matrix2, 2); -mat_cast_impl!(Matrix2, m11, m12, - m21, m22); -add_impl!(Matrix2, m11, m12, m21, m22); -sub_impl!(Matrix2, m11, m12, m21, m22); -scalar_add_impl!(Matrix2, m11, m12, m21, m22); -scalar_sub_impl!(Matrix2, m11, m12, m21, m22); -scalar_mul_impl!(Matrix2, m11, m12, m21, m22); -scalar_div_impl!(Matrix2, m11, m12, m21, m22); -absolute_impl!(Matrix2, m11, m12, - m21, m22); -zero_impl!(Matrix2, m11, m12, - m21, m22); +matrix_impl!(Matrix2, 2, Vector2, DVector2, m11, m12, + m21, m22); one_impl!(Matrix2, ::one, ::zero, ::zero, ::one); -iterable_impl!(Matrix2, 2); -iterable_mut_impl!(Matrix2, 2); dim_impl!(Matrix2, 2); -indexable_impl!(Matrix2, 2); -index_impl!(Matrix2, 2); -at_fast_impl!(Matrix2, 2); // (specialized); mul_impl!(Matrix2, 2); // (specialized); rmul_impl!(Matrix2, Vector2, 2); // (specialized); lmul_impl!(Matrix2, Vector2, 2); // (specialized); inverse_impl!(Matrix2, 2); -transpose_impl!(Matrix2, 2); -approx_eq_impl!(Matrix2); -row_impl!(Matrix2, Vector2, 2); -column_impl!(Matrix2, Vector2, 2); -column_slice_impl!(Matrix2, Vector2, DVector2, 2); -row_slice_impl!(Matrix2, Vector2, DVector2, 2); -diag_impl!(Matrix2, Vector2, 2); to_homogeneous_impl!(Matrix2, Matrix3, 2, 3); from_homogeneous_impl!(Matrix2, Matrix3, 2, 3); -outer_impl!(Vector2, Matrix2); eigen_qr_impl!(Matrix2, Vector2); -arbitrary_impl!(Matrix2, m11, m12, m21, m22); -rand_impl!(Matrix2, m11, m12, m21, m22); -mean_impl!(Matrix2, Vector2, 2); +componentwise_arbitrary!(Matrix2, m11, m12, m21, m22); +componentwise_rand!(Matrix2, m11, m12, m21, m22); mat_display_impl!(Matrix2, 2); /// Square matrix of dimension 3. @@ -157,91 +103,30 @@ pub struct Matrix3 { eye_impl!(Matrix3, 3, m11, m22, m33); -mat_impl!(Matrix3, m11, m12, m13, - m21, m22, m23, - m31, m32, m33); -repeat_impl!(Matrix3, m11, m12, m13, - m21, m22, m23, - m31, m32, m33); -conversion_impl!(Matrix3, 3); -mat_cast_impl!(Matrix3, m11, m12, m13, - m21, m22, m23, - m31, m32, m33); -add_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -sub_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -scalar_add_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -scalar_sub_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -scalar_mul_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -scalar_div_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -absolute_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); -zero_impl!(Matrix3, - m11, m12, m13, - m21, m22, m23, - m31, m32, m33 -); +matrix_impl!(Matrix3, 3, Vector3, DVector3, m11, m12, m13, + m21, m22, m23, + m31, m32, m33); one_impl!(Matrix3, ::one , ::zero, ::zero, ::zero, ::one , ::zero, ::zero, ::zero, ::one); -iterable_impl!(Matrix3, 3); -iterable_mut_impl!(Matrix3, 3); dim_impl!(Matrix3, 3); -indexable_impl!(Matrix3, 3); -index_impl!(Matrix3, 3); -at_fast_impl!(Matrix3, 3); // (specialized); mul_impl!(Matrix3, 3); // (specialized); rmul_impl!(Matrix3, Vector3, 3); // (specialized); lmul_impl!(Matrix3, Vector3, 3); // (specialized); inverse_impl!(Matrix3, 3); -transpose_impl!(Matrix3, 3); -approx_eq_impl!(Matrix3); -// (specialized); row_impl!(Matrix3, Vector3, 3); -// (specialized); column_impl!(Matrix3, Vector3, 3); -column_slice_impl!(Matrix3, Vector3, DVector3, 3); -row_slice_impl!(Matrix3, Vector3, DVector3, 3); -diag_impl!(Matrix3, Vector3, 3); to_homogeneous_impl!(Matrix3, Matrix4, 3, 4); from_homogeneous_impl!(Matrix3, Matrix4, 3, 4); -outer_impl!(Vector3, Matrix3); eigen_qr_impl!(Matrix3, Vector3); -arbitrary_impl!(Matrix3, +componentwise_arbitrary!(Matrix3, m11, m12, m13, m21, m22, m23, m31, m32, m33 ); -rand_impl!(Matrix3, +componentwise_rand!(Matrix3, m11, m12, m13, m21, m22, m23, m31, m32, m33 ); -mean_impl!(Matrix3, Vector3, 3); mat_display_impl!(Matrix3, 3); /// Square matrix of dimension 4. @@ -256,68 +141,7 @@ pub struct Matrix4 { eye_impl!(Matrix4, 4, m11, m22, m33, m44); -mat_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -repeat_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -conversion_impl!(Matrix4, 4); -mat_cast_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -add_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -sub_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -scalar_add_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -scalar_sub_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -scalar_mul_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -scalar_div_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -absolute_impl!(Matrix4, - m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44 -); -zero_impl!(Matrix4, +matrix_impl!(Matrix4, 4, Vector4, DVector4, m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, @@ -327,42 +151,28 @@ one_impl!(Matrix4, ::one , ::zero, ::zero, ::zero, ::zero, ::one , ::zero, ::zero, ::zero, ::zero, ::one , ::zero, ::zero, ::zero, ::zero, ::one); -iterable_impl!(Matrix4, 4); -iterable_mut_impl!(Matrix4, 4); dim_impl!(Matrix4, 4); -indexable_impl!(Matrix4, 4); -index_impl!(Matrix4, 4); -at_fast_impl!(Matrix4, 4); mat_mul_mat_impl!(Matrix4, 4); mat_mul_vec_impl!(Matrix4, Vector4, 4, ::zero); vec_mul_mat_impl!(Matrix4, Vector4, 4, ::zero); mat_mul_point_impl!(Matrix4, Point4, 4, Origin::origin); point_mul_mat_impl!(Matrix4, Point4, 4, Origin::origin); inverse_impl!(Matrix4, 4); -transpose_impl!(Matrix4, 4); -approx_eq_impl!(Matrix4); -row_impl!(Matrix4, Vector4, 4); -column_impl!(Matrix4, Vector4, 4); -column_slice_impl!(Matrix4, Vector4, DVector4, 4); -row_slice_impl!(Matrix4, Vector4, DVector4, 4); -diag_impl!(Matrix4, Vector4, 4); to_homogeneous_impl!(Matrix4, Matrix5, 4, 5); from_homogeneous_impl!(Matrix4, Matrix5, 4, 5); -outer_impl!(Vector4, Matrix4); eigen_qr_impl!(Matrix4, Vector4); -arbitrary_impl!(Matrix4, +componentwise_arbitrary!(Matrix4, m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44 ); -rand_impl!(Matrix4, +componentwise_rand!(Matrix4, m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44 ); -mean_impl!(Matrix4, Vector4, 4); mat_display_impl!(Matrix4, 4); /// Square matrix of dimension 5. @@ -378,36 +188,7 @@ pub struct Matrix5 { eye_impl!(Matrix5, 5, m11, m22, m33, m44, m55); -mat_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -repeat_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -conversion_impl!(Matrix5, 5); -mat_cast_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -absolute_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -zero_impl!(Matrix5, +matrix_impl!(Matrix5, 5, Vector5, DVector5, m11, m12, m13, m14, m15, m21, m22, m23, m24, m25, m31, m32, m33, m34, m35, @@ -421,86 +202,30 @@ one_impl!(Matrix5, ::zero, ::zero, ::zero, ::one , ::zero, ::zero, ::zero, ::zero, ::zero, ::one ); -add_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -sub_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -scalar_add_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -scalar_sub_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -scalar_mul_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -scalar_div_impl!(Matrix5, - m11, m12, m13, m14, m15, - m21, m22, m23, m24, m25, - m31, m32, m33, m34, m35, - m41, m42, m43, m44, m45, - m51, m52, m53, m54, m55 -); -iterable_impl!(Matrix5, 5); -iterable_mut_impl!(Matrix5, 5); dim_impl!(Matrix5, 5); -indexable_impl!(Matrix5, 5); -index_impl!(Matrix5, 5); -at_fast_impl!(Matrix5, 5); mat_mul_mat_impl!(Matrix5, 5); mat_mul_vec_impl!(Matrix5, Vector5, 5, ::zero); vec_mul_mat_impl!(Matrix5, Vector5, 5, ::zero); mat_mul_point_impl!(Matrix5, Point5, 5, Origin::origin); point_mul_mat_impl!(Matrix5, Point5, 5, Origin::origin); inverse_impl!(Matrix5, 5); -transpose_impl!(Matrix5, 5); -approx_eq_impl!(Matrix5); -row_impl!(Matrix5, Vector5, 5); -column_impl!(Matrix5, Vector5, 5); -column_slice_impl!(Matrix5, Vector5, DVector5, 5); -row_slice_impl!(Matrix5, Vector5, DVector5, 5); -diag_impl!(Matrix5, Vector5, 5); to_homogeneous_impl!(Matrix5, Matrix6, 5, 6); from_homogeneous_impl!(Matrix5, Matrix6, 5, 6); -outer_impl!(Vector5, Matrix5); eigen_qr_impl!(Matrix5, Vector5); -arbitrary_impl!(Matrix5, +componentwise_arbitrary!(Matrix5, m11, m12, m13, m14, m15, m21, m22, m23, m24, m25, m31, m32, m33, m34, m35, m41, m42, m43, m44, m45, m51, m52, m53, m54, m55 ); -rand_impl!(Matrix5, +componentwise_rand!(Matrix5, m11, m12, m13, m14, m15, m21, m22, m23, m24, m25, m31, m32, m33, m34, m35, m41, m42, m43, m44, m45, m51, m52, m53, m54, m55 ); -mean_impl!(Matrix5, Vector5, 5); mat_display_impl!(Matrix5, 5); /// Square matrix of dimension 6. @@ -517,7 +242,7 @@ pub struct Matrix6 { eye_impl!(Matrix6, 6, m11, m22, m33, m44, m55, m66); -mat_impl!(Matrix6, +matrix_impl!(Matrix6, 6, Vector6, DVector6, m11, m12, m13, m14, m15, m16, m21, m22, m23, m24, m25, m26, m31, m32, m33, m34, m35, m36, @@ -525,78 +250,6 @@ mat_impl!(Matrix6, m51, m52, m53, m54, m55, m56, m61, m62, m63, m64, m65, m66 ); -repeat_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -conversion_impl!(Matrix6, 6); -mat_cast_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -add_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -sub_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -scalar_add_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -scalar_sub_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -scalar_mul_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -scalar_div_impl!(Matrix6, - m11, m12, m13, m14, m15, m16, - m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, - m41, m42, m43, m44, m45, m46, - m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66 -); -absolute_impl!(Matrix6, m11, m12, m13, m14, m15, m16, m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, m41, m42, m43, m44, m45, m46, m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66); - -zero_impl!(Matrix6, m11, m12, m13, m14, m15, m16, m21, m22, m23, m24, m25, m26, - m31, m32, m33, m34, m35, m36, m41, m42, m43, m44, m45, m46, m51, m52, m53, m54, m55, m56, - m61, m62, m63, m64, m65, m66); one_impl!(Matrix6, ::one , ::zero, ::zero, ::zero, ::zero, ::zero, @@ -606,28 +259,15 @@ one_impl!(Matrix6, ::zero, ::zero, ::zero, ::zero, ::one , ::zero, ::zero, ::zero, ::zero, ::zero, ::zero, ::one ); -iterable_impl!(Matrix6, 6); -iterable_mut_impl!(Matrix6, 6); dim_impl!(Matrix6, 6); -indexable_impl!(Matrix6, 6); -index_impl!(Matrix6, 6); -at_fast_impl!(Matrix6, 6); mat_mul_mat_impl!(Matrix6, 6); mat_mul_vec_impl!(Matrix6, Vector6, 6, ::zero); vec_mul_mat_impl!(Matrix6, Vector6, 6, ::zero); mat_mul_point_impl!(Matrix6, Point6, 6, Origin::origin); point_mul_mat_impl!(Matrix6, Point6, 6, Origin::origin); inverse_impl!(Matrix6, 6); -transpose_impl!(Matrix6, 6); -approx_eq_impl!(Matrix6); -row_impl!(Matrix6, Vector6, 6); -column_impl!(Matrix6, Vector6, 6); -column_slice_impl!(Matrix6, Vector6, DVector6, 6); -row_slice_impl!(Matrix6, Vector6, DVector6, 6); -diag_impl!(Matrix6, Vector6, 6); -outer_impl!(Vector6, Matrix6); eigen_qr_impl!(Matrix6, Vector6); -arbitrary_impl!(Matrix6, +componentwise_arbitrary!(Matrix6, m11, m12, m13, m14, m15, m16, m21, m22, m23, m24, m25, m26, m31, m32, m33, m34, m35, m36, @@ -635,7 +275,7 @@ arbitrary_impl!(Matrix6, m51, m52, m53, m54, m55, m56, m61, m62, m63, m64, m65, m66 ); -rand_impl!(Matrix6, +componentwise_rand!(Matrix6, m11, m12, m13, m14, m15, m16, m21, m22, m23, m24, m25, m26, m31, m32, m33, m34, m35, m36, @@ -643,5 +283,4 @@ rand_impl!(Matrix6, m51, m52, m53, m54, m55, m56, m61, m62, m63, m64, m65, m66 ); -mean_impl!(Matrix6, Vector6, 6); mat_display_impl!(Matrix6, 6); diff --git a/src/structs/matrix_macros.rs b/src/structs/matrix_macros.rs index 3c401c6b..21404076 100644 --- a/src/structs/matrix_macros.rs +++ b/src/structs/matrix_macros.rs @@ -1,20 +1,22 @@ #![macro_use] -macro_rules! mat_impl( - ($t: ident, $($compN: ident),+) => ( - impl $t { - #[inline] - pub fn new($($compN: N ),+) -> $t { - $t { - $($compN: $compN ),+ +macro_rules! matrix_impl( + ($t: ident, $dimension: expr, $vector: ident, $dvector: ident, $($compN: ident),+) => ( + impl $t { + #[inline] + pub fn new($($compN: N ),+) -> $t { + $t { + $($compN: $compN ),+ + } } } - } - ) -); -macro_rules! conversion_impl( - ($t: ident, $dimension: expr) => ( + + /* + * + * Conversions (AsRef, AsMut, From) + * + */ impl AsRef<[[N; $dimension]; $dimension]> for $t { #[inline] fn as_ref(&self) -> &[[N; $dimension]; $dimension] { @@ -58,11 +60,13 @@ macro_rules! conversion_impl( tref.clone() } } - ) -); -macro_rules! at_fast_impl( - ($t: ident, $dimension: expr) => ( + + /* + * + * Unsafe indexing. + * + */ impl $t { #[inline] pub unsafe fn at_fast(&self, (i, j): (usize, usize)) -> N { @@ -76,331 +80,77 @@ macro_rules! at_fast_impl( .get_unchecked_mut(i + j * $dimension)) = val } } - ) -); -macro_rules! mat_cast_impl( - ($t: ident, $($compN: ident),+) => ( + + /* + * + * Cast + * + */ impl> Cast<$t> for $t { #[inline] fn from(v: $t) -> $t { $t::new($(Cast::from(v.$compN)),+) } } - ) -); -macro_rules! add_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Add<$t> for $t { - type Output = $t; + /* + * + * Iterable + * + */ + impl Iterable for $t { #[inline] - fn add(self, right: $t) -> $t { - $t::new($(self.$compN + right.$compN),+) - } - } - - impl> AddAssign<$t> for $t { - #[inline] - fn add_assign(&mut self, right: $t) { - $( self.$compN += right.$compN; )+ - } - } - ) -); - -macro_rules! sub_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Sub<$t> for $t { - type Output = $t; - - #[inline] - fn sub(self, right: $t) -> $t { - $t::new($(self.$compN - right.$compN),+) - } - } - - - impl> SubAssign<$t> for $t { - #[inline] - fn sub_assign(&mut self, right: $t) { - $( self.$compN -= right.$compN; )+ - } - } - ) -); - -macro_rules! mat_mul_scalar_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Mul for N { - type Output = $t; - - #[inline] - fn mul(self, right: N) -> $t { - $t::new($(self.$compN * *right),+) - } - } - - impl> MulAssign for $t { - #[inline] - fn mul_assign(&mut self, right: N) { - $( self.$compN *= *right; )+ - } - } - - impl Mul<$t> for f32 { - type Output = $t; - - #[inline] - fn mul(self, right: $t) -> $t { - $t::new($(self * right.$compN),+) - } - } - - impl Mul<$t> for f64 { - type Output = $t; - - #[inline] - fn mul(self, right: $t) -> $t { - $t::new($(self * right.$compN),+) - } - } - ) -); - -macro_rules! mat_div_scalar_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Div for $t { - type Output = $t; - - #[inline] - fn div(self, right: N) -> $t { - $t::new($(self.$compN / *right),+) - } - } - - impl> DivAssign for $t { - #[inline] - fn div_assign(&mut self, right: N) { - $( self.$compN /= *right; )+ - } - } - ) -); - -macro_rules! mat_add_scalar_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Add for $t { - type Output = $t; - - #[inline] - fn add(self, right: N) -> $t { - $t::new($(self.$compN + *right),+) - } - } - - impl> AddAssign for $t { - #[inline] - fn add_assign(&mut self, right: N) { - $( self.$compN += *right; )+ - } - } - - impl Add<$t> for f32 { - type Output = $t; - - #[inline] - fn add(self, right: $t) -> $t { - $t::new($(self + right.$compN),+) - } - } - - impl Add<$t> for f64 { - type Output = $t; - - #[inline] - fn add(self, right: $t) -> $t { - $t::new($(self + right.$compN),+) - } - } - ) -); - -macro_rules! mat_sub_scalar_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Sub for $t { - type Output = $t; - - #[inline] - fn sub(self, right: &N) -> $t { - $t::new($(self.$compN - *right),+) - } - } - - impl> SubAssign for $t { - #[inline] - fn sub_assign(&mut self, right: N) { - $( self.$compN -= *right; )+ - } - } - - impl Sub for $t { - type Output = $t; - - #[inline] - fn sub(self, right: $t) -> $t { - $t::new($(self - right.$compN),+) - } - } - - impl Sub for $t { - type Output = $t; - - #[inline] - fn sub(self, right: $t) -> $t { - $t::new($(self - right.$compN),+) - } - } - ) -); - - -macro_rules! eye_impl( - ($t: ident, $dimension: expr, $($comp_diagN: ident),+) => ( - impl Eye for $t { - fn new_identity(dimension: usize) -> $t { - assert!(dimension == $dimension); - let mut eye: $t = ::zero(); - $(eye.$comp_diagN = ::one();)+ - eye - } - } - ) -); - -macro_rules! repeat_impl( - ($t: ident, $($compN: ident),+) => ( - impl Repeat for $t { - fn repeat(val: N) -> $t { - $t { - $($compN: val ),+ + fn iter(&self) -> Iter { + unsafe { + mem::transmute::<&$t, &[N; $dimension * $dimension]>(self).iter() } } } - ) -); -macro_rules! absolute_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Absolute<$t> for $t { - #[inline] - fn abs(m: &$t) -> $t { - $t::new($(::abs(&m.$compN) ),+) - } - } - ) -); - -macro_rules! iterable_impl( - ($t: ident, $dimension: expr) => ( - impl Iterable for $t { - #[inline] - fn iter<'l>(&'l self) -> Iter<'l, N> { - unsafe { - mem::transmute::<&'l $t, &'l [N; $dimension * $dimension]>(self).iter() - } - } - } - ) -); - -macro_rules! iterable_mut_impl( - ($t: ident, $dimension: expr) => ( - impl IterableMut for $t { - #[inline] - fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> { - unsafe { - mem::transmute::<&'l mut $t, &'l mut [N; $dimension * $dimension]>(self).iter_mut() - } - } - } - ) -); - -macro_rules! one_impl( - ($t: ident, $($valueN: expr),+ ) => ( - impl One for $t { - #[inline] - fn one() -> $t { - $t::new($($valueN() ),+) - } - } - ) -); - -macro_rules! zero_impl( - ($t: ident, $($compN: ident),+ ) => ( - impl Zero for $t { - #[inline] - fn zero() -> $t { - $t { - $($compN: ::zero() ),+ + impl IterableMut for $t { + #[inline] + fn iter_mut(& mut self) -> IterMut { + unsafe { + mem::transmute::<&mut $t, &mut [N; $dimension * $dimension]>(self).iter_mut() + } } } - #[inline] - fn is_zero(&self) -> bool { - $(::is_zero(&self.$compN) )&&+ - } - } - ) -); -macro_rules! dim_impl( - ($t: ident, $dimension: expr) => ( - impl Dimension for $t { - #[inline] - fn dimension(_: Option<$t>) -> usize { - $dimension - } - } - ) -); - -macro_rules! indexable_impl( - ($t: ident, $dimension: expr) => ( - impl Shape<(usize, usize)> for $t { - #[inline] - fn shape(&self) -> (usize, usize) { - ($dimension, $dimension) - } - } - - impl Indexable<(usize, usize), N> for $t { - #[inline] - fn swap(&mut self, (i1, j1): (usize, usize), (i2, j2): (usize, usize)) { - unsafe { - mem::transmute::<&mut $t, &mut [N; $dimension * $dimension]>(self) - .swap(i1 + j1 * $dimension, i2 + j2 * $dimension) + /* + * + * Shape/Indexable/Index + * + */ + impl Shape<(usize, usize)> for $t { + #[inline] + fn shape(&self) -> (usize, usize) { + ($dimension, $dimension) } } - #[inline] - unsafe fn unsafe_at(&self, (i, j): (usize, usize)) -> N { - (*mem::transmute::<&$t, &[N; $dimension * $dimension]>(self).get_unchecked(i + j * $dimension)) + impl Indexable<(usize, usize), N> for $t { + #[inline] + fn swap(&mut self, (i1, j1): (usize, usize), (i2, j2): (usize, usize)) { + unsafe { + mem::transmute::<&mut $t, &mut [N; $dimension * $dimension]>(self) + .swap(i1 + j1 * $dimension, i2 + j2 * $dimension) + } + } + + #[inline] + unsafe fn unsafe_at(&self, (i, j): (usize, usize)) -> N { + (*mem::transmute::<&$t, &[N; $dimension * $dimension]>(self).get_unchecked(i + j * $dimension)) + } + + #[inline] + unsafe fn unsafe_set(&mut self, (i, j): (usize, usize), val: N) { + (*mem::transmute::<&mut $t, &mut [N; $dimension * $dimension]>(self).get_unchecked_mut(i + j * $dimension)) = val + } } - #[inline] - unsafe fn unsafe_set(&mut self, (i, j): (usize, usize), val: N) { - (*mem::transmute::<&mut $t, &mut [N; $dimension * $dimension]>(self).get_unchecked_mut(i + j * $dimension)) = val - } - } - ) -); - -macro_rules! index_impl( - ($t: ident, $dimension: expr) => ( impl Index<(usize, usize)> for $t { type Output = N; @@ -418,96 +168,167 @@ macro_rules! index_impl( } } } - ) -); -macro_rules! column_slice_impl( - ($t: ident, $tv: ident, $slice: ident, $dimension: expr) => ( - impl ColumnSlice<$slice> for $t { - fn column_slice(&self, cid: usize, rstart: usize, rend: usize) -> $slice { + + /* + * + * Row/Column + * + */ + impl Column<$vector> for $t { + #[inline] + fn ncols(&self) -> usize { + Dimension::dimension(None::<$t>) + } + + #[inline] + fn set_column(&mut self, column: usize, v: $vector) { + for (i, e) in v.iter().enumerate() { + self[(i, column)] = *e; + } + } + + #[inline] + fn column(&self, column: usize) -> $vector { + let mut res: $vector = ::zero(); + + for (i, e) in res.iter_mut().enumerate() { + *e = self[(i, column)]; + } + + res + } + } + + impl ColumnSlice<$dvector> for $t { + fn column_slice(&self, cid: usize, rstart: usize, rend: usize) -> $dvector { let column = self.column(cid); - $slice::from_slice(rend - rstart, &column.as_ref()[rstart .. rend]) - } - } - ) -); - -macro_rules! row_impl( - ($t: ident, $tv: ident, $dimension: expr) => ( - impl Row<$tv> for $t { - #[inline] - fn nrows(&self) -> usize { - Dimension::dimension(None::<$t>) - } - - #[inline] - fn set_row(&mut self, row: usize, v: $tv) { - for (i, e) in v.iter().enumerate() { - self[(row, i)] = *e; + $dvector::from_slice(rend - rstart, &column.as_ref()[rstart .. rend]) } } - #[inline] - fn row(&self, row: usize) -> $tv { - let mut res: $tv = ::zero(); - - for (i, e) in res.iter_mut().enumerate() { - *e = self[(row, i)]; + impl Row<$vector> for $t { + #[inline] + fn nrows(&self) -> usize { + Dimension::dimension(None::<$t>) } - res - } - } - ) -); + #[inline] + fn set_row(&mut self, row: usize, v: $vector) { + for (i, e) in v.iter().enumerate() { + self[(row, i)] = *e; + } + } -macro_rules! row_slice_impl( - ($t: ident, $tv: ident, $slice: ident, $dimension: expr) => ( - impl RowSlice<$slice> for $t { - fn row_slice(&self, rid: usize, cstart: usize, cend: usize) -> $slice { + #[inline] + fn row(&self, row: usize) -> $vector { + let mut res: $vector = ::zero(); + + for (i, e) in res.iter_mut().enumerate() { + *e = self[(row, i)]; + } + + res + } + } + + impl RowSlice<$dvector> for $t { + fn row_slice(&self, rid: usize, cstart: usize, cend: usize) -> $dvector { let row = self.row(rid); - $slice::from_slice(cend - cstart, &row.as_ref()[cstart .. cend]) - } - } - ) -); - -macro_rules! column_impl( - ($t: ident, $tv: ident, $dimension: expr) => ( - impl Column<$tv> for $t { - #[inline] - fn ncols(&self) -> usize { - Dimension::dimension(None::<$t>) - } - - #[inline] - fn set_column(&mut self, column: usize, v: $tv) { - for (i, e) in v.iter().enumerate() { - self[(i, column)] = *e; + $dvector::from_slice(cend - cstart, &row.as_ref()[cstart .. cend]) } } - #[inline] - fn column(&self, column: usize) -> $tv { - let mut res: $tv = ::zero(); - for (i, e) in res.iter_mut().enumerate() { - *e = self[(i, column)]; - } - - res - } - } - ) -); - -macro_rules! diag_impl( - ($t: ident, $tv: ident, $dimension: expr) => ( - impl Diagonal<$tv> for $t { + /* + * + * Transpose + * + */ + impl Transpose for $t { #[inline] - fn from_diagonal(diagonal: &$tv) -> $t { + fn transpose(&self) -> $t { + let mut res = *self; + + res.transpose_mut(); + res + } + + #[inline] + fn transpose_mut(&mut self) { + for i in 1 .. $dimension { + for j in 0 .. i { + self.swap((i, j), (j, i)) + } + } + } + } + + + /* + * + * ApproxEq + * + */ + impl> ApproxEq for $t { + #[inline] + fn approx_epsilon(_: Option<$t>) -> N { + ApproxEq::approx_epsilon(None::) + } + + #[inline] + fn approx_ulps(_: Option<$t>) -> u32 { + ApproxEq::approx_ulps(None::) + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { + let mut zip = self.iter().zip(other.iter()); + zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon)) + } + + #[inline] + fn approx_eq_ulps(&self, other: &$t, ulps: u32) -> bool { + let mut zip = self.iter().zip(other.iter()); + zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps)) + } + } + + + /* + * + * Mean + * + */ + impl + Clone> Mean<$vector> for $t { + fn mean(&self) -> $vector { + let mut res: $vector = ::zero(); + let normalizer: N = Cast::from(1.0f64 / $dimension as f64); + + for i in 0 .. $dimension { + for j in 0 .. $dimension { + unsafe { + let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer; + res.unsafe_set(j, acc); + } + } + } + + res + } + } + + + /* + * + * Diagonal + * + */ + impl Diagonal<$vector> for $t { + #[inline] + fn from_diagonal(diagonal: &$vector) -> $t { let mut res: $t = ::zero(); res.set_diagonal(diagonal); @@ -516,8 +337,8 @@ macro_rules! diag_impl( } #[inline] - fn diagonal(&self) -> $tv { - let mut diagonal: $tv = ::zero(); + fn diagonal(&self) -> $vector { + let mut diagonal: $vector = ::zero(); for i in 0 .. $dimension { unsafe { diagonal.unsafe_set(i, self.unsafe_at((i, i))) } @@ -527,17 +348,61 @@ macro_rules! diag_impl( } } - impl DiagMut<$tv> for $t { + impl DiagonalMut<$vector> for $t { #[inline] - fn set_diagonal(&mut self, diagonal: &$tv) { + fn set_diagonal(&mut self, diagonal: &$vector) { for i in 0 .. $dimension { unsafe { self.unsafe_set((i, i), diagonal.unsafe_at(i)) } } } } + + + /* + * + * Outer + * + */ + impl + Zero> Outer for $vector { + type OuterProductType = $t; + + #[inline] + fn outer(&self, other: &$vector) -> $t { + let mut res: $t = ::zero(); + + for i in 0 .. ::dimension::<$vector>() { + for j in 0 .. ::dimension::<$vector>() { + res[(i, j)] = self[i] * other[j] + } + } + res + } + } + + /* + * + * Componentwise unary operations. + * + */ + componentwise_repeat!($t, $($compN),+); + componentwise_absolute!($t, $($compN),+); + componentwise_zero!($t, $($compN),+); + + /* + * + * Pointwise binary operations. + * + */ + pointwise_add!($t, $($compN),+); + pointwise_sub!($t, $($compN),+); + pointwise_scalar_add!($t, $($compN),+); + pointwise_scalar_sub!($t, $($compN),+); + pointwise_scalar_div!($t, $($compN),+); + pointwise_scalar_mul!($t, $($compN),+); ) ); + macro_rules! mat_mul_mat_impl( ($t: ident, $dimension: expr) => ( impl Mul<$t> for $t { @@ -727,56 +592,6 @@ macro_rules! inverse_impl( ) ); -macro_rules! transpose_impl( - ($t: ident, $dimension: expr) => ( - impl Transpose for $t { - #[inline] - fn transpose(&self) -> $t { - let mut res = *self; - - res.transpose_mut(); - res - } - - #[inline] - fn transpose_mut(&mut self) { - for i in 1..$dimension { - for j in 0..i { - self.swap((i, j), (j, i)) - } - } - } - } - ) -); - -macro_rules! approx_eq_impl( - ($t: ident) => ( - impl> ApproxEq for $t { - #[inline] - fn approx_epsilon(_: Option<$t>) -> N { - ApproxEq::approx_epsilon(None::) - } - - #[inline] - fn approx_ulps(_: Option<$t>) -> u32 { - ApproxEq::approx_ulps(None::) - } - - #[inline] - fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { - let mut zip = self.iter().zip(other.iter()); - zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon)) - } - - #[inline] - fn approx_eq_ulps(&self, other: &$t, ulps: u32) -> bool { - let mut zip = self.iter().zip(other.iter()); - zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps)) - } - } - ) -); macro_rules! to_homogeneous_impl( ($t: ident, $t2: ident, $dimension: expr, $dim2: expr) => ( @@ -785,8 +600,8 @@ macro_rules! to_homogeneous_impl( fn to_homogeneous(&self) -> $t2 { let mut res: $t2 = ::one(); - for i in 0..$dimension { - for j in 0..$dimension { + for i in 0 .. $dimension { + for j in 0 .. $dimension { res[(i, j)] = self[(i, j)] } } @@ -804,8 +619,8 @@ macro_rules! from_homogeneous_impl( fn from(m: &$t2) -> $t { let mut res: $t = ::one(); - for i in 0..$dimension { - for j in 0..$dimension { + for i in 0 .. $dimension { + for j in 0 .. $dimension { res[(i, j)] = m[(i, j)] } } @@ -819,24 +634,6 @@ macro_rules! from_homogeneous_impl( ) ); -macro_rules! outer_impl( - ($t: ident, $m: ident) => ( - impl + Zero> Outer for $t { - type OuterProductType = $m; - - #[inline] - fn outer(&self, other: &$t) -> $m { - let mut res: $m = ::zero(); - for i in 0..Dimension::dimension(None::<$t>) { - for j in 0..Dimension::dimension(None::<$t>) { - res[(i, j)] = self[i] * other[j] - } - } - res - } - } - ) -); macro_rules! eigen_qr_impl( ($t: ident, $v: ident) => ( @@ -850,27 +647,6 @@ macro_rules! eigen_qr_impl( ); -macro_rules! mean_impl( - ($t: ident, $v: ident, $dimension: expr) => ( - impl + Clone> Mean<$v> for $t { - fn mean(&self) -> $v { - let mut res: $v = ::zero(); - let normalizer: N = Cast::from(1.0f64 / $dimension as f64); - - for i in 0 .. $dimension { - for j in 0 .. $dimension { - unsafe { - let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer; - res.unsafe_set(j, acc); - } - } - } - - res - } - } - ) -); macro_rules! mat_display_impl( ($t: ident, $dimension: expr) => ( @@ -924,3 +700,39 @@ macro_rules! mat_display_impl( } ) ); + +macro_rules! one_impl( + ($t: ident, $($valueN: expr),+ ) => ( + impl One for $t { + #[inline] + fn one() -> $t { + $t::new($($valueN() ),+) + } + } + ) +); + +macro_rules! eye_impl( + ($t: ident, $dimension: expr, $($comp_diagN: ident),+) => ( + impl Eye for $t { + fn new_identity(dimension: usize) -> $t { + assert!(dimension == $dimension); + let mut eye: $t = ::zero(); + $(eye.$comp_diagN = ::one();)+ + eye + } + } + ) +); + + +macro_rules! dim_impl( + ($t: ident, $dimension: expr) => ( + impl Dimension for $t { + #[inline] + fn dimension(_: Option<$t>) -> usize { + $dimension + } + } + ) +); diff --git a/src/structs/mod.rs b/src/structs/mod.rs index 5eae0cbf..983b8ac5 100644 --- a/src/structs/mod.rs +++ b/src/structs/mod.rs @@ -11,10 +11,12 @@ pub use self::similarity::{Similarity2, Similarity3}; pub use self::perspective::{Perspective3, PerspectiveMatrix3}; pub use self::orthographic::{Orthographic3, OrthographicMatrix3}; pub use self::quaternion::{Quaternion, UnitQuaternion}; +pub use self::unit::Unit; #[cfg(feature="generic_sizes")] pub use self::vectorn::VectorN; +mod common_macros; mod dmatrix_macros; mod dmatrix; mod vectorn_macros; @@ -37,6 +39,7 @@ mod similarity_macros; mod similarity; mod perspective; mod orthographic; +mod unit; // Specialization for some 1d, 2d and 3d operations. #[doc(hidden)] diff --git a/src/structs/orthographic.rs b/src/structs/orthographic.rs index 12b27cc8..7e355279 100644 --- a/src/structs/orthographic.rs +++ b/src/structs/orthographic.rs @@ -71,41 +71,41 @@ impl Arbitrary for Orthographic3 { } } -impl Orthographic3 { +impl Orthographic3 { /// The smallest x-coordinate of the view cuboid. #[inline] pub fn left(&self) -> N { - self.left.clone() + self.left } /// The largest x-coordinate of the view cuboid. #[inline] pub fn right(&self) -> N { - self.right.clone() + self.right } /// The smallest y-coordinate of the view cuboid. #[inline] pub fn bottom(&self) -> N { - self.bottom.clone() + self.bottom } /// The largest y-coordinate of the view cuboid. #[inline] pub fn top(&self) -> N { - self.top.clone() + self.top } /// The near plane offset of the view cuboid. #[inline] pub fn znear(&self) -> N { - self.znear.clone() + self.znear } /// The far plane offset of the view cuboid. #[inline] pub fn zfar(&self) -> N { - self.zfar.clone() + self.zfar } /// Sets the smallest x-coordinate of the view cuboid. @@ -183,23 +183,20 @@ impl OrthographicMatrix3 { } /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view. - pub fn new_with_fov(aspect: N, vfov: N, znear: N, zfar: N) -> OrthographicMatrix3 { + pub fn from_fov(aspect: N, vfov: N, znear: N, zfar: N) -> OrthographicMatrix3 { assert!(znear < zfar, "The far plane must be farther than the near plane."); assert!(!::is_zero(&aspect)); - let _1: N = ::one(); - let _2 = _1 + _1; - let width = zfar * (vfov / _2).tan(); + let half: N = ::cast(0.5); + let width = zfar * (vfov * half).tan(); let height = width / aspect; - OrthographicMatrix3::new(-width / _2, width / _2, -height / _2, height / _2, znear, zfar) + OrthographicMatrix3::new(-width * half, width * half, -height * half, height * half, znear, zfar) } /// Creates a new orthographic matrix from a 4D matrix. - /// - /// This is unsafe because the input matrix is not checked to be a orthographic projection. #[inline] - pub unsafe fn new_with_matrix(matrix: Matrix4) -> OrthographicMatrix3 { + pub fn from_matrix_unchecked(matrix: Matrix4) -> OrthographicMatrix3 { OrthographicMatrix3 { matrix: matrix } @@ -207,7 +204,7 @@ impl OrthographicMatrix3 { /// Returns a reference to the 4D matrix (using homogeneous coordinates) of this projection. #[inline] - pub fn as_matrix<'a>(&'a self) -> &'a Matrix4 { + pub fn as_matrix(&self) -> &Matrix4 { &self.matrix } @@ -334,11 +331,11 @@ impl OrthographicMatrix3 { } } -impl OrthographicMatrix3 { +impl OrthographicMatrix3 { /// Returns the 4D matrix (using homogeneous coordinates) of this projection. #[inline] - pub fn to_matrix<'a>(&'a self) -> Matrix4 { - self.matrix.clone() + pub fn to_matrix(&self) -> Matrix4 { + self.matrix } } @@ -351,7 +348,7 @@ impl Arbitrary for OrthographicMatrix3 { } -/// Similarityple helper function for rejection sampling +/// Simple helper function for rejection sampling #[cfg(feature="arbitrary")] #[inline] pub fn reject bool, T: Arbitrary>(g: &mut G, f: F) -> T { diff --git a/src/structs/perspective.rs b/src/structs/perspective.rs index f3a7f213..4788e279 100644 --- a/src/structs/perspective.rs +++ b/src/structs/perspective.rs @@ -63,29 +63,29 @@ impl Arbitrary for Perspective3 { } } -impl Perspective3 { +impl Perspective3 { /// Gets the `width / height` aspect ratio. #[inline] pub fn aspect(&self) -> N { - self.aspect.clone() + self.aspect } /// Gets the y field of view of the view frustrum. #[inline] pub fn fovy(&self) -> N { - self.fovy.clone() + self.fovy } /// Gets the near plane offset of the view frustrum. #[inline] pub fn znear(&self) -> N { - self.znear.clone() + self.znear } /// Gets the far plane offset of the view frustrum. #[inline] pub fn zfar(&self) -> N { - self.zfar.clone() + self.zfar } /// Sets the `width / height` aspect ratio of the view frustrum. @@ -154,10 +154,8 @@ impl PerspectiveMatrix3 { } /// Creates a new perspective projection matrix from a 4D matrix. - /// - /// This is unsafe because the input matrix is not checked to be a perspective projection. #[inline] - pub unsafe fn new_with_matrix(matrix: Matrix4) -> PerspectiveMatrix3 { + pub fn from_matrix_unchecked(matrix: Matrix4) -> PerspectiveMatrix3 { PerspectiveMatrix3 { matrix: matrix } @@ -165,7 +163,7 @@ impl PerspectiveMatrix3 { /// Returns a reference to the 4D matrix (using homogeneous coordinates) of this projection. #[inline] - pub fn as_matrix<'a>(&'a self) -> &'a Matrix4 { + pub fn as_matrix(&self) -> &Matrix4 { &self.matrix } @@ -178,30 +176,23 @@ impl PerspectiveMatrix3 { /// Gets the y field of view of the view frustrum. #[inline] pub fn fovy(&self) -> N { - let _1: N = ::one(); - let _2 = _1 + _1; - - (_1 / self.matrix.m22).atan() * _2 + (::one::() / self.matrix.m22).atan() * ::cast(2.0) } /// Gets the near plane offset of the view frustrum. #[inline] pub fn znear(&self) -> N { - let _1: N = ::one(); - let _2 = _1 + _1; - let ratio = (-self.matrix.m33 + _1) / (-self.matrix.m33 - _1); + let ratio = (-self.matrix.m33 + ::one::()) / (-self.matrix.m33 - ::one::()); - self.matrix.m34 / (_2 * ratio) - self.matrix.m34 / _2 + self.matrix.m34 / (ratio * ::cast(2.0)) - self.matrix.m34 / ::cast(2.0) } /// Gets the far plane offset of the view frustrum. #[inline] pub fn zfar(&self) -> N { - let _1: N = ::one(); - let _2 = _1 + _1; - let ratio = (-self.matrix.m33 + _1) / (-self.matrix.m33 - _1); + let ratio = (-self.matrix.m33 + ::one()) / (-self.matrix.m33 - ::one()); - (self.matrix.m34 - ratio * self.matrix.m34) / _2 + (self.matrix.m34 - ratio * self.matrix.m34) / ::cast(2.0) } // FIXME: add a method to retrieve znear and zfar simultaneously? @@ -217,11 +208,8 @@ impl PerspectiveMatrix3 { /// Updates this projection with a new y field of view of the view frustrum. #[inline] pub fn set_fovy(&mut self, fovy: N) { - let _1: N = ::one(); - let _2 = _1 + _1; - - let old_m22 = self.matrix.m22.clone(); - self.matrix.m22 = _1 / (fovy / _2).tan(); + let old_m22 = self.matrix.m22; + self.matrix.m22 = ::one::() / (fovy / ::cast(2.0)).tan(); self.matrix.m11 = self.matrix.m11 * (self.matrix.m22 / old_m22); } @@ -242,18 +230,15 @@ impl PerspectiveMatrix3 { /// Updates this projection matrix with new near and far plane offsets of the view frustrum. #[inline] pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) { - let _1: N = ::one(); - let _2 = _1 + _1; - self.matrix.m33 = (zfar + znear) / (znear - zfar); - self.matrix.m34 = zfar * znear * _2 / (znear - zfar); + self.matrix.m34 = zfar * znear * ::cast(2.0) / (znear - zfar); } /// Projects a point. #[inline] pub fn project_point(&self, p: &Point3) -> Point3 { - let _1: N = ::one(); - let inverse_denom = -_1 / p.z; + let inverse_denom = -::one::() / p.z; + Point3::new( self.matrix.m11 * p.x * inverse_denom, self.matrix.m22 * p.y * inverse_denom, @@ -264,8 +249,8 @@ impl PerspectiveMatrix3 { /// Projects a vector. #[inline] pub fn project_vector(&self, p: &Vector3) -> Vector3 { - let _1: N = ::one(); - let inverse_denom = -_1 / p.z; + let inverse_denom = -::one::() / p.z; + Vector3::new( self.matrix.m11 * p.x * inverse_denom, self.matrix.m22 * p.y * inverse_denom, @@ -274,11 +259,11 @@ impl PerspectiveMatrix3 { } } -impl PerspectiveMatrix3 { +impl PerspectiveMatrix3 { /// Returns the 4D matrix (using homogeneous coordinates) of this projection. #[inline] - pub fn to_matrix<'a>(&'a self) -> Matrix4 { - self.matrix.clone() + pub fn to_matrix(&self) -> Matrix4 { + self.matrix } } diff --git a/src/structs/point.rs b/src/structs/point.rs index 442e1ab3..699d7aaa 100644 --- a/src/structs/point.rs +++ b/src/structs/point.rs @@ -27,38 +27,9 @@ pub struct Point1 { pub x: N } -new_impl!(Point1, x); -origin_impl!(Point1, x); -pord_impl!(Point1, x,); -scalar_mul_impl!(Point1, x); -scalar_div_impl!(Point1, x); -scalar_add_impl!(Point1, x); -scalar_sub_impl!(Point1, x); -vec_cast_impl!(Point1, x); -conversion_impl!(Point1, 1); -index_impl!(Point1); -indexable_impl!(Point1, 1); -at_fast_impl!(Point1, 1); -repeat_impl!(Point1, val, x); -dim_impl!(Point1, 1); -container_impl!(Point1); -point_as_vec_impl!(Point1, Vector1, x); -point_sub_impl!(Point1, Vector1); -neg_impl!(Point1, x); -point_add_vec_impl!(Point1, Vector1, x); -point_sub_vec_impl!(Point1, Vector1, x); -approx_eq_impl!(Point1, x); +point_impl!(Point1, Vector1, Point2, y | x); +vectorlike_impl!(Point1, 1, x); from_iterator_impl!(Point1, iterator); -bounded_impl!(Point1, x); -axpy_impl!(Point1, x); -iterable_impl!(Point1, 1); -iterable_mut_impl!(Point1, 1); -point_to_homogeneous_impl!(Point1, Point2, y, x); -point_from_homogeneous_impl!(Point1, Point2, y, x); -num_float_point_impl!(Point1, Vector1); -arbitrary_point_impl!(Point1, x); -rand_impl!(Point1, x); -point_display_impl!(Point1); /// Point of dimension 2. /// @@ -73,38 +44,9 @@ pub struct Point2 { pub y: N } -new_impl!(Point2, x, y); -origin_impl!(Point2, x, y); -pord_impl!(Point2, x, y); -scalar_mul_impl!(Point2, x, y); -scalar_div_impl!(Point2, x, y); -scalar_add_impl!(Point2, x, y); -scalar_sub_impl!(Point2, x, y); -vec_cast_impl!(Point2, x, y); -conversion_impl!(Point2, 2); -index_impl!(Point2); -indexable_impl!(Point2, 2); -at_fast_impl!(Point2, 2); -repeat_impl!(Point2, val, x, y); -dim_impl!(Point2, 2); -container_impl!(Point2); -point_as_vec_impl!(Point2, Vector2, x, y); -point_sub_impl!(Point2, Vector2); -neg_impl!(Point2, x, y); -point_add_vec_impl!(Point2, Vector2, x, y); -point_sub_vec_impl!(Point2, Vector2, x, y); -approx_eq_impl!(Point2, x, y); +point_impl!(Point2, Vector2, Point3, z | x, y); +vectorlike_impl!(Point2, 2, x, y); from_iterator_impl!(Point2, iterator, iterator); -bounded_impl!(Point2, x, y); -axpy_impl!(Point2, x, y); -iterable_impl!(Point2, 2); -iterable_mut_impl!(Point2, 2); -point_to_homogeneous_impl!(Point2, Point3, z, x, y); -point_from_homogeneous_impl!(Point2, Point3, z, x, y); -num_float_point_impl!(Point2, Vector2); -arbitrary_point_impl!(Point2, x, y); -rand_impl!(Point2, x, y); -point_display_impl!(Point2); /// Point of dimension 3. /// @@ -121,38 +63,9 @@ pub struct Point3 { pub z: N } -new_impl!(Point3, x, y, z); -origin_impl!(Point3, x, y, z); -pord_impl!(Point3, x, y, z); -scalar_mul_impl!(Point3, x, y, z); -scalar_div_impl!(Point3, x, y, z); -scalar_add_impl!(Point3, x, y, z); -scalar_sub_impl!(Point3, x, y, z); -vec_cast_impl!(Point3, x, y, z); -conversion_impl!(Point3, 3); -index_impl!(Point3); -indexable_impl!(Point3, 3); -at_fast_impl!(Point3, 3); -repeat_impl!(Point3, val, x, y, z); -dim_impl!(Point3, 3); -container_impl!(Point3); -point_as_vec_impl!(Point3, Vector3, x, y, z); -point_sub_impl!(Point3, Vector3); -neg_impl!(Point3, x, y, z); -point_add_vec_impl!(Point3, Vector3, x, y, z); -point_sub_vec_impl!(Point3, Vector3, x, y, z); -approx_eq_impl!(Point3, x, y, z); +point_impl!(Point3, Vector3, Point4, w | x, y, z); +vectorlike_impl!(Point3, 3, x, y, z); from_iterator_impl!(Point3, iterator, iterator, iterator); -bounded_impl!(Point3, x, y, z); -axpy_impl!(Point3, x, y, z); -iterable_impl!(Point3, 3); -iterable_mut_impl!(Point3, 3); -point_to_homogeneous_impl!(Point3, Point4, w, x, y, z); -point_from_homogeneous_impl!(Point3, Point4, w, x, y, z); -num_float_point_impl!(Point3, Vector3); -arbitrary_point_impl!(Point3, x, y, z); -rand_impl!(Point3, x, y, z); -point_display_impl!(Point3); /// Point of dimension 4. /// @@ -171,38 +84,9 @@ pub struct Point4 { pub w: N } -new_impl!(Point4, x, y, z, w); -origin_impl!(Point4, x, y, z, w); -pord_impl!(Point4, x, y, z, w); -scalar_mul_impl!(Point4, x, y, z, w); -scalar_div_impl!(Point4, x, y, z, w); -scalar_add_impl!(Point4, x, y, z, w); -scalar_sub_impl!(Point4, x, y, z, w); -vec_cast_impl!(Point4, x, y, z, w); -conversion_impl!(Point4, 4); -index_impl!(Point4); -indexable_impl!(Point4, 4); -at_fast_impl!(Point4, 4); -repeat_impl!(Point4, val, x, y, z, w); -dim_impl!(Point4, 4); -container_impl!(Point4); -point_as_vec_impl!(Point4, Vector4, x, y, z, w); -point_sub_impl!(Point4, Vector4); -neg_impl!(Point4, x, y, z, w); -point_add_vec_impl!(Point4, Vector4, x, y, z, w); -point_sub_vec_impl!(Point4, Vector4, x, y, z, w); -approx_eq_impl!(Point4, x, y, z, w); +point_impl!(Point4, Vector4, Point5, a | x, y, z, w); +vectorlike_impl!(Point4, 4, x, y, z, w); from_iterator_impl!(Point4, iterator, iterator, iterator, iterator); -bounded_impl!(Point4, x, y, z, w); -axpy_impl!(Point4, x, y, z, w); -iterable_impl!(Point4, 4); -iterable_mut_impl!(Point4, 4); -point_to_homogeneous_impl!(Point4, Point5, a, x, y, z, w); -point_from_homogeneous_impl!(Point4, Point5, a, x, y, z, w); -num_float_point_impl!(Point4, Vector4); -arbitrary_point_impl!(Point4, x, y, z, w); -rand_impl!(Point4, x, y, z, w); -point_display_impl!(Point4); /// Point of dimension 5. /// @@ -223,38 +107,9 @@ pub struct Point5 { pub a: N } -new_impl!(Point5, x, y, z, w, a); -origin_impl!(Point5, x, y, z, w, a); -pord_impl!(Point5, x, y, z, w, a); -scalar_mul_impl!(Point5, x, y, z, w, a); -scalar_div_impl!(Point5, x, y, z, w, a); -scalar_add_impl!(Point5, x, y, z, w, a); -scalar_sub_impl!(Point5, x, y, z, w, a); -vec_cast_impl!(Point5, x, y, z, w, a); -conversion_impl!(Point5, 5); -index_impl!(Point5); -indexable_impl!(Point5, 5); -at_fast_impl!(Point5, 5); -repeat_impl!(Point5, val, x, y, z, w, a); -dim_impl!(Point5, 5); -container_impl!(Point5); -point_as_vec_impl!(Point5, Vector5, x, y, z, w, a); -point_sub_impl!(Point5, Vector5); -neg_impl!(Point5, x, y, z, w, a); -point_add_vec_impl!(Point5, Vector5, x, y, z, w, a); -point_sub_vec_impl!(Point5, Vector5, x, y, z, w, a); -approx_eq_impl!(Point5, x, y, z, w, a); +point_impl!(Point5, Vector5, Point6, b | x, y, z, w, a); +vectorlike_impl!(Point5, 5, x, y, z, w, a); from_iterator_impl!(Point5, iterator, iterator, iterator, iterator, iterator); -bounded_impl!(Point5, x, y, z, w, a); -axpy_impl!(Point5, x, y, z, w, a); -iterable_impl!(Point5, 5); -iterable_mut_impl!(Point5, 5); -point_to_homogeneous_impl!(Point5, Point6, b, x, y, z, w, a); -point_from_homogeneous_impl!(Point5, Point6, b, x, y, z, w, a); -num_float_point_impl!(Point5, Vector5); -arbitrary_point_impl!(Point5, x, y, z, w, a); -rand_impl!(Point5, x, y, z, w, a); -point_display_impl!(Point5); /// Point of dimension 6. /// @@ -277,33 +132,6 @@ pub struct Point6 { pub b: N } -new_impl!(Point6, x, y, z, w, a, b); -origin_impl!(Point6, x, y, z, w, a, b); -pord_impl!(Point6, x, y, z, w, a, b); -scalar_mul_impl!(Point6, x, y, z, w, a, b); -scalar_div_impl!(Point6, x, y, z, w, a, b); -scalar_add_impl!(Point6, x, y, z, w, a, b); -scalar_sub_impl!(Point6, x, y, z, w, a, b); -vec_cast_impl!(Point6, x, y, z, w, a, b); -conversion_impl!(Point6, 6); -index_impl!(Point6); -indexable_impl!(Point6, 6); -at_fast_impl!(Point6, 6); -repeat_impl!(Point6, val, x, y, z, w, a, b); -dim_impl!(Point6, 6); -container_impl!(Point6); -point_as_vec_impl!(Point6, Vector6, x, y, z, w, a, b); -point_sub_impl!(Point6, Vector6); -neg_impl!(Point6, x, y, z, w, a, b); -point_add_vec_impl!(Point6, Vector6, x, y, z, w, a, b); -point_sub_vec_impl!(Point6, Vector6, x, y, z, w, a, b); -approx_eq_impl!(Point6, x, y, z, w, a, b); +point_impl!(Point6, Vector6 | x, y, z, w, a, b); +vectorlike_impl!(Point6, 6, x, y, z, w, a, b); from_iterator_impl!(Point6, iterator, iterator, iterator, iterator, iterator, iterator); -bounded_impl!(Point6, x, y, z, w, a, b); -axpy_impl!(Point6, x, y, z, w, a, b); -iterable_impl!(Point6, 6); -iterable_mut_impl!(Point6, 6); -num_float_point_impl!(Point6, Vector6); -arbitrary_point_impl!(Point6, x, y, z, w, a, b); -rand_impl!(Point6, x, y, z, w, a, b); -point_display_impl!(Point6); diff --git a/src/structs/point_macros.rs b/src/structs/point_macros.rs index 6e549111..077255cb 100644 --- a/src/structs/point_macros.rs +++ b/src/structs/point_macros.rs @@ -1,7 +1,13 @@ #![macro_use] -macro_rules! origin_impl( - ($t: ident, $($compN: ident),+) => ( +macro_rules! point_impl( + ($t: ident, $tv: ident | $($compN: ident),+) => ( + + /* + * + * Origin. + * + */ impl Origin for $t { #[inline] fn origin() -> $t { @@ -15,11 +21,13 @@ macro_rules! origin_impl( $(self.$compN.is_zero() )&&+ } } - ) -); -macro_rules! point_sub_impl( - ($t: ident, $tv: ident) => ( + + /* + * + * Point - Point + * + */ impl> Sub<$t> for $t { type Output = $tv; @@ -28,11 +36,13 @@ macro_rules! point_sub_impl( *self.as_vector() - *right.as_vector() } } - ) -); -macro_rules! point_add_vec_impl( - ($t: ident, $tv: ident, $($compN: ident),+) => ( + + /* + * + * Point + Vector + * + */ impl> Add<$tv> for $t { type Output = $t; @@ -48,11 +58,13 @@ macro_rules! point_add_vec_impl( $( self.$compN += right.$compN; )+ } } - ) -); -macro_rules! point_sub_vec_impl( - ($t: ident, $tv: ident, $($compN: ident),+) => ( + + /* + * + * Point - Vector + * + */ impl> Sub<$tv> for $t { type Output = $t; @@ -68,11 +80,14 @@ macro_rules! point_sub_vec_impl( $( self.$compN -= right.$compN; )+ } } - ) -); -macro_rules! point_as_vec_impl( - ($t: ident, $tv: ident, $($compN: ident),+) => ( + + + /* + * + * Point as vector. + * + */ impl $t { /// Converts this point to its associated vector. #[inline] @@ -84,7 +99,7 @@ macro_rules! point_as_vec_impl( /// Converts a reference to this point to a reference to its associated vector. #[inline] - pub fn as_vector<'a>(&'a self) -> &'a $tv { + pub fn as_vector(&self) -> &$tv { unsafe { mem::transmute(self) } @@ -105,7 +120,7 @@ macro_rules! point_as_vec_impl( } #[inline] - fn as_vector<'a>(&'a self) -> &'a $tv { + fn as_vector(&self) -> &$tv { self.as_vector() } @@ -114,40 +129,14 @@ macro_rules! point_as_vec_impl( self.set_coords(v) } } - ) -); -macro_rules! point_to_homogeneous_impl( - ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( - impl ToHomogeneous<$t2> for $t { - fn to_homogeneous(&self) -> $t2 { - let mut res: $t2 = Origin::origin(); - $( res.$compN = self.$compN; )+ - res.$extra = ::one(); - res - } - } - ) -); - -macro_rules! point_from_homogeneous_impl( - ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( - impl + One + Zero> FromHomogeneous<$t2> for $t { - fn from(v: &$t2) -> $t { - let mut res: $t = Origin::origin(); - - $( res.$compN = v.$compN / v.$extra; )+ - - res - } - } - ) -); - -macro_rules! num_float_point_impl( - ($t: ident, $tv: ident) => ( + /* + * + * NumPoint / FloatPoint + * + */ impl NumPoint for $t where N: BaseNum { } @@ -155,25 +144,13 @@ macro_rules! num_float_point_impl( impl FloatPoint for $t where N: BaseFloat + ApproxEq { } - ) -); -macro_rules! arbitrary_point_impl( - ($t: ident, $($compN: ident),*) => ( - #[cfg(feature="arbitrary")] - impl Arbitrary for $t { - #[inline] - fn arbitrary(g: &mut G) -> $t { - $t { - $($compN: Arbitrary::arbitrary(g),)* - } - } - } - ) -); -macro_rules! point_display_impl( - ($t: ident) => ( + /* + * + * Display + * + */ impl fmt::Display for $t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // FIXME: differenciate them from vectors ? @@ -190,5 +167,34 @@ macro_rules! point_display_impl( write!(f, ")") } } + ); + ($t: ident, $tv: ident, $th: ident, $comp_extra: ident | $($compN: ident),+) => ( + point_impl!($t, $tv | $($compN),+); + + /* + * + * ToHomogeneous / FromHomogeneous + * + */ + impl ToHomogeneous<$th> for $t { + fn to_homogeneous(&self) -> $th { + let mut res: $th = Origin::origin(); + + $( res.$compN = self.$compN; )+ + res.$comp_extra = ::one(); + + res + } + } + + impl + One + Zero> FromHomogeneous<$th> for $t { + fn from(v: &$th) -> $t { + let mut res: $t = Origin::origin(); + + $( res.$compN = v.$compN / v.$comp_extra; )+ + + res + } + } ) ); diff --git a/src/structs/quaternion.rs b/src/structs/quaternion.rs index d785321a..737ec988 100644 --- a/src/structs/quaternion.rs +++ b/src/structs/quaternion.rs @@ -7,7 +7,7 @@ use std::ops::{Add, Sub, Mul, Div, Neg, AddAssign, SubAssign, MulAssign, DivAssi use std::iter::{FromIterator, IntoIterator}; use rand::{Rand, Rng}; use num::{Zero, One}; -use structs::{Vector3, Point3, Rotation3, Matrix3}; +use structs::{Vector3, Point3, Rotation3, Matrix3, Unit}; use traits::operations::{ApproxEq, Inverse, PartialOrder, PartialOrdering, Axpy}; use traits::structure::{Cast, Indexable, Iterable, IterableMut, Dimension, Shape, BaseFloat, BaseNum, Bounded, Repeat}; @@ -31,35 +31,21 @@ pub struct Quaternion { pub k: N } -impl Quaternion { - /// Creates a new quaternion from its components. - #[inline] - pub fn new(w: N, i: N, j: N, k: N) -> Quaternion { - Quaternion { - w: w, - i: i, - j: j, - k: k - } - } - +impl Quaternion { /// The vector part `(i, j, k)` of this quaternion. #[inline] - pub fn vector<'a>(&'a self) -> &'a Vector3 { - // FIXME: do this require a `repr(C)` ? - unsafe { - mem::transmute(&self.i) - } + pub fn vector(&self) -> &Vector3 { + unsafe { mem::transmute(&self.i) } } /// The scalar part `w` of this quaternion. #[inline] - pub fn scalar<'a>(&'a self) -> &'a N { - &self.w + pub fn scalar(&self) -> N { + self.w } } -impl + Copy> Quaternion { +impl> Quaternion { /// Compute the conjugate of this quaternion. #[inline] pub fn conjugate(&self) -> Quaternion { @@ -75,7 +61,46 @@ impl + Copy> Quaternion { } } -impl> Inverse for Quaternion { +impl Quaternion { + /// Creates a new quaternion from its scalar and vector parts. + pub fn from_parts(scalar: N, vector: Vector3) -> Quaternion { + Quaternion::new(scalar, vector.x, vector.y, vector.z) + } + + /// Creates a new quaternion from its polar decomposition. + /// + /// Note that `axis` is assumed to be a unit vector. + pub fn from_polar_decomposition(scale: N, theta: N, axis: Unit>) + -> Quaternion { + let rot = UnitQuaternion::from_axisangle(axis, theta * ::cast(2.0)); + + rot.unwrap() * scale + } + + /// The polar decomposition of this quaternion. + /// + /// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation + /// axis. If the rotation angle is zero, the rotation axis is set to the `y` axis. + pub fn polar_decomposition(&self) -> (N, N, Unit>) { + let default_axis = Unit::from_unit_value_unchecked(Vector3::y()); + + if let Some((q, n)) = Unit::try_new_and_get(*self, ::zero()) { + if let Some(axis) = Unit::try_new(self.vector(), ::zero()) { + let angle = q.angle() / ::cast(2.0); + + (n, angle, axis) + } + else { + (n, ::zero(), default_axis) + } + } + else { + (::zero(), ::zero(), default_axis) + } + } +} + +impl Inverse for Quaternion { #[inline] fn inverse(&self) -> Option> { let mut res = *self; @@ -97,17 +122,16 @@ impl> Inverse for Quaternion { } else { self.conjugate_mut(); - self.w = self.w / norm_squared; - self.i = self.i / norm_squared; - self.j = self.j / norm_squared; - self.k = self.k / norm_squared; + *self /= norm_squared; true } } } -impl Norm for Quaternion { +impl Norm for Quaternion { + type NormType = N; + #[inline] fn norm_squared(&self) -> N { self.w * self.w + self.i * self.i + self.j * self.j + self.k * self.k @@ -115,21 +139,42 @@ impl Norm for Quaternion { #[inline] fn normalize(&self) -> Quaternion { - let n = self.norm(); - Quaternion::new(self.w / n, self.i / n, self.j / n, self.k / n) + let n = ::norm(self); + *self / n } #[inline] fn normalize_mut(&mut self) -> N { - let n = Norm::norm(self); - - self.w = self.w / n; - self.i = self.i / n; - self.j = self.j / n; - self.k = self.k / n; + let n = ::norm(self); + *self /= n; n } + + #[inline] + fn try_normalize(&self, min_norm: N) -> Option> { + let n = ::norm(self); + + if n <= min_norm { + None + } + else { + Some(*self / n) + } + } + + #[inline] + fn try_normalize_mut(&mut self, min_norm: N) -> Option { + let n = ::norm(self); + + if n <= min_norm { + None + } + else { + *self /= n; + Some(n) + } + } } impl Mul> for Quaternion @@ -154,7 +199,7 @@ impl MulAssign> for Quaternion } } -impl + BaseFloat> Div> for Quaternion { +impl Div> for Quaternion { type Output = Quaternion; #[inline] @@ -163,140 +208,162 @@ impl + BaseFloat> Div> for Quaternion { } } -impl + BaseFloat> DivAssign> for Quaternion { +impl DivAssign> for Quaternion { #[inline] fn div_assign(&mut self, right: Quaternion) { *self *= right.inverse().expect("Unable to invert the denominator.") } } +impl Quaternion { + /// Compute the exponential of a quaternion. + #[inline] + pub fn exp(&self) -> Self { + let v = *self.vector(); + let nn = v.norm_squared(); + + if nn.is_zero() { + ::one() + } + else { + let n = nn.sqrt(); + let nv = v / n * n.sin(); + Quaternion::from_parts(n.cos(), nv) * self.scalar().exp() + } + } + + /// Compute the natural logarithm of a quaternion. + #[inline] + pub fn ln(&self) -> Self { + let n = self.norm(); + let v = self.vector(); + let s = self.scalar(); + + Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos()) + } + + /// Raise the quaternion to a given floating power. + #[inline] + pub fn powf(&self, n: N) -> Self { + (self.ln() * n).exp() + } +} + +impl One for Quaternion where T: Copy + One + Zero + Sub + Add { + #[inline] + fn one() -> Self { + Quaternion::new(T::one(), T::zero(), T::zero(), T::zero()) + } +} + impl fmt::Display for Quaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Quaternion {} − ({}, {}, {})", self.w, self.i, self.j, self.k) } } -rand_impl!(Quaternion, w, i, j, k); +/// A unit quaternions. May be used to represent a rotation. +pub type UnitQuaternion = Unit>; - -/// A unit quaternion that can represent a 3D rotation. -#[repr(C)] -#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] -pub struct UnitQuaternion { - q: Quaternion +impl UnitQuaternion { + /// The underlying quaternion. + /// + /// Same as `self.as_ref()`. + #[inline] + pub fn quaternion(&self) -> &Quaternion { + self.as_ref() + } } impl UnitQuaternion { - /// Creates a new unit quaternion from the axis-angle representation of a rotation. + /// Creates a new quaternion from a unit vector (the rotation axis) and an angle + /// (the rotation angle). #[inline] - pub fn new(axisangle: Vector3) -> UnitQuaternion { - let sqang = Norm::norm_squared(&axisangle); + pub fn from_axisangle(axis: Unit>, angle: N) -> UnitQuaternion { + let (sang, cang) = (angle / ::cast(2.0)).sin_cos(); - if ::is_zero(&sqang) { - ::one() - } - else { - let ang = sqang.sqrt(); - let (s, c) = (ang / Cast::from(2.0)).sin_cos(); + let q = Quaternion::from_parts(cang, axis.unwrap() * sang); + Unit::from_unit_value_unchecked(q) + } - let s_ang = s / ang; - - unsafe { - UnitQuaternion::new_with_unit_quaternion( - Quaternion::new( - c, - axisangle.x * s_ang, - axisangle.y * s_ang, - axisangle.z * s_ang) - ) - } - } + /// Same as `::from_axisangle` with the axis multiplied with the angle. + #[inline] + pub fn from_scaled_axis(axis: Vector3) -> UnitQuaternion { + let two: N = ::cast(2.0); + let q = Quaternion::from_parts(::zero(), axis / two).exp(); + UnitQuaternion::from_unit_value_unchecked(q) } /// Creates a new unit quaternion from a quaternion. /// /// The input quaternion will be normalized. #[inline] - pub fn new_with_quaternion(q: Quaternion) -> UnitQuaternion { - UnitQuaternion { q: q.normalize() } + pub fn from_quaternion(q: &Quaternion) -> UnitQuaternion { + Unit::new(&q) } /// Creates a new unit quaternion from Euler angles. /// /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw. #[inline] - pub fn new_with_euler_angles(roll: N, pitch: N, yaw: N) -> UnitQuaternion { - let _0_5: N = Cast::from(0.5); - let (sr, cr) = (roll * _0_5).sin_cos(); - let (sp, cp) = (pitch * _0_5).sin_cos(); - let (sy, cy) = (yaw * _0_5).sin_cos(); + pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> UnitQuaternion { + let (sr, cr) = (roll * ::cast(0.5)).sin_cos(); + let (sp, cp) = (pitch * ::cast(0.5)).sin_cos(); + let (sy, cy) = (yaw * ::cast(0.5)).sin_cos(); - unsafe { - UnitQuaternion::new_with_unit_quaternion( - Quaternion::new( + let q = Quaternion::new( cr * cp * cy + sr * sp * sy, sr * cp * cy - cr * sp * sy, cr * sp * cy + sr * cp * sy, - cr * cp * sy - sr * sp * cy) - ) - } + cr * cp * sy - sr * sp * cy); + + Unit::from_unit_value_unchecked(q) + } + + /// The rotation angle of this unit quaternion. + #[inline] + pub fn angle(&self) -> N { + self.as_ref().scalar().acos() * ::cast(2.0) + } + + /// The rotation axis of this unit quaternion or `None` if the rotation is zero. + #[inline] + pub fn axis(&self) -> Option>> { + Unit::try_new(self.as_ref().vector(), ::zero()) } /// Builds a rotation matrix from this quaternion. pub fn to_rotation_matrix(&self) -> Rotation3 { - let _2: N = Cast::from(2.0); - let ww = self.q.w * self.q.w; - let ii = self.q.i * self.q.i; - let jj = self.q.j * self.q.j; - let kk = self.q.k * self.q.k; - let ij = _2 * self.q.i * self.q.j; - let wk = _2 * self.q.w * self.q.k; - let wj = _2 * self.q.w * self.q.j; - let ik = _2 * self.q.i * self.q.k; - let jk = _2 * self.q.j * self.q.k; - let wi = _2 * self.q.w * self.q.i; + let ww = self.as_ref().w * self.as_ref().w; + let ii = self.as_ref().i * self.as_ref().i; + let jj = self.as_ref().j * self.as_ref().j; + let kk = self.as_ref().k * self.as_ref().k; + let ij = self.as_ref().i * self.as_ref().j * ::cast(2.0); + let wk = self.as_ref().w * self.as_ref().k * ::cast(2.0); + let wj = self.as_ref().w * self.as_ref().j * ::cast(2.0); + let ik = self.as_ref().i * self.as_ref().k * ::cast(2.0); + let jk = self.as_ref().j * self.as_ref().k * ::cast(2.0); + let wi = self.as_ref().w * self.as_ref().i * ::cast(2.0); - unsafe { - Rotation3::new_with_matrix( - Matrix3::new( - ww + ii - jj - kk, ij - wk, wj + ik, - wk + ij, ww - ii + jj - kk, jk - wi, - ik - wj, wi + jk, ww - ii - jj + kk - ) + Rotation3::from_matrix_unchecked( + Matrix3::new( + ww + ii - jj - kk, ij - wk, wj + ik, + wk + ij, ww - ii + jj - kk, jk - wi, + ik - wj, wi + jk, ww - ii - jj + kk ) - } - } -} - - -impl UnitQuaternion { - /// Creates a new unit quaternion from a quaternion. - /// - /// This is unsafe because the input quaternion will not be normalized. - #[inline] - pub unsafe fn new_with_unit_quaternion(q: Quaternion) -> UnitQuaternion { - UnitQuaternion { - q: q - } - } - - /// The `Quaternion` representation of this unit quaternion. - #[inline] - pub fn quaternion<'a>(&'a self) -> &'a Quaternion { - &self.q + ) } } impl One for UnitQuaternion { #[inline] fn one() -> UnitQuaternion { - unsafe { - UnitQuaternion::new_with_unit_quaternion(Quaternion::new(::one(), ::zero(), ::zero(), ::zero())) - } + let one = Quaternion::new(::one(), ::zero(), ::zero(), ::zero()); + UnitQuaternion::from_unit_value_unchecked(one) } } -impl> Inverse for UnitQuaternion { +impl> Inverse for UnitQuaternion { #[inline] fn inverse(&self) -> Option> { let mut cpy = *self; @@ -307,7 +374,7 @@ impl> Inverse for UnitQuaternion { #[inline] fn inverse_mut(&mut self) -> bool { - self.q.conjugate_mut(); + *self = Unit::from_unit_value_unchecked(self.as_ref().conjugate()); true } @@ -316,7 +383,7 @@ impl> Inverse for UnitQuaternion { impl Rand for UnitQuaternion { #[inline] fn rand(rng: &mut R) -> UnitQuaternion { - UnitQuaternion::new(rng.gen()) + UnitQuaternion::new(&rng.gen()) } } @@ -333,28 +400,28 @@ impl> ApproxEq for UnitQuaternion { #[inline] fn approx_eq_eps(&self, other: &UnitQuaternion, eps: &N) -> bool { - ApproxEq::approx_eq_eps(&self.q, &other.q, eps) + ApproxEq::approx_eq_eps(self.as_ref(), other.as_ref(), eps) } #[inline] fn approx_eq_ulps(&self, other: &UnitQuaternion, ulps: u32) -> bool { - ApproxEq::approx_eq_ulps(&self.q, &other.q, ulps) + ApproxEq::approx_eq_ulps(self.as_ref(), other.as_ref(), ulps) } } -impl> Div> for UnitQuaternion { +impl Div> for UnitQuaternion { type Output = UnitQuaternion; #[inline] fn div(self, other: UnitQuaternion) -> UnitQuaternion { - UnitQuaternion { q: self.q / other.q } + Unit::from_unit_value_unchecked(self.unwrap() / other.unwrap()) } } -impl> DivAssign> for UnitQuaternion { +impl DivAssign> for UnitQuaternion { #[inline] fn div_assign(&mut self, other: UnitQuaternion) { - self.q /= other.q + *self = Unit::from_unit_value_unchecked(*self.as_ref() / *other.as_ref()) } } @@ -363,14 +430,14 @@ impl Mul> for UnitQuaternion { #[inline] fn mul(self, right: UnitQuaternion) -> UnitQuaternion { - UnitQuaternion { q: self.q * right.q } + Unit::from_unit_value_unchecked(self.unwrap() * right.unwrap()) } } impl MulAssign> for UnitQuaternion { #[inline] fn mul_assign(&mut self, right: UnitQuaternion) { - self.q *= right.q + *self = Unit::from_unit_value_unchecked(*self.as_ref() * *right.as_ref()) } } @@ -379,13 +446,10 @@ impl Mul> for UnitQuaternion { #[inline] fn mul(self, right: Vector3) -> Vector3 { - let _2: N = ::one::() + ::one(); - let mut t = ::cross(self.q.vector(), &right); - t.x = t.x * _2; - t.y = t.y * _2; - t.z = t.z * _2; + let two: N = ::one::() + ::one(); + let t = ::cross(self.as_ref().vector(), &right) * two; - Vector3::new(t.x * self.q.w, t.y * self.q.w, t.z * self.q.w) + ::cross(self.q.vector(), &t) + right + t * self.as_ref().w + ::cross(self.as_ref().vector(), &t) + right } } @@ -437,15 +501,11 @@ impl> MulAssign> for Point3 { impl Rotation> for UnitQuaternion { #[inline] fn rotation(&self) -> Vector3 { - let _2 = ::one::() + ::one(); - let mut v = *self.q.vector(); - let ang = _2 * v.normalize_mut().atan2(self.q.w); - - if ::is_zero(&ang) { - ::zero() + if let Some(v) = self.axis() { + v.unwrap() * self.angle() } else { - Vector3::new(v.x * ang, v.y * ang, v.z * ang) + ::zero() } } @@ -461,7 +521,7 @@ impl Rotation> for UnitQuaternion { #[inline] fn append_rotation(&self, amount: &Vector3) -> UnitQuaternion { - *self * UnitQuaternion::new(*amount) + *self * UnitQuaternion::from_scaled_axis(*amount) } #[inline] @@ -471,12 +531,12 @@ impl Rotation> for UnitQuaternion { #[inline] fn prepend_rotation(&self, amount: &Vector3) -> UnitQuaternion { - UnitQuaternion::new(*amount) * *self + UnitQuaternion::from_scaled_axis(*amount) * *self } #[inline] fn set_rotation(&mut self, v: Vector3) { - *self = UnitQuaternion::new(v) + *self = UnitQuaternion::from_scaled_axis(v); } } @@ -513,16 +573,15 @@ impl> Rotate> for UnitQuaternion { } } -impl> RotationTo for UnitQuaternion { +impl RotationTo for UnitQuaternion { type AngleType = N; type DeltaRotationType = UnitQuaternion; #[inline] fn angle_to(&self, other: &Self) -> N { let delta = self.rotation_to(other); - let _2 = ::one::() + ::one(); - _2 * delta.q.vector().norm().atan2(delta.q.w) + delta.as_ref().w.acos() * ::cast(2.0) } #[inline] @@ -557,42 +616,69 @@ impl> Transform> for UnitQuaternion { impl fmt::Display for UnitQuaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Unit quaternion {} − ({}, {}, {})", self.q.w, self.q.i, self.q.j, self.q.k) + write!(f, "Unit quaternion {} − ({}, {}, {})", + self.as_ref().w, self.as_ref().i, self.as_ref().j, self.as_ref().k) + } +} + +/* + * + * Dimension + * + */ +impl Dimension for UnitQuaternion { + #[inline] + fn dimension(_: Option>) -> usize { + 3 } } #[cfg(feature="arbitrary")] impl Arbitrary for UnitQuaternion { fn arbitrary(g: &mut G) -> UnitQuaternion { - UnitQuaternion::new(Arbitrary::arbitrary(g)) + UnitQuaternion::new(&Arbitrary::arbitrary(g)) } } +impl UnitQuaternion { + /// Compute the exponential of a quaternion. + /// + /// Note that this function yields a `Quaternion` because it looses the unit property. + pub fn exp(&self) -> Quaternion { + self.as_ref().exp() + } -pord_impl!(Quaternion, w, i, j, k); -vec_axis_impl!(Quaternion, w, i, j, k); -vec_cast_impl!(Quaternion, w, i, j, k); -conversion_impl!(Quaternion, 4); -index_impl!(Quaternion); -indexable_impl!(Quaternion, 4); -at_fast_impl!(Quaternion, 4); -repeat_impl!(Quaternion, val, w, i, j, k); -dim_impl!(Quaternion, 3); -container_impl!(Quaternion); -add_impl!(Quaternion, w, i, j, k); -sub_impl!(Quaternion, w, i, j, k); -scalar_add_impl!(Quaternion, w, i, j, k); -scalar_sub_impl!(Quaternion, w, i, j, k); -scalar_mul_impl!(Quaternion, w, i, j, k); -scalar_div_impl!(Quaternion, w, i, j, k); -neg_impl!(Quaternion, w, i, j, k); -zero_one_impl!(Quaternion, w, i, j, k); -approx_eq_impl!(Quaternion, w, i, j, k); + /// Compute the natural logarithm of a quaternion. + /// + /// Note that this function yields a `Quaternion` because it looses the unit property. The + /// vector part of the return value corresponds to the axis-angle representation (divided by + /// 2.0) of this unit quaternion. + pub fn ln(&self) -> Quaternion { + if let Some(v) = self.axis() { + Quaternion::from_parts(::zero(), v.unwrap() * self.angle()) + } + else { + ::zero() + } + } + + /// Raise this unit quaternion to a given floating power. + /// + /// If this unit quaternion represents a rotation by `theta`, then the resulting quaternion + /// rotates by `n * theta`. + pub fn powf(&self, n: N) -> Self { + if let Some(v) = self.axis() { + UnitQuaternion::from_axisangle(v, self.angle() * n) + } + else { + ::one() + } + } +} + +componentwise_zero!(Quaternion, w, i, j, k); +component_basis_element!(Quaternion, w, i, j, k); +pointwise_add!(Quaternion, w, i, j, k); +pointwise_sub!(Quaternion, w, i, j, k); from_iterator_impl!(Quaternion, iterator, iterator, iterator, iterator); -bounded_impl!(Quaternion, w, i, j, k); -axpy_impl!(Quaternion, w, i, j, k); -iterable_impl!(Quaternion, 4); -iterable_mut_impl!(Quaternion, 4); -arbitrary_impl!(Quaternion, w, i, j, k); - -dim_impl!(UnitQuaternion, 3); +vectorlike_impl!(Quaternion, 4, w, i, j, k); diff --git a/src/structs/rotation.rs b/src/structs/rotation.rs index d1520fab..c8be3a11 100644 --- a/src/structs/rotation.rs +++ b/src/structs/rotation.rs @@ -1,7 +1,7 @@ //! Rotations matrices. use std::fmt; -use std::ops::{Mul, Neg, MulAssign, Index}; +use std::ops::{Mul, MulAssign, Index}; use rand::{Rand, Rng}; use num::{Zero, One}; use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, RotationTo, Transform, @@ -22,21 +22,21 @@ pub struct Rotation2 { submatrix: Matrix2 } -impl> Rotation2 { +impl Rotation2 { /// Builds a 2 dimensional rotation matrix from an angle in radian. pub fn new(angle: Vector1) -> Rotation2 { let (sia, coa) = angle.x.sin_cos(); Rotation2 { - submatrix: Matrix2::new(coa.clone(), -sia, sia, coa) + submatrix: Matrix2::new(coa, -sia, sia, coa) } } } -impl Rotation> for Rotation2 { +impl Rotation> for Rotation2 { #[inline] fn rotation(&self) -> Vector1 { - Vector1::new((-self.submatrix.m12).atan2(self.submatrix.m11.clone())) + Vector1::new((-self.submatrix.m12).atan2(self.submatrix.m11)) } #[inline] @@ -51,7 +51,7 @@ impl Rotation> for Rotation2 { #[inline] fn append_rotation(&self, rotation: &Vector1) -> Rotation2 { - Rotation2::new(rotation.clone()) * *self + Rotation2::new(*rotation) * *self } #[inline] @@ -61,7 +61,7 @@ impl Rotation> for Rotation2 { #[inline] fn prepend_rotation(&self, rotation: &Vector1) -> Rotation2 { - *self * Rotation2::new(rotation.clone()) + *self * Rotation2::new(*rotation) } #[inline] @@ -105,13 +105,6 @@ impl AbsoluteRotate> for Rotation2 { } } -#[cfg(feature="arbitrary")] -impl> Arbitrary for Rotation2 { - fn arbitrary(g: &mut G) -> Rotation2 { - Rotation2::new(Arbitrary::arbitrary(g)) - } -} - /* * 3d rotation @@ -124,7 +117,7 @@ pub struct Rotation3 { } -impl Rotation3 { +impl Rotation3 { /// Builds a 3 dimensional rotation matrix from an axis and an angle. /// /// # Arguments @@ -137,37 +130,34 @@ impl Rotation3 { else { let mut axis = axisangle; let angle = axis.normalize_mut(); - let _1: N = ::one(); - let ux = axis.x.clone(); - let uy = axis.y.clone(); - let uz = axis.z.clone(); + let ux = axis.x; + let uy = axis.y; + let uz = axis.z; let sqx = ux * ux; let sqy = uy * uy; let sqz = uz * uz; let (sin, cos) = angle.sin_cos(); - let one_m_cos = _1 - cos; + let one_m_cos = ::one::() - cos; Rotation3 { submatrix: Matrix3::new( - (sqx + (_1 - sqx) * cos), + (sqx + (::one::() - sqx) * cos), (ux * uy * one_m_cos - uz * sin), (ux * uz * one_m_cos + uy * sin), (ux * uy * one_m_cos + uz * sin), - (sqy + (_1 - sqy) * cos), + (sqy + (::one::() - sqy) * cos), (uy * uz * one_m_cos - ux * sin), (ux * uz * one_m_cos - uy * sin), (uy * uz * one_m_cos + ux * sin), - (sqz + (_1 - sqz) * cos)) + (sqz + (::one::() - sqz) * cos)) } } } /// Builds a rotation matrix from an orthogonal matrix. - /// - /// This is unsafe because the orthogonality of `matrix` is not checked. - pub unsafe fn new_with_matrix(matrix: Matrix3) -> Rotation3 { + pub fn from_matrix_unchecked(matrix: Matrix3) -> Rotation3 { Rotation3 { submatrix: matrix } @@ -176,24 +166,22 @@ impl Rotation3 { /// Creates a new rotation from Euler angles. /// /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw. - pub fn new_with_euler_angles(roll: N, pitch: N, yaw: N) -> Rotation3 { + pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Rotation3 { let (sr, cr) = roll.sin_cos(); let (sp, cp) = pitch.sin_cos(); let (sy, cy) = yaw.sin_cos(); - unsafe { - Rotation3::new_with_matrix( - Matrix3::new( - cy * cp, cy * sp * sr - sy * cr, cy * sp * cr + sy * sr, - sy * cp, sy * sp * sr + cy * cr, sy * sp * cr - cy * sr, - -sp, cp * sr, cp * cr + Rotation3::from_matrix_unchecked( + Matrix3::new( + cy * cp, cy * sp * sr - sy * cr, cy * sp * cr + sy * sr, + sy * cp, sy * sp * sr + cy * cr, sy * sp * cr - cy * sr, + -sp, cp * sr, cp * cr ) ) - } } } -impl Rotation3 { +impl Rotation3 { /// Creates a rotation that corresponds to the local frame of an observer standing at the /// origin and looking toward `dir`. /// @@ -210,12 +198,10 @@ impl Rotation3 { let xaxis = Norm::normalize(&Cross::cross(up, &zaxis)); let yaxis = Norm::normalize(&Cross::cross(&zaxis, &xaxis)); - unsafe { - Rotation3::new_with_matrix(Matrix3::new( - xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(), - xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(), - xaxis.z , yaxis.z , zaxis.z)) - } + Rotation3::from_matrix_unchecked(Matrix3::new( + xaxis.x, yaxis.x, zaxis.x, + xaxis.y, yaxis.y, zaxis.y, + xaxis.z, yaxis.z, zaxis.z)) } @@ -250,17 +236,13 @@ impl Rotation3 { } } -impl> -Rotation> for Rotation3 { +impl Rotation> for Rotation3 { #[inline] fn rotation(&self) -> Vector3 { let angle = ((self.submatrix.m11 + self.submatrix.m22 + self.submatrix.m33 - ::one()) / Cast::from(2.0)).acos(); - if angle != angle { - // FIXME: handle that correctly - ::zero() - } - else if ::is_zero(&angle) { + if !angle.is_finite() || ::is_zero(&angle) { + // FIXME: handle the non-finite case robustly. ::zero() } else { @@ -296,7 +278,7 @@ Rotation> for Rotation3 { #[inline] fn append_rotation(&self, axisangle: &Vector3) -> Rotation3 { - Rotation3::new(axisangle.clone()) * *self + Rotation3::new(*axisangle) * *self } #[inline] @@ -306,7 +288,7 @@ Rotation> for Rotation3 { #[inline] fn prepend_rotation(&self, axisangle: &Vector3) -> Rotation3 { - *self * Rotation3::new(axisangle.clone()) + *self * Rotation3::new(*axisangle) } #[inline] @@ -331,7 +313,7 @@ impl RotationTo for Rotation3 { } } -impl Rand for Rotation3 { +impl Rand for Rotation3 { #[inline] fn rand(rng: &mut R) -> Rotation3 { Rotation3::new(rng.gen()) @@ -348,60 +330,13 @@ impl AbsoluteRotate> for Rotation3 { } } -#[cfg(feature="arbitrary")] -impl Arbitrary for Rotation3 { - fn arbitrary(g: &mut G) -> Rotation3 { - Rotation3::new(Arbitrary::arbitrary(g)) - } -} - /* * Common implementations. */ -submat_impl!(Rotation2, Matrix2); -rotate_impl!(Rotation2, Vector2, Point2); -transform_impl!(Rotation2, Vector2, Point2); +rotation_impl!(Rotation2, Matrix2, Vector2, Vector1, Point2, Matrix3); dim_impl!(Rotation2, 2); -rotation_mul_rotation_impl!(Rotation2); -rotation_mul_vec_impl!(Rotation2, Vector2); -vec_mul_rotation_impl!(Rotation2, Vector2); -rotation_mul_point_impl!(Rotation2, Point2); -point_mul_rotation_impl!(Rotation2, Point2); -one_impl!(Rotation2); -eye_impl!(Rotation2); -rotation_matrix_impl!(Rotation2, Vector2, Vector1); -column_impl!(Rotation2, Vector2); -row_impl!(Rotation2, Vector2); -index_impl!(Rotation2); -absolute_impl!(Rotation2, Matrix2); -to_homogeneous_impl!(Rotation2, Matrix3); -inverse_impl!(Rotation2); -transpose_impl!(Rotation2); -approx_eq_impl!(Rotation2); -diag_impl!(Rotation2, Vector2); -rotation_display_impl!(Rotation2); -submat_impl!(Rotation3, Matrix3); -rotate_impl!(Rotation3, Vector3, Point3); -transform_impl!(Rotation3, Vector3, Point3); +rotation_impl!(Rotation3, Matrix3, Vector3, Vector3, Point3, Matrix4); dim_impl!(Rotation3, 3); -rotation_mul_rotation_impl!(Rotation3); -rotation_mul_vec_impl!(Rotation3, Vector3); -vec_mul_rotation_impl!(Rotation3, Vector3); -rotation_mul_point_impl!(Rotation3, Point3); -point_mul_rotation_impl!(Rotation3, Point3); -one_impl!(Rotation3); -eye_impl!(Rotation3); -rotation_matrix_impl!(Rotation3, Vector3, Vector3); -column_impl!(Rotation3, Vector3); -row_impl!(Rotation3, Vector3); -index_impl!(Rotation3); -absolute_impl!(Rotation3, Matrix3); -to_homogeneous_impl!(Rotation3, Matrix4); -inverse_impl!(Rotation3); -transpose_impl!(Rotation3); -approx_eq_impl!(Rotation3); -diag_impl!(Rotation3, Vector3); -rotation_display_impl!(Rotation3); diff --git a/src/structs/rotation_macros.rs b/src/structs/rotation_macros.rs index a0074393..22307968 100644 --- a/src/structs/rotation_macros.rs +++ b/src/structs/rotation_macros.rs @@ -1,87 +1,83 @@ #![macro_use] -macro_rules! submat_impl( - ($t: ident, $submatrix: ident) => ( +macro_rules! rotation_impl( + ($t: ident, $submatrix: ident, $vector: ident, $rotvector: ident, $point: ident, $homogeneous: ident) => ( impl $t { /// This rotation's underlying matrix. #[inline] - pub fn submatrix<'r>(&'r self) -> &'r $submatrix { + pub fn submatrix(&self) -> &$submatrix { &self.submatrix } } - ) -); -macro_rules! rotate_impl( - ($t: ident, $tv: ident, $tp: ident) => ( - impl Rotate<$tv> for $t { + + /* + * + * Rotate Vector and Point + * + */ + impl Rotate<$vector> for $t { #[inline] - fn rotate(&self, v: &$tv) -> $tv { + fn rotate(&self, v: &$vector) -> $vector { *self * *v } #[inline] - fn inverse_rotate(&self, v: &$tv) -> $tv { + fn inverse_rotate(&self, v: &$vector) -> $vector { *v * *self } } - impl Rotate<$tp> for $t { + impl Rotate<$point> for $t { #[inline] - fn rotate(&self, p: &$tp) -> $tp { + fn rotate(&self, p: &$point) -> $point { *self * *p } #[inline] - fn inverse_rotate(&self, p: &$tp) -> $tp { + fn inverse_rotate(&self, p: &$point) -> $point { *p * *self } } - ) -); -macro_rules! transform_impl( - ($t: ident, $tv: ident, $tp: ident) => ( - impl Transform<$tv> for $t { + + /* + * + * Transform Vector and Point + * + */ + impl Transform<$vector> for $t { #[inline] - fn transform(&self, v: &$tv) -> $tv { + fn transform(&self, v: &$vector) -> $vector { self.rotate(v) } #[inline] - fn inverse_transform(&self, v: &$tv) -> $tv { + fn inverse_transform(&self, v: &$vector) -> $vector { self.inverse_rotate(v) } } - impl Transform<$tp> for $t { + impl Transform<$point> for $t { #[inline] - fn transform(&self, p: &$tp) -> $tp { + fn transform(&self, p: &$point) -> $point { self.rotate(p) } #[inline] - fn inverse_transform(&self, p: &$tp) -> $tp { + fn inverse_transform(&self, p: &$point) -> $point { self.inverse_rotate(p) } } - ) -); -macro_rules! dim_impl( - ($t: ident, $dimension: expr) => ( - impl Dimension for $t { - #[inline] - fn dimension(_: Option<$t>) -> usize { - $dimension - } - } - ) -); -macro_rules! rotation_matrix_impl( - ($t: ident, $tlv: ident, $tav: ident) => ( - impl + BaseFloat> RotationMatrix, $tav> for $t { + + /* + * + * Rotation Matrix + * + */ + impl + BaseFloat> RotationMatrix, $rotvector> for $t { type Output = $t; #[inline] @@ -89,22 +85,26 @@ macro_rules! rotation_matrix_impl( self.clone() } } - ) -); -macro_rules! one_impl( - ($t: ident) => ( + + /* + * + * One + * + */ impl One for $t { #[inline] fn one() -> $t { $t { submatrix: ::one() } } } - ) -); -macro_rules! eye_impl( - ($t: ident) => ( + + /* + * + * Eye + * + */ impl Eye for $t { #[inline] fn new_identity(dimension: usize) -> $t { @@ -116,27 +116,31 @@ macro_rules! eye_impl( } } } - ) -); -macro_rules! diag_impl( - ($t: ident, $tv: ident) => ( - impl Diagonal<$tv> for $t { + + /* + * + * Diagonal + * + */ + impl Diagonal<$vector> for $t { #[inline] - fn from_diagonal(diagonal: &$tv) -> $t { + fn from_diagonal(diagonal: &$vector) -> $t { $t { submatrix: Diagonal::from_diagonal(diagonal) } } #[inline] - fn diagonal(&self) -> $tv { + fn diagonal(&self) -> $vector { self.submatrix.diagonal() } } - ) -); -macro_rules! rotation_mul_rotation_impl( - ($t: ident) => ( + + /* + * + * Rotation * Rotation + * + */ impl Mul<$t> for $t { type Output = $t; @@ -152,56 +156,75 @@ macro_rules! rotation_mul_rotation_impl( self.submatrix *= right.submatrix } } - ) -); -macro_rules! rotation_mul_vec_impl( - ($t: ident, $tv: ident) => ( - impl Mul<$tv> for $t { - type Output = $tv; + + /* + * + * Rotation * Vector + * + */ + impl Mul<$vector> for $t { + type Output = $vector; #[inline] - fn mul(self, right: $tv) -> $tv { + fn mul(self, right: $vector) -> $vector { self.submatrix * right } } - ) -); -macro_rules! rotation_mul_point_impl( - ($t: ident, $tv: ident) => ( - rotation_mul_vec_impl!($t, $tv); - ) -); - -macro_rules! vec_mul_rotation_impl( - ($t: ident, $tv: ident) => ( - impl Mul<$t> for $tv { - type Output = $tv; + impl Mul<$t> for $vector { + type Output = $vector; #[inline] - fn mul(self, right: $t) -> $tv { + fn mul(self, right: $t) -> $vector { self * right.submatrix } } - impl MulAssign<$t> for $tv { + impl MulAssign<$t> for $vector { #[inline] fn mul_assign(&mut self, right: $t) { *self *= right.submatrix } } - ) -); -macro_rules! point_mul_rotation_impl( - ($t: ident, $tv: ident) => ( - vec_mul_rotation_impl!($t, $tv); - ) -); -macro_rules! inverse_impl( - ($t: ident) => ( + /* + * + * Rotation * Point + * + */ + impl Mul<$point> for $t { + type Output = $point; + + #[inline] + fn mul(self, right: $point) -> $point { + self.submatrix * right + } + } + + impl Mul<$t> for $point { + type Output = $point; + + #[inline] + fn mul(self, right: $t) -> $point { + self * right.submatrix + } + } + + impl MulAssign<$t> for $point { + #[inline] + fn mul_assign(&mut self, right: $t) { + *self *= right.submatrix + } + } + + + /* + * + * Inverse + * + */ impl Inverse for $t { #[inline] fn inverse_mut(&mut self) -> bool { @@ -217,11 +240,13 @@ macro_rules! inverse_impl( Some(self.transpose()) } } - ) -); -macro_rules! transpose_impl( - ($t: ident) => ( + + /* + * + * Transpose + * + */ impl Transpose for $t { #[inline] fn transpose(&self) -> $t { @@ -233,51 +258,57 @@ macro_rules! transpose_impl( self.submatrix.transpose_mut() } } - ) -); -macro_rules! row_impl( - ($t: ident, $tv: ident) => ( - impl Row<$tv> for $t { + + /* + * + * Row + * + */ + impl Row<$vector> for $t { #[inline] fn nrows(&self) -> usize { self.submatrix.nrows() } #[inline] - fn row(&self, i: usize) -> $tv { + fn row(&self, i: usize) -> $vector { self.submatrix.row(i) } #[inline] - fn set_row(&mut self, i: usize, row: $tv) { + fn set_row(&mut self, i: usize, row: $vector) { self.submatrix.set_row(i, row); } } - ) -); -macro_rules! column_impl( - ($t: ident, $tv: ident) => ( - impl Column<$tv> for $t { + + /* + * + * Column + * + */ + impl Column<$vector> for $t { #[inline] fn ncols(&self) -> usize { self.submatrix.ncols() } #[inline] - fn column(&self, i: usize) -> $tv { + fn column(&self, i: usize) -> $vector { self.submatrix.column(i) } #[inline] - fn set_column(&mut self, i: usize, column: $tv) { + fn set_column(&mut self, i: usize, column: $vector) { self.submatrix.set_column(i, column); } } - ) -); -macro_rules! index_impl( - ($t: ident) => ( + + /* + * + * Index + * + */ impl Index<(usize, usize)> for $t { type Output = N; @@ -285,22 +316,26 @@ macro_rules! index_impl( &self.submatrix[i] } } - ) -); -macro_rules! to_homogeneous_impl( - ($t: ident, $tm: ident) => ( - impl ToHomogeneous<$tm> for $t { + + /* + * + * ToHomogeneous + * + */ + impl ToHomogeneous<$homogeneous> for $t { #[inline] - fn to_homogeneous(&self) -> $tm { + fn to_homogeneous(&self) -> $homogeneous { self.submatrix.to_homogeneous() } } - ) -); -macro_rules! approx_eq_impl( - ($t: ident) => ( + + /* + * + * ApproxEq + * + */ impl> ApproxEq for $t { #[inline] fn approx_epsilon(_: Option<$t>) -> N { @@ -327,22 +362,27 @@ macro_rules! approx_eq_impl( ApproxEq::approx_eq_ulps(&self.submatrix, &other.submatrix, ulps) } } - ) -); -macro_rules! absolute_impl( - ($t: ident, $tm: ident) => ( - impl> Absolute<$tm> for $t { + + /* + * + * Absolute + * + */ + impl> Absolute<$submatrix> for $t { #[inline] - fn abs(m: &$t) -> $tm { + fn abs(m: &$t) -> $submatrix { Absolute::abs(&m.submatrix) } } - ) -); -macro_rules! rotation_display_impl( - ($t: ident) => ( + + + /* + * + * Display + * + */ impl fmt::Display for $t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); @@ -352,5 +392,29 @@ macro_rules! rotation_display_impl( writeln!(f, "}}") } } + + + /* + * + * Arbitrary + * + */ + #[cfg(feature="arbitrary")] + impl Arbitrary for $t { + fn arbitrary(g: &mut G) -> $t { + $t::new(Arbitrary::arbitrary(g)) + } + } + ) +); + +macro_rules! dim_impl( + ($t: ident, $dimension: expr) => ( + impl Dimension for $t { + #[inline] + fn dimension(_: Option<$t>) -> usize { + $dimension + } + } ) ); diff --git a/src/structs/similarity.rs b/src/structs/similarity.rs index 1fb6eb1d..f0dbef03 100644 --- a/src/structs/similarity.rs +++ b/src/structs/similarity.rs @@ -6,7 +6,7 @@ use num::One; use structs::matrix::{Matrix3, Matrix4}; use traits::structure::{Dimension, Column, BaseFloat, BaseNum}; use traits::operations::{Inverse, ApproxEq}; -use traits::geometry::{Rotation, Transform, Transformation, Translation, ToHomogeneous}; +use traits::geometry::{Transform, Transformation, ToHomogeneous}; use structs::vector::{Vector1, Vector2, Vector3}; use structs::point::{Point2, Point3}; @@ -49,38 +49,9 @@ pub struct Similarity3 { pub isometry: Isometry3 } -sim_impl!(Similarity2, Isometry2, Rotation2, Vector2, Vector1); -dim_impl!(Similarity2, 2); -sim_scale_impl!(Similarity2); -sim_one_impl!(Similarity2); -sim_mul_sim_impl!(Similarity2); -sim_mul_isometry_impl!(Similarity2, Isometry2); -sim_mul_rotation_impl!(Similarity2, Rotation2); -sim_mul_point_vec_impl!(Similarity2, Point2); -sim_mul_point_vec_impl!(Similarity2, Vector2); -transformation_impl!(Similarity2); -sim_transform_impl!(Similarity2, Point2); -sim_inverse_impl!(Similarity2); -sim_to_homogeneous_impl!(Similarity2, Matrix3); -sim_approx_eq_impl!(Similarity2); -sim_rand_impl!(Similarity2); -sim_arbitrary_impl!(Similarity2); -sim_display_impl!(Similarity2); -sim_impl!(Similarity3, Isometry3, Rotation3, Vector3, Vector3); +similarity_impl!(Similarity2, Isometry2, Rotation2, Vector2, Vector1, Point2, Matrix3); +dim_impl!(Similarity2, 2); + +similarity_impl!(Similarity3, Isometry3, Rotation3, Vector3, Vector3, Point3, Matrix4); dim_impl!(Similarity3, 3); -sim_scale_impl!(Similarity3); -sim_one_impl!(Similarity3); -sim_mul_sim_impl!(Similarity3); -sim_mul_isometry_impl!(Similarity3, Isometry3); -sim_mul_rotation_impl!(Similarity3, Rotation3); -sim_mul_point_vec_impl!(Similarity3, Point3); -sim_mul_point_vec_impl!(Similarity3, Vector3); -transformation_impl!(Similarity3); -sim_transform_impl!(Similarity3, Point3); -sim_inverse_impl!(Similarity3); -sim_to_homogeneous_impl!(Similarity3, Matrix4); -sim_approx_eq_impl!(Similarity3); -sim_rand_impl!(Similarity3); -sim_arbitrary_impl!(Similarity3); -sim_display_impl!(Similarity3); diff --git a/src/structs/similarity_macros.rs b/src/structs/similarity_macros.rs index 8bac2e62..73e8aaf7 100644 --- a/src/structs/similarity_macros.rs +++ b/src/structs/similarity_macros.rs @@ -1,13 +1,22 @@ #![macro_use] -macro_rules! sim_impl( - ($t: ident, $isometry: ident, $rotation_matrix: ident, $subvector: ident, $subrotvector: ident) => ( +macro_rules! similarity_impl( + ($t: ident, + $isometry: ident, $rotation_matrix: ident, + $vector: ident, $rotvector: ident, + $point: ident, + $homogeneous_matrix: ident) => ( impl $t { + /* + * + * Constructors. + * + */ /// Creates a new similarity transformation from a vector, an axis-angle rotation, and a scale factor. /// /// The scale factor may be negative but not zero. #[inline] - pub fn new(translation: $subvector, rotation: $subrotvector, scale: N) -> $t { + pub fn new(translation: $vector, rotation: $rotvector, scale: N) -> $t { assert!(!scale.is_zero(), "A similarity transformation scale factor cannot be zero."); $t { @@ -20,12 +29,12 @@ macro_rules! sim_impl( /// /// The scale factor may be negative but not zero. #[inline] - pub fn new_with_rotation_matrix(translation: $subvector, rotation: $rotation_matrix, scale: N) -> $t { + pub fn from_rotation_matrix(translation: $vector, rotation: $rotation_matrix, scale: N) -> $t { assert!(!scale.is_zero(), "A similarity transformation scale factor cannot be zero."); $t { scale: scale, - isometry: $isometry::new_with_rotation_matrix(translation, rotation) + isometry: $isometry::from_rotation_matrix(translation, rotation) } } @@ -33,7 +42,7 @@ macro_rules! sim_impl( /// /// The scale factor may be negative but not zero. #[inline] - pub fn new_with_isometry(isometry: $isometry, scale: N) -> $t { + pub fn from_isometry(isometry: $isometry, scale: N) -> $t { assert!(!scale.is_zero(), "A similarity transformation scale factor cannot be zero."); $t { @@ -41,13 +50,12 @@ macro_rules! sim_impl( isometry: isometry } } - } - ) -); -macro_rules! sim_scale_impl( - ($t: ident) => ( - impl $t { + /* + * + * Methods related to scaling. + * + */ /// The scale factor of this similarity transformation. #[inline] pub fn scale(&self) -> N { @@ -72,7 +80,7 @@ macro_rules! sim_scale_impl( #[inline] pub fn append_scale(&self, s: &N) -> $t { assert!(!s.is_zero(), "Cannot append a zero scale to a similarity transformation."); - $t::new_with_rotation_matrix(self.isometry.translation * *s, self.isometry.rotation, self.scale * *s) + $t::from_rotation_matrix(self.isometry.translation * *s, self.isometry.rotation, self.scale * *s) } /// Prepends in-place a scale to this similarity transformation. @@ -86,7 +94,7 @@ macro_rules! sim_scale_impl( #[inline] pub fn prepend_scale(&self, s: &N) -> $t { assert!(!s.is_zero(), "A similarity transformation scale must not be zero."); - $t::new_with_isometry(self.isometry, self.scale * *s) + $t::from_isometry(self.isometry, self.scale * *s) } /// Sets the scale of this similarity transformation. @@ -96,28 +104,67 @@ macro_rules! sim_scale_impl( self.scale = s } } - ) -); -macro_rules! sim_one_impl( - ($t: ident) => ( + /* + * + * One Impl. + * + */ impl One for $t { #[inline] fn one() -> $t { - $t::new_with_isometry(::one(), ::one()) + $t::from_isometry(::one(), ::one()) } } - ) -); -macro_rules! sim_mul_sim_impl( - ($t: ident) => ( + + /* + * + * Transformation + * + */ + impl Transformation<$t> for $t { + fn transformation(&self) -> $t { + *self + } + + fn inverse_transformation(&self) -> $t { + // inversion will never fails + Inverse::inverse(self).unwrap() + } + + fn append_transformation_mut(&mut self, t: &$t) { + *self = *t * *self + } + + fn append_transformation(&self, t: &$t) -> $t { + *t * *self + } + + fn prepend_transformation_mut(&mut self, t: &$t) { + *self = *self * *t + } + + fn prepend_transformation(&self, t: &$t) -> $t { + *self * *t + } + + fn set_transformation(&mut self, t: $t) { + *self = t + } + } + + /* + * + * Similarity × Similarity + * + */ impl Mul<$t> for $t { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { - $t::new_with_rotation_matrix( + $t::from_rotation_matrix( self.isometry.translation + self.isometry.rotation * (right.isometry.translation * self.scale), self.isometry.rotation * right.isometry.rotation, self.scale * right.scale) @@ -132,115 +179,130 @@ macro_rules! sim_mul_sim_impl( self.scale *= right.scale; } } - ) -); -macro_rules! sim_mul_isometry_impl( - ($t: ident, $ti: ident) => ( - impl Mul<$ti> for $t { + + /* + * + * Similarity × Isometry + * + */ + impl Mul<$isometry> for $t { type Output = $t; #[inline] - fn mul(self, right: $ti) -> $t { - $t::new_with_rotation_matrix( + fn mul(self, right: $isometry) -> $t { + $t::from_rotation_matrix( self.isometry.translation + self.isometry.rotation * (right.translation * self.scale), self.isometry.rotation * right.rotation, self.scale) } } - impl MulAssign<$ti> for $t { + impl MulAssign<$isometry> for $t { #[inline] - fn mul_assign(&mut self, right: $ti) { + fn mul_assign(&mut self, right: $isometry) { self.isometry.translation += self.isometry.rotation * (right.translation * self.scale); self.isometry.rotation *= right.rotation; } } - impl Mul<$t> for $ti { + impl Mul<$t> for $isometry { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { - $t::new_with_rotation_matrix( + $t::from_rotation_matrix( self.translation + self.rotation * right.isometry.translation, self.rotation * right.isometry.rotation, right.scale) } } - ) -); -macro_rules! sim_mul_rotation_impl( - ($t: ident, $tr: ident) => ( - impl Mul<$tr> for $t { + /* + * + * Similarity × Rotation + * + */ + impl Mul<$rotation_matrix> for $t { type Output = $t; #[inline] - fn mul(self, right: $tr) -> $t { - $t::new_with_rotation_matrix( + fn mul(self, right: $rotation_matrix) -> $t { + $t::from_rotation_matrix( self.isometry.translation, self.isometry.rotation * right, self.scale) } } - impl MulAssign<$tr> for $t { + impl MulAssign<$rotation_matrix> for $t { #[inline] - fn mul_assign(&mut self, right: $tr) { + fn mul_assign(&mut self, right: $rotation_matrix) { self.isometry.rotation *= right; } } - impl Mul<$t> for $tr { + impl Mul<$t> for $rotation_matrix { type Output = $t; #[inline] fn mul(self, right: $t) -> $t { - $t::new_with_rotation_matrix( + $t::from_rotation_matrix( self * right.isometry.translation, self * right.isometry.rotation, right.scale) } } - ) -); -macro_rules! sim_mul_point_vec_impl( - ($t: ident, $tv: ident) => ( - impl Mul<$tv> for $t { - type Output = $tv; + /* + * + * Similarity × { Point, Vector } + * + */ + impl Mul<$vector> for $t { + type Output = $vector; #[inline] - fn mul(self, right: $tv) -> $tv { + fn mul(self, right: $vector) -> $vector { self.isometry * (right * self.scale) } } + impl Mul<$point> for $t { + type Output = $point; + + #[inline] + fn mul(self, right: $point) -> $point { + self.isometry * (right * self.scale) + } + } // NOTE: there is no viable pre-multiplication definition because of the translation // component. - ) -); -macro_rules! sim_transform_impl( - ($t: ident, $tp: ident) => ( - impl Transform<$tp> for $t { + /* + * + * Similarity × Point + * + */ + impl Transform<$point> for $t { #[inline] - fn transform(&self, p: &$tp) -> $tp { + fn transform(&self, p: &$point) -> $point { self.isometry.transform(&(*p * self.scale)) } #[inline] - fn inverse_transform(&self, p: &$tp) -> $tp { + fn inverse_transform(&self, p: &$point) -> $point { self.isometry.inverse_transform(p) / self.scale } } - ) -); -macro_rules! sim_inverse_impl( - ($t: ident) => ( + + /* + * + * Inverse + * + */ impl> Inverse for $t { #[inline] fn inverse_mut(&mut self) -> bool { @@ -263,28 +325,32 @@ macro_rules! sim_inverse_impl( Some(res) } } - ) -); -macro_rules! sim_to_homogeneous_impl( - ($t: ident, $th: ident) => ( - impl ToHomogeneous<$th> for $t { - fn to_homogeneous(&self) -> $th { + + /* + * + * ToHomogeneous + * + */ + impl ToHomogeneous<$homogeneous_matrix> for $t { + fn to_homogeneous(&self) -> $homogeneous_matrix { let mut res = (*self.isometry.rotation.submatrix() * self.scale).to_homogeneous(); // copy the translation - let dimension = Dimension::dimension(None::<$th>); + let dimension = Dimension::dimension(None::<$homogeneous_matrix>); res.set_column(dimension - 1, self.isometry.translation.as_point().to_homogeneous().to_vector()); res } } - ) -); -macro_rules! sim_approx_eq_impl( - ($t: ident) => ( + + /* + * + * ApproxEq + * + */ impl> ApproxEq for $t { #[inline] fn approx_epsilon(_: Option<$t>) -> N { @@ -308,11 +374,13 @@ macro_rules! sim_approx_eq_impl( ApproxEq::approx_eq_ulps(&self.isometry, &other.isometry, ulps) } } - ) -); -macro_rules! sim_rand_impl( - ($t: ident) => ( + + /* + * + * Rand + * + */ impl Rand for $t { #[inline] fn rand(rng: &mut R) -> $t { @@ -321,28 +389,32 @@ macro_rules! sim_rand_impl( scale = rng.gen(); } - $t::new_with_isometry(rng.gen(), scale) + $t::from_isometry(rng.gen(), scale) } } - ) -); -macro_rules! sim_arbitrary_impl( - ($t: ident) => ( + + /* + * + * Arbitrary + * + */ #[cfg(feature="arbitrary")] impl Arbitrary for $t { fn arbitrary(g: &mut G) -> $t { - $t::new_with_isometry( + $t::from_isometry( Arbitrary::arbitrary(g), Arbitrary::arbitrary(g) ) } } - ) -); -macro_rules! sim_display_impl( - ($t: ident) => ( + + /* + * + * Display + * + */ impl fmt::Display for $t { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(writeln!(f, "Similarity transformation {{")); diff --git a/src/structs/specializations/matrix.rs b/src/structs/specializations/matrix.rs index d390f912..27868e7b 100644 --- a/src/structs/specializations/matrix.rs +++ b/src/structs/specializations/matrix.rs @@ -3,7 +3,7 @@ use structs::vector::{Vector2, Vector3}; use structs::point::{Point2, Point3}; use structs::matrix::{Matrix1, Matrix2, Matrix3}; use traits::operations::{Inverse, Determinant, ApproxEq}; -use traits::structure::{Row, Column, BaseNum}; +use traits::structure::BaseNum; // some specializations: impl> Inverse for Matrix1 { @@ -24,9 +24,8 @@ impl> Inverse for Matrix1 { false } else { - let _1: N = ::one(); + self.m11 = ::one::() / Determinant::determinant(self); - self.m11 = _1 / Determinant::determinant(self); true } } @@ -130,85 +129,6 @@ impl Determinant for Matrix3 { } } -impl Row> for Matrix3 { - #[inline] - fn nrows(&self) -> usize { - 3 - } - - #[inline] - fn row(&self, i: usize) -> Vector3 { - match i { - 0 => Vector3::new(self.m11, self.m12, self.m13), - 1 => Vector3::new(self.m21, self.m22, self.m23), - 2 => Vector3::new(self.m31, self.m32, self.m33), - _ => panic!(format!("Index out of range: 3d matrices do not have {} rows.", i)) - } - } - - #[inline] - fn set_row(&mut self, i: usize, r: Vector3) { - match i { - 0 => { - self.m11 = r.x; - self.m12 = r.y; - self.m13 = r.z; - }, - 1 => { - self.m21 = r.x; - self.m22 = r.y; - self.m23 = r.z; - }, - 2 => { - self.m31 = r.x; - self.m32 = r.y; - self.m33 = r.z; - }, - _ => panic!(format!("Index out of range: 3d matrices do not have {} rows.", i)) - - } - } -} - -impl Column> for Matrix3 { - #[inline] - fn ncols(&self) -> usize { - 3 - } - - #[inline] - fn column(&self, i: usize) -> Vector3 { - match i { - 0 => Vector3::new(self.m11, self.m21, self.m31), - 1 => Vector3::new(self.m12, self.m22, self.m32), - 2 => Vector3::new(self.m13, self.m23, self.m33), - _ => panic!(format!("Index out of range: 3d matrices do not have {} cols.", i)) - } - } - - #[inline] - fn set_column(&mut self, i: usize, r: Vector3) { - match i { - 0 => { - self.m11 = r.x; - self.m21 = r.y; - self.m31 = r.z; - }, - 1 => { - self.m12 = r.x; - self.m22 = r.y; - self.m32 = r.z; - }, - 2 => { - self.m13 = r.x; - self.m23 = r.y; - self.m33 = r.z; - }, - _ => panic!(format!("Index out of range: 3d matrices do not have {} cols.", i)) - - } - } -} impl + Add> Mul> for Matrix3 { type Output = Matrix3; @@ -234,7 +154,7 @@ impl + Add> Mul> for Matr impl + Add> Mul> for Matrix2 { type Output = Matrix2; - #[inline(always)] + #[inline] fn mul(self, right: Matrix2) -> Matrix2 { Matrix2::new( self.m11 * right.m11 + self.m12 * right.m21, @@ -249,7 +169,7 @@ impl + Add> Mul> for Matr impl + Add> Mul> for Matrix3 { type Output = Vector3; - #[inline(always)] + #[inline] fn mul(self, right: Vector3) -> Vector3 { Vector3::new( self.m11 * right.x + self.m12 * right.y + self.m13 * right.z, @@ -262,7 +182,7 @@ impl + Add> Mul> for Matr impl + Add> Mul> for Vector3 { type Output = Vector3; - #[inline(always)] + #[inline] fn mul(self, right: Matrix3) -> Vector3 { Vector3::new( self.x * right.m11 + self.y * right.m21 + self.z * right.m31, @@ -275,7 +195,7 @@ impl + Add> Mul> for Vect impl + Add> Mul> for Vector2 { type Output = Vector2; - #[inline(always)] + #[inline] fn mul(self, right: Matrix2) -> Vector2 { Vector2::new( self.x * right.m11 + self.y * right.m21, @@ -287,7 +207,7 @@ impl + Add> Mul> for Vect impl + Add> Mul> for Matrix2 { type Output = Vector2; - #[inline(always)] + #[inline] fn mul(self, right: Vector2) -> Vector2 { Vector2::new( self.m11 * right.x + self.m12 * right.y, @@ -299,7 +219,7 @@ impl + Add> Mul> for Matr impl + Add> Mul> for Matrix3 { type Output = Point3; - #[inline(always)] + #[inline] fn mul(self, right: Point3) -> Point3 { Point3::new( self.m11 * right.x + self.m12 * right.y + self.m13 * right.z, @@ -312,7 +232,7 @@ impl + Add> Mul> for Matri impl + Add> Mul> for Point3 { type Output = Point3; - #[inline(always)] + #[inline] fn mul(self, right: Matrix3) -> Point3 { Point3::new( self.x * right.m11 + self.y * right.m21 + self.z * right.m31, @@ -325,7 +245,7 @@ impl + Add> Mul> for Poin impl + Add> Mul> for Point2 { type Output = Point2; - #[inline(always)] + #[inline] fn mul(self, right: Matrix2) -> Point2 { Point2::new( self.x * right.m11 + self.y * right.m21, @@ -337,7 +257,7 @@ impl + Add> Mul> for Poin impl + Add> Mul> for Matrix2 { type Output = Point2; - #[inline(always)] + #[inline] fn mul(self, right: Point2) -> Point2 { Point2::new( self.m11 * right.x + self.m12 * right.y, @@ -350,7 +270,7 @@ impl + Add> Mul> for Matri macro_rules! impl_mul_assign_from_mul( ($tleft: ident, $tright: ident) => ( impl + Add> MulAssign<$tright> for $tleft { - #[inline(always)] + #[inline] fn mul_assign(&mut self, right: $tright) { // NOTE: there is probably no interesting optimization compared to the not-inplace // operation. diff --git a/src/structs/specializations/primitives.rs b/src/structs/specializations/primitives.rs index 636bdf6b..0605df53 100644 --- a/src/structs/specializations/primitives.rs +++ b/src/structs/specializations/primitives.rs @@ -5,7 +5,7 @@ use traits::structure::Cast; macro_rules! primitive_cast_impl( ($from: ty, $to: ty) => ( impl Cast<$from> for $to { - #[inline(always)] + #[inline] fn from(t: $from) -> $to { t as $to } diff --git a/src/structs/specializations/vector.rs b/src/structs/specializations/vector.rs index c5367e94..681c82fe 100644 --- a/src/structs/specializations/vector.rs +++ b/src/structs/specializations/vector.rs @@ -115,12 +115,12 @@ impl Row> for Vector2 { } impl Basis for Vector1 { - #[inline(always)] + #[inline] fn canonical_basis) -> bool>(mut f: F) { f(Vector1::new(::one())); } - #[inline(always)] + #[inline] fn orthonormal_subspace_basis) -> bool>(_: &Vector1, _: F) { } #[inline] @@ -135,7 +135,7 @@ impl Basis for Vector1 { } impl> Basis for Vector2 { - #[inline(always)] + #[inline] fn canonical_basis) -> bool>(mut f: F) { if !f(Vector2::new(::one(), ::zero())) { return }; f(Vector2::new(::zero(), ::one())); @@ -161,21 +161,21 @@ impl> Basis for Vector2 { } impl Basis for Vector3 { - #[inline(always)] + #[inline] fn canonical_basis) -> bool>(mut f: F) { if !f(Vector3::new(::one(), ::zero(), ::zero())) { return }; if !f(Vector3::new(::zero(), ::one(), ::zero())) { return }; f(Vector3::new(::zero(), ::zero(), ::one())); } - #[inline(always)] + #[inline] fn orthonormal_subspace_basis) -> bool>(n: &Vector3, mut f: F) { let a = if n.x.abs() > n.y.abs() { - Norm::normalize(&Vector3::new(n.z, ::zero(), -n.x)) + ::normalize(&Vector3::new(n.z, ::zero(), -n.x)) } else { - Norm::normalize(&Vector3::new(::zero(), -n.z, n.y)) + ::normalize(&Vector3::new(::zero(), -n.z, n.y)) }; if !f(Cross::cross(&a, n)) { return }; @@ -272,14 +272,14 @@ static SAMPLES_3_F64: [Vector3; 42] = [ impl UniformSphereSample for Vector1 where Vector1: One { - #[inline(always)] + #[inline] fn sample)>(mut f: F) { f(::one()) } } impl + Copy> UniformSphereSample for Vector2 { - #[inline(always)] + #[inline] fn sample)>(mut f: F) { for sample in SAMPLES_2_F64.iter() { f(Cast::from(*sample)) @@ -288,7 +288,7 @@ impl + Copy> UniformSphereSample for Vector2 { } impl + Copy> UniformSphereSample for Vector3 { - #[inline(always)] + #[inline] fn sample)>(mut f: F) { for sample in SAMPLES_3_F64.iter() { f(Cast::from(*sample)) @@ -297,7 +297,7 @@ impl + Copy> UniformSphereSample for Vector3 { } impl + Copy> UniformSphereSample for Vector4 { - #[inline(always)] + #[inline] fn sample)>(_: F) { panic!("UniformSphereSample::>::sample : Not yet implemented.") // for sample in SAMPLES_3_F32.iter() { diff --git a/src/structs/unit.rs b/src/structs/unit.rs new file mode 100644 index 00000000..f6730e96 --- /dev/null +++ b/src/structs/unit.rs @@ -0,0 +1,78 @@ +use traits::geometry::Norm; + + +/// A wrapper that ensures the undelying algebraic entity has a unit norm. +#[repr(C)] +#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] +pub struct Unit { + v: T +} + +impl Unit { + /// Normalize the given value and return it wrapped on a `Unit` structure. + #[inline] + pub fn new(v: &T) -> Self { + Unit { v: v.normalize() } + } + + /// Attempts to normalize the given value and return it wrapped on a `Unit` structure. + /// + /// Returns `None` if the norm was smaller or equal to `min_norm`. + #[inline] + pub fn try_new(v: &T, min_norm: T::NormType) -> Option { + v.try_normalize(min_norm).map(|v| Unit { v: v }) + } + + /// Normalize the given value and return it wrapped on a `Unit` structure and its norm. + #[inline] + pub fn new_and_get(mut v: T) -> (Self, T::NormType) { + let n = v.normalize_mut(); + + (Unit { v: v }, n) + } + + /// Normalize the given value and return it wrapped on a `Unit` structure and its norm. + /// + /// Returns `None` if the norm was smaller or equal to `min_norm`. + #[inline] + pub fn try_new_and_get(mut v: T, min_norm: T::NormType) -> Option<(Self, T::NormType)> { + if let Some(n) = v.try_normalize_mut(min_norm) { + Some((Unit { v: v }, n)) + } + else { + None + } + } + + /// Normalizes this value again. This is useful when repeated computations + /// might cause a drift in the norm because of float inaccuracies. + /// + /// Returns the norm beform re-normalization (should be close to `1.0`). + #[inline] + pub fn renormalize(&mut self) -> T::NormType { + self.v.normalize_mut() + } +} + +impl Unit { + /// Wraps the given value, assuming it is already normalized. + /// + /// This function is not safe because `v` is not verified to be actually normalized. + #[inline] + pub fn from_unit_value_unchecked(v: T) -> Self { + Unit { v: v } + } + + /// Retrieves the underlying value. + #[inline] + pub fn unwrap(self) -> T { + self.v + } +} + +impl AsRef for Unit { + #[inline] + fn as_ref(&self) -> &T { + &self.v + } +} diff --git a/src/structs/vector.rs b/src/structs/vector.rs index f18ac8e4..45ac1646 100644 --- a/src/structs/vector.rs +++ b/src/structs/vector.rs @@ -29,50 +29,14 @@ pub struct Vector1 { pub x: N } -new_impl!(Vector1, x); -pord_impl!(Vector1, x,); -vec_axis_impl!(Vector1, x); -vec_cast_impl!(Vector1, x); -conversion_impl!(Vector1, 1); -index_impl!(Vector1); -indexable_impl!(Vector1, 1); -at_fast_impl!(Vector1, 1); -repeat_impl!(Vector1, val, x); -dim_impl!(Vector1, 1); -container_impl!(Vector1); -// (specialized); basis_impl!(Vector1, 1); -add_impl!(Vector1, x); -sub_impl!(Vector1, x); -mul_impl!(Vector1, x); -div_impl!(Vector1, x); -scalar_add_impl!(Vector1, x); -scalar_sub_impl!(Vector1, x); -scalar_mul_impl!(Vector1, x); -scalar_div_impl!(Vector1, x); -neg_impl!(Vector1, x); -dot_impl!(Vector1, x); -translation_impl!(Vector1); -norm_impl!(Vector1, x); -approx_eq_impl!(Vector1, x); -zero_one_impl!(Vector1, x); +vector_impl!(Vector1, Point1, x); +vectorlike_impl!(Vector1, 1, x); from_iterator_impl!(Vector1, iterator); -bounded_impl!(Vector1, x); -axpy_impl!(Vector1, x); -iterable_impl!(Vector1, 1); -iterable_mut_impl!(Vector1, 1); +// (specialized); basis_impl!(Vector1, 1); vec_to_homogeneous_impl!(Vector1, Vector2, y, x); vec_from_homogeneous_impl!(Vector1, Vector2, y, x); -translate_impl!(Vector1, Point1); -rotate_impl!(Vector1); -rotate_impl!(Point1); -transform_impl!(Vector1, Point1); -vec_as_point_impl!(Vector1, Point1, x); -num_float_vec_impl!(Vector1); -absolute_vec_impl!(Vector1, x); -arbitrary_impl!(Vector1, x); -rand_impl!(Vector1, x); -mean_impl!(Vector1); -vec_display_impl!(Vector1); + + /// Vector of dimension 2. /// @@ -87,50 +51,14 @@ pub struct Vector2 { pub y: N } -new_impl!(Vector2, x, y); -pord_impl!(Vector2, x, y); -vec_axis_impl!(Vector2, x, y); -vec_cast_impl!(Vector2, x, y); -conversion_impl!(Vector2, 2); -index_impl!(Vector2); -indexable_impl!(Vector2, 2); -at_fast_impl!(Vector2, 2); -repeat_impl!(Vector2, val, x, y); -dim_impl!(Vector2, 2); -container_impl!(Vector2); -// (specialized); basis_impl!(Vector2, 1); -add_impl!(Vector2, x, y); -sub_impl!(Vector2, x, y); -mul_impl!(Vector2, x, y); -div_impl!(Vector2, x, y); -scalar_add_impl!(Vector2, x, y); -scalar_sub_impl!(Vector2, x, y); -scalar_mul_impl!(Vector2, x, y); -scalar_div_impl!(Vector2, x, y); -neg_impl!(Vector2, x, y); -dot_impl!(Vector2, x, y); -translation_impl!(Vector2); -norm_impl!(Vector2, x, y); -approx_eq_impl!(Vector2, x, y); -zero_one_impl!(Vector2, x, y); +vector_impl!(Vector2, Point2, x, y); +vectorlike_impl!(Vector2, 2, x, y); from_iterator_impl!(Vector2, iterator, iterator); -bounded_impl!(Vector2, x, y); -axpy_impl!(Vector2, x, y); -iterable_impl!(Vector2, 2); -iterable_mut_impl!(Vector2, 2); +// (specialized); basis_impl!(Vector2, 1); vec_to_homogeneous_impl!(Vector2, Vector3, z, x, y); vec_from_homogeneous_impl!(Vector2, Vector3, z, x, y); -translate_impl!(Vector2, Point2); -rotate_impl!(Vector2); -rotate_impl!(Point2); -transform_impl!(Vector2, Point2); -vec_as_point_impl!(Vector2, Point2, x, y); -num_float_vec_impl!(Vector2); -absolute_vec_impl!(Vector2, x, y); -arbitrary_impl!(Vector2, x, y); -rand_impl!(Vector2, x, y); -mean_impl!(Vector2); -vec_display_impl!(Vector2); + + /// Vector of dimension 3. /// @@ -147,50 +75,12 @@ pub struct Vector3 { pub z: N } -new_impl!(Vector3, x, y, z); -pord_impl!(Vector3, x, y, z); -vec_axis_impl!(Vector3, x, y, z); -vec_cast_impl!(Vector3, x, y, z); -conversion_impl!(Vector3, 3); -index_impl!(Vector3); -indexable_impl!(Vector3, 3); -at_fast_impl!(Vector3, 3); -repeat_impl!(Vector3, val, x, y, z); -dim_impl!(Vector3, 3); -container_impl!(Vector3); -// (specialized); basis_impl!(Vector3, 1); -add_impl!(Vector3, x, y, z); -sub_impl!(Vector3, x, y, z); -mul_impl!(Vector3, x, y, z); -div_impl!(Vector3, x, y, z); -scalar_add_impl!(Vector3, x, y, z); -scalar_sub_impl!(Vector3, x, y, z); -scalar_mul_impl!(Vector3, x, y, z); -scalar_div_impl!(Vector3, x, y, z); -neg_impl!(Vector3, x, y, z); -dot_impl!(Vector3, x, y, z); -translation_impl!(Vector3); -norm_impl!(Vector3, x, y ,z); -approx_eq_impl!(Vector3, x, y, z); -zero_one_impl!(Vector3, x, y, z); +vector_impl!(Vector3, Point3, x, y, z); +vectorlike_impl!(Vector3, 3, x, y, z); from_iterator_impl!(Vector3, iterator, iterator, iterator); -bounded_impl!(Vector3, x, y, z); -axpy_impl!(Vector3, x, y, z); -iterable_impl!(Vector3, 3); -iterable_mut_impl!(Vector3, 3); +// (specialized); basis_impl!(Vector3, 1); vec_to_homogeneous_impl!(Vector3, Vector4, w, x, y, z); vec_from_homogeneous_impl!(Vector3, Vector4, w, x, y, z); -translate_impl!(Vector3, Point3); -rotate_impl!(Vector3); -rotate_impl!(Point3); -transform_impl!(Vector3, Point3); -vec_as_point_impl!(Vector3, Point3, x, y, z); -num_float_vec_impl!(Vector3); -absolute_vec_impl!(Vector3, x, y, z); -arbitrary_impl!(Vector3, x, y, z); -rand_impl!(Vector3, x, y, z); -mean_impl!(Vector3); -vec_display_impl!(Vector3); /// Vector of dimension 4. @@ -210,50 +100,14 @@ pub struct Vector4 { pub w: N } -new_impl!(Vector4, x, y, z, w); -pord_impl!(Vector4, x, y, z, w); -vec_axis_impl!(Vector4, x, y, z, w); -vec_cast_impl!(Vector4, x, y, z, w); -conversion_impl!(Vector4, 4); -index_impl!(Vector4); -indexable_impl!(Vector4, 4); -at_fast_impl!(Vector4, 4); -repeat_impl!(Vector4, val, x, y, z, w); -dim_impl!(Vector4, 4); -container_impl!(Vector4); -basis_impl!(Vector4, 4); -add_impl!(Vector4, x, y, z, w); -sub_impl!(Vector4, x, y, z, w); -mul_impl!(Vector4, x, y, z, w); -div_impl!(Vector4, x, y, z, w); -scalar_add_impl!(Vector4, x, y, z, w); -scalar_sub_impl!(Vector4, x, y, z, w); -scalar_mul_impl!(Vector4, x, y, z, w); -scalar_div_impl!(Vector4, x, y, z, w); -neg_impl!(Vector4, x, y, z, w); -dot_impl!(Vector4, x, y, z, w); -translation_impl!(Vector4); -norm_impl!(Vector4, x, y, z, w); -approx_eq_impl!(Vector4, x, y, z, w); -zero_one_impl!(Vector4, x, y, z, w); +vector_impl!(Vector4, Point4, x, y, z, w); +vectorlike_impl!(Vector4, 4, x, y, z, w); from_iterator_impl!(Vector4, iterator, iterator, iterator, iterator); -bounded_impl!(Vector4, x, y, z, w); -axpy_impl!(Vector4, x, y, z, w); -iterable_impl!(Vector4, 4); -iterable_mut_impl!(Vector4, 4); +basis_impl!(Vector4, 4); vec_to_homogeneous_impl!(Vector4, Vector5, a, x, y, z, w); vec_from_homogeneous_impl!(Vector4, Vector5, a, x, y, z, w); -translate_impl!(Vector4, Point4); -rotate_impl!(Vector4); -rotate_impl!(Point4); -transform_impl!(Vector4, Point4); -vec_as_point_impl!(Vector4, Point4, x, y, z, w); -num_float_vec_impl!(Vector4); -absolute_vec_impl!(Vector4, x, y, z, w); -arbitrary_impl!(Vector4, x, y, z, w); -rand_impl!(Vector4, x, y, z, w); -mean_impl!(Vector4); -vec_display_impl!(Vector4); + + /// Vector of dimension 5. /// @@ -274,50 +128,13 @@ pub struct Vector5 { pub a: N } -new_impl!(Vector5, x, y, z, w, a); -pord_impl!(Vector5, x, y, z, w, a); -vec_axis_impl!(Vector5, x, y, z, w, a); -vec_cast_impl!(Vector5, x, y, z, w, a); -conversion_impl!(Vector5, 5); -index_impl!(Vector5); -indexable_impl!(Vector5, 5); -at_fast_impl!(Vector5, 5); -repeat_impl!(Vector5, val, x, y, z, w, a); -dim_impl!(Vector5, 5); -container_impl!(Vector5); -basis_impl!(Vector5, 5); -add_impl!(Vector5, x, y, z, w, a); -sub_impl!(Vector5, x, y, z, w, a); -mul_impl!(Vector5, x, y, z, w, a); -div_impl!(Vector5, x, y, z, w, a); -scalar_add_impl!(Vector5, x, y, z, w, a); -scalar_sub_impl!(Vector5, x, y, z, w, a); -scalar_mul_impl!(Vector5, x, y, z, w, a); -scalar_div_impl!(Vector5, x, y, z, w, a); -neg_impl!(Vector5, x, y, z, w, a); -dot_impl!(Vector5, x, y, z, w, a); -translation_impl!(Vector5); -norm_impl!(Vector5, x, y, z, w, a); -approx_eq_impl!(Vector5, x, y, z, w, a); -zero_one_impl!(Vector5, x, y, z, w, a); +vector_impl!(Vector5, Point5, x, y, z, w, a); +vectorlike_impl!(Vector5, 5, x, y, z, w, a); from_iterator_impl!(Vector5, iterator, iterator, iterator, iterator, iterator); -bounded_impl!(Vector5, x, y, z, w, a); -axpy_impl!(Vector5, x, y, z, w, a); -iterable_impl!(Vector5, 5); -iterable_mut_impl!(Vector5, 5); +basis_impl!(Vector5, 5); vec_to_homogeneous_impl!(Vector5, Vector6, b, x, y, z, w, a); vec_from_homogeneous_impl!(Vector5, Vector6, b, x, y, z, w, a); -translate_impl!(Vector5, Point5); -rotate_impl!(Vector5); -rotate_impl!(Point5); -transform_impl!(Vector5, Point5); -vec_as_point_impl!(Vector5, Point5, x, y, z, w, a); -num_float_vec_impl!(Vector5); -absolute_vec_impl!(Vector5, x, y, z, w, a); -arbitrary_impl!(Vector5, x, y, z, w, a); -rand_impl!(Vector5, x, y, z, w, a); -mean_impl!(Vector5); -vec_display_impl!(Vector5); + /// Vector of dimension 6. /// @@ -340,45 +157,8 @@ pub struct Vector6 { pub b: N } -new_impl!(Vector6, x, y, z, w, a, b); -pord_impl!(Vector6, x, y, z, w, a, b); -vec_axis_impl!(Vector6, x, y, z, w, a, b); -vec_cast_impl!(Vector6, x, y, z, w, a, b); -conversion_impl!(Vector6, 6); -index_impl!(Vector6); -indexable_impl!(Vector6, 6); -at_fast_impl!(Vector6, 6); -repeat_impl!(Vector6, val, x, y, z, w, a, b); -dim_impl!(Vector6, 6); -container_impl!(Vector6); -basis_impl!(Vector6, 6); -add_impl!(Vector6, x, y, z, w, a, b); -sub_impl!(Vector6, x, y, z, w, a, b); -mul_impl!(Vector6, x, y, z, w, a, b); -div_impl!(Vector6, x, y, z, w, a, b); -scalar_add_impl!(Vector6, x, y, z, w, a, b); -scalar_sub_impl!(Vector6, x, y, z, w, a, b); -scalar_mul_impl!(Vector6, x, y, z, w, a, b); -scalar_div_impl!(Vector6, x, y, z, w, a, b); -neg_impl!(Vector6, x, y, z, w, a, b); -dot_impl!(Vector6, x, y, z, w, a, b); -translation_impl!(Vector6); -norm_impl!(Vector6, x, y, z, w, a, b); -approx_eq_impl!(Vector6, x, y, z, w, a, b); -zero_one_impl!(Vector6, x, y, z, w, a, b); +vector_impl!(Vector6, Point6, x, y, z, w, a, b); +vectorlike_impl!(Vector6, 6, x, y, z, w, a, b); from_iterator_impl!(Vector6, iterator, iterator, iterator, iterator, iterator, iterator); -bounded_impl!(Vector6, x, y, z, w, a, b); -axpy_impl!(Vector6, x, y, z, w, a, b); -iterable_impl!(Vector6, 6); -iterable_mut_impl!(Vector6, 6); -translate_impl!(Vector6, Point6); -rotate_impl!(Vector6); -rotate_impl!(Point6); -transform_impl!(Vector6, Point6); -vec_as_point_impl!(Vector6, Point6, x, y, z, w, a, b); -num_float_vec_impl!(Vector6); -absolute_vec_impl!(Vector6, x, y, z, w, a, b); -arbitrary_impl!(Vector6, x, y, z, w, a, b); -rand_impl!(Vector6, x, y, z, w, a, b); -mean_impl!(Vector6); -vec_display_impl!(Vector6); + +basis_impl!(Vector6, 6); diff --git a/src/structs/vector_macros.rs b/src/structs/vector_macros.rs index 6f52b342..e2343261 100644 --- a/src/structs/vector_macros.rs +++ b/src/structs/vector_macros.rs @@ -1,21 +1,139 @@ #![macro_use] -macro_rules! new_impl( - ($t: ident, $($compN: ident),+) => ( - impl $t { - /// Creates a new vector. +macro_rules! vectorlike_impl( + ($t: ident, $dimension: expr, $($compN: ident),+) => ( + componentwise_neg!($t, $($compN),+); + componentwise_repeat!($t, $($compN),+); + componentwise_arbitrary!($t, $($compN),+); + componentwise_rand!($t, $($compN),+); + pointwise_scalar_add!($t, $($compN),+); + pointwise_scalar_sub!($t, $($compN),+); + pointwise_scalar_mul!($t, $($compN),+); + pointwise_scalar_div!($t, $($compN),+); + component_new!($t, $($compN),+); + partial_order_impl!($t, $($compN),+); + + + /* + * + * Cast between inner scalar type. + * + */ + impl> Cast<$t> for $t { #[inline] - pub fn new($($compN: N ),+) -> $t { + fn from(v: $t) -> $t { + $t::new($(Cast::from(v.$compN)),+) + } + } + + + /* + * + * ApproxEq + * + */ + impl> ApproxEq for $t { + #[inline] + fn approx_epsilon(_: Option<$t>) -> N { + ApproxEq::approx_epsilon(None::) + } + + #[inline] + fn approx_ulps(_: Option<$t>) -> u32 { + ApproxEq::approx_ulps(None::) + } + + #[inline] + fn approx_eq(&self, other: &$t) -> bool { + $(ApproxEq::approx_eq(&self.$compN, &other.$compN))&&+ + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, eps: &N) -> bool { + $(ApproxEq::approx_eq_eps(&self.$compN, &other.$compN, eps))&&+ + } + + #[inline] + fn approx_eq_ulps(&self, other: &$t, ulps: u32) -> bool { + $(ApproxEq::approx_eq_ulps(&self.$compN, &other.$compN, ulps))&&+ + } + } + + + /* + * + * Unsafe indexing. + * + */ + impl $t { + /// Unsafe read access to a vector element by index. + #[inline] + pub unsafe fn at_fast(&self, i: usize) -> N { + (*self.as_ref().get_unchecked(i)) + } + + /// Unsafe write access to a vector element by index. + #[inline] + pub unsafe fn set_fast(&mut self, i: usize, val: N) { + (*self.as_mut().get_unchecked_mut(i)) = val + } + } + + + /* + * + * Axpy + * + */ + impl> Axpy for $t { + #[inline] + fn axpy(&mut self, a: &N, x: &$t) { + $( self.$compN.axpy(a, &x.$compN); )+ + } + } + + + /* + * + * Bounded + * + */ + impl Bounded for $t { + #[inline] + fn max_value() -> $t { $t { - $($compN: $compN ),+ + $($compN: Bounded::max_value() ),+ + } + } + + #[inline] + fn min_value() -> $t { + $t { + $($compN: Bounded::min_value() ),+ } } } - ); -); -macro_rules! conversion_impl( - ($t: ident, $dimension: expr) => ( + + /* + * + * Container + * + */ + impl $t { + /// The dimension of this entity. + #[inline] + pub fn len(&self) -> usize { + Dimension::dimension(None::<$t>) + } + } + + + /* + * + * Conversions from/to slices + * + */ impl AsRef<[N; $dimension]> for $t { #[inline] fn as_ref(&self) -> &[N; $dimension] { @@ -59,42 +177,507 @@ macro_rules! conversion_impl( vref.clone() } } - ) -); -macro_rules! at_fast_impl( - ($t: ident, $dimension: expr) => ( - impl $t { - /// Unsafe read access to a vector element by index. + + /* + * + * Dimension + * + */ + impl Dimension for $t { #[inline] - pub unsafe fn at_fast(&self, i: usize) -> N { - (*self.as_ref().get_unchecked(i)) + fn dimension(_: Option<$t>) -> usize { + $dimension + } + } + + + /* + * + * Indexable + * + */ + impl Shape for $t { + #[inline] + fn shape(&self) -> usize { + $dimension + } + } + + impl Indexable for $t { + #[inline] + fn swap(&mut self, i1: usize, i2: usize) { + unsafe { + mem::transmute::<&mut $t, &mut [N; $dimension]>(self).swap(i1, i2) + } } - /// Unsafe write access to a vector element by index. #[inline] - pub unsafe fn set_fast(&mut self, i: usize, val: N) { - (*self.as_mut().get_unchecked_mut(i)) = val + unsafe fn unsafe_at(&self, i: usize) -> N { + (*mem::transmute::<&$t, &[N; $dimension]>(self).get_unchecked(i)) + } + + #[inline] + unsafe fn unsafe_set(&mut self, i: usize, val: N) { + (*mem::transmute::<&mut $t, &mut [N; $dimension]>(self).get_unchecked_mut(i)) = val + } + } + + + /* + * + * Index + * + */ + impl Index for $t where [N]: Index { + type Output = <[N] as Index>::Output; + + fn index(&self, i: T) -> &<[N] as Index>::Output { + &self.as_ref()[i] + } + } + + impl IndexMut for $t where [N]: IndexMut { + fn index_mut(&mut self, i: T) -> &mut <[N] as Index>::Output { + &mut self.as_mut()[i] + } + } + + + /* + * + * Iterable + * + */ + impl Iterable for $t { + #[inline] + fn iter(&self) -> Iter { + unsafe { + mem::transmute::<&$t, &[N; $dimension]>(self).iter() + } + } + } + + impl IterableMut for $t { + #[inline] + fn iter_mut(&mut self) -> IterMut { + unsafe { + mem::transmute::<&mut $t, &mut [N; $dimension]>(self).iter_mut() + } } } ) ); -// FIXME: N should be bounded by Ord instead of BaseFloat… -// However, f32/f64 does not implement Ord… -macro_rules! pord_impl( - ($t: ident, $comp0: ident, $($compN: ident),*) => ( +macro_rules! vector_impl( + ($t: ident, $tp: ident, $($compN: ident),+) => ( + pointwise_add!($t, $($compN),+); + pointwise_sub!($t, $($compN),+); + pointwise_mul!($t, $($compN),+); + pointwise_div!($t, $($compN),+); + componentwise_zero!($t, $($compN),+); + componentwise_one!($t, $($compN),+); + componentwise_absolute!($t, $($compN),+); + component_basis_element!($t, $($compN),+); + + + /* + * + * Dot product + * + */ + impl Dot for $t { + #[inline] + fn dot(&self, other: &$t) -> N { + add!($(self.$compN * other.$compN ),+) + } + } + + + /* + * + * Norm + * + */ + impl Norm for $t { + type NormType = N; + + #[inline] + fn norm_squared(&self) -> N { + Dot::dot(self, self) + } + + #[inline] + fn normalize(&self) -> $t { + let mut res : $t = *self; + let _ = res.normalize_mut(); + res + } + + #[inline] + fn normalize_mut(&mut self) -> N { + let n = ::norm(self); + *self /= n; + + n + } + + #[inline] + fn try_normalize(&self, min_norm: N) -> Option<$t> { + let n = ::norm(self); + + if n <= min_norm { + None + } + else { + Some(*self / n) + } + } + + #[inline] + fn try_normalize_mut(&mut self, min_norm: N) -> Option { + let n = ::norm(self); + + if n <= min_norm { + None + } + else { + *self /= n; + Some(n) + } + } + } + + + /* + * + * Translation + * + */ + impl + Neg> Translation<$t> for $t { + #[inline] + fn translation(&self) -> $t { + *self + } + + #[inline] + fn inverse_translation(&self) -> $t { + -*self + } + + #[inline] + fn append_translation_mut(&mut self, t: &$t) { + *self = *t + *self; + } + + #[inline] + fn append_translation(&self, t: &$t) -> $t { + *t + *self + } + + #[inline] + fn prepend_translation_mut(&mut self, t: &$t) { + *self = *self + *t; + } + + #[inline] + fn prepend_translation(&self, t: &$t) -> $t { + *self + *t + } + + #[inline] + fn set_translation(&mut self, t: $t) { + *self = t + } + } + + + + /* + * + * Translate + * + */ + impl + Sub> Translate<$tp> for $t { + fn translate(&self, other: &$tp) -> $tp { + *other + *self + } + + fn inverse_translate(&self, other: &$tp) -> $tp { + *other - *self + } + } + + + /* + * + * Rotate + * + */ + impl Rotate for $t { + fn rotate(&self, other: &O) -> O { + *other + } + + fn inverse_rotate(&self, other: &O) -> O { + *other + } + } + + impl Rotate for $tp { + fn rotate(&self, other: &O) -> O { + *other + } + + fn inverse_rotate(&self, other: &O) -> O { + *other + } + } + + + + /* + * + * Transform + * + */ + impl + Sub> Transform<$tp> for $t { + fn transform(&self, other: &$tp) -> $tp { + self.translate(other) + } + + fn inverse_transform(&self, other: &$tp) -> $tp { + self.inverse_translate(other) + } + } + + + + /* + * + * Conversion to point. + * + */ + impl $t { + /// Converts this vector to a point. + #[inline] + pub fn to_point(self) -> $tp { + $tp::new( + $(self.$compN),+ + ) + } + + /// Reinterprets this vector as a point. + #[inline] + pub fn as_point(&self) -> &$tp { + unsafe { + mem::transmute(self) + } + } + } + + + /* + * + * NumVector / FloatVector + * + */ + impl NumVector for $t + where N: BaseNum { + } + + impl FloatVector for $t + where N: BaseFloat { + } + + + + /* + * + * Mean + * + */ + impl> Mean for $t { + #[inline] + fn mean(&self) -> N { + let normalizer = ::cast(1.0f64 / self.len() as f64); + self.iter().fold(::zero(), |acc, x| acc + *x * normalizer) + } + } + + + /* + * + * Display + * + */ + impl fmt::Display for $t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "(")); + + let mut it = self.iter(); + + let precision = f.precision().unwrap_or(8); + + try!(write!(f, "{:.*}", precision, *it.next().unwrap())); + + for comp in it { + try!(write!(f, ", {:.*}", precision, *comp)); + } + + write!(f, ")") + } + } + ) +); + + +macro_rules! basis_impl( + ($t: ident, $dimension: expr) => ( + impl Basis for $t { + #[inline] + fn canonical_basis) -> bool>(mut f: F) { + for i in 0 .. $dimension { + if !f(Basis::canonical_basis_element(i).unwrap()) { return } + } + } + + #[inline] + fn orthonormal_subspace_basis) -> bool>(n: &$t, mut f: F) { + // Compute the basis of the orthogonal subspace using Gram-Schmidt + // orthogonalization algorithm. + let mut basis: Vec<$t> = Vec::new(); + + for i in 0 .. $dimension { + let mut basis_element : $t = ::zero(); + + unsafe { + basis_element.set_fast(i, ::one()); + } + + if basis.len() == $dimension - 1 { + break; + } + + let mut elt = basis_element; + + elt = elt - *n * Dot::dot(&basis_element, n); + + for v in basis.iter() { + elt = elt - *v * Dot::dot(&elt, v) + }; + + if !ApproxEq::approx_eq(&::norm_squared(&elt), &::zero()) { + let new_element = ::normalize(&elt); + + if !f(new_element) { return }; + + basis.push(new_element); + } + } + } + + #[inline] + fn canonical_basis_element(i: usize) -> Option<$t> { + if i < $dimension { + let mut basis_element : $t = ::zero(); + + unsafe { + basis_element.set_fast(i, ::one()); + } + + Some(basis_element) + } + else { + None + } + } + } + ) +); + + +macro_rules! add ( + // base case + ($x:expr) => { + $x + }; + // `$x` followed by at least one `$y,` + ($x:expr, $($y:expr),+) => { + // call min! on the tail `$y` + Add::add($x, add!($($y),+)) + } +); + + +macro_rules! from_iterator_impl( + ($t: ident, $param0: ident) => ( + impl FromIterator for $t { + #[inline] + fn from_iter>($param0: I) -> $t { + let mut $param0 = $param0.into_iter(); + $t::new($param0.next().unwrap()) + } + } + ); + ($t: ident, $param0: ident, $($paramN: ident),+) => ( + impl FromIterator for $t { + #[inline] + fn from_iter>($param0: I) -> $t { + let mut $param0 = $param0.into_iter(); + $t::new($param0.next().unwrap(), + $($paramN.next().unwrap()),+) + } + } + ) +); + +macro_rules! vec_to_homogeneous_impl( + ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( + impl ToHomogeneous<$t2> for $t { + fn to_homogeneous(&self) -> $t2 { + let mut res: $t2 = ::zero(); + + $( res.$compN = self.$compN; )+ + + res + } + } + ) +); + +macro_rules! vec_from_homogeneous_impl( + ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( + impl + One + Zero> FromHomogeneous<$t2> for $t { + fn from(v: &$t2) -> $t { + let mut res: $t = ::zero(); + + $( res.$compN = v.$compN; )+ + + res + } + } + ) +); + + +// We need to keep this on a separate macro to retrieve the first component nam. +macro_rules! partial_order_impl( + ($t: ident, $comp0: ident $(, $compN: ident)*) => ( + /* + * + * PartialOrder + * + */ impl PartialOrder for $t { #[inline] fn inf(&self, other: &$t) -> $t { - $t::new(self.$comp0.min(other.$comp0) - $(, self.$compN.min(other.$compN))*) + $t::new(self.$comp0.min(other.$comp0), $(self.$compN.min(other.$compN)),*) } #[inline] fn sup(&self, other: &$t) -> $t { - $t::new(self.$comp0.max(other.$comp0) - $(, self.$compN.max(other.$compN))*) + $t::new(self.$comp0.max(other.$comp0), $(self.$compN.max(other.$compN)),*) } #[inline] @@ -154,809 +737,3 @@ macro_rules! pord_impl( } ) ); - -macro_rules! vec_axis_impl( - ($t: ident, $($compN: ident),+) => ( - impl $t { - $( - /// Create a unit vector with its `$compN` component equal to 1.0. - #[inline] - pub fn $compN() -> $t { - let mut res: $t = ::zero(); - - res.$compN = ::one(); - - res - } - )+ - } - ) -); - -macro_rules! vec_cast_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Cast<$t> for $t { - #[inline] - fn from(v: $t) -> $t { - $t::new($(Cast::from(v.$compN)),+) - } - } - ) -); - -macro_rules! indexable_impl( - ($t: ident, $dimension: expr) => ( - impl Shape for $t { - #[inline] - fn shape(&self) -> usize { - $dimension - } - } - - impl Indexable for $t { - #[inline] - fn swap(&mut self, i1: usize, i2: usize) { - unsafe { - mem::transmute::<&mut $t, &mut [N; $dimension]>(self).swap(i1, i2) - } - } - - #[inline] - unsafe fn unsafe_at(&self, i: usize) -> N { - (*mem::transmute::<&$t, &[N; $dimension]>(self).get_unchecked(i)) - } - - #[inline] - unsafe fn unsafe_set(&mut self, i: usize, val: N) { - (*mem::transmute::<&mut $t, &mut [N; $dimension]>(self).get_unchecked_mut(i)) = val - } - } - ) -); - -macro_rules! index_impl( - ($t: ident) => ( - impl Index for $t where [N]: Index { - type Output = <[N] as Index>::Output; - - fn index(&self, i: T) -> &<[N] as Index>::Output { - &self.as_ref()[i] - } - } - - impl IndexMut for $t where [N]: IndexMut { - fn index_mut(&mut self, i: T) -> &mut <[N] as Index>::Output { - &mut self.as_mut()[i] - } - } - ) -); - -macro_rules! repeat_impl( - ($t: ident, $param: ident, $($compN: ident),+) => ( - impl Repeat for $t { - /// Creates a new vector with all its components equal to a given value. - #[inline] - fn repeat($param: N) -> $t { - $t{ - $($compN: $param ),+ - } - } - } - ) -); - -macro_rules! iterable_impl( - ($t: ident, $dimension: expr) => ( - impl Iterable for $t { - #[inline] - fn iter<'l>(&'l self) -> Iter<'l, N> { - unsafe { - mem::transmute::<&'l $t, &'l [N; $dimension]>(self).iter() - } - } - } - ) -); - -macro_rules! iterable_mut_impl( - ($t: ident, $dimension: expr) => ( - impl IterableMut for $t { - #[inline] - fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> { - unsafe { - mem::transmute::<&'l mut $t, &'l mut [N; $dimension]>(self).iter_mut() - } - } - } - ) -); - -macro_rules! dim_impl( - ($t: ident, $dimension: expr) => ( - impl Dimension for $t { - #[inline] - fn dimension(_: Option<$t>) -> usize { - $dimension - } - } - ) -); - -macro_rules! container_impl( - ($t: ident) => ( - impl $t { - /// The dimension of this entity. - #[inline] - pub fn len(&self) -> usize { - Dimension::dimension(None::<$t>) - } - } - ) -); - -macro_rules! basis_impl( - ($t: ident, $dimension: expr) => ( - impl> Basis for $t { - #[inline] - fn canonical_basis) -> bool>(mut f: F) { - for i in 0 .. $dimension { - if !f(Basis::canonical_basis_element(i).unwrap()) { return } - } - } - - #[inline] - fn orthonormal_subspace_basis) -> bool>(n: &$t, mut f: F) { - // Compute the basis of the orthogonal subspace using Gram-Schmidt - // orthogonalization algorithm. - let mut basis: Vec<$t> = Vec::new(); - - for i in 0 .. $dimension { - let mut basis_element : $t = ::zero(); - - unsafe { - basis_element.set_fast(i, ::one()); - } - - if basis.len() == $dimension - 1 { - break; - } - - let mut elt = basis_element; - - elt = elt - *n * Dot::dot(&basis_element, n); - - for v in basis.iter() { - elt = elt - *v * Dot::dot(&elt, v) - }; - - if !ApproxEq::approx_eq(&Norm::norm_squared(&elt), &::zero()) { - let new_element = Norm::normalize(&elt); - - if !f(new_element) { return }; - - basis.push(new_element); - } - } - } - - #[inline] - fn canonical_basis_element(i: usize) -> Option<$t> { - if i < $dimension { - let mut basis_element : $t = ::zero(); - - unsafe { - basis_element.set_fast(i, ::one()); - } - - Some(basis_element) - } - else { - None - } - } - } - ) -); - -macro_rules! axpy_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Axpy for $t { - #[inline] - fn axpy(&mut self, a: &N, x: &$t) { - $( self.$compN.axpy(a, &x.$compN); )+ - } - } - ) -); - -macro_rules! add_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Add<$t> for $t { - type Output = $t; - - #[inline] - fn add(self, right: $t) -> $t { - $t::new($(self.$compN + right.$compN),+) - } - } - - impl> AddAssign<$t> for $t { - #[inline] - fn add_assign(&mut self, right: $t) { - $( self.$compN += right.$compN; )+ - } - } - ) -); - -macro_rules! scalar_add_impl( - ($t: ident, $($compN: ident),+) => ( - // $t against scalar - impl> Add for $t { - type Output = $t; - - #[inline] - fn add(self, right: N) -> $t { - $t::new($(self.$compN + right),+) - } - } - - impl> AddAssign for $t { - #[inline] - fn add_assign(&mut self, right: N) { - $( self.$compN += right; )+ - } - } - - impl Add<$t> for f32 { - type Output = $t; - - #[inline] - fn add(self, right: $t) -> $t { - $t::new($(self + right.$compN),+) - } - } - - impl Add<$t> for f64 { - type Output = $t; - - #[inline] - fn add(self, right: $t) -> $t { - $t::new($(self + right.$compN),+) - } - } - ) -); - -macro_rules! sub_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Sub<$t> for $t { - type Output = $t; - - #[inline] - fn sub(self, right: $t) -> $t { - $t::new($(self.$compN - right.$compN),+) - } - } - - impl> SubAssign<$t> for $t { - #[inline] - fn sub_assign(&mut self, right: $t) { - $( self.$compN -= right.$compN; )+ - } - } - ) -); - -macro_rules! scalar_sub_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Sub for $t { - type Output = $t; - - #[inline] - fn sub(self, right: N) -> $t { - $t::new($(self.$compN - right),+) - } - } - - impl> SubAssign for $t { - #[inline] - fn sub_assign(&mut self, right: N) { - $( self.$compN -= right; )+ - } - } - - impl Sub<$t> for f32 { - type Output = $t; - - #[inline] - fn sub(self, right: $t) -> $t { - $t::new($(self - right.$compN),+) - } - } - - impl Sub<$t> for f64 { - type Output = $t; - - #[inline] - fn sub(self, right: $t) -> $t { - $t::new($(self - right.$compN),+) - } - } - ) -); - -macro_rules! mul_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Mul<$t> for $t { - type Output = $t; - #[inline] - fn mul(self, right: $t) -> $t { - $t::new($(self.$compN * right.$compN),+) - } - } - - impl> MulAssign<$t> for $t { - #[inline] - fn mul_assign(&mut self, right: $t) { - $( self.$compN *= right.$compN; )+ - } - } - ) -); - -macro_rules! scalar_mul_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Mul for $t { - type Output = $t; - - #[inline] - fn mul(self, right: N) -> $t { - $t::new($(self.$compN * right),+) - } - } - - impl> MulAssign for $t { - #[inline] - fn mul_assign(&mut self, right: N) { - $( self.$compN *= right; )+ - } - } - - impl Mul<$t> for f32 { - type Output = $t; - - #[inline] - fn mul(self, right: $t) -> $t { - $t::new($(self * right.$compN),+) - } - } - - impl Mul<$t> for f64 { - type Output = $t; - - #[inline] - fn mul(self, right: $t) -> $t { - $t::new($(self * right.$compN),+) - } - } - ) -); - -macro_rules! div_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Div<$t> for $t { - type Output = $t; - - #[inline] - fn div(self, right: $t) -> $t { - $t::new($(self.$compN / right.$compN),+) - } - } - - impl> DivAssign<$t> for $t { - #[inline] - fn div_assign(&mut self, right: $t) { - $( self.$compN /= right.$compN; )+ - } - } - ) -); - -macro_rules! scalar_div_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Div for $t { - type Output = $t; - - #[inline] - fn div(self, right: N) -> $t { - $t::new($(self.$compN / right),+) - } - } - - impl> DivAssign for $t { - #[inline] - fn div_assign(&mut self, right: N) { - $( self.$compN /= right; )+ - } - } - ) -); - -macro_rules! neg_impl( - ($t: ident, $($compN: ident),+) => ( - impl + Copy> Neg for $t { - type Output = $t; - - #[inline] - fn neg(self) -> $t { - $t::new($(-self.$compN ),+) - } - } - ) -); - -macro_rules! add ( - // base case - ($x:expr) => { - $x - }; - // `$x` followed by at least one `$y,` - ($x:expr, $($y:expr),+) => { - // call min! on the tail `$y` - Add::add($x, add!($($y),+)) - } -); - -macro_rules! dot_impl( - ($t: ident, $($compN: ident),+) => ( - impl Dot for $t { - #[inline] - fn dot(&self, other: &$t) -> N { - add!($(self.$compN * other.$compN ),+) - } - } - ) -); - -macro_rules! translation_impl( - ($t: ident) => ( - impl + Neg> Translation<$t> for $t { - #[inline] - fn translation(&self) -> $t { - *self - } - - #[inline] - fn inverse_translation(&self) -> $t { - -*self - } - - #[inline] - fn append_translation_mut(&mut self, t: &$t) { - *self = *t + *self; - } - - #[inline] - fn append_translation(&self, t: &$t) -> $t { - *t + *self - } - - #[inline] - fn prepend_translation_mut(&mut self, t: &$t) { - *self = *self + *t; - } - - #[inline] - fn prepend_translation(&self, t: &$t) -> $t { - *self + *t - } - - #[inline] - fn set_translation(&mut self, t: $t) { - *self = t - } - } - ) -); - -macro_rules! norm_impl( - ($t: ident, $($compN: ident),+) => ( - impl Norm for $t { - #[inline] - fn norm_squared(&self) -> N { - Dot::dot(self, self) - } - - #[inline] - fn normalize(&self) -> $t { - let mut res : $t = *self; - let _ = res.normalize_mut(); - res - } - - #[inline] - fn normalize_mut(&mut self) -> N { - let l = Norm::norm(self); - - $(self.$compN = self.$compN / l;)* - - l - } - } - ) -); - -macro_rules! approx_eq_impl( - ($t: ident, $($compN: ident),+) => ( - impl> ApproxEq for $t { - #[inline] - fn approx_epsilon(_: Option<$t>) -> N { - ApproxEq::approx_epsilon(None::) - } - - #[inline] - fn approx_ulps(_: Option<$t>) -> u32 { - ApproxEq::approx_ulps(None::) - } - - #[inline] - fn approx_eq(&self, other: &$t) -> bool { - $(ApproxEq::approx_eq(&self.$compN, &other.$compN))&&+ - } - - #[inline] - fn approx_eq_eps(&self, other: &$t, eps: &N) -> bool { - $(ApproxEq::approx_eq_eps(&self.$compN, &other.$compN, eps))&&+ - } - - #[inline] - fn approx_eq_ulps(&self, other: &$t, ulps: u32) -> bool { - $(ApproxEq::approx_eq_ulps(&self.$compN, &other.$compN, ulps))&&+ - } - } - ) -); - -macro_rules! zero_one_impl( - ($t: ident, $($compN: ident),+) => ( - impl One for $t - where N: Copy + One + Sub + Add { - #[inline] - fn one() -> $t { - $t { - $($compN: ::one() ),+ - } - } - } - - impl Zero for $t { - #[inline] - fn zero() -> $t { - $t { - $($compN: ::zero() ),+ - } - } - - #[inline] - fn is_zero(&self) -> bool { - $(self.$compN.is_zero() )&&+ - } - } - ) -); - -macro_rules! from_iterator_impl( - ($t: ident, $param0: ident) => ( - impl FromIterator for $t { - #[inline] - fn from_iter>($param0: I) -> $t { - let mut $param0 = $param0.into_iter(); - $t::new($param0.next().unwrap()) - } - } - ); - ($t: ident, $param0: ident, $($paramN: ident),+) => ( - impl FromIterator for $t { - #[inline] - fn from_iter>($param0: I) -> $t { - let mut $param0 = $param0.into_iter(); - $t::new($param0.next().unwrap(), - $($paramN.next().unwrap()),+) - } - } - ) -); - -macro_rules! bounded_impl( - ($t: ident, $($compN: ident),+) => ( - impl Bounded for $t { - #[inline] - fn max_value() -> $t { - $t { - $($compN: Bounded::max_value() ),+ - } - } - - #[inline] - fn min_value() -> $t { - $t { - $($compN: Bounded::min_value() ),+ - } - } - } - ) -); - -macro_rules! vec_to_homogeneous_impl( - ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( - impl ToHomogeneous<$t2> for $t { - fn to_homogeneous(&self) -> $t2 { - let mut res: $t2 = ::zero(); - - $( res.$compN = self.$compN; )+ - - res - } - } - ) -); - -macro_rules! vec_from_homogeneous_impl( - ($t: ident, $t2: ident, $extra: ident, $($compN: ident),+) => ( - impl + One + Zero> FromHomogeneous<$t2> for $t { - fn from(v: &$t2) -> $t { - let mut res: $t = ::zero(); - - $( res.$compN = v.$compN; )+ - - res - } - } - ) -); - -macro_rules! translate_impl( - ($tv: ident, $t: ident) => ( - impl + Sub> Translate<$t> for $tv { - fn translate(&self, other: &$t) -> $t { - *other + *self - } - - fn inverse_translate(&self, other: &$t) -> $t { - *other - *self - } - } - ) -); - -macro_rules! rotate_impl( - ($t: ident) => ( - impl Rotate for $t { - fn rotate(&self, other: &O) -> O { - *other - } - - fn inverse_rotate(&self, other: &O) -> O { - *other - } - } - ) -); - -macro_rules! transform_impl( - ($tv: ident, $t: ident) => ( - impl + Sub> Transform<$t> for $tv { - fn transform(&self, other: &$t) -> $t { - self.translate(other) - } - - fn inverse_transform(&self, other: &$t) -> $t { - self.inverse_translate(other) - } - } - ) -); - -macro_rules! vec_as_point_impl( - ($tv: ident, $t: ident, $($compN: ident),+) => ( - impl $tv { - /// Converts this vector to a point. - #[inline] - pub fn to_point(self) -> $t { - $t::new( - $(self.$compN),+ - ) - } - - /// Reinterprets this vector as a point. - #[inline] - pub fn as_point(&self) -> &$t { - unsafe { - mem::transmute(self) - } - } - } - ) -); - -macro_rules! num_float_vec_impl( - ($t: ident) => ( - impl NumVector for $t - where N: BaseNum { - } - - impl FloatVector for $t - where N: BaseFloat + ApproxEq { - } - ) -); - -macro_rules! absolute_vec_impl( - ($t: ident, $($compN: ident),+) => ( - impl> Absolute<$t> for $t { - #[inline] - fn abs(m: &$t) -> $t { - $t::new($(::abs(&m.$compN) ),+) - } - } - ) -); - -macro_rules! arbitrary_impl( - ($t: ident, $($compN: ident),*) => ( - #[cfg(feature="arbitrary")] - impl Arbitrary for $t { - #[inline] - fn arbitrary(g: &mut G) -> $t { - $t { $($compN: Arbitrary::arbitrary(g),)* } - } - } - ) -); - -macro_rules! rand_impl( - ($t: ident, $($compN: ident),*) => ( - impl Rand for $t { - #[inline] - fn rand(rng: &mut R) -> $t { - $t { $($compN: Rand::rand(rng), )* } - } - } - ) -); - -macro_rules! mean_impl( - ($t: ident) => ( - impl> Mean for $t { - #[inline] - fn mean(&self) -> N { - let normalizer = ::cast(1.0f64 / self.len() as f64); - self.iter().fold(::zero(), |acc, x| acc + *x * normalizer) - } - } - ) -); - -macro_rules! vec_display_impl( - ($t: ident) => ( - impl fmt::Display for $t { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "(")); - - let mut it = self.iter(); - - let precision = f.precision().unwrap_or(8); - - try!(write!(f, "{:.*}", precision, *it.next().unwrap())); - - for comp in it { - try!(write!(f, ", {:.*}", precision, *comp)); - } - - write!(f, ")") - } - } - ) -); diff --git a/src/structs/vectorn_macros.rs b/src/structs/vectorn_macros.rs index 04b2b79a..74749375 100644 --- a/src/structs/vectorn_macros.rs +++ b/src/structs/vectorn_macros.rs @@ -93,14 +93,14 @@ macro_rules! vecn_dvec_common_impl( */ impl)*> Iterable for $vecn { #[inline] - fn iter<'l>(&'l self) -> Iter<'l, N> { + fn iter(&self) -> Iter { self.as_ref().iter() } } impl)*> IterableMut for $vecn { #[inline] - fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> { + fn iter_mut(&mut self) -> IterMut { self.as_mut().iter_mut() } } @@ -253,6 +253,24 @@ macro_rules! vecn_dvec_common_impl( } } + impl<'a, N: Copy + Div + Zero $(, $param : ArrayLength)*> Div<$vecn> for &'a $vecn { + type Output = $vecn; + + #[inline] + fn div(self, right: $vecn) -> $vecn { + self.clone() / right + } + } + + impl<'a, N: Copy + Div + Zero $(, $param : ArrayLength)*> Div for &'a $vecn { + type Output = $vecn; + + #[inline] + fn div(self, right: N) -> $vecn { + self.clone() / right + } + } + impl)*> DivAssign<$vecn> for $vecn where N: Copy + DivAssign + Zero $(, $param : ArrayLength)* { #[inline] @@ -495,10 +513,12 @@ macro_rules! vecn_dvec_common_impl( * Norm. * */ - impl)*> Norm for $vecn { + impl)*> Norm for $vecn { + type NormType = N; + #[inline] fn norm_squared(&self) -> N { - Dot::dot(self, self) + ::dot(self, self) } #[inline] @@ -510,13 +530,35 @@ macro_rules! vecn_dvec_common_impl( #[inline] fn normalize_mut(&mut self) -> N { - let l = Norm::norm(self); + let n = ::norm(self); + *self /= n; - for n in self.as_mut().iter_mut() { - *n = *n / l; + n + } + + #[inline] + fn try_normalize(&self, min_norm: N) -> Option<$vecn> { + let n = ::norm(self); + + if n <= min_norm { + None } + else { + Some(self / n) + } + } - l + #[inline] + fn try_normalize_mut(&mut self, min_norm: N) -> Option { + let n = ::norm(self); + + if n <= min_norm { + None + } + else { + *self /= n; + Some(n) + } } } diff --git a/src/traits/geometry.rs b/src/traits/geometry.rs index 8c41ae33..559160c5 100644 --- a/src/traits/geometry.rs +++ b/src/traits/geometry.rs @@ -1,6 +1,7 @@ //! Traits of operations having a well-known or explicit geometric meaning. use std::ops::{Neg, Mul}; +use num::Float; use traits::structure::{BaseFloat, SquareMatrix}; /// Trait of object which represent a translation, and to wich new translation @@ -224,23 +225,41 @@ pub trait Dot { } /// Traits of objects having an euclidian norm. -pub trait Norm { +pub trait Norm: Sized { + /// The scalar type for the norm (i.e. the undelying field). + type NormType : BaseFloat; + /// Computes the norm of `self`. #[inline] - fn norm(&self) -> N { + fn norm(&self) -> Self::NormType { self.norm_squared().sqrt() } /// Computes the squared norm of `self`. /// /// This is usually faster than computing the norm itself. - fn norm_squared(&self) -> N; + fn norm_squared(&self) -> Self::NormType; /// Gets the normalized version of a copy of `v`. + /// + /// Might return an invalid result if the vector is zero or close to zero. fn normalize(&self) -> Self; /// Normalizes `self`. - fn normalize_mut(&mut self) -> N; + /// + /// The result might be invalid if the vector is zero or close to zero. + fn normalize_mut(&mut self) -> Self::NormType; + + /// Gets the normalized version of a copy of `v` or `None` if the vector has a norm smaller + /// or equal to `min_norm`. In particular, `.try_normalize(0.0)` returns `None` if the norm is + /// exactly zero. + fn try_normalize(&self, min_norm: Self::NormType) -> Option; + + /// Normalized `v` or does nothing if the vector has a norm smaller + /// or equal to `min_norm`. + /// + /// Returns the old norm or `None` if the normalization failed. + fn try_normalize_mut(&mut self, min_norm: Self::NormType) -> Option; } /** diff --git a/src/traits/mod.rs b/src/traits/mod.rs index ea31e696..ccf756bf 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -7,7 +7,7 @@ pub use traits::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogene pub use traits::structure::{FloatVector, FloatPoint, Basis, Cast, Column, Dimension, Indexable, Iterable, IterableMut, Matrix, SquareMatrix, Row, NumVector, NumPoint, PointAsVector, ColumnSlice, - RowSlice, Diagonal, DiagMut, Eye, Repeat, Shape, BaseFloat, BaseNum, + RowSlice, Diagonal, DiagonalMut, Eye, Repeat, Shape, BaseFloat, BaseNum, Bounded}; pub use traits::operations::{Absolute, ApproxEq, Axpy, Covariance, Determinant, Inverse, Mean, Outer, PartialOrder, Transpose, diff --git a/src/traits/operations.rs b/src/traits/operations.rs index 10ae7947..7059e30e 100644 --- a/src/traits/operations.rs +++ b/src/traits/operations.rs @@ -1,6 +1,7 @@ //! Low level operations on vectors and matrices. -use num::{Float, Signed}; +use std::{mem, f32, f64}; +use num::Signed; use std::ops::Mul; use std::cmp::Ordering; use traits::structure::SquareMatrix; @@ -136,16 +137,14 @@ pub trait PartialOrder { 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 { - if v_min.is_lt() { - Some(min) - } - else if v_max.is_gt() { - Some(max) - } - else { - Some(self) - } + Some(self) } } } @@ -195,8 +194,8 @@ impl ApproxEq for f32 { // IEEE754 floats are in the same order as 2s complement isizes // so this trick (subtracting the isizes) works. - let iself: i32 = unsafe { ::std::mem::transmute(*self) }; - let iother: i32 = unsafe { ::std::mem::transmute(*other) }; + let iself: i32 = unsafe { mem::transmute(*self) }; + let iother: i32 = unsafe { mem::transmute(*other) }; (iself - iother).abs() < ulps as i32 } @@ -224,8 +223,8 @@ impl ApproxEq for f64 { // Otherwise, differing signs should be not-equal, even if within ulps if self.signum() != other.signum() { return false; } - let iself: i64 = unsafe { ::std::mem::transmute(*self) }; - let iother: i64 = unsafe { ::std::mem::transmute(*other) }; + let iself: i64 = unsafe { mem::transmute(*self) }; + let iother: i64 = unsafe { mem::transmute(*other) }; (iself - iother).abs() < ulps as i64 } diff --git a/src/traits/structure.rs b/src/traits/structure.rs index cc3ddea9..02e6d165 100644 --- a/src/traits/structure.rs +++ b/src/traits/structure.rs @@ -6,7 +6,7 @@ use std::ops::{Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, Index, IndexMut, Neg}; use num::{Float, Zero, One}; -use traits::operations::{Axpy, Transpose, Inverse, Absolute}; +use traits::operations::{Axpy, Transpose, Inverse, Absolute, ApproxEq}; use traits::geometry::{Dot, Norm, Origin}; /// Basic integral numeric trait. @@ -21,7 +21,7 @@ pub trait BaseNum: Copy + Zero + One + } /// Basic floating-point number numeric trait. -pub trait BaseFloat: Float + Cast + BaseNum + Neg { +pub trait BaseFloat: Float + Cast + BaseNum + ApproxEq + Neg { /// Archimedes' constant. fn pi() -> Self; /// 2.0 * pi. @@ -176,7 +176,7 @@ pub trait Diagonal { } /// Trait to set the diagonal of square matrices. -pub trait DiagMut: Diagonal { +pub trait DiagonalMut: Diagonal { /// Sets the diagonal of this matrix. fn set_diagonal(&mut self, diagonal: &V); } @@ -211,7 +211,7 @@ pub trait Indexable: Shape + IndexMut { /// Traits of objects which can be iterated through like a vector. pub trait Iterable { /// Gets a vector-like read-only iterator. - fn iter<'l>(&'l self) -> Iter<'l, N>; + fn iter(&self) -> Iter; } /// This is a workaround of current Rust limitations. @@ -219,7 +219,7 @@ pub trait Iterable { /// Traits of mutable objects which can be iterated through like a vector. pub trait IterableMut { /// Gets a vector-like read-write iterator. - fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N>; + fn iter_mut(&mut self) -> IterMut; } /* @@ -243,7 +243,7 @@ pub trait NumVector: Add + Sub + } /// Trait of vector with components implementing the `BaseFloat` trait. -pub trait FloatVector: NumVector + Norm + Neg + Basis { +pub trait FloatVector: NumVector + Norm + Neg + Basis + ApproxEq { } /* @@ -258,7 +258,7 @@ pub trait PointAsVector { fn to_vector(self) -> Self::Vector; /// Converts a reference to this point to a reference to its associated vector. - fn as_vector<'a>(&'a self) -> &'a Self::Vector; + fn as_vector(&self) -> &Self::Vector; // NOTE: this is used in some places to overcome some limitations untill the trait reform is // done on rustc. @@ -289,7 +289,7 @@ pub trait NumPoint: /// Trait of points with components implementing the `BaseFloat` trait. pub trait FloatPoint: NumPoint + Sized - where ::Vector: Norm { + where ::Vector: Norm { /// Computes the square distance between two points. #[inline] fn distance_squared(&self, other: &Self) -> N { diff --git a/tests/quat.rs b/tests/quat.rs index 251fabfc..9912f057 100644 --- a/tests/quat.rs +++ b/tests/quat.rs @@ -1,7 +1,7 @@ extern crate nalgebra as na; extern crate rand; -use na::{Point3, Vector3, Rotation3, UnitQuaternion, Rotation}; +use na::{Point3, Quaternion, Vector3, Rotation3, UnitQuaternion, Rotation, one}; use rand::random; #[test] @@ -9,7 +9,7 @@ fn test_quaternion_as_matrix() { for _ in 0usize .. 10000 { let axis_angle: Vector3 = random(); - assert!(na::approx_eq(&UnitQuaternion::new(axis_angle).to_rotation_matrix(), &Rotation3::new(axis_angle))) + assert!(na::approx_eq(&UnitQuaternion::from_scaled_axis(axis_angle).to_rotation_matrix(), &Rotation3::new(axis_angle))) } } @@ -17,16 +17,16 @@ fn test_quaternion_as_matrix() { fn test_quaternion_mul_vec_or_point_as_matrix() { for _ in 0usize .. 10000 { let axis_angle: Vector3 = random(); - let vector: Vector3 = random(); - let point: Point3 = random(); + let vector: Vector3 = random(); + let point: Point3 = random(); - let matrix = Rotation3::new(axis_angle); - let quaternion = UnitQuaternion::new(axis_angle); + let matrix = Rotation3::new(axis_angle); + let quaternion = UnitQuaternion::from_scaled_axis(axis_angle); assert!(na::approx_eq(&(matrix * vector), &(quaternion * vector))); - assert!(na::approx_eq(&(matrix * point), &(quaternion * point))); + assert!(na::approx_eq(&(matrix * point), &(quaternion * point))); assert!(na::approx_eq(&(vector * matrix), &(vector * quaternion))); - assert!(na::approx_eq(&(point * matrix), &(point * quaternion))); + assert!(na::approx_eq(&(point * matrix), &(point * quaternion))); } } @@ -39,8 +39,8 @@ fn test_quaternion_div_quaternion() { let r1 = Rotation3::new(axis_angle1); let r2 = na::inverse(&Rotation3::new(axis_angle2)).unwrap(); - let q1 = UnitQuaternion::new(axis_angle1); - let q2 = UnitQuaternion::new(axis_angle2); + let q1 = UnitQuaternion::from_scaled_axis(axis_angle1); + let q2 = UnitQuaternion::from_scaled_axis(axis_angle2); assert!(na::approx_eq(&(q1 / q2).to_rotation_matrix(), &(r1 * r2))) } @@ -51,7 +51,7 @@ fn test_quaternion_to_axis_angle() { for _ in 0usize .. 10000 { let axis_angle: Vector3 = random(); - let q = UnitQuaternion::new(axis_angle); + let q = UnitQuaternion::from_scaled_axis(axis_angle); println!("{:?} {:?}", q.rotation(), axis_angle); assert!(na::approx_eq(&q.rotation(), &axis_angle)) @@ -63,8 +63,8 @@ fn test_quaternion_euler_angles() { for _ in 0usize .. 10000 { let angles: Vector3 = random(); - let q = UnitQuaternion::new_with_euler_angles(angles.x, angles.y, angles.z); - let m = Rotation3::new_with_euler_angles(angles.x, angles.y, angles.z); + let q = UnitQuaternion::from_euler_angles(angles.x, angles.y, angles.z); + let m = Rotation3::from_euler_angles(angles.x, angles.y, angles.z); assert!(na::approx_eq(&q.to_rotation_matrix(), &m)) } @@ -90,3 +90,32 @@ fn test_quaternion_angle_between() { assert!(na::approx_eq(&na::norm(&na::rotation(&delta)), &delta_angle)) } + +#[test] +fn test_quaternion_exp_zero_is_one() { + let q = Quaternion::new(0., 0., 0., 0.); + assert!(na::approx_eq(&q.exp(), &one())) +} + +#[test] +fn test_quaternion_neutral() { + for _ in 0 .. 10000 { + let q1: Quaternion = random(); + let qi: Quaternion = one(); + let q2 = q1 * qi; + let q3 = qi * q1; + + assert!(na::approx_eq(&q1, &q2) && na::approx_eq(&q2, &q3)) + } +} + +#[test] +fn test_quaternion_polar_decomposition() { + for _ in 0 .. 10000 { + let q1: Quaternion = random(); + let decomp = q1.polar_decomposition(); + let q2 = Quaternion::from_polar_decomposition(decomp.0, decomp.1, decomp.2); + + assert!(na::approx_eq(&q1, &q2)) + } +}