From 84212f1449b01fddf4eaf45468a594766c684dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 6 Oct 2013 16:54:09 +0200 Subject: [PATCH] Huge api change! Everything changed, hopefully for the best. * everything is accessible from the `na` module. It re-export everything and provides free functions (i-e: na::dot(a, b) instead of a.dot(b)) for most functionalities. * matrix/vector adaptors (Rotmat, Transform) are replaced by plain types: Rot{2, 3, 4} for rotation matrices and Iso{2, 3, 4} for isometries (rotation + translation). This old adaptors system was to hard to understand and to document. * each file related to data structures moved to the `structs` folder. This makes the doc a lot more readable and make people prefer the `na` module instead of individual small modules. * Because `na` exists now, the modules `structs::vec` and `structs::mat` dont re-export anything now. As a side effect, this makes the documentation more readable. --- README.md | 88 +++-- src/adaptors/rotmat.rs | 478 ------------------------- src/adaptors/transform.rs | 394 --------------------- src/bench/mat.rs | 3 +- src/bench/vec.rs | 2 +- src/lib.rs | 118 +++++-- src/na.rs | 549 +++++++++++++++++++++++++++++ src/structs/chol.rs | 27 ++ src/structs/crout.rs | 6 + src/{ => structs}/dmat.rs | 10 +- src/{ => structs}/dvec.rs | 2 +- src/structs/iso.rs | 115 ++++++ src/structs/iso_macros.rs | 319 +++++++++++++++++ src/structs/lower_triangular.rs | 153 ++++++++ src/{ => structs}/mat.rs | 21 +- src/{ => structs}/mat_macros.rs | 32 +- src/{ => structs}/metal.rs | 0 src/structs/mod.rs | 25 ++ src/structs/rot.rs | 328 +++++++++++++++++ src/structs/rot_macros.rs | 231 ++++++++++++ src/structs/spec/complex.rs | 110 ++++++ src/{ => structs}/spec/identity.rs | 6 +- src/{ => structs}/spec/mat.rs | 30 +- src/{ => structs}/spec/vec.rs | 10 +- src/{ => structs}/spec/vec0.rs | 2 +- src/{ => structs}/vec.rs | 13 +- src/{ => structs}/vec_macros.rs | 0 src/tests/mat.rs | 10 +- src/tests/vec.rs | 3 +- src/traits/geometry.rs | 270 +++++++------- src/traits/mod.rs | 15 + src/traits/operations.rs | 8 +- src/traits/structure.rs | 30 +- src/types.rs | 162 --------- 34 files changed, 2216 insertions(+), 1354 deletions(-) delete mode 100644 src/adaptors/rotmat.rs delete mode 100644 src/adaptors/transform.rs create mode 100644 src/na.rs create mode 100644 src/structs/chol.rs create mode 100644 src/structs/crout.rs rename src/{ => structs}/dmat.rs (98%) rename src/{ => structs}/dvec.rs (99%) create mode 100644 src/structs/iso.rs create mode 100644 src/structs/iso_macros.rs create mode 100644 src/structs/lower_triangular.rs rename src/{ => structs}/mat.rs (98%) rename src/{ => structs}/mat_macros.rs (94%) rename src/{ => structs}/metal.rs (100%) create mode 100644 src/structs/mod.rs create mode 100644 src/structs/rot.rs create mode 100644 src/structs/rot_macros.rs create mode 100644 src/structs/spec/complex.rs rename src/{ => structs}/spec/identity.rs (96%) rename src/{ => structs}/spec/mat.rs (93%) rename src/{ => structs}/spec/vec.rs (96%) rename src/{ => structs}/spec/vec0.rs (99%) rename src/{ => structs}/vec.rs (98%) rename src/{ => structs}/vec_macros.rs (100%) create mode 100644 src/traits/mod.rs delete mode 100644 src/types.rs diff --git a/README.md b/README.md index 1360c0b1..733fcaea 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,36 @@ -nalgebra -======== +# nalgebra -**nalgebra** is a _n_-dimensional linear algebra library written with the rust -programming language. +**nalgebra** is a linear algebra library written for Rust targeting: + +* general-purpose linear algebra (still misses a lot of features…). +* real time computer graphics. +* real time computer physics. + +## Using nalgebra +All the functionalities of **nalgebra** are grouped in one place: the `na` module. +This module re-exports everything and includes free functions for all traits methods. +Free functions are useful if you prefer doing something like: `na::dot(v1, v2)` instead of +`v1.dot(v2)`. + +* You can import the whole prelude, including free functions, using: + +```.rust +pub use nalgebra::na::*; +``` + +* If you dont want to import everything but only every trait: + +```.rust +pub use nalgebra::traits::*; +``` + +* If you dont want to import everything but only every structure: + +```.rust +pub use nalgebra::structs::*; +``` +Of course, you can still import `nalgebra::na` alone, and get anything you want using the `na` +prefix. ## Features **nalgebra** is meant to be a general-purpose linear algebra library (but is very far from that…), @@ -10,25 +38,30 @@ and keeps an optimized set of tools for computational graphics and physics. Thos * Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, ..., `Vec6`. * Square matrices with static sizes: `Mat1`, `Mat2`, ..., `Mat6 `. +* Rotation matrices: `Rot2`, `Rot3`, `Rot4`. +* Isometries: `Iso2`, `Iso3`, `Iso4`. * Dynamically sized vector: `DVec`. * Dynamically sized (square or rectangular) matrix: `DMat`. -* Geometry-specific matrix wrapper to ensure at compile-time some properties: `Rotmat`, `Transform`. -* Most well-known geometric functions. -* A few methods for data analysis: `Cov` (covariance), `Mean` (mean). -* Operator overloading using the double trait dispatch [trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/). -This allows using operators for both matrix/matrix multiplication and matrix/vector -multiplication for example. -* Almost one trait per functionality. This is very useful for generic programming. - -Since there is almost one trait per functionality, one might end up importing a lot of traits. To -lighten your `use` prelude, all trait are re-exported by the `nalgebra::vec` and `nalgebra::mat` -modules. Thus, to bring every functionalities of `nalgebra` in scope, you can do: +* A few methods for data analysis: `Cov`, `Mean`. +* Operator overloading using the double trait dispatch [trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/). For example, the following work: ```rust -use nalgebra::vec::*; -use nalgebra::mat::*; +extern mod nalgebra; +use nalgebra::na::{Vec3, Mat3}; + +fn main() { + let v: Vec3 = Zero::zero(); + let m: Mat3 = One::one(); + + let _ = m * v; // matrix-vector multiplication. + let _ = v * m; // vector-matrix multiplication. + let _ = m * m; // matrix-matrix multiplication. + let _ = v * 2.0; // vector-scalar multiplication. +} ``` +* Almost one trait per functionality: useful for generic programming. + ## Compilation You will need the last rust compiler from the master branch. If you encounter problems, make sure you have the last version before creating an issue. @@ -37,21 +70,8 @@ If you encounter problems, make sure you have the last version before creating a cd nalgebra make -There is also a light, but existing, documentation for most functionalities. Use `make doc` to -generate it on the `doc` folder. +You can build the documentation on the `doc` folder using: -## nalgebra in use -Feel free to add your project to this list if you happen to use **nalgebra**! - -* [nphysics](https://github.com/sebcrozet/nphysics): a real-time physics engine. -* [ncollide](https://github.com/sebcrozet/ncollide): a collision detection library. -* [kiss3d](https://github.com/sebcrozet/kiss3d): a minimalistic graphics engine. -* [frog](https://github.com/natal/frog): a machine learning library. - -## Design note - -**nalgebra** is mostly written with non-idiomatic rust code. This is mostly because of limitations -of the trait system not allowing (easy) multiple overloading. Those overloading problems ares -worked around by this -[hack](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/) -(section _What if I want overloading_). +```.rust +make doc +``` diff --git a/src/adaptors/rotmat.rs b/src/adaptors/rotmat.rs deleted file mode 100644 index e6be72ec..00000000 --- a/src/adaptors/rotmat.rs +++ /dev/null @@ -1,478 +0,0 @@ -use std::num::{One, Zero}; -use std::rand::{Rand, Rng}; -use std::cmp::ApproxEq; -use traits::geometry::{Cross, Rotation, Rotate, RotationMatrix, AbsoluteRotate, Transform, - ToHomogeneous, Norm}; -use traits::structure::{Dim, Row, Col, Indexable}; -use traits::operations::{Inv, Transpose, Absolute}; -use vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs}; -use mat::{Mat2, Mat3, Mat4}; - -#[path = "../metal.rs"] -mod metal; - -/// Matrix wrapper representing rotation matrix. -/// -/// It is built uppon another matrix and ensures (at the type-level) that it will always represent -/// a rotation. Rotation matrices have some properties useful for performances, like the fact that -/// the inversion is simply a transposition. -#[deriving(Eq, ToStr, Clone)] -pub struct Rotmat { - priv submat: M -} - -/// Trait of object `o` which can be multiplied by a `Rotmat` `r`: `r * o`. -pub trait RotmatMulRhs { - /// Multiplies a rotation matrix by `Self`. - fn binop(left: &Rotmat, right: &Self) -> Res; -} - -impl, Res> Mul for Rotmat { - #[inline(always)] - fn mul(&self, other: &Rhs) -> Res { - RotmatMulRhs::binop(self, other) - } -} - -impl Rotmat { - /// Gets a copy of the internal representation of the rotation. - pub fn submat(&self) -> M { - self.submat.clone() - } -} - -impl> Rotmat> { - /// Builds a 2 dimensional rotation matrix from an angle in radian. - pub fn from_angle(angle: N) -> Rotmat> { - let (sia, coa) = angle.sin_cos(); - - Rotmat { - submat: Mat2::new(coa.clone(), -sia, sia.clone(), coa) - } - } -} - -impl Rotmat> { - /// Builds a 3 dimensional rotation matrix from an axis and an angle. - /// - /// # Arguments - /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation - /// in radian. Its direction is the axis of rotation. - pub fn from_axis_angle(axisangle: Vec3) -> Rotmat> { - if axisangle.sqnorm().is_zero() { - One::one() - } - else { - let mut axis = axisangle; - let angle = axis.normalize(); - let _1: N = One::one(); - let ux = axis.x.clone(); - let uy = axis.y.clone(); - let uz = axis.z.clone(); - let sqx = ux * ux; - let sqy = uy * uy; - let sqz = uz * uz; - let (sin, cos) = angle.sin_cos(); - let one_m_cos = _1 - cos; - - Rotmat { - submat: Mat3::new( - (sqx + (_1 - 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), - (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)) - } - } - } -} - -impl Rotmat> { - /// Reorient this matrix such that its local `x` axis points to a given point. Note that the - /// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z` - /// for that. - /// - /// # Arguments - /// * at - The point to look at. It is also the direction the matrix `x` axis will be aligned - /// with - /// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear - /// with `at`. Non-colinearity is not checked. - pub fn look_at(&mut self, at: &Vec3, up: &Vec3) { - let xaxis = at.normalized(); - let zaxis = up.cross(&xaxis).normalized(); - let yaxis = zaxis.cross(&xaxis); - - self.submat = Mat3::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) - } - - /// Reorient this matrix such that its local `z` axis points to a given point. - /// - /// # Arguments - /// * at - The point to look at. It is also the direction the matrix `y` axis will be aligned - /// with - /// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear - /// with `at`. Non-colinearity is not checked. - pub fn look_at_z(&mut self, at: &Vec3, up: &Vec3) { - let zaxis = at.normalized(); - let xaxis = up.cross(&zaxis).normalized(); - let yaxis = zaxis.cross(&xaxis); - - self.submat = Mat3::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) - } -} - -impl -RotationMatrix, Vec1, Rotmat>> for Rotmat> { - #[inline] - fn to_rot_mat(&self) -> Rotmat> { - self.clone() - } -} - -impl -Rotation> for Rotmat> { - #[inline] - fn rotation(&self) -> Vec1 { - Vec1::new((-self.submat.at((0, 1))).atan2(&self.submat.at((0, 0)))) - } - - #[inline] - fn inv_rotation(&self) -> Vec1 { - -self.rotation() - } - - #[inline] - fn rotate_by(&mut self, rot: &Vec1) { - *self = self.rotated(rot) - } - - #[inline] - fn rotated(&self, rot: &Vec1) -> Rotmat> { - Rotmat::from_angle(rot.x.clone()) * *self - } - - #[inline] - fn set_rotation(&mut self, rot: Vec1) { - *self = Rotmat::from_angle(rot.x) - } -} - -impl -RotationMatrix, Vec3, Rotmat>> for Rotmat> { - #[inline] - fn to_rot_mat(&self) -> Rotmat> { - self.clone() - } -} - -impl -Rotation> for Rotmat> { - #[inline] - fn rotation(&self) -> Vec3 { - let angle = ((self.submat.m11 + self.submat.m22 + self.submat.m33 - One::one()) / NumCast::from(2.0)).acos(); - - if angle != angle { - // FIXME: handle that correctly - Zero::zero() - } - else if angle.is_zero() { - Zero::zero() - } - else { - let m32_m23 = self.submat.m32 - self.submat.m23; - let m13_m31 = self.submat.m13 - self.submat.m31; - let m21_m12 = self.submat.m21 - self.submat.m12; - - let denom = (m32_m23 * m32_m23 + m13_m31 * m13_m31 + m21_m12 * m21_m12).sqrt(); - - if denom.is_zero() { - // XXX: handle that properly - // fail!("Internal error: singularity.") - Zero::zero() - } - else { - let a_d = angle / denom; - - Vec3::new(m32_m23 * a_d, m13_m31 * a_d, m21_m12 * a_d) - } - } - } - - #[inline] - fn inv_rotation(&self) -> Vec3 { - -self.rotation() - } - - - #[inline] - fn rotate_by(&mut self, rot: &Vec3) { - *self = self.rotated(rot) - } - - #[inline] - fn rotated(&self, axisangle: &Vec3) -> Rotmat> { - Rotmat::from_axis_angle(axisangle.clone()) * *self - } - - #[inline] - fn set_rotation(&mut self, axisangle: Vec3) { - *self = Rotmat::from_axis_angle(axisangle) - } -} - -impl> Rand for Rotmat> { - #[inline] - fn rand(rng: &mut R) -> Rotmat> { - Rotmat::from_angle(rng.gen()) - } -} - -impl + Mul, V>> Rotate for Rotmat { - #[inline] - fn rotate(&self, v: &V) -> V { - self * *v - } - - #[inline] - fn inv_rotate(&self, v: &V) -> V { - v * *self - } -} - -impl + Mul, V>> Transform for Rotmat { - #[inline] - fn transform(&self, v: &V) -> V { - self.rotate(v) - } - - #[inline] - fn inv_transform(&self, v: &V) -> V { - self.inv_rotate(v) - } -} - -impl -Rand for Rotmat> { - #[inline] - fn rand(rng: &mut R) -> Rotmat> { - Rotmat::from_axis_angle(rng.gen()) - } -} - -impl Dim for Rotmat { - #[inline] - fn dim(_: Option>) -> uint { - Dim::dim(None::) - } -} - -impl One for Rotmat { - #[inline] - fn one() -> Rotmat { - Rotmat { submat: One::one() } - } -} - -impl> RotmatMulRhs> for Rotmat { - #[inline] - fn binop(left: &Rotmat, right: &Rotmat) -> Rotmat { - Rotmat { submat: left.submat * right.submat } - } -} - -/* - * Right/Left multiplication implementation for Vec3 and Vec2. - */ -impl, Vec4>, N> RotmatMulRhs> for Vec4 { - #[inline] - fn binop(left: &Rotmat, right: &Vec4) -> Vec4 { - left.submat * *right - } -} - -impl, Vec3>, N> RotmatMulRhs> for Vec3 { - #[inline] - fn binop(left: &Rotmat, right: &Vec3) -> Vec3 { - left.submat * *right - } -} - -impl, Vec2>, N> RotmatMulRhs> for Vec2 { - #[inline] - fn binop(left: &Rotmat, right: &Vec2) -> Vec2 { - left.submat * *right - } -} - -impl>> Vec4MulRhs> for Rotmat { - #[inline] - fn binop(left: &Vec4, right: &Rotmat) -> Vec4 { - *left * right.submat - } -} - -impl>> Vec3MulRhs> for Rotmat { - #[inline] - fn binop(left: &Vec3, right: &Rotmat) -> Vec3 { - *left * right.submat - } -} - -impl>> Vec2MulRhs> for Rotmat { - #[inline] - fn binop(left: &Vec2, right: &Rotmat) -> Vec2 { - *left * right.submat - } -} - -impl Inv for Rotmat { - #[inline] - fn inplace_inverse(&mut self) -> bool { - self.transpose(); - - true - } - - #[inline] - fn inverse(&self) -> Option> { - Some(self.transposed()) - } -} - -impl -Transpose for Rotmat { - #[inline] - fn transposed(&self) -> Rotmat { - Rotmat { submat: self.submat.transposed() } - } - - #[inline] - fn transpose(&mut self) { - self.submat.transpose() - } -} - -impl, R> Row for Rotmat { - #[inline] - fn num_rows(&self) -> uint { - self.submat.num_rows() - } - #[inline] - fn row(&self, i: uint) -> R { - self.submat.row(i) - } - - #[inline] - fn set_row(&mut self, i: uint, row: R) { - self.submat.set_row(i, row); - } -} - -impl, C> Col for Rotmat { - #[inline] - fn num_cols(&self) -> uint { - self.submat.num_cols() - } - - #[inline] - fn col(&self, i: uint) -> C { - self.submat.col(i) - } - - #[inline] - fn set_col(&mut self, i: uint, col: C) { - self.submat.set_col(i, col); - } -} - -// we loose the info that we are a rotation matrix -impl, M2> ToHomogeneous for Rotmat { - #[inline] - fn to_homogeneous(&self) -> M2 { - self.submat.to_homogeneous() - } -} - -impl, M: ApproxEq> ApproxEq for Rotmat { - #[inline] - fn approx_epsilon() -> N { - // ApproxEq::::approx_epsilon() - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") - } - - #[inline] - fn approx_eq(&self, other: &Rotmat) -> bool { - self.submat.approx_eq(&other.submat) - } - - #[inline] - fn approx_eq_eps(&self, other: &Rotmat, epsilon: &N) -> bool { - self.submat.approx_eq_eps(&other.submat, epsilon) - } -} - -impl, M2> Absolute for Rotmat { - #[inline] - fn absolute(&self) -> M2 { - self.submat.absolute() - } -} - -impl AbsoluteRotate> for Rotmat> { - #[inline] - fn absolute_rotate(&self, v: &Vec4) -> Vec4 { - Vec4::new( - self.submat.m11.abs() * v.x + - self.submat.m12.abs() * v.y + - self.submat.m13.abs() * v.z + - self.submat.m14.abs() * v.w, - - self.submat.m21.abs() * v.x + - self.submat.m22.abs() * v.y + - self.submat.m23.abs() * v.z + - self.submat.m24.abs() * v.w, - - self.submat.m31.abs() * v.x + - self.submat.m32.abs() * v.y + - self.submat.m33.abs() * v.z + - self.submat.m34.abs() * v.w, - - self.submat.m41.abs() * v.x + - self.submat.m42.abs() * v.y + - self.submat.m43.abs() * v.z + - self.submat.m44.abs() * v.w) - } -} - -impl AbsoluteRotate> for Rotmat> { - #[inline] - fn absolute_rotate(&self, v: &Vec3) -> Vec3 { - Vec3::new( - self.submat.m11.abs() * v.x + self.submat.m12.abs() * v.y + self.submat.m13.abs() * v.z, - self.submat.m21.abs() * v.x + self.submat.m22.abs() * v.y + self.submat.m23.abs() * v.z, - self.submat.m31.abs() * v.x + self.submat.m32.abs() * v.y + self.submat.m33.abs() * v.z) - } -} - -impl AbsoluteRotate> for Rotmat> { - #[inline] - fn absolute_rotate(&self, v: &Vec2) -> Vec2 { - // the matrix is skew-symetric, so we dont need to compute the absolute value of every - // component. - let m11 = self.submat.m11.abs(); - let m12 = self.submat.m12.abs(); - let m22 = self.submat.m22.abs(); - - Vec2::new(m11 * v.x + m12 * v.y, m12 * v.x + m22 * v.y) - } -} diff --git a/src/adaptors/transform.rs b/src/adaptors/transform.rs deleted file mode 100644 index abfac99e..00000000 --- a/src/adaptors/transform.rs +++ /dev/null @@ -1,394 +0,0 @@ -use std::num::{One, Zero}; -use std::rand::{Rand, Rng}; -use std::cmp::ApproxEq; -use traits::structure::{Dim, Mat, Col}; -use traits::operations::{Absolute, Inv, RMul}; -use traits::geometry::{Rotation, Rotate, RotationMatrix, Translation, Translate, Transformation, - ToHomogeneous, FromHomogeneous, AbsoluteRotate}; -use Ts = traits::geometry::Transform; -use adaptors::rotmat::Rotmat; -use vec::{Vec2, Vec3, Vec2MulRhs, Vec3MulRhs}; -use mat::Mat3; - -/// Matrix-Vector wrapper used to represent a matrix multiplication followed by a translation. -/// -/// Usually, a matrix in homogeneous coordinate is used to be able to apply an affine transform with -/// a translation to a vector. This is weird because it makes a `n`-dimentional transformation be -/// an `n + 1`-matrix. Using the `Transform` wrapper avoid homogeneous coordinates by having the -/// translation separate from the other transformations. This is particularity useful when the -/// underlying transform is a rotation (see `Rotmat`): this makes inversion much faster than -/// inverting the homogeneous matrix itself. -#[deriving(Eq, ToStr, Clone)] -pub struct Transform { - priv submat : M, - priv subtrans : V -} - -// FIXME: this should be Trasform -impl Transform { - /// Builds a new transform from a matrix and a vector. - #[inline] - pub fn new(trans: V, mat: M) -> Transform { - Transform { - submat: mat, - subtrans: trans - } - } -} - -/// Trait of object `o` which can be multiplied by a `Transform` `t`: `t * o`. -pub trait TransformMulRhs { - /// Multiplies a transformation matrix by `Self`. - fn binop(left: &Transform, right: &Self) -> Res; -} - -impl, Res> Mul for Transform { - #[inline(always)] - fn mul(&self, other: &Rhs) -> Res { - TransformMulRhs::binop(self, other) - } -} - -impl Transform { - /// Gets a copy of the internal matrix. - #[inline] - pub fn submat(&self) -> M { - self.submat.clone() - } - - /// Gets a copy of the internal translation. - #[inline] - pub fn subtrans(&self) -> V { - self.subtrans.clone() - } -} - -impl + RotationMatrix, M2: Mat + Rotation> -RotationMatrix for Transform { - #[inline] - fn to_rot_mat(&self) -> M2 { - self.submat.to_rot_mat() - } -} - -impl Transform, Rotmat>> { - /// Reorient and translate this transformation such that its local `x` axis points to a given - /// direction. Note that the usually known `look_at` function does the same thing but with the - /// `z` axis. See `look_at_z` for that. - /// - /// # Arguments - /// * eye - The new translation of the transformation. - /// * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be - /// aligned with. - /// * up - Vector pointing up. The only requirement of this parameter is to not be colinear - /// with `at`. Non-colinearity is not checked. - pub fn look_at(&mut self, eye: &Vec3, at: &Vec3, up: &Vec3) { - self.submat.look_at(&(*at - *eye), up); - self.subtrans = eye.clone(); - } - - /// Reorient and translate this transformation such that its local `z` axis points to a given - /// direction. - /// - /// # Arguments - /// * eye - The new translation of the transformation. - /// * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be - /// aligned with - /// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear - /// with `at`. Non-colinearity is not checked. - pub fn look_at_z(&mut self, eye: &Vec3, at: &Vec3, up: &Vec3) { - self.submat.look_at_z(&(*at - *eye), up); - self.subtrans = eye.clone(); - } -} - -impl Dim for Transform { - #[inline] - fn dim(_: Option>) -> uint { - Dim::dim(None::) - } -} - -impl One for Transform { - #[inline] - fn one() -> Transform { - Transform { - submat: One::one(), subtrans: Zero::zero() - } - } -} - -impl Zero for Transform { - #[inline] - fn zero() -> Transform { - Transform { - submat: Zero::zero(), subtrans: Zero::zero() - } - } - - #[inline] - fn is_zero(&self) -> bool { - self.submat.is_zero() && self.subtrans.is_zero() - } -} - -impl + Mul, V: Add> TransformMulRhs> for Transform { - #[inline] - fn binop(left: &Transform, right: &Transform) -> Transform { - Transform { - submat: left.submat * right.submat, - subtrans: left.subtrans + left.submat.rmul(&right.subtrans) - } - } -} - -impl, M: Mul, Vec2>> -TransformMulRhs, M, Vec2> for Vec2 { - #[inline] - fn binop(left: &Transform, M>, right: &Vec2) -> Vec2 { - left.subtrans + left.submat * *right - } -} - -impl, M: Mul, Vec3>> -TransformMulRhs, M, Vec3> for Vec3 { - #[inline] - fn binop(left: &Transform, M>, right: &Vec3) -> Vec3 { - left.subtrans + left.submat * *right - } -} - -impl, M: Vec2MulRhs>> -Vec2MulRhs> for Transform, M> { - #[inline] - fn binop(left: &Vec2, right: &Transform, M>) -> Vec2 { - (left + right.subtrans) * right.submat - } -} - -impl, M: Vec3MulRhs>> -Vec3MulRhs> for Transform, M> { - #[inline] - fn binop(left: &Vec3, right: &Transform, M>) -> Vec3 { - (left + right.subtrans) * right.submat - } -} - -impl> Translation for Transform { - #[inline] - fn translation(&self) -> V { - self.subtrans.translation() - } - - #[inline] - fn inv_translation(&self) -> V { - self.subtrans.inv_translation() - } - - #[inline] - fn translate_by(&mut self, t: &V) { - self.subtrans.translate_by(t) - } - - #[inline] - fn translated(&self, t: &V) -> Transform { - Transform::new(self.subtrans.translated(t), self.submat.clone()) - } - - #[inline] - fn set_translation(&mut self, t: V) { - self.subtrans.set_translation(t) - } -} - -impl, _0> Translate for Transform<_0, M> { - #[inline] - fn translate(&self, v: &V) -> V { - self.submat.translate(v) - } - - #[inline] - fn inv_translate(&self, v: &V) -> V { - self.submat.inv_translate(v) - } -} - -impl + RMul + One, V, AV> -Rotation for Transform { - #[inline] - fn rotation(&self) -> AV { - self.submat.rotation() - } - - #[inline] - fn inv_rotation(&self) -> AV { - self.submat.inv_rotation() - } - - - #[inline] - fn rotate_by(&mut self, rot: &AV) { - // FIXME: this does not seem opitmal - let mut delta: M = One::one(); - delta.rotate_by(rot); - self.submat.rotate_by(rot); - self.subtrans = delta.rmul(&self.subtrans); - } - - #[inline] - fn rotated(&self, rot: &AV) -> Transform { - // FIXME: this does not seem opitmal - let _1: M = One::one(); - let delta = _1.rotated(rot); - - Transform::new(delta.rmul(&self.subtrans), self.submat.rotated(rot)) - } - - #[inline] - fn set_rotation(&mut self, rot: AV) { - // FIXME: should the translation be changed too? - self.submat.set_rotation(rot) - } -} - -impl, _0> Rotate for Transform<_0, M> { - #[inline] - fn rotate(&self, v: &V) -> V { - self.submat.rotate(v) - } - - #[inline] - fn inv_rotate(&self, v: &V) -> V { - self.submat.inv_rotate(v) - } -} - -impl + Mul + Clone, V: Add + Neg + Clone> -Transformation> for Transform { - fn transformation(&self) -> Transform { - self.clone() - } - - fn inv_transformation(&self) -> Transform { - // FIXME: fail or return a Some> ? - match self.inverse() { - Some(t) => t, - None => fail!("This transformation was not inversible.") - } - } - - fn transform_by(&mut self, other: &Transform) { - *self = other * *self - } - - fn transformed(&self, t: &Transform) -> Transform { - t * *self - } - - fn set_transformation(&mut self, t: Transform) { - *self = t - } -} - -impl, V: Add + Sub> -Ts for Transform { - #[inline] - fn transform(&self, v: &V) -> V { - self.submat.transform(v) + self.subtrans - } - - #[inline] - fn inv_transform(&self, v: &V) -> V { - self.submat.inv_transform(&(v - self.subtrans)) - } -} - -impl + Clone, V: Neg + Clone> -Inv for Transform { - #[inline] - fn inplace_inverse(&mut self) -> bool { - if !self.submat.inplace_inverse() { - false - } - else { - self.subtrans = self.submat.rmul(&-self.subtrans); - true - } - } - - #[inline] - fn inverse(&self) -> Option> { - let mut res = self.clone(); - - if res.inplace_inverse() { - Some(res) - } - else { - None - } - } -} - -impl, M2: Dim + Col, V: ToHomogeneous + Clone, V2> -ToHomogeneous for Transform { - fn to_homogeneous(&self) -> M2 { - let mut res = self.submat.to_homogeneous(); - - // copy the translation - let dim = Dim::dim(None::); - - res.set_col(dim - 1, self.subtrans.to_homogeneous()); - - res - } -} - -impl + Dim, M2: FromHomogeneous, V> -FromHomogeneous for Transform { - fn from(m: &M) -> Transform { - Transform::new(m.col(Dim::dim(None::) - 1), FromHomogeneous::from(m)) - } -} - -impl, M:ApproxEq, V:ApproxEq> -ApproxEq for Transform { - #[inline] - fn approx_epsilon() -> N { - fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") - // ApproxEq::::approx_epsilon() - } - - #[inline] - fn approx_eq(&self, other: &Transform) -> bool { - self.submat.approx_eq(&other.submat) && - self.subtrans.approx_eq(&other.subtrans) - } - - #[inline] - fn approx_eq_eps(&self, other: &Transform, epsilon: &N) -> bool { - self.submat.approx_eq_eps(&other.submat, epsilon) && - self.subtrans.approx_eq_eps(&other.subtrans, epsilon) - } -} - -impl Rand for Transform { - #[inline] - fn rand(rng: &mut R) -> Transform { - Transform::new(rng.gen(), rng.gen()) - } -} - -impl, M: Absolute, V2, M2> -Absolute> for Transform { - #[inline] - fn absolute(&self) -> Transform { - Transform::new(self.subtrans.absolute(), self.submat.absolute()) - } -} - -impl> AbsoluteRotate for Transform { - #[inline] - fn absolute_rotate(&self, v: &V) -> V { - self.submat.absolute_rotate(v) - } -} diff --git a/src/bench/mat.rs b/src/bench/mat.rs index ac0b9e8c..46ba61f7 100644 --- a/src/bench/mat.rs +++ b/src/bench/mat.rs @@ -1,7 +1,6 @@ use std::rand::random; use extra::test::BenchHarness; -use mat::*; -use vec::*; +use na::*; macro_rules! bench_mul_mat( ($bh: expr, $t: ty) => { diff --git a/src/bench/vec.rs b/src/bench/vec.rs index 59fc6a8f..5692d440 100644 --- a/src/bench/vec.rs +++ b/src/bench/vec.rs @@ -1,6 +1,6 @@ use std::rand::random; use extra::test::BenchHarness; -use vec::*; +use na::*; macro_rules! bench_dot_vec( ($bh: expr, $t: ty) => { diff --git a/src/lib.rs b/src/lib.rs index 63789b18..463484a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,92 @@ /*! +# nalgebra -# A n-dimensional linear algebra library. +**nalgebra** is a linear algebra library written for Rust targeting: + +* general-purpose linear algebra (still misses a lot of features…). +* real time computer graphics. +* real time computer physics. + +## Using **nalgebra** +All the functionalities of **nalgebra** are grouped in one place: the `na` module. +This module re-exports everything and includes free functions for all traits methods. +Free functions are useful if you prefer doing something like: `na::dot(v1, v2)` instead of +`v1.dot(v2)`. + +* You can import the whole prelude, including free functions, using: + +```.rust +pub use nalgebra::na::*; +``` + +* If you dont want to import everything but only every trait: + +```.rust +pub use nalgebra::traits::*; +``` + +* If you dont want to import everything but only every structure: + +```.rust +pub use nalgebra::structs::*; +``` +Of course, you can still import `nalgebra::na` alone, and get anything you want using the `na` +prefix. + +## Features +**nalgebra** is meant to be a general-purpose linear algebra library (but is very far from that…), +and keeps an optimized set of tools for computational graphics and physics. Those features include: + +* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, ..., `Vec6`. +* Square matrices with static sizes: `Mat1`, `Mat2`, ..., `Mat6 `. +* Rotation matrices: `Rot2`, `Rot3`, `Rot4`. +* Isometries: `Iso2`, `Iso3`, `Iso4`. +* Dynamically sized vector: `DVec`. +* Dynamically sized (square or rectangular) matrix: `DMat`. +* A few methods for data analysis: `Cov`, `Mean`. +* Operator overloading using the double trait dispatch + [trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/). + For example, the following work: + +```rust +extern mod nalgebra; +use nalgebra::na::{Vec3, Mat3}; + +fn main() { + let v: Vec3 = Zero::zero(); + let m: Mat3 = One::one(); + + let _ = m * v; // matrix-vector multiplication. + let _ = v * m; // vector-matrix multiplication. + let _ = m * m; // matrix-matrix multiplication. + let _ = v * 2.0; // vector-scalar multiplication. +} +``` + +* Almost one trait per functionality: useful for generic programming. + +## Compilation +You will need the last rust compiler from the master branch. +If you encounter problems, make sure you have the last version before creating an issue. + + git clone git://github.com/sebcrozet/nalgebra.git + cd nalgebra + make + +You can build the documentation on the `doc` folder using: + +```.rust +make doc +``` + +## **nalgebra** in use +Here are some projects using **nalgebra**. +Feel free to add your project to this list if you happen to use **nalgebra**! + +* [nphysics](https://github.com/sebcrozet/nphysics): a real-time physics engine. +* [ncollide](https://github.com/sebcrozet/ncollide): a collision detection library. +* [kiss3d](https://github.com/sebcrozet/kiss3d): a minimalistic graphics engine. +* [frog](https://github.com/natal/frog): a machine learning library. */ #[link(name = "nalgebra" @@ -16,34 +102,10 @@ extern mod std; extern mod extra; -pub mod dmat; -pub mod dvec; -pub mod vec; -pub mod mat; -pub mod types; +pub mod na; +pub mod structs; +pub mod traits; -/// Wrappers around raw matrices to restrict their behaviour. -pub mod adaptors { - pub mod rotmat; - pub mod transform; -} - -/// Traits implemented by matrices and vectors. Re-exported by the `mat` or the `vec` module. -pub mod traits { - pub mod geometry; - pub mod structure; - pub mod operations; -} - -// specialization for some 1d, 2d and 3d operations -#[doc(hidden)] -mod spec { - mod identity; - mod mat; - mod vec0; - mod vec; - // mod complex; -} // mod lower_triangular; // mod chol; diff --git a/src/na.rs b/src/na.rs new file mode 100644 index 00000000..8d471f98 --- /dev/null +++ b/src/na.rs @@ -0,0 +1,549 @@ +//! **nalgebra** prelude. + +pub use traits::{ + Absolute, + AbsoluteRotate, + AlgebraicVec, + AlgebraicVecExt, + Basis, + Col, + Cov, + Cross, + CrossMatrix, + Dim, + Dot, + FromHomogeneous, + Indexable, + Inv, + Iterable, + IterableMut, + LMul, + Mat, + MatCast, + Mean, + Norm, + Outer, + RMul, + Rotate, Rotation, RotationMatrix, RotationWithTranslation, + Row, + ScalarAdd, ScalarSub, + ToHomogeneous, + Transform, Transformation, + Translate, Translation, + Transpose, + UniformSphereSample, + Vec, + VecCast, + VecExt +}; + +pub use structs::{ + DMat, DVec, + Iso2, Iso3, Iso4, + Mat1, Mat2, Mat3, Mat4, + Mat5, Mat6, + Rot2, Rot3, Rot4, + Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6 +}; + +// +// +// Geometry +// +// + +/* + * Translation + */ + +/// Gets the translation applicable by the given object. +/// +/// ```rust +/// extern mod nalgebra; +/// use nalgebra::types::{Vec3, Affmat}; +/// use nalgebra::na; +/// +/// pub main() { +/// let t = Affmat::new_translation3d(1.0, 1.0, 1.0); +/// let trans = na::translation(t); +/// +/// assert!(trans == Vec3::new(1.0, 1.0, 1.0)); +/// } +/// ``` +#[inline(always)] +pub fn translation>(m: &M) -> V { + m.translation() +} + +/// Gets the inverse translation applicable by the given object. +/// +/// ```rust +/// extern mod nalgebra; +/// use nalgebra::types::{Vec3, Affmat}; +/// use nalgebra::na; +/// +/// pub main() { +/// let t = Affmat::new_translation3d(1.0, 1.0, 1.0); +/// let itrans = na::inv_translation(t); +/// +/// assert!(itrans == Vec3::new(-1.0, -1.0, -1.0)); +/// } +/// ``` +#[inline(always)] +pub fn inv_translation>(m: &M) -> V { + m.inv_translation() +} + +/// In-place version of `translated`. +#[inline(always)] +pub fn translate_by>(m: &mut M, v: &V) { + m.translate_by(v) +} + +/// Gets a translated copy of the given object. +#[inline(always)] +pub fn translated>(m: &M, v: &V) -> M { + m.translated(v) +} + +/// Sets the translation of the given object. +#[inline(always)] +pub fn set_translation>(m: &mut M, v: V) { + m.set_translation(v) +} + +/* + * Translate + */ + +/// FIXME +#[inline(always)] +pub fn translate>(m: &M, v: &V) -> V { + m.translate(v) +} + +/// FIXME +#[inline(always)] +pub fn inv_translate>(m: &M, v: &V) -> V { + m.inv_translate(v) +} + +/* + * Rotation + */ + +/// Gets the rotation applicable by the given object. +/// +/// ```rust +/// extern mod nalgebra; +/// use nalgebra::na; +/// +/// pub main() { +/// let t = na::rotation3d(1.0, 1.0, 1.0); +/// +/// assert!(na::rotation(t) == na::vec3(1.0, 1.0, 1.0)); +/// } +/// ``` +#[inline(always)] +pub fn rotation>(m: &M) -> V { + m.rotation() +} + + +/// Gets the rotation applicable by the given object. +/// +/// ```rust +/// extern mod nalgebra; +/// use nalgebra::na; +/// +/// pub main() { +/// let t = na::rotation3d(1.0, 1.0, 1.0); +/// +/// assert!(na::inv_rotation(t) == na::vec3(-1.0, -1.0, -1.0)); +/// } +/// ``` +#[inline(always)] +pub fn inv_rotation>(m: &M) -> V { + m.inv_rotation() +} + +/// FIXME +#[inline(always)] +pub fn rotate_by>(m: &mut M, v: &V) { + m.rotate_by(v) +} + +/// FIXME +#[inline(always)] +pub fn rotated>(m: &M, v: &V) -> M { + m.rotated(v) +} + +/// FIXME +#[inline(always)] +pub fn set_rotation>(m: &mut M, v: V) { + m.set_rotation(v) +} + +/* + * Rotate + */ + +/// FIXME +#[inline(always)] +pub fn rotate>(m: &M, v: &V) -> V { + m.rotate(v) +} + +/// FIXME +#[inline(always)] +pub fn inv_rotate>(m: &M, v: &V) -> V { + m.inv_rotate(v) +} + +/* + * RotationWithTranslation + */ + +/// FIXME +#[inline(always)] +pub fn rotated_wrt_point, + AV, + M: RotationWithTranslation>( + m: &M, + amount: &AV, + center: &LV) -> M { + m.rotated_wrt_point(amount, center) +} + +/// FIXME +#[inline(always)] +pub fn rotate_wrt_point, + AV, + M: RotationWithTranslation>( + m: &mut M, + amount: &AV, + center: &LV) { + m.rotate_wrt_point(amount, center) +} + +/// FIXME +#[inline(always)] +pub fn rotated_wrt_center, + AV, + M: RotationWithTranslation>( + m: &M, + amount: &AV) -> M { + m.rotated_wrt_center(amount) +} + +/// FIXME +#[inline(always)] +pub fn rotate_wrt_center, + AV, + M: RotationWithTranslation>( + m: &mut M, + amount: &AV) { + m.rotate_wrt_center(amount) +} + +/* + * RotationMatrix + */ + +/// FIXME +#[inline(always)] +pub fn to_rot_mat + Rotation, R: RotationMatrix>(r: &R) -> M { + r.to_rot_mat() +} + +/* + * AbsoluteRotate + */ + +/// FIXME +#[inline(always)] +pub fn absolute_rotate>(m: &M, v: &V) -> V { + m.absolute_rotate(v) +} + +/* + * Transformation + */ + +/// FIXME +#[inline(always)] +pub fn transformation>(m: &M) -> V { + m.transformation() +} + +/// FIXME +#[inline(always)] +pub fn inv_transformation>(m: &M) -> V { + m.inv_transformation() +} + +/// FIXME +#[inline(always)] +pub fn transform_by>(m: &mut M, v: &V) { + m.transform_by(v) +} + +/// FIXME +#[inline(always)] +pub fn transformed>(m: &M, v: &V) -> M { + m.transformed(v) +} + +/// FIXME +#[inline(always)] +pub fn set_transformation>(m: &mut M, v: V) { + m.set_transformation(v) +} + +/* + * Transform + */ + +/// FIXME +#[inline(always)] +pub fn transform>(m: &M, v: &V) -> V { + m.transform(v) +} + +/// FIXME +#[inline(always)] +pub fn inv_transform>(m: &M, v: &V) -> V { + m.inv_transform(v) +} + +/* + * Dot + */ + +/// FIXME +#[inline(always)] +pub fn dot, N>(a: &V, b: &V) -> N { + a.dot(b) +} + +/// FIXME +#[inline(always)] +pub fn sub_dot, N>(a: &V, b: &V, c: &V) -> N { + a.sub_dot(b, c) +} + +/* + * Norm + */ + +/// FIXME +#[inline(always)] +pub fn norm, N: Algebraic>(v: &V) -> N { + v.norm() +} + +/// FIXME +#[inline(always)] +pub fn sqnorm, N: Algebraic>(v: &V) -> N { + v.sqnorm() +} + +/// FIXME +#[inline(always)] +pub fn normalized, N: Algebraic>(v: &V) -> V { + v.normalized() +} + +/// FIXME +#[inline(always)] +pub fn normalize, N: Algebraic>(v: &mut V) -> N { + v.normalize() +} + +/* + * Cross + */ + +/// FIXME +#[inline(always)] +pub fn cross, AV>(a: &LV, b: &LV) -> AV { + a.cross(b) +} + +/* + * CrossMatrix + */ + +/// FIXME +#[inline(always)] +pub fn cross_matrix, M>(v: &V) -> M { + v.cross_matrix() +} + +/* + * ToHomogeneous + */ + +/// FIXME +#[inline(always)] +pub fn to_homogeneous, Res>(m: &M) -> Res { + m.to_homogeneous() +} + +/* + * FromHomogeneous + */ + +/// FIXME +#[inline(always)] +pub fn from_homogeneous>(m: &M) -> Res { + FromHomogeneous::from(m) +} + +/* + * UniformSphereSample + */ + +/// FIXME +#[inline(always)] +pub fn sample_sphere(f: &fn(V)) { + UniformSphereSample::sample(f) +} + +// +// +// Operations +// +// + + +/* + * Absolute + */ + +/// FIXME +#[inline(always)] +pub fn absolute, Res>(m: &M) -> Res { + m.absolute() +} + +/* + * Inv + */ + +/// FIXME +#[inline(always)] +pub fn inverted(m: &M) -> Option { + m.inverted() +} + +/// FIXME +#[inline(always)] +pub fn invert(m: &mut M) -> bool { + m.invert() +} + +/* + * Transpose + */ + +/// FIXME +#[inline(always)] +pub fn transposed(m: &M) -> M { + m.transposed() +} + +/// FIXME +#[inline(always)] +pub fn transpose(m: &mut M) { + m.transpose() +} + +/* + * Outer + */ + +/// FIXME +#[inline(always)] +pub fn outer, M>(a: &V, b: &V) -> M { + a.outer(b) +} + +/* + * Cov + */ + +/// FIXME +#[inline(always)] +pub fn cov, Res>(observations: &M) -> Res { + observations.cov() +} + +/* + * Mean + */ + +/// FIXME +#[inline(always)] +pub fn mean>(observations: &M) -> N { + observations.mean() +} + +// +// +// Structure +// +// + +/* + * MatCast + */ + +/// FIXME +#[inline(always)] +pub fn cast_mat, Res>(m: M) -> Res { + MatCast::from(m) +} + +/* + * VecCast + */ + +/// FIXME +#[inline(always)] +pub fn cast_vec, Res>(v: V) -> Res { + VecCast::from(v) +} + +/* + * Basis + */ + +/// FIXME +#[inline(always)] +pub fn canonical_basis(f: &fn(V) -> bool) { + Basis::canonical_basis(f) +} + +/// FIXME +#[inline(always)] +pub fn orthonormal_subspace_basis(v: &V, f: &fn(V) -> bool) { + v.orthonormal_subspace_basis(f) +} + +/* + * Row + */ + +/* + * Col + */ + +/* + * Dim + */ + +/* + * Indexable + */ diff --git a/src/structs/chol.rs b/src/structs/chol.rs new file mode 100644 index 00000000..64f938ab --- /dev/null +++ b/src/structs/chol.rs @@ -0,0 +1,27 @@ +// use lower_triangular::LowerTriangularMat; +// +// /// Choleski factorization. +// pub trait Chol { +// /// Choleski LL* factorization for a symetric definite positive matrix. +// fn chol(self) -> LowerTriangularMat; +// } +// +// impl Chol for DMat { +// fn chol(self) -> LowerTriangularMat { +// } +// } +// +// impl Chol for LowerTriangularMat { +// fn chol(self) -> LowerTriangularMat { +// } +// } +// +// impl Chol for UpperTriangularMat { +// fn chol(self) -> LowerTriangularMat { +// } +// } +// +// impl Chol for DiagonalMat { +// fn chol(self) -> LowerTriangularMat { +// } +// } diff --git a/src/structs/crout.rs b/src/structs/crout.rs new file mode 100644 index 00000000..0c5c762b --- /dev/null +++ b/src/structs/crout.rs @@ -0,0 +1,6 @@ +use lower_triangular::LowerTriangularMat; + +pub trait Crout { + /// Crout LDL* factorization for a symetric definite indefinite matrix. + fn crout(self, &mut DiagonalMat) -> LowerTriangularMat; +} diff --git a/src/dmat.rs b/src/structs/dmat.rs similarity index 98% rename from src/dmat.rs rename to src/structs/dmat.rs index b1603626..0346b5cf 100644 --- a/src/dmat.rs +++ b/src/structs/dmat.rs @@ -1,6 +1,6 @@ //! Matrix with dimensions unknown at compile-time. -#[doc(hidden)]; // we hide doc to not have to document the $trhs double dispatch trait. +#[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait. use std::rand::Rand; use std::rand; @@ -8,7 +8,7 @@ use std::num::{One, Zero}; use std::vec; use std::cmp::ApproxEq; use std::util; -use dvec::{DVec, DVecMulRhs}; +use structs::dvec::{DVec, DVecMulRhs}; use traits::operations::{Inv, Transpose, Mean, Cov}; #[doc(hidden)] @@ -277,10 +277,10 @@ DVecMulRhs> for DMat { impl Inv for DMat { #[inline] - fn inverse(&self) -> Option> { + fn inverted(&self) -> Option> { let mut res : DMat = self.clone(); - if res.inplace_inverse() { + if res.invert() { Some(res) } else { @@ -288,7 +288,7 @@ Inv for DMat { } } - fn inplace_inverse(&mut self) -> bool { + fn invert(&mut self) -> bool { assert!(self.nrows == self.ncols); let dim = self.nrows; diff --git a/src/dvec.rs b/src/structs/dvec.rs similarity index 99% rename from src/dvec.rs rename to src/structs/dvec.rs index 565b3db9..cbccaed8 100644 --- a/src/dvec.rs +++ b/src/structs/dvec.rs @@ -1,6 +1,6 @@ //! Vector with dimensions unknown at compile-time. -#[doc(hidden)]; // we hide doc to not have to document the $trhs double dispatch trait. +#[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait. use std::num::{Zero, One, Algebraic}; use std::rand::Rand; diff --git a/src/structs/iso.rs b/src/structs/iso.rs new file mode 100644 index 00000000..81c26cf5 --- /dev/null +++ b/src/structs/iso.rs @@ -0,0 +1,115 @@ +//! Isometric transformations. + +#[allow(missing_doc)]; + +use std::num::{Zero, One}; +use std::rand::{Rand, Rng}; +use structs::mat::{Mat3, Mat4, Mat5}; +use traits::structure::{Dim, Col}; +use traits::operations::{Inv}; +use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation, + Translate, Translation, ToHomogeneous}; + +use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs}; +use structs::rot::{Rot2, Rot3, Rot4}; + +mod metal; +mod iso_macros; + +/// Two dimensional isometry. +/// +/// This is the composition of a rotation followed by a translation. +/// Isometries conserve angles and distances, hence do not allow shearing nor scaling. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +pub struct Iso2 { + /// The rotation applicable by this isometry. + rotation: Rot2, + /// The translation applicable by this isometry. + translation: Vec2 +} + +/// Three dimensional isometry. +/// +/// This is the composition of a rotation followed by a translation. +/// Isometries conserve angles and distances, hence do not allow shearing nor scaling. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +pub struct Iso3 { + /// The rotation applicable by this isometry. + rotation: Rot3, + /// The translation applicable by this isometry. + translation: Vec3 +} + +/// Four dimensional isometry. +/// +/// Isometries conserve angles and distances, hence do not allow shearing nor scaling. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +pub struct Iso4 { + /// The rotation applicable by this isometry. + rotation: Rot4, + /// The translation applicable by this isometry. + translation: Vec4 +} + +iso_impl!(Iso2, Rot2, Vec2) +double_dispatch_binop_decl_trait!(Iso2, Iso2MulRhs) +mul_redispatch_impl!(Iso2, Iso2MulRhs) +rotation_matrix_impl!(Iso2, Rot2, Vec2, Vec1) +rotation_impl!(Iso2, Rot2, Vec1) +dim_impl!(Iso2, 2) +one_impl!(Iso2) +absolute_rotate_impl!(Iso2, Vec2) +rand_impl!(Iso2) +approx_eq_impl!(Iso2) +to_homogeneous_impl!(Iso2, Mat3) +inv_impl!(Iso2) +transform_impl!(Iso2, Vec2) +transformation_impl!(Iso2) +rotate_impl!(Iso2, Vec2) +translation_impl!(Iso2, Vec2) +translate_impl!(Iso2, Vec2) +iso_mul_iso_impl!(Iso2, Iso2MulRhs) +iso_mul_vec_impl!(Iso2, Vec2, Iso2MulRhs) +vec_mul_iso_impl!(Iso2, Vec2, Vec2MulRhs) + +iso_impl!(Iso3, Rot3, Vec3) +double_dispatch_binop_decl_trait!(Iso3, Iso3MulRhs) +mul_redispatch_impl!(Iso3, Iso3MulRhs) +rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3) +rotation_impl!(Iso3, Rot3, Vec3) +dim_impl!(Iso3, 3) +one_impl!(Iso3) +absolute_rotate_impl!(Iso3, Vec3) +rand_impl!(Iso3) +approx_eq_impl!(Iso3) +to_homogeneous_impl!(Iso3, Mat4) +inv_impl!(Iso3) +transform_impl!(Iso3, Vec3) +transformation_impl!(Iso3) +rotate_impl!(Iso3, Vec3) +translation_impl!(Iso3, Vec3) +translate_impl!(Iso3, Vec3) +iso_mul_iso_impl!(Iso3, Iso3MulRhs) +iso_mul_vec_impl!(Iso3, Vec3, Iso3MulRhs) +vec_mul_iso_impl!(Iso3, Vec3, Vec3MulRhs) + +iso_impl!(Iso4, Rot4, Vec4) +double_dispatch_binop_decl_trait!(Iso4, Iso4MulRhs) +mul_redispatch_impl!(Iso4, Iso4MulRhs) +// rotation_matrix_impl!(Iso4, Rot4, Vec4, Vec4) +// rotation_impl!(Iso4, Rot4, Vec4) +dim_impl!(Iso4, 4) +one_impl!(Iso4) +// absolute_rotate_impl!(Iso4, Vec4) +// rand_impl!(Iso4) +approx_eq_impl!(Iso4) +to_homogeneous_impl!(Iso4, Mat5) +inv_impl!(Iso4) +transform_impl!(Iso4, Vec4) +transformation_impl!(Iso4) +// rotate_impl!(Iso4, Vec4) +translation_impl!(Iso4, Vec4) +translate_impl!(Iso4, Vec4) +iso_mul_iso_impl!(Iso4, Iso4MulRhs) +iso_mul_vec_impl!(Iso4, Vec4, Iso4MulRhs) +vec_mul_iso_impl!(Iso4, Vec4, Vec4MulRhs) diff --git a/src/structs/iso_macros.rs b/src/structs/iso_macros.rs new file mode 100644 index 00000000..b8bf31cf --- /dev/null +++ b/src/structs/iso_macros.rs @@ -0,0 +1,319 @@ +#[macro_escape]; + +macro_rules! iso_impl( + ($t: ident, $submat: ident, $subvec: ident) => ( + impl $t { + /// Creates a new isometry from a rotation matrix and a vector. + #[inline] + pub fn new(translation: $subvec, rotation: $submat) -> $t { + $t { + rotation: rotation, + translation: translation + } + } + } + ) +) + +macro_rules! rotation_matrix_impl( + ($t: ident, $trot: ident, $tlv: ident, $tav: ident) => ( + impl + RotationMatrix<$tlv, $tav, $trot> for $t { + #[inline] + fn to_rot_mat(&self) -> $trot { + self.rotation.clone() + } + } + ) +) + + +macro_rules! dim_impl( + ($t: ident, $dim: expr) => ( + impl Dim for $t { + #[inline] + fn dim(_: Option<$t>) -> uint { + $dim + } + } + ) +) + +macro_rules! one_impl( + ($t: ident) => ( + impl One for $t { + #[inline] + fn one() -> $t { + $t::new(Zero::zero(), One::one()) + } + } + ) +) + +macro_rules! iso_mul_iso_impl( + ($t: ident, $tmul: ident) => ( + impl $tmul> for $t { + #[inline] + fn binop(left: &$t, right: &$t) -> $t { + $t::new(left.translation + left.rotation * right.translation, left.rotation * right.rotation) + } + } + ) +) + +macro_rules! iso_mul_vec_impl( + ($t: ident, $tv: ident, $tmul: ident) => ( + impl $tmul> for $tv { + #[inline] + fn binop(left: &$t, right: &$tv) -> $tv { + left.translation + left.rotation * *right + } + } + ) +) + +macro_rules! vec_mul_iso_impl( + ($t: ident, $tv: ident, $tmul: ident) => ( + impl $tmul> for $t { + #[inline] + fn binop(left: &$tv, right: &$t) -> $tv { + (left + right.translation) * right.rotation + } + } + ) +) + +macro_rules! translation_impl( + ($t: ident, $tv: ident) => ( + impl + Add + Clone> Translation<$tv> for $t { + #[inline] + fn translation(&self) -> $tv { + self.translation.clone() + } + + #[inline] + fn inv_translation(&self) -> $tv { + -self.translation + } + + #[inline] + fn translate_by(&mut self, t: &$tv) { + self.translation = self.translation + *t + } + + #[inline] + fn translated(&self, t: &$tv) -> $t { + $t::new(self.translation + *t, self.rotation.clone()) + } + + #[inline] + fn set_translation(&mut self, t: $tv) { + self.translation = t + } + } + ) +) + +macro_rules! translate_impl( + ($t: ident, $tv: ident) => ( + impl + Sub> Translate<$tv> for $t { + #[inline] + fn translate(&self, v: &$tv) -> $tv { + v + self.translation + } + + #[inline] + fn inv_translate(&self, v: &$tv) -> $tv { + v - self.translation + } + } + ) +) + +macro_rules! rotation_impl( + ($t: ident, $trot: ident, $tav: ident) => ( + impl Rotation<$tav> for $t { + #[inline] + fn rotation(&self) -> $tav { + self.rotation.rotation() + } + + #[inline] + fn inv_rotation(&self) -> $tav { + self.rotation.inv_rotation() + } + + + #[inline] + fn rotate_by(&mut self, rot: &$tav) { + // FIXME: this does not seem opitmal + let mut delta: $trot = One::one(); + delta.rotate_by(rot); + self.rotation.rotate_by(rot); + self.translation = delta * self.translation; + } + + #[inline] + fn rotated(&self, rot: &$tav) -> $t { + // FIXME: this does not seem opitmal + let _1: $trot = One::one(); + let delta = _1.rotated(rot); + + $t::new(delta * self.translation, self.rotation.rotated(rot)) + } + + #[inline] + fn set_rotation(&mut self, rot: $tav) { + // FIXME: should the translation be changed too? + self.rotation.set_rotation(rot) + } + } + ) +) + +macro_rules! rotate_impl( + ($t: ident, $tv: ident) => ( + impl Rotate<$tv> for $t { + #[inline] + fn rotate(&self, v: &$tv) -> $tv { + self.rotation.rotate(v) + } + + #[inline] + fn inv_rotate(&self, v: &$tv) -> $tv { + self.rotation.inv_rotate(v) + } + } + ) +) + +macro_rules! transformation_impl( + ($t: ident) => ( + impl Transformation<$t> for $t { + fn transformation(&self) -> $t { + self.clone() + } + + fn inv_transformation(&self) -> $t { + // inversion will never fails + self.inverted().unwrap() + } + + fn transform_by(&mut self, other: &$t) { + *self = other * *self + } + + fn transformed(&self, t: &$t) -> $t { + t * *self + } + + fn set_transformation(&mut self, t: $t) { + *self = t + } + } + ) +) + +macro_rules! transform_impl( + ($t: ident, $tv: ident) => ( + impl Transform<$tv> for $t { + #[inline] + fn transform(&self, v: &$tv) -> $tv { + self.rotation.transform(v) + self.translation + } + + #[inline] + fn inv_transform(&self, v: &$tv) -> $tv { + self.rotation.inv_transform(&(v - self.translation)) + } + } + ) +) + +macro_rules! inv_impl( + ($t: ident) => ( + impl Inv for $t { + #[inline] + fn invert(&mut self) -> bool { + self.rotation.invert(); + self.translation = self.rotation * -self.translation; + + // always succeed + true + } + + #[inline] + fn inverted(&self) -> Option<$t> { + let mut res = self.clone(); + + res.invert(); + + // always succeed + Some(res) + } + } + ) +) + +macro_rules! to_homogeneous_impl( + ($t: ident, $th: ident) => ( + impl ToHomogeneous<$th> for $t { + fn to_homogeneous(&self) -> $th { + let mut res = self.rotation.to_homogeneous(); + + // copy the translation + let dim = Dim::dim(None::<$th>); + + res.set_col(dim - 1, self.translation.to_homogeneous()); + + res + } + } + ) +) + +macro_rules! approx_eq_impl( + ($t: ident) => ( + impl> ApproxEq for $t { + #[inline] + fn approx_epsilon() -> N { + fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") + // ApproxEq::::approx_epsilon() + } + + #[inline] + fn approx_eq(&self, other: &$t) -> bool { + self.rotation.approx_eq(&other.rotation) && + self.translation.approx_eq(&other.translation) + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { + self.rotation.approx_eq_eps(&other.rotation, epsilon) && + self.translation.approx_eq_eps(&other.translation, epsilon) + } + } + ) +) + +macro_rules! rand_impl( + ($t: ident) => ( + 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 { + #[inline] + fn absolute_rotate(&self, v: &$tv) -> $tv { + self.rotation.absolute_rotate(v) + } + } + ) +) diff --git a/src/structs/lower_triangular.rs b/src/structs/lower_triangular.rs new file mode 100644 index 00000000..4d435ae6 --- /dev/null +++ b/src/structs/lower_triangular.rs @@ -0,0 +1,153 @@ +use std::rand::Rand; +use std::rand; +use std::num::{One, Zero}; +use std::vec; + +/// A structure optimized to store lower triangular matrices. +pub struct LowerTriangularMat { + priv dim: uint, + priv mij: ~[N] +} + +/// Trait to be implemented by objects which can be left-multiplied by a lower triangular array. +pub trait LowerTriangularMatMulRhs { + /// Apply the muliplicitaion. + fn binop(left: &LowerTriangularMat, right: &Self) -> Res; +} + +impl, Res> Mul for LowerTriangularMat { + #[inline(always)] + fn mul(&self, other: &Rhs) -> Res { + LowerTriangularMatMulRhs::binop(self, other) + } +} + +impl LowerTriangularMat { + /// Creates a lower triangular matrix without initializing its arguments. + #[inline] + pub unsafe fn new_uninitialized(dim: uint) -> LowerTriangularMat { + let mut vec = vec::with_capacity(dim * (dim + 1) / 2); + vec::raw::set_len(&mut vec, dim * (dim + 1) / 2); + + LowerTriangularMat { + dim: dim, + mij: vec + } + } +} + +impl LowerTriangularMat { + /// Creates a lower triangular matrix filled with zeros. + #[inline] + pub fn new_zeros(dim: uint) -> LowerTriangularMat { + LowerTriangularMat::from_elem(dim, Zero::zero()) + } + + /// Tests if every entry of the matrix are exactly zeros. + #[inline] + pub fn is_zero(&self) -> bool { + self.mij.iter().all(|e| e.is_zero()) + } +} + +impl LowerTriangularMat { + /// Creates a lower triangular matrix filled with random elements. + #[inline] + pub fn new_random(dim: uint) -> LowerTriangularMat { + LowerTriangularMat::from_fn(dim, |_, _| rand::random()) + } +} + +impl LowerTriangularMat { + /// Creates a lower triangular matrix filled with ones. + #[inline] + pub fn new_ones(dim: uint) -> LowerTriangularMat { + LowerTriangularMat::from_elem(dim, One::one()) + } +} + +impl LowerTriangularMat { + /// Creates a lower triangular matrix filled with a given value. + #[inline] + pub fn from_elem(dim: uint, val: N) -> LowerTriangularMat { + LowerTriangularMat { + dim: dim, + mij: vec::from_elem(dim * (dim + 1) / 2, val) + } + } +} + +impl LowerTriangularMat { + /// Creates a lower triangular matrix filled by a function. + #[inline(always)] + pub fn from_fn(dim: uint, f: &fn(uint, uint) -> N) -> LowerTriangularMat { + let mij = do vec::from_fn(dim * (dim + 1) / 2) |i| { + let l = (((1.0f64 + 8.0f64 * i as f64).sqrt() - 1.) / 2.0f64).floor() as uint; + let c = i - l * (l + 1) / 2; + + f(l, c) + }; + + LowerTriangularMat { + dim: dim, + mij: mij + } + } + + #[inline] + fn offset(&self, i: uint, j: uint) -> uint { + i * (i + 1) / 2 + j + 1 + } + + /// Transforms this matrix into an array. This consumes the matrix and is O(1). + #[inline] + pub fn to_array(self) -> ~[N] { + self.mij + } +} + +impl LowerTriangularMat { + /// Changes the value of a component of the matrix. + /// Fails if the indices point outside of the lower-triangular part of the matrix. + /// + /// # Arguments + /// * `row` - 0-based index of the line to be changed + /// * `col` - 0-based index of the column to be changed + #[inline] + pub fn set(&mut self, row: uint, col: uint, val: N) { + assert!(row < self.dim); + assert!(col < self.dim); + assert!(col <= row); + unsafe { self.set_fast(row, col, val) } + } + + /// Just like `set` without bounds checking. + #[inline] + pub unsafe fn set_fast(&mut self, row: uint, col: uint, val: N) { + let offset = self.offset(row, col); + *self.mij.unsafe_mut_ref(offset) = val + } + + /// Reads the value of a component of the matrix. + /// Fails if the indices point outside of the lower-triangular part of the matrix. + /// + /// # Arguments + /// * `row` - 0-based index of the line to be read + /// * `col` - 0-based index of the column to be read + #[inline] + pub fn at(&self, row: uint, col: uint) -> N { + assert!(row < self.dim); + assert!(col < self.dim); + unsafe { self.at_fast(row, col) } + } + + /// Just like `at` without bounds checking. + #[inline] + pub unsafe fn at_fast(&self, row: uint, col: uint) -> N { + if col > row { + Zero::zero() + } + + vec::raw::get(self.mij, self.offset(row, col)) + } +} diff --git a/src/mat.rs b/src/structs/mat.rs similarity index 98% rename from src/mat.rs rename to src/structs/mat.rs index 9592b1f3..d7476da6 100644 --- a/src/mat.rs +++ b/src/structs/mat.rs @@ -6,17 +6,12 @@ use std::cast; use std::num::{One, Zero}; use std::cmp::ApproxEq; use std::vec::{VecIterator, VecMutIterator}; -use vec::*; +use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Vec1MulRhs, Vec4MulRhs, + Vec5MulRhs, Vec6MulRhs}; -// traits -pub use traits::structure::{Mat, Dim, Indexable, Iterable, IterableMut, MatCast, Row, Col}; -pub use traits::operations::{Absolute, ScalarSub, ScalarAdd, Inv, RMul, Transpose, Mean, Cov}; -pub use traits::geometry::{Rotation, RotationMatrix, Rotate, Transformation, Transform, - Translation, Translate, ToHomogeneous, FromHomogeneous, - RotationWithTranslation, AbsoluteRotate}; - -// structs -pub use dmat::DMat; +use traits::structure::{MatCast, Row, Col, Iterable, IterableMut, Dim, Indexable}; +use traits::operations::{Absolute, Transpose, Inv, Outer}; +use traits::geometry::{ToHomogeneous, FromHomogeneous}; mod metal; mod mat_macros; @@ -118,7 +113,6 @@ indexable_impl!(Mat1, 1) mat_mul_mat_impl!(Mat1, Mat1MulRhs, 1) mat_mul_vec_impl!(Mat1, Vec1, Mat1MulRhs, 1) vec_mul_mat_impl!(Mat1, Vec1, Vec1MulRhs, 1) -transform_impl!(Mat1, Vec1) // (specialized) inv_impl!(Mat1, 1) transpose_impl!(Mat1, 1) approx_eq_impl!(Mat1) @@ -214,7 +208,6 @@ at_fast_impl!(Mat2, 2) // (specialized) mul_impl!(Mat2, 2) // (specialized) rmul_impl!(Mat2, Vec2, 2) // (specialized) lmul_impl!(Mat2, Vec2, 2) -transform_impl!(Mat2, Vec2) // (specialized) inv_impl!(Mat2, 2) transpose_impl!(Mat2, 2) approx_eq_impl!(Mat2) @@ -324,7 +317,6 @@ at_fast_impl!(Mat3, 3) // (specialized) mul_impl!(Mat3, 3) // (specialized) rmul_impl!(Mat3, Vec3, 3) // (specialized) lmul_impl!(Mat3, Vec3, 3) -transform_impl!(Mat3, Vec3) // (specialized) inv_impl!(Mat3, 3) transpose_impl!(Mat3, 3) approx_eq_impl!(Mat3) @@ -486,7 +478,6 @@ at_fast_impl!(Mat4, 4) mat_mul_mat_impl!(Mat4, Mat4MulRhs, 4) mat_mul_vec_impl!(Mat4, Vec4, Mat4MulRhs, 4) vec_mul_mat_impl!(Mat4, Vec4, Vec4MulRhs, 4) -transform_impl!(Mat4, Vec4) inv_impl!(Mat4, 4) transpose_impl!(Mat4, 4) approx_eq_impl!(Mat4) @@ -664,7 +655,6 @@ at_fast_impl!(Mat5, 5) mat_mul_mat_impl!(Mat5, Mat5MulRhs, 5) mat_mul_vec_impl!(Mat5, Vec5, Mat5MulRhs, 5) vec_mul_mat_impl!(Mat5, Vec5, Vec5MulRhs, 5) -transform_impl!(Mat5, Vec5) inv_impl!(Mat5, 5) transpose_impl!(Mat5, 5) approx_eq_impl!(Mat5) @@ -894,7 +884,6 @@ at_fast_impl!(Mat6, 6) mat_mul_mat_impl!(Mat6, Mat6MulRhs, 6) mat_mul_vec_impl!(Mat6, Vec6, Mat6MulRhs, 6) vec_mul_mat_impl!(Mat6, Vec6, Vec6MulRhs, 6) -transform_impl!(Mat6, Vec6) inv_impl!(Mat6, 6) transpose_impl!(Mat6, 6) approx_eq_impl!(Mat6) diff --git a/src/mat_macros.rs b/src/structs/mat_macros.rs similarity index 94% rename from src/mat_macros.rs rename to src/structs/mat_macros.rs index 272bd2e2..28700a18 100644 --- a/src/mat_macros.rs +++ b/src/structs/mat_macros.rs @@ -200,7 +200,7 @@ macro_rules! row_impl( ($t: ident, $tv: ident, $dim: expr) => ( impl Row<$tv> for $t { #[inline] - fn num_rows(&self) -> uint { + fn nrows(&self) -> uint { Dim::dim(None::<$t>) } @@ -229,7 +229,7 @@ macro_rules! col_impl( ($t: ident, $tv: ident, $dim: expr) => ( impl Col<$tv> for $t { #[inline] - fn num_cols(&self) -> uint { + fn ncols(&self) -> uint { Dim::dim(None::<$t>) } @@ -326,35 +326,15 @@ macro_rules! mat_mul_vec_impl( ) ) -macro_rules! transform_impl( - ($t: ident, $v: ident) => ( - impl - Transform<$v> for $t { - #[inline] - fn transform(&self, v: &$v) -> $v { - self.rmul(v) - } - - #[inline] - fn inv_transform(&self, v: &$v) -> $v { - match self.inverse() { - Some(t) => t.transform(v), - None => fail!("Cannot use inv_transform on a non-inversible matrix.") - } - } - } - ) -) - macro_rules! inv_impl( ($t: ident, $dim: expr) => ( impl Inv for $t { #[inline] - fn inverse(&self) -> Option<$t> { + fn inverted(&self) -> Option<$t> { let mut res : $t = self.clone(); - if res.inplace_inverse() { + if res.invert() { Some(res) } else { @@ -362,7 +342,7 @@ macro_rules! inv_impl( } } - fn inplace_inverse(&mut self) -> bool { + fn invert(&mut self) -> bool { let mut res: $t = One::one(); let _0N: N = Zero::zero(); @@ -528,7 +508,7 @@ macro_rules! from_homogeneous_impl( macro_rules! outer_impl( ($t: ident, $m: ident) => ( - impl + Zero + Clone> Outer<$t, $m> for $t { + impl + Zero + Clone> Outer<$m> for $t { #[inline] fn outer(&self, other: &$t) -> $m { let mut res: $m = Zero::zero(); diff --git a/src/metal.rs b/src/structs/metal.rs similarity index 100% rename from src/metal.rs rename to src/structs/metal.rs diff --git a/src/structs/mod.rs b/src/structs/mod.rs new file mode 100644 index 00000000..b1628daa --- /dev/null +++ b/src/structs/mod.rs @@ -0,0 +1,25 @@ +//! Data structures and implementations. + +pub use self::dmat::DMat; +pub use self::dvec::DVec; +pub use self::vec::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6}; +pub use self::mat::{Mat1, Mat2, Mat3, Mat4, Mat5, Mat6}; +pub use self::rot::{Rot2, Rot3, Rot4}; +pub use self::iso::{Iso2, Iso3, Iso4}; + +pub mod dmat; +pub mod dvec; +pub mod vec; +pub mod mat; +pub mod rot; +pub mod iso; + +// specialization for some 1d, 2d and 3d operations +#[doc(hidden)] +mod spec { + mod identity; + mod mat; + mod vec0; + mod vec; + // mod complex; +} diff --git a/src/structs/rot.rs b/src/structs/rot.rs new file mode 100644 index 00000000..43244323 --- /dev/null +++ b/src/structs/rot.rs @@ -0,0 +1,328 @@ +//! Rotations matrices. + +#[allow(missing_doc)]; + +use std::num::{Zero, One}; +use std::rand::{Rand, Rng}; +use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Transform, ToHomogeneous, + Norm, Cross}; +use traits::structure::{Dim, Indexable, Row, Col}; +use traits::operations::{Absolute, Inv, Transpose}; +use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs}; +use structs::mat::{Mat2, Mat3, Mat4, Mat5}; + +mod metal; +mod rot_macros; + +/// Two dimensional rotation matrix. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +pub struct Rot2 { + priv submat: Mat2 +} + +impl> Rot2 { + /// Builds a 2 dimensional rotation matrix from an angle in radian. + pub fn from_angle(angle: N) -> Rot2 { + let (sia, coa) = angle.sin_cos(); + + Rot2 { + submat: Mat2::new(coa.clone(), -sia, sia.clone(), coa) + } + } +} + +impl +Rotation> for Rot2 { + #[inline] + fn rotation(&self) -> Vec1 { + Vec1::new((-self.submat.at((0, 1))).atan2(&self.submat.at((0, 0)))) + } + + #[inline] + fn inv_rotation(&self) -> Vec1 { + -self.rotation() + } + + #[inline] + fn rotate_by(&mut self, rot: &Vec1) { + *self = self.rotated(rot) + } + + #[inline] + fn rotated(&self, rot: &Vec1) -> Rot2 { + Rot2::from_angle(rot.x.clone()) * *self + } + + #[inline] + fn set_rotation(&mut self, rot: Vec1) { + *self = Rot2::from_angle(rot.x) + } +} + +impl> Rand for Rot2 { + #[inline] + fn rand(rng: &mut R) -> Rot2 { + Rot2::from_angle(rng.gen()) + } +} + +impl AbsoluteRotate> for Rot2 { + #[inline] + fn absolute_rotate(&self, v: &Vec2) -> Vec2 { + // the matrix is skew-symetric, so we dont need to compute the absolute value of every + // component. + let m11 = self.submat.m11.abs(); + let m12 = self.submat.m12.abs(); + let m22 = self.submat.m22.abs(); + + Vec2::new(m11 * v.x + m12 * v.y, m12 * v.x + m22 * v.y) + } +} + +/* + * 3d rotation + */ +/// Three dimensional rotation matrix. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +pub struct Rot3 { + priv submat: Mat3 +} + + +impl Rot3 { + /// Builds a 3 dimensional rotation matrix from an axis and an angle. + /// + /// # Arguments + /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation + /// in radian. Its direction is the axis of rotation. + pub fn from_axis_angle(axisangle: Vec3) -> Rot3 { + if axisangle.sqnorm().is_zero() { + One::one() + } + else { + let mut axis = axisangle; + let angle = axis.normalize(); + let _1: N = One::one(); + let ux = axis.x.clone(); + let uy = axis.y.clone(); + let uz = axis.z.clone(); + let sqx = ux * ux; + let sqy = uy * uy; + let sqz = uz * uz; + let (sin, cos) = angle.sin_cos(); + let one_m_cos = _1 - cos; + + Rot3 { + submat: Mat3::new( + (sqx + (_1 - 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), + (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)) + } + } + } +} + +impl Rot3 { + /// Reorient this matrix such that its local `x` axis points to a given point. Note that the + /// usually known `look_at` function does the same thing but with the `z` axis. See `look_at_z` + /// for that. + /// + /// # Arguments + /// * at - The point to look at. It is also the direction the matrix `x` axis will be aligned + /// with + /// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear + /// with `at`. Non-colinearity is not checked. + pub fn look_at(&mut self, at: &Vec3, up: &Vec3) { + let xaxis = at.normalized(); + let zaxis = up.cross(&xaxis).normalized(); + let yaxis = zaxis.cross(&xaxis); + + self.submat = Mat3::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) + } + + /// Reorient this matrix such that its local `z` axis points to a given point. + /// + /// # Arguments + /// * at - The point to look at. It is also the direction the matrix `y` axis will be aligned + /// with + /// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear + /// with `at`. Non-colinearity is not checked. + pub fn look_at_z(&mut self, at: &Vec3, up: &Vec3) { + let zaxis = at.normalized(); + let xaxis = up.cross(&zaxis).normalized(); + let yaxis = zaxis.cross(&xaxis); + + self.submat = Mat3::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) + } +} + +impl +Rotation> for Rot3 { + #[inline] + fn rotation(&self) -> Vec3 { + let angle = ((self.submat.m11 + self.submat.m22 + self.submat.m33 - One::one()) / NumCast::from(2.0)).acos(); + + if angle != angle { + // FIXME: handle that correctly + Zero::zero() + } + else if angle.is_zero() { + Zero::zero() + } + else { + let m32_m23 = self.submat.m32 - self.submat.m23; + let m13_m31 = self.submat.m13 - self.submat.m31; + let m21_m12 = self.submat.m21 - self.submat.m12; + + let denom = (m32_m23 * m32_m23 + m13_m31 * m13_m31 + m21_m12 * m21_m12).sqrt(); + + if denom.is_zero() { + // XXX: handle that properly + // fail!("Internal error: singularity.") + Zero::zero() + } + else { + let a_d = angle / denom; + + Vec3::new(m32_m23 * a_d, m13_m31 * a_d, m21_m12 * a_d) + } + } + } + + #[inline] + fn inv_rotation(&self) -> Vec3 { + -self.rotation() + } + + + #[inline] + fn rotate_by(&mut self, rot: &Vec3) { + *self = self.rotated(rot) + } + + #[inline] + fn rotated(&self, axisangle: &Vec3) -> Rot3 { + Rot3::from_axis_angle(axisangle.clone()) * *self + } + + #[inline] + fn set_rotation(&mut self, axisangle: Vec3) { + *self = Rot3::from_axis_angle(axisangle) + } +} + +impl +Rand for Rot3 { + #[inline] + fn rand(rng: &mut R) -> Rot3 { + Rot3::from_axis_angle(rng.gen()) + } +} + +impl AbsoluteRotate> for Rot3 { + #[inline] + fn absolute_rotate(&self, v: &Vec3) -> Vec3 { + Vec3::new( + self.submat.m11.abs() * v.x + self.submat.m12.abs() * v.y + self.submat.m13.abs() * v.z, + self.submat.m21.abs() * v.x + self.submat.m22.abs() * v.y + self.submat.m23.abs() * v.z, + self.submat.m31.abs() * v.x + self.submat.m32.abs() * v.y + self.submat.m33.abs() * v.z) + } +} + +/// Four dimensional rotation matrix. +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +pub struct Rot4 { + priv submat: Mat4 +} + +impl AbsoluteRotate> for Rot4 { + #[inline] + fn absolute_rotate(&self, v: &Vec4) -> Vec4 { + Vec4::new( + self.submat.m11.abs() * v.x + self.submat.m12.abs() * v.y + + self.submat.m13.abs() * v.z + self.submat.m14.abs() * v.w, + + self.submat.m21.abs() * v.x + self.submat.m22.abs() * v.y + + self.submat.m23.abs() * v.z + self.submat.m24.abs() * v.w, + + self.submat.m31.abs() * v.x + self.submat.m32.abs() * v.y + + self.submat.m33.abs() * v.z + self.submat.m34.abs() * v.w, + + self.submat.m41.abs() * v.x + self.submat.m42.abs() * v.y + + self.submat.m43.abs() * v.z + self.submat.m44.abs() * v.w) + } +} + + +/* + * Common implementations. + */ + +double_dispatch_binop_decl_trait!(Rot2, Rot2MulRhs) +mul_redispatch_impl!(Rot2, Rot2MulRhs) +submat_impl!(Rot2, Mat2) +rotate_impl!(Rot2, Vec2) +transform_impl!(Rot2, Vec2) +dim_impl!(Rot2, 2) +rot_mul_rot_impl!(Rot2, Rot2MulRhs) +rot_mul_vec_impl!(Rot2, Vec2, Rot2MulRhs) +vec_mul_rot_impl!(Rot2, Vec2, Vec2MulRhs) +one_impl!(Rot2) +rotation_matrix_impl!(Rot2, Vec2, Vec1) +col_impl!(Rot2, Vec2) +row_impl!(Rot2, Vec2) +absolute_impl!(Rot2, Mat2) +to_homogeneous_impl!(Rot2, Mat3) +inv_impl!(Rot2) +transpose_impl!(Rot2) +approx_eq_impl!(Rot2) + +double_dispatch_binop_decl_trait!(Rot3, Rot3MulRhs) +mul_redispatch_impl!(Rot3, Rot3MulRhs) +submat_impl!(Rot3, Mat3) +rotate_impl!(Rot3, Vec3) +transform_impl!(Rot3, Vec3) +dim_impl!(Rot3, 3) +rot_mul_rot_impl!(Rot3, Rot3MulRhs) +rot_mul_vec_impl!(Rot3, Vec3, Rot3MulRhs) +vec_mul_rot_impl!(Rot3, Vec3, Vec3MulRhs) +one_impl!(Rot3) +rotation_matrix_impl!(Rot3, Vec3, Vec3) +col_impl!(Rot3, Vec3) +row_impl!(Rot3, Vec3) +absolute_impl!(Rot3, Mat3) +to_homogeneous_impl!(Rot3, Mat4) +inv_impl!(Rot3) +transpose_impl!(Rot3) +approx_eq_impl!(Rot3) + +double_dispatch_binop_decl_trait!(Rot4, Rot4MulRhs) +mul_redispatch_impl!(Rot4, Rot4MulRhs) +submat_impl!(Rot4, Mat4) +rotate_impl!(Rot4, Vec4) +transform_impl!(Rot4, Vec4) +dim_impl!(Rot4, 4) +rot_mul_rot_impl!(Rot4, Rot4MulRhs) +rot_mul_vec_impl!(Rot4, Vec4, Rot4MulRhs) +vec_mul_rot_impl!(Rot4, Vec4, Vec4MulRhs) +one_impl!(Rot4) +// rotation_matrix_impl!(Rot4, Vec4, Vec4) +col_impl!(Rot4, Vec4) +row_impl!(Rot4, Vec4) +absolute_impl!(Rot4, Mat4) +to_homogeneous_impl!(Rot4, Mat5) +inv_impl!(Rot4) +transpose_impl!(Rot4) +approx_eq_impl!(Rot4) diff --git a/src/structs/rot_macros.rs b/src/structs/rot_macros.rs new file mode 100644 index 00000000..23326c52 --- /dev/null +++ b/src/structs/rot_macros.rs @@ -0,0 +1,231 @@ +#[macro_escape]; + +macro_rules! submat_impl( + ($t: ident, $submat: ident) => ( + impl $t { + #[inline] + pub fn submat<'r>(&'r self) -> &'r $submat { + &'r self.submat + } + } + ) +) + +macro_rules! rotate_impl( + ($t: ident, $tv: ident) => ( + impl Rotate<$tv> for $t { + #[inline] + fn rotate(&self, v: &$tv) -> $tv { + self * *v + } + + #[inline] + fn inv_rotate(&self, v: &$tv) -> $tv { + v * *self + } + } + ) +) + +macro_rules! transform_impl( + ($t: ident, $tv: ident) => ( + impl Transform<$tv> for $t { + #[inline] + fn transform(&self, v: &$tv) -> $tv { + self.rotate(v) + } + + #[inline] + fn inv_transform(&self, v: &$tv) -> $tv { + self.inv_rotate(v) + } + } + ) +) + +macro_rules! dim_impl( + ($t: ident, $dim: expr) => ( + impl Dim for $t { + #[inline] + fn dim(_: Option<$t>) -> uint { + $dim + } + } + ) +) + +macro_rules! rotation_matrix_impl( + ($t: ident, $tlv: ident, $tav: ident) => ( + impl + RotationMatrix<$tlv, $tav, $t> for $t { + #[inline] + fn to_rot_mat(&self) -> $t { + self.clone() + } + } + ) +) + +macro_rules! one_impl( + ($t: ident) => ( + impl One for $t { + #[inline] + fn one() -> $t { + $t { submat: One::one() } + } + } + ) +) + +macro_rules! rot_mul_rot_impl( + ($t: ident, $mulrhs: ident) => ( + impl $mulrhs> for $t { + #[inline] + fn binop(left: &$t, right: &$t) -> $t { + $t { submat: left.submat * right.submat } + } + } + ) +) + +macro_rules! rot_mul_vec_impl( + ($t: ident, $tv: ident, $mulrhs: ident) => ( + impl $mulrhs> for $tv { + #[inline] + fn binop(left: &$t, right: &$tv) -> $tv { + left.submat * *right + } + } + ) +) + +macro_rules! vec_mul_rot_impl( + ($t: ident, $tv: ident, $mulrhs: ident) => ( + impl $mulrhs> for $t { + #[inline] + fn binop(left: &$tv, right: &$t) -> $tv { + *left * right.submat + } + } + ) +) + +macro_rules! inv_impl( + ($t: ident) => ( + impl Inv for $t { + #[inline] + fn invert(&mut self) -> bool { + self.transpose(); + + // always succeed + true + } + + #[inline] + fn inverted(&self) -> Option<$t> { + // always succeed + Some(self.transposed()) + } + } + ) +) + +macro_rules! transpose_impl( + ($t: ident) => ( + impl Transpose for $t { + #[inline] + fn transposed(&self) -> $t { + $t { submat: self.submat.transposed() } + } + + #[inline] + fn transpose(&mut self) { + self.submat.transpose() + } + } + ) +) + +macro_rules! row_impl( + ($t: ident, $tv: ident) => ( + impl Row<$tv> for $t { + #[inline] + fn nrows(&self) -> uint { + self.submat.nrows() + } + #[inline] + fn row(&self, i: uint) -> $tv { + self.submat.row(i) + } + + #[inline] + fn set_row(&mut self, i: uint, row: $tv) { + self.submat.set_row(i, row); + } + } + ) +) + +macro_rules! col_impl( + ($t: ident, $tv: ident) => ( + impl Col<$tv> for $t { + #[inline] + fn ncols(&self) -> uint { + self.submat.ncols() + } + #[inline] + fn col(&self, i: uint) -> $tv { + self.submat.col(i) + } + + #[inline] + fn set_col(&mut self, i: uint, col: $tv) { + self.submat.set_col(i, col); + } + } + ) +) + +macro_rules! to_homogeneous_impl( + ($t: ident, $tm: ident) => ( + impl ToHomogeneous<$tm> for $t { + #[inline] + fn to_homogeneous(&self) -> $tm { + self.submat.to_homogeneous() + } + } + ) +) + +macro_rules! approx_eq_impl( + ($t: ident) => ( + impl> ApproxEq for $t { + #[inline] + fn approx_epsilon() -> N { + // ApproxEq::::approx_epsilon() + fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.") + } + + #[inline] + fn approx_eq(&self, other: &$t) -> bool { + self.submat.approx_eq(&other.submat) + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { + self.submat.approx_eq_eps(&other.submat, epsilon) + } + } + ) +) + +macro_rules! absolute_impl( + ($t: ident, $tm: ident) => ( + impl Absolute<$tm> for $t { + #[inline] + fn absolute(&self) -> $tm { + self.submat.absolute() + } + } + ) +) diff --git a/src/structs/spec/complex.rs b/src/structs/spec/complex.rs new file mode 100644 index 00000000..ec043e14 --- /dev/null +++ b/src/structs/spec/complex.rs @@ -0,0 +1,110 @@ +/// Implement nalgebra traits for complex numbers from `extra::complex::Cmplex`. + +use std::num::Zero; +use extra::complex::Cmplx; +use traits::operations::{Absolute, Inv}; +use traits::structure::{Dim}; + +impl Absolute> for Cmplx { + #[inline] + fn absolute(&self) -> Cmplx { + Cmplx::new(self.re.clone(), self.im.clone()) + } +} + +impl Inv for Cmplx { + #[inline] + fn inverse(&self) -> Option> { + if self.is_zero() { + None + } + else { + let _1: N = NumCast::from(1.0); + let divisor = _1 / (self.re * self.re - self.im * self.im); + + Some(Cmplx::new(self.re * divisor, -self.im * divisor)) + } + } + + #[inline] + fn inplace_inverse(&mut self) -> bool { + if self.is_zero() { + false + } + else { + let _1: N = NumCast::from(1.0); + let divisor = _1 / (self.re * self.re - self.im * self.im); + + self.re = self.re * divisor; + self.im = -self.im * divisor; + + true + } + } +} + +impl Dim for Cmplx { + #[inline] + fn dim(unsused_self: Option>) -> uint { + 2 + } +} + +impl Rotation> for Cmplx { + #[inline] + fn rotation(&self) -> Vec2 { + } + + #[inline] + fn inv_rotation(&self) -> Vec2 { + -self.rotation(); + } + + #[inline] + fn rotate_by(&mut self, rotation: &Vec2) { + } + + #[inline] + fn rotated(&self, rotation: &Vec2) -> Cmplx { + } + + #[inline] + fn set_rotation(&mut self, rotation: Vec2) { + } +} + +impl Rotate> for Cmplx { + #[inline] + fn rotate(&self, rotation: &V) -> V { + } + + #[inline] + fn inv_rotate(&self, rotation: &V) -> V { + } +} + +impl RotationMatrix, Vec2, Rotmat>> for Cmplx { + #[inline] + fn to_rot_mat(&self) -> Rotmat> { + } +} + +impl Norm for Cmplx { + #[inline] + fn sqnorm(&self) -> N { + } + + #[inline] + fn normalized(&self) -> Self { + } + + #[inline] + fn normalize(&mut self) -> N { + } +} + +impl AbsoluteRotate { + #[inline] + fn absolute_rotate(&elf, v: &V) -> V { + } +} diff --git a/src/spec/identity.rs b/src/structs/spec/identity.rs similarity index 96% rename from src/spec/identity.rs rename to src/structs/spec/identity.rs index 92b646e1..11a05763 100644 --- a/src/spec/identity.rs +++ b/src/structs/spec/identity.rs @@ -1,5 +1,5 @@ use std::num::{One, Zero}; -use mat; +use structs::mat; use traits::operations::{Inv, Transpose}; use traits::geometry::{Translation, Translate, Rotation, Rotate, Transformation, Transform}; @@ -11,11 +11,11 @@ impl One for mat::Identity { } impl Inv for mat::Identity { - fn inverse(&self) -> Option { + fn inverted(&self) -> Option { Some(mat::Identity::new()) } - fn inplace_inverse(&mut self) -> bool { + fn invert(&mut self) -> bool { true } } diff --git a/src/spec/mat.rs b/src/structs/spec/mat.rs similarity index 93% rename from src/spec/mat.rs rename to src/structs/spec/mat.rs index 7bf2161d..4174791b 100644 --- a/src/spec/mat.rs +++ b/src/structs/spec/mat.rs @@ -1,16 +1,18 @@ use std::num::{Zero, One}; -use vec::{Vec2, Vec3, Vec2MulRhs, Vec3MulRhs}; -use mat::{Mat1, Mat2, Mat3, Inv, Row, Col, Mat3MulRhs, Mat2MulRhs}; -use mat; +use structs::vec::{Vec2, Vec3, Vec2MulRhs, Vec3MulRhs}; +use structs::mat::{Mat1, Mat2, Mat3, Mat3MulRhs, Mat2MulRhs}; +use structs::mat; +use traits::operations::{Inv}; +use traits::structure::{Row, Col}; // some specializations: impl Inv for Mat1 { #[inline] - fn inverse(&self) -> Option> { + fn inverted(&self) -> Option> { let mut res : Mat1 = self.clone(); - if res.inplace_inverse() { + if res.invert() { Some(res) } else { @@ -19,7 +21,7 @@ Inv for Mat1 { } #[inline] - fn inplace_inverse(&mut self) -> bool { + fn invert(&mut self) -> bool { if self.m11.is_zero() { false } @@ -34,10 +36,10 @@ Inv for Mat1 { impl Inv for Mat2 { #[inline] - fn inverse(&self) -> Option> { + fn inverted(&self) -> Option> { let mut res : Mat2 = self.clone(); - if res.inplace_inverse() { + if res.invert() { Some(res) } else { @@ -46,7 +48,7 @@ Inv for Mat2 { } #[inline] - fn inplace_inverse(&mut self) -> bool { + fn invert(&mut self) -> bool { let det = self.m11 * self.m22 - self.m21 * self.m12; if det.is_zero() { @@ -65,10 +67,10 @@ Inv for Mat2 { impl Inv for Mat3 { #[inline] - fn inverse(&self) -> Option> { + fn inverted(&self) -> Option> { let mut res = self.clone(); - if res.inplace_inverse() { + if res.invert() { Some(res) } else { @@ -77,7 +79,7 @@ Inv for Mat3 { } #[inline] - fn inplace_inverse(&mut self) -> bool { + fn invert(&mut self) -> bool { let minor_m12_m23 = self.m22 * self.m33 - self.m32 * self.m23; let minor_m11_m23 = self.m21 * self.m33 - self.m31 * self.m23; let minor_m11_m22 = self.m21 * self.m32 - self.m31 * self.m22; @@ -111,7 +113,7 @@ Inv for Mat3 { impl Row> for Mat3 { #[inline] - fn num_rows(&self) -> uint { + fn nrows(&self) -> uint { 3 } @@ -151,7 +153,7 @@ impl Row> for Mat3 { impl Col> for Mat3 { #[inline] - fn num_cols(&self) -> uint { + fn ncols(&self) -> uint { 3 } diff --git a/src/spec/vec.rs b/src/structs/spec/vec.rs similarity index 96% rename from src/spec/vec.rs rename to src/structs/spec/vec.rs index a8575fa5..dff4d43b 100644 --- a/src/spec/vec.rs +++ b/src/structs/spec/vec.rs @@ -1,6 +1,8 @@ use std::num::{Zero, One}; -use vec::{Vec1, Vec2, Vec3, Vec4, Norm, VecCast, UniformSphereSample, Cross, CrossMatrix, Basis}; -use mat::{Mat3, Row}; +use traits::structure::{VecCast, Row, Basis}; +use traits::geometry::{Norm, Cross, CrossMatrix, UniformSphereSample}; +use structs::vec::{Vec1, Vec2, Vec3, Vec4}; +use structs::mat::Mat3; impl + Sub> Cross> for Vec2 { #[inline] @@ -39,10 +41,10 @@ impl + Zero + Clone> CrossMatrix> for Vec3 { } } -// FIXME: iplement this for all other vectors +// FIXME: implement this for all other vectors impl Row> for Vec2 { #[inline] - fn num_rows(&self) -> uint { + fn nrows(&self) -> uint { 2 } diff --git a/src/spec/vec0.rs b/src/structs/spec/vec0.rs similarity index 99% rename from src/spec/vec0.rs rename to src/structs/spec/vec0.rs index ff2f12ed..eed3a6e4 100644 --- a/src/spec/vec0.rs +++ b/src/structs/spec/vec0.rs @@ -5,7 +5,7 @@ use std::iter::{Iterator, FromIterator}; use std::cmp::ApproxEq; use traits::structure::{Iterable, IterableMut, Indexable, Basis, Dim}; use traits::geometry::{Translation, Dot, Norm}; -use vec; +use structs::vec; impl vec::Vec0 { /// Creates a new vector. diff --git a/src/vec.rs b/src/structs/vec.rs similarity index 98% rename from src/vec.rs rename to src/structs/vec.rs index 9723063d..825da00e 100644 --- a/src/vec.rs +++ b/src/structs/vec.rs @@ -9,16 +9,9 @@ use std::vec::{VecIterator, VecMutIterator}; use std::iter::{Iterator, FromIterator}; use std::cmp::ApproxEq; -use traits::geometry::{Transform, Rotate}; - -pub use traits::geometry::{FromHomogeneous, ToHomogeneous, Dot, Norm, Cross, CrossMatrix, - Translation, Translate, UniformSphereSample}; -pub use traits::structure::{VecCast, Vec, VecExt, AlgebraicVec, AlgebraicVecExt, Basis, Dim, - Indexable, Iterable, IterableMut}; -pub use traits::operations::{Outer, ScalarAdd, ScalarSub}; - -// structs -pub use dvec::DVec; +use traits::geometry::{Transform, Rotate, FromHomogeneous, ToHomogeneous, Dot, Norm, + Translation, Translate}; +use traits::structure::{VecCast, Basis, Dim, Indexable, Iterable, IterableMut}; mod metal; mod vec_macros; diff --git a/src/vec_macros.rs b/src/structs/vec_macros.rs similarity index 100% rename from src/vec_macros.rs rename to src/structs/vec_macros.rs diff --git a/src/tests/mat.rs b/src/tests/mat.rs index 18aca05f..ad1b73f5 100644 --- a/src/tests/mat.rs +++ b/src/tests/mat.rs @@ -1,16 +1,14 @@ use std::num::{Real, One, abs}; use std::rand::random; use std::cmp::ApproxEq; -use vec::*; -use mat::*; -use adaptors::rotmat::Rotmat; +use na::*; macro_rules! test_inv_mat_impl( ($t: ty) => ( do 10000.times { let randmat : $t = random(); - assert!((randmat.inverse().unwrap() * randmat).approx_eq(&One::one())); + assert!((randmat.inverted().unwrap() * randmat).approx_eq(&One::one())); } ); ) @@ -88,7 +86,7 @@ fn test_inv_mat6() { #[test] fn test_rotation2() { do 10000.times { - let randmat: Rotmat> = One::one(); + let randmat: Rot2 = One::one(); let ang = &Vec1::new(abs::(random()) % Real::pi()); assert!(randmat.rotated(ang).rotation().approx_eq(ang)); @@ -105,7 +103,7 @@ fn test_index_mat2() { #[test] fn test_inv_rotation3() { do 10000.times { - let randmat: Rotmat> = One::one(); + let randmat: Rot3 = One::one(); let dir: Vec3 = random(); let ang = &(dir.normalized() * (abs::(random()) % Real::pi())); let rot = randmat.rotated(ang); diff --git a/src/tests/vec.rs b/src/tests/vec.rs index 19cd3fae..aa25841e 100644 --- a/src/tests/vec.rs +++ b/src/tests/vec.rs @@ -1,8 +1,7 @@ use std::num::{Zero, One}; use std::rand::{random}; use std::cmp::ApproxEq; -use vec::*; -use mat::*; +use na::*; macro_rules! test_iterator_impl( ($t: ty, $n: ty) => ( diff --git a/src/traits/geometry.rs b/src/traits/geometry.rs index d1096595..a364c2dd 100644 --- a/src/traits/geometry.rs +++ b/src/traits/geometry.rs @@ -61,141 +61,6 @@ pub trait Rotate { fn inv_rotate(&self, v: &V) -> V; } -/// Trait of object which represent a transformation, and to which new transformations can -/// be appended. -/// -/// A transformation is assumed to be an isometry without reflexion. -pub trait Transformation { - /// Gets the transformation of `self`. - fn transformation(&self) -> M; - - /// Gets the inverse transformation of `self`. - fn inv_transformation(&self) -> M; - - /// In-place version of `transformed`. - fn transform_by(&mut self, &M); - - /// Appends a transformation to `self`. - fn transformed(&self, &M) -> Self; - - /// Sets the transformation of `self`. - fn set_transformation(&mut self, M); -} - -/// Trait of objects able to transform other objects. -/// -/// This is typically implemented by matrices which transform vectors. -pub trait Transform { - /// Applies a transformation to `v`. - fn transform(&self, &V) -> V; - /// Applies an inverse transformation to `v`. - fn inv_transform(&self, &V) -> V; -} - -/// Trait of transformation having a rotation extractable as a rotation matrix. This can typically -/// be implemented by quaternions to convert them to a rotation matrix. -pub trait RotationMatrix + Rotation> : Rotation { - /// Gets the rotation matrix represented by `self`. - fn to_rot_mat(&self) -> R; -} - -/// Traits of objects having a dot product. -pub trait Dot { - /// Computes the dot (inner) product of two vectors. - #[inline] - fn dot(&self, &Self) -> N; - - /** - * Short-cut to compute the projection of a point on a vector, but without - * computing intermediate vectors. - * The following equation must be verified: - * - * ~~~{.rust} - * a.sub_dot(b, c) == (a - b).dot(c) - * ~~~ - * - */ - #[inline] - fn sub_dot(&self, b: &Self, c: &Self) -> N; -} - -/// Traits of objects having an euclidian norm. -pub trait Norm { - /// Computes the norm of `self`. - #[inline] - fn norm(&self) -> N { - self.sqnorm().sqrt() - } - - /// Computes the squared norm of `self`. - /// - /// This is usually faster than computing the norm itself. - #[inline] - fn sqnorm(&self) -> N; - - /// Gets the normalized version of `self`. - #[inline] - fn normalized(&self) -> Self; - - /// In-place version of `normalized`. - #[inline] - fn normalize(&mut self) -> N; -} - -/** - * Trait of elements having a cross product. - */ -pub trait Cross { - /// Computes the cross product between two elements (usually vectors). - fn cross(&self, other: &Self) -> V; -} - -/// Traits of objects which can be put in homogeneous coordinates form. -pub trait ToHomogeneous { - /// Gets the homogeneous coordinates form of this object. - fn to_homogeneous(&self) -> U; -} - -/// Traits of objects which can be build from an homogeneous coordinate form. -pub trait FromHomogeneous { - /// Builds an object from its homogeneous coordinate form. - /// - /// Note that this this is not required that `from` is the inverse of `to_homogeneous`. - /// Typically, `from` will remove some informations unrecoverable by `to_homogeneous`. - fn from(&U) -> Self; -} - -/** - * Trait of elements having a cross product operation which can be expressed as a matrix. - */ -pub trait CrossMatrix { - /// The matrix associated to any cross product with this vector. I.e. `v.cross(anything)` = - /// `v.cross_matrix().rmul(anything)`. - fn cross_matrix(&self) -> M; -} - -/// Composition of a rotation and an absolute value. -/// -/// The operation is accessible using the `RotationMatrix`, `Absolute`, and `RMul` traits, but -/// doing so is not easy in generic code as it can be a cause of type over-parametrization. -pub trait AbsoluteRotate { - /// This is the same as: - /// - /// ~~~{.rust} - /// self.rotation_matrix().absolute().rmul(v) - /// ~~~ - fn absolute_rotate(&self, v: &V) -> V; -} - -/// Trait of vectors able to sample a unit sphere. -/// -/// The number of sample must be sufficient to approximate a sphere using a support mapping -/// function. -pub trait UniformSphereSample { - /// Iterate through the samples. - fn sample(&fn(Self)); -} - /// Various composition of rotation and translation. /// /// Utilities to make rotations with regard to a point different than the origin. All those @@ -261,3 +126,138 @@ pub trait RotationWithTranslation, AV>: Rotation + Translation, AV, M: Rotation + Translation> RotationWithTranslation for M { } + +/// Trait of transformation having a rotation extractable as a rotation matrix. This can typically +/// be implemented by quaternions to convert them to a rotation matrix. +pub trait RotationMatrix + Rotation> : Rotation { + /// Gets the rotation matrix represented by `self`. + fn to_rot_mat(&self) -> M; +} + +/// Composition of a rotation and an absolute value. +/// +/// The operation is accessible using the `RotationMatrix`, `Absolute`, and `RMul` traits, but +/// doing so is not easy in generic code as it can be a cause of type over-parametrization. +pub trait AbsoluteRotate { + /// This is the same as: + /// + /// ~~~{.rust} + /// self.rotation_matrix().absolute().rmul(v) + /// ~~~ + fn absolute_rotate(&self, v: &V) -> V; +} + +/// Trait of object which represent a transformation, and to which new transformations can +/// be appended. +/// +/// A transformation is assumed to be an isometry without reflexion. +pub trait Transformation { + /// Gets the transformation of `self`. + fn transformation(&self) -> M; + + /// Gets the inverse transformation of `self`. + fn inv_transformation(&self) -> M; + + /// In-place version of `transformed`. + fn transform_by(&mut self, &M); + + /// Appends a transformation to `self`. + fn transformed(&self, &M) -> Self; + + /// Sets the transformation of `self`. + fn set_transformation(&mut self, M); +} + +/// Trait of objects able to transform other objects. +/// +/// This is typically implemented by matrices which transform vectors. +pub trait Transform { + /// Applies a transformation to `v`. + fn transform(&self, &V) -> V; + /// Applies an inverse transformation to `v`. + fn inv_transform(&self, &V) -> V; +} + +/// Traits of objects having a dot product. +pub trait Dot { + /// Computes the dot (inner) product of two vectors. + #[inline] + fn dot(&self, &Self) -> N; + + /** + * Short-cut to compute the projection of a point on a vector, but without + * computing intermediate vectors. + * The following equation must be verified: + * + * ~~~{.rust} + * a.sub_dot(b, c) == (a - b).dot(c) + * ~~~ + * + */ + #[inline] + fn sub_dot(&self, b: &Self, c: &Self) -> N; +} + +/// Traits of objects having an euclidian norm. +pub trait Norm { + /// Computes the norm of `self`. + #[inline] + fn norm(&self) -> N { + self.sqnorm().sqrt() + } + + /// Computes the squared norm of `self`. + /// + /// This is usually faster than computing the norm itself. + #[inline] + fn sqnorm(&self) -> N; + + /// Gets the normalized version of `self`. + #[inline] + fn normalized(&self) -> Self; + + /// In-place version of `normalized`. + #[inline] + fn normalize(&mut self) -> N; +} + +/** + * Trait of elements having a cross product. + */ +pub trait Cross { + /// Computes the cross product between two elements (usually vectors). + fn cross(&self, other: &Self) -> V; +} + +/** + * Trait of elements having a cross product operation which can be expressed as a matrix. + */ +pub trait CrossMatrix { + /// The matrix associated to any cross product with this vector. I.e. `v.cross(anything)` = + /// `v.cross_matrix().rmul(anything)`. + fn cross_matrix(&self) -> M; +} + +/// Traits of objects which can be put in homogeneous coordinates form. +pub trait ToHomogeneous { + /// Gets the homogeneous coordinates form of this object. + fn to_homogeneous(&self) -> U; +} + +/// Traits of objects which can be build from an homogeneous coordinate form. +pub trait FromHomogeneous { + /// Builds an object from its homogeneous coordinate form. + /// + /// Note that this this is not required that `from` is the inverse of `to_homogeneous`. + /// Typically, `from` will remove some informations unrecoverable by `to_homogeneous`. + fn from(&U) -> Self; +} + +/// Trait of vectors able to sample a unit sphere. +/// +/// The number of sample must be sufficient to approximate a sphere using a support mapping +/// function. +pub trait UniformSphereSample { + /// Iterate through the samples. + fn sample(&fn(Self)); +} diff --git a/src/traits/mod.rs b/src/traits/mod.rs new file mode 100644 index 00000000..99de789f --- /dev/null +++ b/src/traits/mod.rs @@ -0,0 +1,15 @@ +//! Mathematical traits. + +pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneous, Norm, Rotate, + Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous, + Transform, Transformation, Translate, Translation, UniformSphereSample}; + +pub use self::structure::{AlgebraicVec, AlgebraicVecExt, Basis, Col, Dim, Indexable, Iterable, + IterableMut, Mat, MatCast, Row, Vec, VecCast, VecExt}; + +pub use self::operations::{Absolute, Cov, Inv, LMul, Mean, Outer, RMul, ScalarAdd, ScalarSub, + Transpose}; + +pub mod geometry; +pub mod structure; +pub mod operations; diff --git a/src/traits/operations.rs b/src/traits/operations.rs index 93185e98..6de2620b 100644 --- a/src/traits/operations.rs +++ b/src/traits/operations.rs @@ -12,9 +12,9 @@ pub trait Absolute { /// Trait of objects having an inverse. Typically used to implement matrix inverse. pub trait Inv { /// Returns the inverse of `self`. - fn inverse(&self) -> Option; + fn inverted(&self) -> Option; /// In-place version of `inverse`. - fn inplace_inverse(&mut self) -> bool; + fn invert(&mut self) -> bool; } /// Trait of objects which can be transposed. @@ -27,9 +27,9 @@ pub trait Transpose { } /// Traits of objects having an outer product. -pub trait Outer { +pub trait Outer { /// Computes the outer product: `self * other` - fn outer(&self, other: &V) -> M; + fn outer(&self, other: &Self) -> M; } /// Trait for computing the covariance of a set of data. diff --git a/src/traits/structure.rs b/src/traits/structure.rs index 89a61611..eb5fe118 100644 --- a/src/traits/structure.rs +++ b/src/traits/structure.rs @@ -70,38 +70,12 @@ pub trait Basis { /// Iterates through a basis of the subspace orthogonal to `self`. fn orthonormal_subspace_basis(&self, &fn(Self) -> bool); - - /// Creates the canonical basis of the space in which this object lives. - fn canonical_basis_list() -> ~[Self] { - let mut res = ~[]; - - do Basis::canonical_basis |elem| { - res.push(elem); - - true - } - - res - } - - /// Creates a basis of the subspace orthogonal to `self`. - fn orthonormal_subspace_basis_list(&self) -> ~[Self] { - let mut res = ~[]; - - do self.orthonormal_subspace_basis |elem| { - res.push(elem); - - true - } - - res - } } /// Trait to access rows of a matrix or a vector. pub trait Row { /// The number of column of `self`. - fn num_rows(&self) -> uint; + fn nrows(&self) -> uint; /// Reads the `i`-th row of `self`. fn row(&self, i: uint) -> R; /// Writes the `i`-th row of `self`. @@ -114,7 +88,7 @@ pub trait Row { /// Trait to access columns of a matrix or vector. pub trait Col { /// The number of column of this matrix or vector. - fn num_cols(&self) -> uint; + fn ncols(&self) -> uint; /// Reads the `i`-th column of `self`. fn col(&self, i: uint) -> C; diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 3d9cdc8f..00000000 --- a/src/types.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Useful type aliases. - -use vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6}; -use mat::{Mat1, Mat2, Mat3, Mat4, Mat5, Mat6}; -use adaptors::rotmat::Rotmat; -use adaptors::transform::Transform; - -// 1D -/// 1-dimensional `f64`-valued vector. -pub type Vec1f64 = Vec1; -/// 1-dimensional `f32`-valued vector. -pub type Vec1f32 = Vec1; - -/// 1-dimensional `f64`-valued matrix. -pub type Mat1f64 = Mat1; -/// 1-dimensional `f32`-valued matrix. -pub type Mat1f32 = Mat1; - -// /// 1-dimensional `f64`-valued rotation matrix. -// pub type Rot1f64 = Rotmat>; -// /// 1-dimensional `f32`-valued rotation matrix. -// pub type Rot1f32 = Rotmat>; -// -// /// 1-dimensional `f64`-valued isometric transform. -// pub type Iso1f64 = Transform; -// /// 1-dimensional `f32`-valued isometric transform. -// pub type Iso1f32 = Transform; - -/// 1-dimensional `f64`-valued general transform. -pub type Aff1f64 = Transform; -/// 1-dimensional `f32`-valued general transform. -pub type Aff1f32 = Transform; - -// 2D -/// 2-dimensional `f64`-valued vector. -pub type Vec2f64 = Vec2; -/// 2-dimensional `f32`-valued vector. -pub type Vec2f32 = Vec2; - -/// 2-dimensional `f64`-valued matrix. -pub type Mat2f64 = Mat2; -/// 2-dimensional `f32`-valued matrix. -pub type Mat2f32 = Mat2; - -/// 2-dimensional `f64`-valued rotation matrix. -pub type Rot2f64 = Rotmat>; -/// 2-dimensional `f32`-valued rotation matrix. -pub type Rot2f32 = Rotmat>; - -/// 2-dimensional `f64`-valued isometric transform. -pub type Iso2f64 = Transform; -/// 2-dimensional `f32`-valued isometric transform. -pub type Iso2f32 = Transform; - -/// 2-dimensional `f64`-valued general transform. -pub type Aff2f64 = Transform; -/// 2-dimensional `f32`-valued general transform. -pub type Aff2f32 = Transform; - -// 3D -/// 3-dimensional `f64`-valued vector. -pub type Vec3f64 = Vec3; -/// 3-dimensional `f32`-valued vector. -pub type Vec3f32 = Vec3; - -/// 3-dimensional `f64`-valued matrix. -pub type Mat3f64 = Mat3; -/// 3-dimensional `f32`-valued matrix. -pub type Mat3f32 = Mat3; - -/// 3-dimensional `f64`-valued rotation matrix. -pub type Rot3f64 = Rotmat>; -/// 3-dimensional `f32`-valued rotation matrix. -pub type Rot3f32 = Rotmat>; - -/// 3-dimensional `f64`-valued isometric transform. -pub type Iso3f64 = Transform; -/// 3-dimensional `f32`-valued isometric transform. -pub type Iso3f32 = Transform; - -/// 3-dimensional `f64`-valued general transform. -pub type Aff3f64 = Transform; -/// 3-dimensional `f32`-valued general transform. -pub type Aff3f32 = Transform; - -// 4D -/// 4-dimensional `f64`-valued vector. -pub type Vec4f64 = Vec4; -/// 4-dimensional `f32`-valued vector. -pub type Vec4f32 = Vec4; - -/// 4-dimensional `f64`-valued matrix. -pub type Mat4f64 = Mat4; -/// 4-dimensional `f32`-valued matrix. -pub type Mat4f32 = Mat4; - -/// 4-dimensional `f64`-valued rotation matrix. -pub type Rot4f64 = Rotmat>; -/// 4-dimensional `f32`-valued rotation matrix. -pub type Rot4f32 = Rotmat>; - -/// 4-dimensional `f64`-valued isometric transform. -pub type Iso4f64 = Transform; -/// 4-dimensional `f32`-valued isometric transform. -pub type Iso4f32 = Transform; - -/// 4-dimensional `f64`-valued general transform. -pub type Aff4f64 = Transform; -/// 4-dimensional `f32`-valued general transform. -pub type Aff4f32 = Transform; - -// 5D -/// 5-dimensional `f64`-valued vector. -pub type Vec5f64 = Vec5; -/// 5-dimensional `f32`-valued vector. -pub type Vec5f32 = Vec5; - -/// 5-dimensional `f64`-valued matrix. -pub type Mat5f64 = Mat5; -/// 5-dimensional `f32`-valued matrix. -pub type Mat5f32 = Mat5; - -// /// 5-dimensional `f64`-valued rotation matrix. -// pub type Rot5f64 = Rotmat>; -// /// 5-dimensional `f32`-valued rotation matrix. -// pub type Rot5f32 = Rotmat>; -// -// /// 5-dimensional `f64`-valued isometric transform. -// pub type Iso5f64 = Transform; -// /// 5-dimensional `f32`-valued isometric transform. -// pub type Iso5f32 = Transform; - -/// 5-dimensional `f64`-valued general transform. -pub type Aff5f64 = Transform; -/// 5-dimensional `f32`-valued general transform. -pub type Aff5f32 = Transform; - -// 6D -/// 6-dimensional `f64`-valued vector. -pub type Vec6f64 = Vec6; -/// 6-dimensional `f32`-valued vector. -pub type Vec6f32 = Vec6; - -/// 6-dimensional `f64`-valued matrix. -pub type Mat6f64 = Mat6; -/// 6-dimensional `f32`-valued matrix. -pub type Mat6f32 = Mat6; - -// /// 6-dimensional `f64`-valued rotation matrix. -// pub type Rot6f64 = Rotmat>; -// /// 6-dimensional `f32`-valued rotation matrix. -// pub type Rot6f32 = Rotmat>; -// -// /// 6-dimensional `f64`-valued isometric transform. -// pub type Iso6f64 = Transform; -// /// 6-dimensional `f32`-valued isometric transform. -// pub type Iso6f32 = Transform; - -/// 6-dimensional `f64`-valued general transform. -pub type Aff6f64 = Transform; -/// 6-dimensional `f32`-valued general transform. -pub type Aff6f32 = Transform;