From 84232869113e5c851197ced03d77e460381724bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Thu, 17 Oct 2013 22:40:44 +0200 Subject: [PATCH] Switch to column-major representation. Matrices are now column-major. This will be useful to interop with opengl and lapack. --- src/structs/dmat.rs | 48 +++++++++++++++++--- src/structs/iso.rs | 6 +-- src/structs/mat.rs | 40 ++++++++--------- src/structs/mat_macros.rs | 10 ++--- src/structs/rot.rs | 10 ++--- src/tests/mat.rs | 92 ++++++++++++++++++++++++++++++--------- 6 files changed, 148 insertions(+), 58 deletions(-) diff --git a/src/structs/dmat.rs b/src/structs/dmat.rs index 464a9237..9ca6bc99 100644 --- a/src/structs/dmat.rs +++ b/src/structs/dmat.rs @@ -101,16 +101,35 @@ impl DMat { } /// Builds a matrix filled with the components provided by a vector. + /// The vector contains the matrix data in row-major order. + /// Note that `from_col_vec` is a lot faster than `from_row_vec` since a `DMat` stores its data + /// in column-major order. /// /// The vector must have at least `nrows * ncols` elements. #[inline] - pub fn from_vec(nrows: uint, ncols: uint, vec: &[N]) -> DMat { - assert!(nrows * ncols <= vec.len()); + pub fn from_row_vec(nrows: uint, ncols: uint, vec: &[N]) -> DMat { + let mut res = DMat::from_col_vec(ncols, nrows, vec); + + // we transpose because the buffer is row_major + res.transpose(); + + res + } + + /// Builds a matrix filled with the components provided by a vector. + /// The vector contains the matrix data in column-major order. + /// Note that `from_col_vec` is a lot faster than `from_row_vec` since a `DMat` stores its data + /// in column-major order. + /// + /// The vector must have at least `nrows * ncols` elements. + #[inline] + pub fn from_col_vec(nrows: uint, ncols: uint, vec: &[N]) -> DMat { + assert!(nrows * ncols == vec.len()); DMat { nrows: nrows, ncols: ncols, - mij: vec.slice_to(nrows * ncols).to_owned() + mij: vec.to_owned() } } } @@ -139,10 +158,29 @@ impl DMat { } /// Transforms this matrix into an array. This consumes the matrix and is O(1). + /// The returned vector contains the matrix data in column-major order. #[inline] pub fn to_vec(self) -> ~[N] { self.mij } + + /// Gets a reference to this matrix data. + /// The returned vector contains the matrix data in column-major order. + #[inline] + pub fn as_vec<'r>(&'r self) -> &'r [N] { + let res: &'r [N] = self.mij; + + res + } + + /// Gets a mutable reference to this matrix data. + /// The returned vector contains the matrix data in column-major order. + #[inline] + pub fn as_mut_vec<'r>(&'r mut self) -> &'r mut [N] { + let res: &'r mut [N] = self.mij; + + res + } } // FIXME: add a function to modify the dimension (to avoid useless allocations)? @@ -167,9 +205,9 @@ impl DMat { } impl DMat { - #[inline] + #[inline(always)] fn offset(&self, i: uint, j: uint) -> uint { - i * self.ncols + j + i + j * self.nrows } /// Changes the value of a component of the matrix. diff --git a/src/structs/iso.rs b/src/structs/iso.rs index 2dd9c324..c2fc5ceb 100644 --- a/src/structs/iso.rs +++ b/src/structs/iso.rs @@ -20,7 +20,7 @@ mod iso_macros; /// /// 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)] +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)] pub struct Iso2 { /// The rotation applicable by this isometry. rotation: Rot2, @@ -32,7 +32,7 @@ pub struct Iso2 { /// /// 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)] +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)] pub struct Iso3 { /// The rotation applicable by this isometry. rotation: Rot3, @@ -43,7 +43,7 @@ pub struct Iso3 { /// Four dimensional isometry. /// /// Isometries conserve angles and distances, hence do not allow shearing nor scaling. -#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)] pub struct Iso4 { /// The rotation applicable by this isometry. rotation: Rot4, diff --git a/src/structs/mat.rs b/src/structs/mat.rs index b46853e4..855bb8f2 100644 --- a/src/structs/mat.rs +++ b/src/structs/mat.rs @@ -127,8 +127,8 @@ outer_impl!(Vec1, Mat1) /// Square matrix of dimension 2. #[deriving(Eq, Encodable, Decodable, Clone, DeepClone, IterBytes, Rand, Zero, ToStr)] pub struct Mat2 { - m11: N, m12: N, - m21: N, m22: N + m11: N, m21: N, + m12: N, m22: N } double_dispatch_binop_decl_trait!(Mat2, Mat2MulRhs) @@ -224,9 +224,9 @@ outer_impl!(Vec2, Mat2) /// Square matrix of dimension 3. #[deriving(Eq, Encodable, Decodable, Clone, DeepClone, IterBytes, Rand, Zero, ToStr)] pub struct Mat3 { - m11: N, m12: N, m13: N, - m21: N, m22: N, m23: N, - m31: N, m32: N, m33: N + m11: N, m21: N, m31: N, + m12: N, m22: N, m32: N, + m13: N, m23: N, m33: N } double_dispatch_binop_decl_trait!(Mat3, Mat3MulRhs) @@ -335,10 +335,10 @@ outer_impl!(Vec3, Mat3) /// Square matrix of dimension 4. #[deriving(Eq, Encodable, Decodable, Clone, DeepClone, IterBytes, Rand, Zero, ToStr)] pub struct Mat4 { - m11: N, m12: N, m13: N, m14: N, - m21: N, m22: N, m23: N, m24: N, - m31: N, m32: N, m33: N, m34: N, - m41: N, m42: N, m43: N, m44: N + m11: N, m21: N, m31: N, m41: N, + m12: N, m22: N, m32: N, m42: N, + m13: N, m23: N, m33: N, m43: N, + m14: N, m24: N, m34: N, m44: N } double_dispatch_binop_decl_trait!(Mat4, Mat4MulRhs) @@ -498,11 +498,11 @@ outer_impl!(Vec4, Mat4) /// Square matrix of dimension 5. #[deriving(Eq, Encodable, Decodable, Clone, DeepClone, IterBytes, Rand, Zero, ToStr)] pub struct Mat5 { - m11: N, m12: N, m13: N, m14: N, m15: N, - m21: N, m22: N, m23: N, m24: N, m25: N, - m31: N, m32: N, m33: N, m34: N, m35: N, - m41: N, m42: N, m43: N, m44: N, m45: N, - m51: N, m52: N, m53: N, m54: N, m55: N + m11: N, m21: N, m31: N, m41: N, m51: N, + m12: N, m22: N, m32: N, m42: N, m52: N, + m13: N, m23: N, m33: N, m43: N, m53: N, + m14: N, m24: N, m34: N, m44: N, m54: N, + m15: N, m25: N, m35: N, m45: N, m55: N } double_dispatch_binop_decl_trait!(Mat5, Mat5MulRhs) @@ -677,12 +677,12 @@ outer_impl!(Vec5, Mat5) /// Square matrix of dimension 6. #[deriving(Eq, Encodable, Decodable, Clone, DeepClone, IterBytes, Rand, Zero, ToStr)] pub struct Mat6 { - m11: N, m12: N, m13: N, m14: N, m15: N, m16: N, - m21: N, m22: N, m23: N, m24: N, m25: N, m26: N, - m31: N, m32: N, m33: N, m34: N, m35: N, m36: N, - m41: N, m42: N, m43: N, m44: N, m45: N, m46: N, - m51: N, m52: N, m53: N, m54: N, m55: N, m56: N, - m61: N, m62: N, m63: N, m64: N, m65: N, m66: N + m11: N, m21: N, m31: N, m41: N, m51: N, m61: N, + m12: N, m22: N, m32: N, m42: N, m52: N, m62: N, + m13: N, m23: N, m33: N, m43: N, m53: N, m63: N, + m14: N, m24: N, m34: N, m44: N, m54: N, m64: N, + m15: N, m25: N, m35: N, m45: N, m55: N, m65: N, + m16: N, m26: N, m36: N, m46: N, m56: N, m66: N } double_dispatch_binop_decl_trait!(Mat6, Mat6MulRhs) diff --git a/src/structs/mat_macros.rs b/src/structs/mat_macros.rs index 9f383a8e..6118dfb7 100644 --- a/src/structs/mat_macros.rs +++ b/src/structs/mat_macros.rs @@ -20,13 +20,13 @@ macro_rules! at_fast_impl( #[inline] unsafe fn at_fast(&self, (i, j): (uint, uint)) -> N { (*cast::transmute::<&$t, &[N, ..$dim * $dim]>(self) - .unsafe_ref(i * $dim + j)).clone() + .unsafe_ref(i + j * $dim)).clone() } #[inline] unsafe fn set_fast(&mut self, (i, j): (uint, uint), val: N) { (*cast::transmute::<&mut $t, &mut [N, ..$dim * $dim]>(self) - .unsafe_mut_ref(i * $dim + j)) = val + .unsafe_mut_ref(i + j * $dim)) = val } } ) @@ -174,14 +174,14 @@ macro_rules! indexable_impl( #[inline] fn at(&self, (i, j): (uint, uint)) -> N { unsafe { - cast::transmute::<&$t, &[N, ..$dim * $dim]>(self)[i * $dim + j].clone() + cast::transmute::<&$t, &[N, ..$dim * $dim]>(self)[i + j * $dim].clone() } } #[inline] fn set(&mut self, (i, j): (uint, uint), val: N) { unsafe { - cast::transmute::<&mut $t, &mut [N, ..$dim * $dim]>(self)[i * $dim + j] = val + cast::transmute::<&mut $t, &mut [N, ..$dim * $dim]>(self)[i + j * $dim] = val } } @@ -189,7 +189,7 @@ macro_rules! indexable_impl( fn swap(&mut self, (i1, j1): (uint, uint), (i2, j2): (uint, uint)) { unsafe { cast::transmute::<&mut $t, &mut [N, ..$dim * $dim]>(self) - .swap(i1 * $dim + j1, i2 * $dim + j2) + .swap(i1 + j1 * $dim, i2 + j2 * $dim) } } } diff --git a/src/structs/rot.rs b/src/structs/rot.rs index 116f97a0..88595c00 100644 --- a/src/structs/rot.rs +++ b/src/structs/rot.rs @@ -6,7 +6,7 @@ use std::num::{Zero, One}; use std::rand::{Rand, Rng}; use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Transform, ToHomogeneous, Norm, Cross}; -use traits::structure::{Cast, Dim, Indexable, Row, Col}; +use traits::structure::{Cast, Dim, 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}; @@ -15,7 +15,7 @@ mod metal; mod rot_macros; /// Two dimensional rotation matrix. -#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)] pub struct Rot2 { priv submat: Mat2 } @@ -35,7 +35,7 @@ impl Rotation> for Rot2 { #[inline] fn rotation(&self) -> Vec1 { - Vec1::new((-self.submat.at((0, 1))).atan2(&self.submat.at((0, 0)))) + Vec1::new((-self.submat.m12).atan2(&self.submat.m11)) } #[inline] @@ -93,7 +93,7 @@ impl AbsoluteRotate> for Rot2 { * 3d rotation */ /// Three dimensional rotation matrix. -#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)] pub struct Rot3 { priv submat: Mat3 } @@ -264,7 +264,7 @@ impl AbsoluteRotate> for Rot3 { } /// Four dimensional rotation matrix. -#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)] +#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)] pub struct Rot4 { priv submat: Mat4 } diff --git a/src/tests/mat.rs b/src/tests/mat.rs index e8e62937..47cf1f2a 100644 --- a/src/tests/mat.rs +++ b/src/tests/mat.rs @@ -1,8 +1,7 @@ use std::num::{Real, abs}; use std::rand::random; use std::cmp::ApproxEq; -use na::{Vec1, DMat, DVec}; -use na::Indexable; // FIXME: get rid of that +use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable}; use na; macro_rules! test_inv_mat_impl( @@ -27,62 +26,62 @@ macro_rules! test_transpose_mat_impl( #[test] fn test_transpose_mat1() { - test_transpose_mat_impl!(na::Mat1); + test_transpose_mat_impl!(Mat1); } #[test] fn test_transpose_mat2() { - test_transpose_mat_impl!(na::Mat2); + test_transpose_mat_impl!(Mat2); } #[test] fn test_transpose_mat3() { - test_transpose_mat_impl!(na::Mat3); + test_transpose_mat_impl!(Mat3); } #[test] fn test_transpose_mat4() { - test_transpose_mat_impl!(na::Mat4); + test_transpose_mat_impl!(Mat4); } #[test] fn test_transpose_mat5() { - test_transpose_mat_impl!(na::Mat5); + test_transpose_mat_impl!(Mat5); } #[test] fn test_transpose_mat6() { - test_transpose_mat_impl!(na::Mat6); + test_transpose_mat_impl!(Mat6); } #[test] fn test_inv_mat1() { - test_inv_mat_impl!(na::Mat1); + test_inv_mat_impl!(Mat1); } #[test] fn test_inv_mat2() { - test_inv_mat_impl!(na::Mat2); + test_inv_mat_impl!(Mat2); } #[test] fn test_inv_mat3() { - test_inv_mat_impl!(na::Mat3); + test_inv_mat_impl!(Mat3); } #[test] fn test_inv_mat4() { - test_inv_mat_impl!(na::Mat4); + test_inv_mat_impl!(Mat4); } #[test] fn test_inv_mat5() { - test_inv_mat_impl!(na::Mat5); + test_inv_mat_impl!(Mat5); } #[test] fn test_inv_mat6() { - test_inv_mat_impl!(na::Mat6); + test_inv_mat_impl!(Mat6); } #[test] @@ -97,7 +96,7 @@ fn test_rotation2() { #[test] fn test_index_mat2() { - let mat: na::Mat2 = random(); + let mat: Mat2 = random(); assert!(mat.at((0, 1)) == na::transpose(&mat).at((1, 0))); } @@ -105,8 +104,8 @@ fn test_index_mat2() { #[test] fn test_inv_rotation3() { do 10000.times { - let randmat: na::Rot3 = na::one(); - let dir: na::Vec3 = random(); + let randmat: Rot3 = na::one(); + let dir: Vec3 = random(); let ang = na::normalize(&dir) * (abs::(random()) % Real::pi()); let rot = na::append_rotation(&randmat, &ang); @@ -116,7 +115,7 @@ fn test_inv_rotation3() { #[test] fn test_mean_dmat() { - let mat = DMat::from_vec( + let mat = DMat::from_row_vec( 3, 3, [ @@ -131,7 +130,7 @@ fn test_mean_dmat() { #[test] fn test_cov_dmat() { - let mat = DMat::from_vec( + let mat = DMat::from_row_vec( 5, 3, [ @@ -143,7 +142,7 @@ fn test_cov_dmat() { ] ); - let expected = DMat::from_vec( + let expected = DMat::from_row_vec( 3, 3, [ @@ -155,3 +154,56 @@ fn test_cov_dmat() { assert!(na::cov(&mat).approx_eq(&expected)); } + +#[test] +fn test_transpose_dmat() { + let mat = DMat::from_row_vec( + 8, + 4, + [ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24, + 25, 26, 27, 28, + 29, 30, 31, 32 + ] + ); + + assert!(na::transpose(&na::transpose(&mat)) == mat); +} + +#[test] +fn test_dmat_from_vec() { + let mat1 = DMat::from_row_vec( + 8, + 4, + [ + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + 17, 18, 19, 20, + 21, 22, 23, 24, + 25, 26, 27, 28, + 29, 30, 31, 32 + ] + ); + + let mat2 = DMat::from_col_vec( + 8, + 4, + [ + 1, 5, 9, 13, 17, 21, 25, 29, + 2, 6, 10, 14, 18, 22, 26, 30, + 3, 7, 11, 15, 19, 23, 27, 31, + 4, 8, 12, 16, 20, 24, 28, 32 + ] + ); + + println!("mat1: {:?}, mat2: {:?}", mat1, mat2); + + assert!(mat1 == mat2); +}