diff --git a/src/dim1/mat1.rs b/src/dim1/mat1.rs index 788a1ac7..ec6cd4ff 100644 --- a/src/dim1/mat1.rs +++ b/src/dim1/mat1.rs @@ -4,6 +4,7 @@ use std::cmp::ApproxEq; use traits::dim::Dim; use traits::inv::Inv; use traits::transpose::Transpose; +use traits::flatten::Flatten; use traits::workarounds::rlmul::{RMul, LMul}; use dim1::vec1::Vec1; @@ -105,3 +106,18 @@ impl Rand for Mat1 fn rand(rng: &mut R) -> Mat1 { Mat1::new(rng.gen()) } } + +impl Flatten for Mat1 +{ + fn flat_size() -> uint + { 1 } + + fn from_flattened(l: &[N], off: uint) -> Mat1 + { Mat1::new(l[off]) } + + fn to_flattened(&self) -> ~[N] + { ~[ self.m11 ] } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { l[off] = self.m11 } +} diff --git a/src/dim1/vec1.rs b/src/dim1/vec1.rs index daa3e12a..cf484fb1 100644 --- a/src/dim1/vec1.rs +++ b/src/dim1/vec1.rs @@ -7,6 +7,7 @@ use traits::dot::Dot; use traits::norm::Norm; use traits::translation::Translation; use traits::sub_dot::SubDot; +use traits::flatten::Flatten; use traits::workarounds::scalar_op::{ScalarMul, ScalarDiv, ScalarAdd, ScalarSub}; #[deriving(Eq, ToStr)] @@ -169,3 +170,18 @@ impl Rand for Vec1 fn rand(rng: &mut R) -> Vec1 { Vec1::new(rng.gen()) } } + +impl Flatten for Vec1 +{ + fn flat_size() -> uint + { 1 } + + fn from_flattened(l: &[N], off: uint) -> Vec1 + { Vec1::new(l[off]) } + + fn to_flattened(&self) -> ~[N] + { ~[ self.x ] } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { l[off] = self.x } +} diff --git a/src/dim2/mat2.rs b/src/dim2/mat2.rs index 49e690a7..f60acaad 100644 --- a/src/dim2/mat2.rs +++ b/src/dim2/mat2.rs @@ -5,6 +5,7 @@ use std::util::swap; use traits::dim::Dim; use traits::inv::Inv; use traits::transpose::Transpose; +use traits::flatten::Flatten; use traits::workarounds::rlmul::{RMul, LMul}; use dim2::vec2::Vec2; @@ -158,3 +159,23 @@ impl Rand for Mat2 fn rand(rng: &mut R) -> Mat2 { Mat2::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()) } } + +impl Flatten for Mat2 +{ + fn flat_size() -> uint + { 4 } + + fn from_flattened(l: &[N], off: uint) -> Mat2 + { Mat2::new(l[off], l[off + 1], l[off + 2], l[off + 3]) } + + fn to_flattened(&self) -> ~[N] + { ~[ self.m11, self.m12, self.m21, self.m22 ] } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { + l[off] = self.m11; + l[off + 1] = self.m12; + l[off + 2] = self.m21; + l[off + 3] = self.m22; + } +} diff --git a/src/dim2/vec2.rs b/src/dim2/vec2.rs index 68d97609..8c3bfce4 100644 --- a/src/dim2/vec2.rs +++ b/src/dim2/vec2.rs @@ -8,6 +8,7 @@ use traits::dim::Dim; use traits::dot::Dot; use traits::sub_dot::SubDot; use traits::norm::Norm; +use traits::flatten::Flatten; use traits::translation::Translation; use traits::workarounds::scalar_op::{ScalarMul, ScalarDiv, ScalarAdd, ScalarSub}; @@ -203,3 +204,21 @@ impl Rand for Vec2 fn rand(rng: &mut R) -> Vec2 { Vec2::new(rng.gen(), rng.gen()) } } + +impl Flatten for Vec2 +{ + fn flat_size() -> uint + { 2 } + + fn from_flattened(l: &[N], off: uint) -> Vec2 + { Vec2::new(l[off], l[off + 1]) } + + fn to_flattened(&self) -> ~[N] + { ~[ self.x, self.y ] } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { + l[off] = self.x; + l[off + 1] = self.y; + } +} diff --git a/src/dim3/mat3.rs b/src/dim3/mat3.rs index 8fdad125..6466114b 100644 --- a/src/dim3/mat3.rs +++ b/src/dim3/mat3.rs @@ -5,6 +5,7 @@ use std::util::swap; use traits::dim::Dim; use traits::inv::Inv; use traits::transpose::Transpose; +use traits::flatten::Flatten; use traits::workarounds::rlmul::{RMul, LMul}; use dim3::vec3::Vec3; @@ -212,3 +213,36 @@ impl Rand for Mat3 rng.gen(), rng.gen(), rng.gen()) } } + +impl Flatten for Mat3 +{ + fn flat_size() -> uint + { 9 } + + fn from_flattened(l: &[N], off: uint) -> Mat3 + { Mat3::new(l[off + 0], l[off + 1], l[off + 2], + l[off + 3], l[off + 4], l[off + 5], + l[off + 6], l[off + 7], l[off + 8]) } + + fn to_flattened(&self) -> ~[N] + { + ~[ + self.m11, self.m12, self.m13, + self.m21, self.m22, self.m23, + self.m31, self.m32, self.m33 + ] + } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { + l[off + 0] = self.m11; + l[off + 1] = self.m12; + l[off + 2] = self.m13; + l[off + 3] = self.m21; + l[off + 4] = self.m22; + l[off + 5] = self.m23; + l[off + 6] = self.m31; + l[off + 7] = self.m32; + l[off + 8] = self.m33; + } +} diff --git a/src/dim3/vec3.rs b/src/dim3/vec3.rs index 70842146..d4eb4f4c 100644 --- a/src/dim3/vec3.rs +++ b/src/dim3/vec3.rs @@ -7,6 +7,7 @@ use traits::dim::Dim; use traits::dot::Dot; use traits::sub_dot::SubDot; use traits::norm::Norm; +use traits::flatten::Flatten; use traits::translation::Translation; use traits::workarounds::scalar_op::{ScalarMul, ScalarDiv, ScalarAdd, ScalarSub}; @@ -232,3 +233,22 @@ impl Rand for Vec3 fn rand(rng: &mut R) -> Vec3 { Vec3::new(rng.gen(), rng.gen(), rng.gen()) } } + +impl Flatten for Vec3 +{ + fn flat_size() -> uint + { 3 } + + fn from_flattened(l: &[N], off: uint) -> Vec3 + { Vec3::new(l[off], l[off + 1], l[off + 2]) } + + fn to_flattened(&self) -> ~[N] + { ~[ self.x, self.y, self.z ] } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { + l[off] = self.x; + l[off + 1] = self.y; + l[off + 2] = self.z; + } +} diff --git a/src/nalgebra.rc b/src/nalgebra.rc index 348546e0..d85d9b86 100644 --- a/src/nalgebra.rc +++ b/src/nalgebra.rc @@ -69,6 +69,7 @@ pub mod traits pub mod ring; pub mod division_ring; pub mod sub_dot; + pub mod flatten; /// This package contains everything done because the current compiler either /// crashes or miss features. diff --git a/src/ndim/nmat.rs b/src/ndim/nmat.rs index 84fcd704..555c633d 100644 --- a/src/ndim/nmat.rs +++ b/src/ndim/nmat.rs @@ -6,6 +6,7 @@ use traits::dim::Dim; use traits::inv::Inv; use traits::division_ring::DivisionRing; use traits::transpose::Transpose; +use traits::flatten::Flatten; use traits::workarounds::rlmul::{RMul, LMul}; use ndim::dmat::{DMat, one_mat_with_dim, zero_mat_with_dim, is_zero_mat}; use ndim::nvec::NVec; @@ -168,3 +169,39 @@ impl Rand for NMat res } } + +impl Flatten for NMat +{ + fn flat_size() -> uint + { Dim::dim::() * Dim::dim::() } + + fn from_flattened(l: &[N], off: uint) -> NMat + { + let dim = Dim::dim::(); + let mut res = Zero::zero::>(); + + for iterate(0u, dim * dim) |i| + { res.mij.mij[i] = l[off + i] } + + res + } + + fn to_flattened(&self) -> ~[N] + { + let dim = Dim::dim::(); + let mut res = ~[]; + + for iterate(0u, dim * dim) |i| + { res.push(self.mij.mij[i]) } + + res + } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { + let dim = Dim::dim::(); + + for iterate(0u, dim * dim) |i| + { l[off + i] = self.mij.mij[i] } + } +} diff --git a/src/ndim/nvec.rs b/src/ndim/nvec.rs index fe0e262c..52204212 100644 --- a/src/ndim/nvec.rs +++ b/src/ndim/nvec.rs @@ -12,6 +12,7 @@ use traits::dot::Dot; use traits::sub_dot::SubDot; use traits::norm::Norm; use traits::translation::Translation; +use traits::flatten::Flatten; use traits::workarounds::scalar_op::{ScalarMul, ScalarDiv, ScalarAdd, ScalarSub}; // D is a phantom parameter, used only as a dimensional token. @@ -196,3 +197,39 @@ impl Rand for NVec res } } + +impl Flatten for NVec +{ + fn flat_size() -> uint + { Dim::dim::() } + + fn from_flattened(l: &[N], off: uint) -> NVec + { + let dim = Dim::dim::(); + let mut res = Zero::zero::>(); + + for iterate(0u, dim) |i| + { res.at.at[i] = l[off + i] } + + res + } + + fn to_flattened(&self) -> ~[N] + { + let dim = Dim::dim::(); + let mut res = ~[]; + + for iterate(0u, dim) |i| + { res.push(self.at.at[i]) } + + res + } + + fn to_flattened_inplace(&self, l: &mut [N], off: uint) + { + let dim = Dim::dim::(); + + for iterate(0u, dim) |i| + { l[off + i] = self.at.at[i] } + } +} diff --git a/src/tests/mat.rs b/src/tests/mat.rs index d1dc19c4..afd49981 100644 --- a/src/tests/mat.rs +++ b/src/tests/mat.rs @@ -1,5 +1,7 @@ #[test] -use std::num::{Real, One, abs}; +use std::vec; +#[test] +use std::num::{Real, Zero, One, abs}; #[test] use std::rand::{random}; #[test] @@ -8,8 +10,8 @@ use std::cmp::ApproxEq; use traits::inv::Inv; #[test] use traits::rotation::Rotation; -// #[test] -// use traits::dim::d7; +#[test] +use traits::dim::d7; #[test] use dim1::vec1::Vec1; #[test] @@ -18,10 +20,12 @@ use dim1::mat1::Mat1; use dim2::mat2::Mat2; #[test] use dim3::mat3::Mat3; -// #[test] -// use ndim::nmat::NMat; +#[test] +use ndim::nmat::NMat; #[test] use adaptors::rotmat::Rotmat; +#[test] +use traits::flatten::Flatten; macro_rules! test_inv_mat_impl( ($t: ty) => ( @@ -34,6 +38,21 @@ macro_rules! test_inv_mat_impl( ); ) +macro_rules! test_flatten_impl( + ($t: ty, $n: ty) => ( + for 10000.times + { + let v: $t = random(); + let mut l: ~[$n] = vec::from_elem(42 + Flatten::flat_size::<$n, $t>(), Zero::zero::<$n>()); + + v.to_flattened_inplace(l, 42); + + assert!(Flatten::from_flattened::<$n, $t>(v.to_flattened(), 0) == v); + assert!(Flatten::from_flattened::<$n, $t>(l, 42) == v); + } + ) +) + #[test] fn test_inv_mat1() { test_inv_mat_impl!(Mat1); } @@ -51,6 +70,22 @@ fn test_inv_mat3() // fn test_inv_nmat() // { test_inv_mat_impl!(NMat); } +#[test] +fn test_flatten_mat1() +{ test_flatten_impl!(Mat1, f64); } + +#[test] +fn test_flatten_mat2() +{ test_flatten_impl!(Mat2, f64); } + +#[test] +fn test_flatten_mat3() +{ test_flatten_impl!(Mat3, f64); } + +#[test] +fn test_flatten_nmat() +{ test_flatten_impl!(NMat, f64); } + #[test] fn test_rotation2() { diff --git a/src/tests/vec.rs b/src/tests/vec.rs index 89941413..4dc9f479 100644 --- a/src/tests/vec.rs +++ b/src/tests/vec.rs @@ -1,4 +1,6 @@ #[test] +use std::vec; +#[test] use std::iterator::IteratorUtil; #[test] use std::num::{Zero, One}; @@ -24,6 +26,8 @@ use traits::cross::Cross; use traits::dot::Dot; #[test] use traits::norm::Norm; +#[test] +use traits::flatten::Flatten; macro_rules! test_commut_dot_impl( ($t: ty) => ( @@ -75,6 +79,21 @@ macro_rules! test_subspace_basis_impl( ); ) +macro_rules! test_flatten_impl( + ($t: ty, $n: ty) => ( + for 10000.times + { + let v: $t = random(); + let mut l: ~[$n] = vec::from_elem(42 + Flatten::flat_size::<$n, $t>(), Zero::zero::<$n>()); + + v.to_flattened_inplace(l, 42); + + assert!(Flatten::from_flattened::<$n, $t>(v.to_flattened(), 0) == v); + assert!(Flatten::from_flattened::<$n, $t>(l, 42) == v); + } + ) +) + #[test] fn test_cross_vec3() { @@ -136,3 +155,19 @@ fn test_subspace_basis_vec3() #[test] fn test_subspace_basis_nvec() { test_subspace_basis_impl!(NVec); } + +#[test] +fn test_flatten_vec1() +{ test_flatten_impl!(Vec1, f64); } + +#[test] +fn test_flatten_vec2() +{ test_flatten_impl!(Vec2, f64); } + +#[test] +fn test_flatten_vec3() +{ test_flatten_impl!(Vec3, f64); } + +#[test] +fn test_flatten_nvec() +{ test_flatten_impl!(NVec, f64); } diff --git a/src/traits/flatten.rs b/src/traits/flatten.rs new file mode 100644 index 00000000..21b30340 --- /dev/null +++ b/src/traits/flatten.rs @@ -0,0 +1,34 @@ +/// Trait of objects which can be written as a list of values, and read from +/// that list. +pub trait Flatten +{ + /// The number of elements needed to flatten this object. + fn flat_size() -> uint; + + /** + * Creates a new object from its flattened version. Its flattened version is + * a continuous list of values. It is assumet that `flat_size` elements will + * be read. + * + * - `l`: list from which the flat version must be read. + * - `off`: index from which (included) the flat version read must begin. + * It is assumed that the caller gives a valid input. + */ + fn from_flattened(l: &[N], off: uint) -> Self; // FIXME: keep (vector + index) or use an iterator? + + /** + * Creates a flattened version of `self`. The result vector must be of size + * `flat_size`. + */ + fn to_flattened(&self) -> ~[N]; + + /** + * Creates a flattened version of `self` on a vector. It is assumed that + * `flat_size` elements will be written contiguously. + * + * - `l`: list to which the flat version must be written. + * - `off`: index from which (included) the flat version write must begin. + * It is assumed that the caller allocated a long enough list. + */ + fn to_flattened_inplace(&self, l: &mut [N], off: uint); // FIXME: keep (vector + index) or use an iterator (to a mutable value…)? +}