Switch to column-major representation.

Matrices are now column-major.
This will be useful to interop with opengl and lapack.
This commit is contained in:
Sébastien Crozet 2013-10-17 22:40:44 +02:00
parent 90e40aaec0
commit 8423286911
6 changed files with 148 additions and 58 deletions

View File

@ -101,16 +101,35 @@ impl<N: Clone> DMat<N> {
}
/// 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<N> {
assert!(nrows * ncols <= vec.len());
pub fn from_row_vec(nrows: uint, ncols: uint, vec: &[N]) -> DMat<N> {
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<N> {
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<N> DMat<N> {
}
/// 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<N: One + Zero + Clone> DMat<N> {
}
impl<N: Clone> DMat<N> {
#[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.

View File

@ -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<N> {
/// The rotation applicable by this isometry.
rotation: Rot2<N>,
@ -32,7 +32,7 @@ pub struct Iso2<N> {
///
/// 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<N> {
/// The rotation applicable by this isometry.
rotation: Rot3<N>,
@ -43,7 +43,7 @@ pub struct Iso3<N> {
/// 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<N> {
/// The rotation applicable by this isometry.
rotation: Rot4<N>,

View File

@ -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<N> {
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<N> {
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<N> {
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<N> {
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<N> {
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)

View File

@ -20,13 +20,13 @@ macro_rules! at_fast_impl(
#[inline]
unsafe fn at_fast(&self, (i, j): (uint, uint)) -> N {
(*cast::transmute::<&$t<N>, &[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<N>, &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>, &[N, ..$dim * $dim]>(self)[i * $dim + j].clone()
cast::transmute::<&$t<N>, &[N, ..$dim * $dim]>(self)[i + j * $dim].clone()
}
}
#[inline]
fn set(&mut self, (i, j): (uint, uint), val: N) {
unsafe {
cast::transmute::<&mut $t<N>, &mut [N, ..$dim * $dim]>(self)[i * $dim + j] = val
cast::transmute::<&mut $t<N>, &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<N>, &mut [N, ..$dim * $dim]>(self)
.swap(i1 * $dim + j1, i2 * $dim + j2)
.swap(i1 + j1 * $dim, i2 + j2 * $dim)
}
}
}

View File

@ -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<N> {
priv submat: Mat2<N>
}
@ -35,7 +35,7 @@ impl<N: Trigonometric + Num + Clone>
Rotation<Vec1<N>> for Rot2<N> {
#[inline]
fn rotation(&self) -> Vec1<N> {
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<N: Signed> AbsoluteRotate<Vec2<N>> for Rot2<N> {
* 3d rotation
*/
/// Three dimensional rotation matrix.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)]
pub struct Rot3<N> {
priv submat: Mat3<N>
}
@ -264,7 +264,7 @@ impl<N: Signed> AbsoluteRotate<Vec3<N>> for Rot3<N> {
}
/// Four dimensional rotation matrix.
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr)]
#[deriving(Eq, Encodable, Decodable, Clone, DeepClone, ToStr, IterBytes)]
pub struct Rot4<N> {
priv submat: Mat4<N>
}

View File

@ -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<f64>);
test_transpose_mat_impl!(Mat1<f64>);
}
#[test]
fn test_transpose_mat2() {
test_transpose_mat_impl!(na::Mat2<f64>);
test_transpose_mat_impl!(Mat2<f64>);
}
#[test]
fn test_transpose_mat3() {
test_transpose_mat_impl!(na::Mat3<f64>);
test_transpose_mat_impl!(Mat3<f64>);
}
#[test]
fn test_transpose_mat4() {
test_transpose_mat_impl!(na::Mat4<f64>);
test_transpose_mat_impl!(Mat4<f64>);
}
#[test]
fn test_transpose_mat5() {
test_transpose_mat_impl!(na::Mat5<f64>);
test_transpose_mat_impl!(Mat5<f64>);
}
#[test]
fn test_transpose_mat6() {
test_transpose_mat_impl!(na::Mat6<f64>);
test_transpose_mat_impl!(Mat6<f64>);
}
#[test]
fn test_inv_mat1() {
test_inv_mat_impl!(na::Mat1<f64>);
test_inv_mat_impl!(Mat1<f64>);
}
#[test]
fn test_inv_mat2() {
test_inv_mat_impl!(na::Mat2<f64>);
test_inv_mat_impl!(Mat2<f64>);
}
#[test]
fn test_inv_mat3() {
test_inv_mat_impl!(na::Mat3<f64>);
test_inv_mat_impl!(Mat3<f64>);
}
#[test]
fn test_inv_mat4() {
test_inv_mat_impl!(na::Mat4<f64>);
test_inv_mat_impl!(Mat4<f64>);
}
#[test]
fn test_inv_mat5() {
test_inv_mat_impl!(na::Mat5<f64>);
test_inv_mat_impl!(Mat5<f64>);
}
#[test]
fn test_inv_mat6() {
test_inv_mat_impl!(na::Mat6<f64>);
test_inv_mat_impl!(Mat6<f64>);
}
#[test]
@ -97,7 +96,7 @@ fn test_rotation2() {
#[test]
fn test_index_mat2() {
let mat: na::Mat2<f64> = random();
let mat: Mat2<f64> = 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<f64> = na::one();
let dir: na::Vec3<f64> = random();
let randmat: Rot3<f64> = na::one();
let dir: Vec3<f64> = random();
let ang = na::normalize(&dir) * (abs::<f64>(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);
}