diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a9575d0..d04a3bdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,20 +4,89 @@ documented here. This project adheres to [Semantic Versioning](http://semver.org/). -## [0.13.0] - WIP + +## [0.13.0] + +### Modified + * The trait `Axpy` takes one additional parameter for the type of `x`. + * The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we + reordered M and N to be in alphabetical order). + ### Added + * `alga::general::Real` is now re-exported by nalgebra. + * `.trace()` that computes the trace of a matrix (the sum of its diagonal + elements.) + * `::zeros(...)` that creates a matrix filled with zeroes. + * `::from_partial_diagonal(...)` that creates a matrix from diagonal elements. + The matrix can be rectangular. If not enough elements are provided, the rest + of the diagonal is set to 0. + * `.conjugate_transpose()` computes the transposed conjugate of a + complex matrix. + * `.conjugate_transpose_to(...)` computes the transposed conjugate of a + complex matrix. The result written into a user-provided matrix. + * `.transpose_to(...)` is the same as `.transpose()` but stores the result in + the provided matrix. + * `.conjugate_transpose_to(...)` is the same as `.conjugate_transpose()` but + stores the result in the provided matrix. + * Implements `IntoIterator` for `&Matrix`, `&mut Matrix` and `Matrix`. + * `.mul_to(...)` multiplies two matrices and stores the result to the given buffer. + * `.tr_mul_to(...)` left-multiplies `self.transpose()` to another matrix and stores the result to the given buffer. + * `.rows_range(...)` that retrieves a reference to a range of rows. + * `.rows_range_mut(...)` that retrieves a mutable reference to a range of rows. + * `.columns_range(...)` that retrieves a reference to a range of columns. + * `.columns_range_mut(...)` that retrieves a mutable reference to a range of columns. + * `.add_scalar(...)` that adds a scalar to each component of a matrix. + * `.add_scalar_mut(...)` that adds in-place a scalar to each component of a matrix. * `.kronecker(a, b)` computes the kronecker product (i.e. matrix tensor product) of two matrices. - * `.set_row(i, row)` sets the i-th row of the matrix. - * `.set_column(j, column)` sets the i-th column of the matrix. +Matrix decompositions: + * Cholesky, SVD, LU, QR, Hessenberg, Schur, Symmetric eigendecompositions, + Bidiagonal, Symmetric tridiagonal + * Computation of householder reflectors and givens rotations. + +Matrix edition: + * `.upper_triangle()` extracts the upper triangle of a matrix, including the diagonal. + * `.lower_triangle()` extracts the lower triangle of a matrix, including the diagonal. + * `.fill(...)` fills the matrix with a single value. + * `.fill_with_identity(...)` fills the matrix with the identity. + * `.fill_diagonal(...)` fills the matrix diagonal with a single value. + * `.fill_row(...)` fills a selected matrix row with a single value. + * `.fill_column(...)` fills a selected matrix column with a single value. + * `.set_diagonal(...)` sets the matrix diagonal. + * `.set_row(...)` sets a selected row. + * `.set_column(...)` sets a selected column. + * `.fill_lower_triangle(...)` fills some sub-diagonals bellow the main diagonal with a value. + * `.fill_upper_triangle(...)` fills some sub-diagonals above the main diagonal with a value. + * `.swap_rows(...)` swaps two rows. + * `.swap_columns(...)` swaps two columns. + +Column removal: + * `.remove_column(...)` removes one column. + * `.remove_fixed_columns(...)` removes `D` columns. + * `.remove_columns(...)` removes a number of columns known at run-time. + +Row removal: + * `.remove_row(...)` removes one row. + * `.remove_fixed_rows(...)` removes `D` rows. + * `.remove_rows(...)` removes a number of rows known at run-time. + +Column insertion: + * `.insert_column(...)` adds one column at the given position. + * `.insert_fixed_columns(...)` adds `D` columns at the given position. + * `.insert_columns(...)` adds at the given position a number of columns known at run-time. + +Row insertion: + * `.insert_row(...)` adds one row at the given position. + * `.insert_fixed_rows(...)` adds `D` rows at the given position. + * `.insert_rows(...)` adds at the given position a number of rows known at run-time. ## [0.12.0] The main change of this release is the update of the dependency serde to 1.0. ### Added - * `.trace()` that computes the trace of a matrix (i.e., the sum of its - diagonal elements.) + * `.trace()` that computes the trace of a matrix (the sum of its diagonal + elements.) ## [0.11.0] The [website](http://nalgebra.org) has been fully rewritten and gives a good diff --git a/Cargo.toml b/Cargo.toml index e57e3f48..bf8235b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,20 +16,21 @@ name = "nalgebra" path = "src/lib.rs" [features] -arbitrary = [ "quickcheck" ] +arbitrary = [ "quickcheck" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] +debug = [ ] [dependencies] -typenum = "1.4" -generic-array = "0.8" -rand = "0.3" -num-traits = "0.1" -num-complex = "0.1" -approx = "0.1" -alga = "0.5" -serde = { version = "1.0", optional = true } -serde_derive = { version = "1.0", optional = true } -# clippy = "*" +typenum = "1.7" +generic-array = "0.8" +rand = "0.3" +num-traits = "0.1" +num-complex = "0.1" +approx = "0.1" +alga = "0.5" +matrixmultiply = "0.1" +serde = { version = "1.0", optional = true } +serde_derive = { version = "1.0", optional = true } [dependencies.quickcheck] optional = true @@ -37,3 +38,6 @@ version = "0.4" [dev-dependencies] serde_json = "1.0" + +[workspace] +members = [ "nalgebra-lapack" ] diff --git a/Makefile b/Makefile index b0eb255d..ad1fafcc 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ all: - CARGO_INCREMENTAL=1 cargo build --features "arbitrary serde-serialize" + cargo check --features "debug arbitrary serde-serialize" doc: - CARGO_INCREMENTAL=1 cargo doc --no-deps --features "arbitrary serde-serialize" + cargo doc --no-deps --features "debug arbitrary serde-serialize" bench: cargo bench test: - cargo test --features "arbitrary serde-serialize" + cargo test --features "debug arbitrary serde-serialize" diff --git a/benches/common/macros.rs b/benches/common/macros.rs index 74b0e0cc..55d6ba3c 100644 --- a/benches/common/macros.rs +++ b/benches/common/macros.rs @@ -4,20 +4,12 @@ macro_rules! bench_binop( ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { #[bench] fn $name(bh: &mut Bencher) { - const LEN: usize = 1 << 13; - let mut rng = IsaacRng::new_unseeded(); - - let elems1: Vec<$t1> = (0usize .. LEN).map(|_| rng.gen::<$t1>()).collect(); - let elems2: Vec<$t2> = (0usize .. LEN).map(|_| rng.gen::<$t2>()).collect(); - let mut i = 0; + let a = rng.gen::<$t1>(); + let b = rng.gen::<$t2>(); bh.iter(|| { - i = (i + 1) & (LEN - 1); - - unsafe { - test::black_box(elems1.get_unchecked(i).$binop(*elems2.get_unchecked(i))) - } + a.$binop(b) }) } } @@ -27,43 +19,27 @@ macro_rules! bench_binop_ref( ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { #[bench] fn $name(bh: &mut Bencher) { - const LEN: usize = 1 << 13; - let mut rng = IsaacRng::new_unseeded(); - - let elems1: Vec<$t1> = (0usize .. LEN).map(|_| rng.gen::<$t1>()).collect(); - let elems2: Vec<$t2> = (0usize .. LEN).map(|_| rng.gen::<$t2>()).collect(); - let mut i = 0; + let a = rng.gen::<$t1>(); + let b = rng.gen::<$t2>(); bh.iter(|| { - i = (i + 1) & (LEN - 1); - - unsafe { - test::black_box(elems1.get_unchecked(i).$binop(elems2.get_unchecked(i))) - } + a.$binop(&b) }) } } ); -macro_rules! bench_binop_na( - ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { +macro_rules! bench_binop_fn( + ($name: ident, $t1: ty, $t2: ty, $binop: path) => { #[bench] fn $name(bh: &mut Bencher) { - const LEN: usize = 1 << 13; - let mut rng = IsaacRng::new_unseeded(); - - let elems1: Vec<$t1> = (0usize .. LEN).map(|_| rng.gen::<$t1>()).collect(); - let elems2: Vec<$t2> = (0usize .. LEN).map(|_| rng.gen::<$t2>()).collect(); - let mut i = 0; + let a = rng.gen::<$t1>(); + let b = rng.gen::<$t2>(); bh.iter(|| { - i = (i + 1) & (LEN - 1); - - unsafe { - test::black_box(na::$binop(elems1.get_unchecked(i), elems2.get_unchecked(i))) - } + $binop(&a, &b) }) } } diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs new file mode 100644 index 00000000..442adafe --- /dev/null +++ b/benches/core/matrix.rs @@ -0,0 +1,192 @@ +use rand::{IsaacRng, Rng}; +use test::{self, Bencher}; +use na::{Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, + MatrixN, U10, + DMatrix, DVector}; +use std::ops::{Add, Sub, Mul, Div}; + +#[path="../common/macros.rs"] +mod macros; + +bench_binop!(mat2_mul_m, Matrix2, Matrix2, mul); +bench_binop!(mat3_mul_m, Matrix3, Matrix3, mul); +bench_binop!(mat4_mul_m, Matrix4, Matrix4, mul); + +bench_binop_ref!(mat2_tr_mul_m, Matrix2, Matrix2, tr_mul); +bench_binop_ref!(mat3_tr_mul_m, Matrix3, Matrix3, tr_mul); +bench_binop_ref!(mat4_tr_mul_m, Matrix4, Matrix4, tr_mul); + +bench_binop!(mat2_add_m, Matrix2, Matrix2, add); +bench_binop!(mat3_add_m, Matrix3, Matrix3, add); +bench_binop!(mat4_add_m, Matrix4, Matrix4, add); + +bench_binop!(mat2_sub_m, Matrix2, Matrix2, sub); +bench_binop!(mat3_sub_m, Matrix3, Matrix3, sub); +bench_binop!(mat4_sub_m, Matrix4, Matrix4, sub); + +bench_binop!(mat2_mul_v, Matrix2, Vector2, mul); +bench_binop!(mat3_mul_v, Matrix3, Vector3, mul); +bench_binop!(mat4_mul_v, Matrix4, Vector4, mul); + +bench_binop_ref!(mat2_tr_mul_v, Matrix2, Vector2, tr_mul); +bench_binop_ref!(mat3_tr_mul_v, Matrix3, Vector3, tr_mul); +bench_binop_ref!(mat4_tr_mul_v, Matrix4, Vector4, tr_mul); + +bench_binop!(mat2_mul_s, Matrix2, f32, mul); +bench_binop!(mat3_mul_s, Matrix3, f32, mul); +bench_binop!(mat4_mul_s, Matrix4, f32, mul); + +bench_binop!(mat2_div_s, Matrix2, f32, div); +bench_binop!(mat3_div_s, Matrix3, f32, div); +bench_binop!(mat4_div_s, Matrix4, f32, div); + +bench_unop!(mat2_inv, Matrix2, try_inverse); +bench_unop!(mat3_inv, Matrix3, try_inverse); +bench_unop!(mat4_inv, Matrix4, try_inverse); + +bench_unop!(mat2_transpose, Matrix2, transpose); +bench_unop!(mat3_transpose, Matrix3, transpose); +bench_unop!(mat4_transpose, Matrix4, transpose); + +#[bench] +fn mat_div_scalar(b: &mut Bencher) { + let a = DMatrix::from_row_slice(1000, 1000, &vec![2.0;1000000]); + let n = 42.0; + + b.iter(|| { + let mut aa = a.clone(); + let mut b = aa.slice_mut((0, 0), (1000, 1000)); + b /= n + }) +} + +#[bench] +fn mat100_add_mat100(bench: &mut Bencher) { + let a = DMatrix::::new_random(100, 100); + let b = DMatrix::::new_random(100, 100); + + bench.iter(|| { &a + &b }) +} + +#[bench] +fn mat4_mul_mat4(bench: &mut Bencher) { + let a = DMatrix::::new_random(4, 4); + let b = DMatrix::::new_random(4, 4); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat5_mul_mat5(bench: &mut Bencher) { + let a = DMatrix::::new_random(5, 5); + let b = DMatrix::::new_random(5, 5); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat6_mul_mat6(bench: &mut Bencher) { + let a = DMatrix::::new_random(6, 6); + let b = DMatrix::::new_random(6, 6); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat7_mul_mat7(bench: &mut Bencher) { + let a = DMatrix::::new_random(7, 7); + let b = DMatrix::::new_random(7, 7); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat8_mul_mat8(bench: &mut Bencher) { + let a = DMatrix::::new_random(8, 8); + let b = DMatrix::::new_random(8, 8); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat9_mul_mat9(bench: &mut Bencher) { + let a = DMatrix::::new_random(9, 9); + let b = DMatrix::::new_random(9, 9); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat10_mul_mat10(bench: &mut Bencher) { + let a = DMatrix::::new_random(10, 10); + let b = DMatrix::::new_random(10, 10); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat10_mul_mat10_static(bench: &mut Bencher) { + let a = MatrixN::::new_random(); + let b = MatrixN::::new_random(); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat100_mul_mat100(bench: &mut Bencher) { + let a = DMatrix::::new_random(100, 100); + let b = DMatrix::::new_random(100, 100); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn mat500_mul_mat500(bench: &mut Bencher) { + let a = DMatrix::::from_element(500, 500, 5f64); + let b = DMatrix::::from_element(500, 500, 6f64); + + bench.iter(|| { &a * &b }) +} + +#[bench] +fn copy_from(bench: &mut Bencher) { + let a = DMatrix::::new_random(1000, 1000); + let mut b = DMatrix::::new_random(1000, 1000); + + bench.iter(|| { + b.copy_from(&a); + }) +} + +#[bench] +fn axpy(bench: &mut Bencher) { + let x = DVector::::from_element(100000, 2.0); + let mut y = DVector::::from_element(100000, 3.0); + let a = 42.0; + + bench.iter(|| { + y.axpy(a, &x, 1.0); + }) +} + +#[bench] +fn tr_mul_to(bench: &mut Bencher) { + let a = DMatrix::::new_random(1000, 1000); + let b = DVector::::new_random(1000); + let mut c = DVector::from_element(1000, 0.0); + + bench.iter(|| { + a.tr_mul_to(&b, &mut c) + }) +} + +#[bench] +fn mat_mul_mat(bench: &mut Bencher) { + let a = DMatrix::::new_random(100, 100); + let b = DMatrix::::new_random(100, 100); + let mut ab = DMatrix::::from_element(100, 100, 0.0); + + bench.iter(|| { + test::black_box(a.mul_to(&b, &mut ab)); + }) +} diff --git a/benches/core/mod.rs b/benches/core/mod.rs new file mode 100644 index 00000000..9699a728 --- /dev/null +++ b/benches/core/mod.rs @@ -0,0 +1,2 @@ +mod matrix; +mod vector; diff --git a/benches/core/vector.rs b/benches/core/vector.rs new file mode 100644 index 00000000..fb94de36 --- /dev/null +++ b/benches/core/vector.rs @@ -0,0 +1,128 @@ +use rand::{IsaacRng, Rng}; +use test::{self, Bencher}; +use typenum::U10000; +use na::{Vector2, Vector3, Vector4, VectorN, DVector}; +use std::ops::{Add, Sub, Mul, Div}; + +#[path="../common/macros.rs"] +mod macros; + +bench_binop!(vec2_add_v_f32, Vector2, Vector2, add); +bench_binop!(vec3_add_v_f32, Vector3, Vector3, add); +bench_binop!(vec4_add_v_f32, Vector4, Vector4, add); + +bench_binop!(vec2_add_v_f64, Vector2, Vector2, add); +bench_binop!(vec3_add_v_f64, Vector3, Vector3, add); +bench_binop!(vec4_add_v_f64, Vector4, Vector4, add); + +bench_binop!(vec2_sub_v, Vector2, Vector2, sub); +bench_binop!(vec3_sub_v, Vector3, Vector3, sub); +bench_binop!(vec4_sub_v, Vector4, Vector4, sub); + +bench_binop!(vec2_mul_s, Vector2, f32, mul); +bench_binop!(vec3_mul_s, Vector3, f32, mul); +bench_binop!(vec4_mul_s, Vector4, f32, mul); + +bench_binop!(vec2_div_s, Vector2, f32, div); +bench_binop!(vec3_div_s, Vector3, f32, div); +bench_binop!(vec4_div_s, Vector4, f32, div); + +bench_binop_ref!(vec2_dot_f32, Vector2, Vector2, dot); +bench_binop_ref!(vec3_dot_f32, Vector3, Vector3, dot); +bench_binop_ref!(vec4_dot_f32, Vector4, Vector4, dot); + +bench_binop_ref!(vec2_dot_f64, Vector2, Vector2, dot); +bench_binop_ref!(vec3_dot_f64, Vector3, Vector3, dot); +bench_binop_ref!(vec4_dot_f64, Vector4, Vector4, dot); + +bench_binop_ref!(vec3_cross, Vector3, Vector3, cross); + +bench_unop!(vec2_norm, Vector2, norm); +bench_unop!(vec3_norm, Vector3, norm); +bench_unop!(vec4_norm, Vector4, norm); + +bench_unop!(vec2_normalize, Vector2, normalize); +bench_unop!(vec3_normalize, Vector3, normalize); +bench_unop!(vec4_normalize, Vector4, normalize); + +bench_binop_ref!(vec10000_dot_f64, VectorN, VectorN, dot); +bench_binop_ref!(vec10000_dot_f32, VectorN, VectorN, dot); + +#[bench] +fn vec10000_axpy_f64(bh: &mut Bencher) { + let mut rng = IsaacRng::new_unseeded(); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + + bh.iter(|| { + a.axpy(n, &b, 1.0) + }) +} + +#[bench] +fn vec10000_axpy_beta_f64(bh: &mut Bencher) { + let mut rng = IsaacRng::new_unseeded(); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + let beta = rng.gen::(); + + bh.iter(|| { + a.axpy(n, &b, beta) + }) +} + +#[bench] +fn vec10000_axpy_f64_slice(bh: &mut Bencher) { + let mut rng = IsaacRng::new_unseeded(); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + + bh.iter(|| { + let mut a = a.fixed_rows_mut::(0); + let b = b.fixed_rows::(0); + + a.axpy(n, &b, 1.0) + }) +} + +#[bench] +fn vec10000_axpy_f64_static(bh: &mut Bencher) { + let mut rng = IsaacRng::new_unseeded(); + let mut a = VectorN::::new_random(); + let b = VectorN::::new_random(); + let n = rng.gen::(); + + // NOTE: for some reasons, it is much faster if the arument are boxed (Box::new(VectorN...)). + bh.iter(|| { + a.axpy(n, &b, 1.0) + }) +} + + +#[bench] +fn vec10000_axpy_f32(bh: &mut Bencher) { + let mut rng = IsaacRng::new_unseeded(); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + + bh.iter(|| { + a.axpy(n, &b, 1.0) + }) +} + +#[bench] +fn vec10000_axpy_beta_f32(bh: &mut Bencher) { + let mut rng = IsaacRng::new_unseeded(); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + let beta = rng.gen::(); + + bh.iter(|| { + a.axpy(n, &b, beta) + }) +} diff --git a/benches/geometry/mod.rs b/benches/geometry/mod.rs new file mode 100644 index 00000000..0f9eb371 --- /dev/null +++ b/benches/geometry/mod.rs @@ -0,0 +1 @@ +mod quaternion; diff --git a/benches/geometry/quaternion.rs b/benches/geometry/quaternion.rs new file mode 100644 index 00000000..0740ee63 --- /dev/null +++ b/benches/geometry/quaternion.rs @@ -0,0 +1,22 @@ +use rand::{IsaacRng, Rng}; +use test::{self, Bencher}; +use na::{Quaternion, UnitQuaternion, Vector3}; +use std::ops::{Add, Sub, Mul, Div}; + +#[path="../common/macros.rs"] +mod macros; + +bench_binop!(quaternion_add_q, Quaternion, Quaternion, add); +bench_binop!(quaternion_sub_q, Quaternion, Quaternion, sub); +bench_binop!(quaternion_mul_q, Quaternion, Quaternion, mul); + +bench_binop!(unit_quaternion_mul_v, UnitQuaternion, Vector3, mul); + +bench_binop!(quaternion_mul_s, Quaternion, f32, mul); +bench_binop!(quaternion_div_s, Quaternion, f32, div); + +bench_unop!(quaternion_inv, Quaternion, try_inverse); +bench_unop!(unit_quaternion_inv, UnitQuaternion, inverse); + +// bench_unop_self!(quaternion_conjugate, Quaternion, conjugate); +// bench_unop!(quaternion_normalize, Quaternion, normalize); diff --git a/benches/lib.rs b/benches/lib.rs new file mode 100644 index 00000000..7acdc3c0 --- /dev/null +++ b/benches/lib.rs @@ -0,0 +1,20 @@ +#![feature(test)] + +extern crate test; +extern crate rand; +extern crate typenum; +extern crate nalgebra as na; + + +use rand::{Rng, IsaacRng}; +use na::DMatrix; + + +mod core; +mod linalg; +mod geometry; + +fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix { + let mut rng = IsaacRng::new_unseeded(); + DMatrix::::from_fn(nrows, ncols, |_, _| rng.gen()) +} diff --git a/benches/linalg/bidiagonal.rs b/benches/linalg/bidiagonal.rs new file mode 100644 index 00000000..e35ae109 --- /dev/null +++ b/benches/linalg/bidiagonal.rs @@ -0,0 +1,75 @@ +use test::{self, Bencher}; +use na::{Matrix4, DMatrix, Bidiagonal}; + +#[path="../common/macros.rs"] +mod macros; + +// Without unpack. +#[bench] +fn bidiagonalize_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) +} + +#[bench] +fn bidiagonalize_100x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 500); + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) +} + +#[bench] +fn bidiagonalize_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) +} + +#[bench] +fn bidiagonalize_500x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 100); + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) +} + +#[bench] +fn bidiagonalize_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) +} + + +// With unpack. +#[bench] +fn bidiagonalize_unpack_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) +} + +#[bench] +fn bidiagonalize_unpack_100x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 500); + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) +} + +#[bench] +fn bidiagonalize_unpack_500x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 100); + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) +} + +#[bench] +fn bidiagonalize_unpack_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) +} + diff --git a/benches/linalg/cholesky.rs b/benches/linalg/cholesky.rs new file mode 100644 index 00000000..6337c226 --- /dev/null +++ b/benches/linalg/cholesky.rs @@ -0,0 +1,109 @@ +use test::{self, Bencher}; +use na::{DMatrix, DVector, Cholesky}; + +#[bench] +fn cholesky_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + + bh.iter(|| test::black_box(Cholesky::new(m.clone()))) +} + +#[bench] +fn cholesky_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + + bh.iter(|| test::black_box(Cholesky::new(m.clone()))) +} + +// With unpack. +#[bench] +fn cholesky_decompose_unpack_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + + bh.iter(|| { + let chol = Cholesky::new(m.clone()).unwrap(); + let _ = chol.unpack(); + }) +} +#[bench] +fn cholesky_decompose_unpack_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + + bh.iter(|| { + let chol = Cholesky::new(m.clone()).unwrap(); + let _ = chol.unpack(); + }) +} + +#[bench] +fn cholesky_solve_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let m = &m * m.transpose(); + let v = DVector::::new_random(10); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.iter(|| { + let _ = chol.solve(&v); + }) +} + +#[bench] +fn cholesky_solve_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + let v = DVector::::new_random(100); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.iter(|| { + let _ = chol.solve(&v); + }) +} + +#[bench] +fn cholesky_solve_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + let v = DVector::::new_random(500); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.iter(|| { + let _ = chol.solve(&v); + }) +} + +#[bench] +fn cholesky_inverse_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let m = &m * m.transpose(); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.iter(|| { + let _ = chol.inverse(); + }) +} + +#[bench] +fn cholesky_inverse_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.iter(|| { + let _ = chol.inverse(); + }) +} + +#[bench] +fn cholesky_inverse_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.iter(|| { + let _ = chol.inverse(); + }) +} diff --git a/benches/linalg/eigen.rs b/benches/linalg/eigen.rs new file mode 100644 index 00000000..54aa77a5 --- /dev/null +++ b/benches/linalg/eigen.rs @@ -0,0 +1,30 @@ +use test::Bencher; +use na::{DMatrix, Eigen}; + +#[bench] +fn eigen_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + + bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0)) +} + +#[bench] +fn eigen_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + + bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0)) +} + +#[bench] +fn eigenvalues_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + + bh.iter(|| m.clone().eigenvalues(1.0e-7, 0)) +} + +#[bench] +fn eigenvalues_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + + bh.iter(|| m.clone().eigenvalues(1.0e-7, 0)) +} diff --git a/benches/linalg/full_piv_lu.rs b/benches/linalg/full_piv_lu.rs new file mode 100644 index 00000000..e98e13dd --- /dev/null +++ b/benches/linalg/full_piv_lu.rs @@ -0,0 +1,114 @@ +use test::{self, Bencher}; +use na::{DMatrix, DVector, FullPivLU}; + +// Without unpack. +#[bench] +fn full_piv_lu_decompose_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + bh.iter(|| test::black_box(FullPivLU::new(m.clone()))) +} + +#[bench] +fn full_piv_lu_decompose_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| test::black_box(FullPivLU::new(m.clone()))) +} + +#[bench] +fn full_piv_lu_decompose_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| test::black_box(FullPivLU::new(m.clone()))) +} + +#[bench] +fn full_piv_lu_solve_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + lu.solve(&mut b); + }) +} + +#[bench] +fn full_piv_lu_solve_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + lu.solve(&mut b); + }) +} + +#[bench] +fn full_piv_lu_solve_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + lu.solve(&mut b); + }) +} + +#[bench] +fn full_piv_lu_inverse_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.try_inverse()) + }) +} + +#[bench] +fn full_piv_lu_inverse_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.try_inverse()) + }) +} + +#[bench] +fn full_piv_lu_inverse_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.try_inverse()) + }) +} + +#[bench] +fn full_piv_lu_determinant_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.determinant()) + }) +} + +#[bench] +fn full_piv_lu_determinant_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.determinant()) + }) +} + +#[bench] +fn full_piv_lu_determinant_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let lu = FullPivLU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.determinant()) + }) +} diff --git a/benches/linalg/hessenberg.rs b/benches/linalg/hessenberg.rs new file mode 100644 index 00000000..90e00b98 --- /dev/null +++ b/benches/linalg/hessenberg.rs @@ -0,0 +1,60 @@ +use test::{self, Bencher}; +use na::{Matrix4, DMatrix, Hessenberg}; + +#[path="../common/macros.rs"] +mod macros; + +// Without unpack. +#[bench] +fn hessenberg_decompose_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) +} + +#[bench] +fn hessenberg_decompose_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) +} + +#[bench] +fn hessenberg_decompose_200x200(bh: &mut Bencher) { + let m = DMatrix::::new_random(200, 200); + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) +} + + +#[bench] +fn hessenberg_decompose_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) +} + + +// With unpack. +#[bench] +fn hessenberg_decompose_unpack_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) +} + +#[bench] +fn hessenberg_decompose_unpack_200x200(bh: &mut Bencher) { + let m = DMatrix::::new_random(200, 200); + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) +} + +#[bench] +fn hessenberg_decompose_unpack_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) +} diff --git a/benches/linalg/lu.rs b/benches/linalg/lu.rs new file mode 100644 index 00000000..33cbb3a5 --- /dev/null +++ b/benches/linalg/lu.rs @@ -0,0 +1,114 @@ +use test::{self, Bencher}; +use na::{DMatrix, DVector, LU}; + +// Without unpack. +#[bench] +fn lu_decompose_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + bh.iter(|| test::black_box(LU::new(m.clone()))) +} + +#[bench] +fn lu_decompose_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| test::black_box(LU::new(m.clone()))) +} + +#[bench] +fn lu_decompose_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| test::black_box(LU::new(m.clone()))) +} + +#[bench] +fn lu_solve_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let lu = LU::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + lu.solve(&mut b); + }) +} + +#[bench] +fn lu_solve_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let lu = LU::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + lu.solve(&mut b); + }) +} + +#[bench] +fn lu_solve_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let lu = LU::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + lu.solve(&mut b); + }) +} + +#[bench] +fn lu_inverse_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let lu = LU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.try_inverse()) + }) +} + +#[bench] +fn lu_inverse_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let lu = LU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.try_inverse()) + }) +} + +#[bench] +fn lu_inverse_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let lu = LU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.try_inverse()) + }) +} + +#[bench] +fn lu_determinant_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let lu = LU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.determinant()) + }) +} + +#[bench] +fn lu_determinant_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let lu = LU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.determinant()) + }) +} + +#[bench] +fn lu_determinant_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let lu = LU::new(m.clone()); + + bh.iter(|| { + test::black_box(lu.determinant()) + }) +} diff --git a/benches/linalg/mod.rs b/benches/linalg/mod.rs new file mode 100644 index 00000000..c2cc4ade --- /dev/null +++ b/benches/linalg/mod.rs @@ -0,0 +1,11 @@ +mod solve; +mod cholesky; +mod qr; +mod hessenberg; +mod bidiagonal; +mod lu; +mod full_piv_lu; +mod svd; +mod schur; +mod symmetric_eigen; +// mod eigen; diff --git a/benches/linalg/qr.rs b/benches/linalg/qr.rs new file mode 100644 index 00000000..a2d455ea --- /dev/null +++ b/benches/linalg/qr.rs @@ -0,0 +1,137 @@ +use test::{self, Bencher}; +use na::{Matrix4, DMatrix, DVector, QR}; + +#[path="../common/macros.rs"] +mod macros; + +// Without unpack. +#[bench] +fn qr_decompose_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| test::black_box(QR::new(m.clone()))) +} + +#[bench] +fn qr_decompose_100x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 500); + bh.iter(|| test::black_box(QR::new(m.clone()))) +} + +#[bench] +fn qr_decompose_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(QR::new(m.clone()))) +} + +#[bench] +fn qr_decompose_500x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 100); + bh.iter(|| test::black_box(QR::new(m.clone()))) +} + +#[bench] +fn qr_decompose_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| test::black_box(QR::new(m.clone()))) +} + + +// With unpack. +#[bench] +fn qr_decompose_unpack_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) +} + +#[bench] +fn qr_decompose_unpack_100x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 500); + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) +} + +#[bench] +fn qr_decompose_unpack_500x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 100); + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) +} + +#[bench] +fn qr_decompose_unpack_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) +} + +#[bench] +fn qr_solve_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let qr = QR::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + qr.solve(&mut b); + }) +} + +#[bench] +fn qr_solve_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let qr = QR::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + qr.solve(&mut b); + }) +} + +#[bench] +fn qr_solve_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let qr = QR::new(m.clone()); + + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + qr.solve(&mut b); + }) +} + +#[bench] +fn qr_inverse_10x10(bh: &mut Bencher) { + let m = DMatrix::::new_random(10, 10); + let qr = QR::new(m.clone()); + + bh.iter(|| { + test::black_box(qr.try_inverse()) + }) +} + +#[bench] +fn qr_inverse_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let qr = QR::new(m.clone()); + + bh.iter(|| { + test::black_box(qr.try_inverse()) + }) +} + +#[bench] +fn qr_inverse_500x500(bh: &mut Bencher) { + let m = DMatrix::::new_random(500, 500); + let qr = QR::new(m.clone()); + + bh.iter(|| { + test::black_box(qr.try_inverse()) + }) +} diff --git a/benches/linalg/schur.rs b/benches/linalg/schur.rs new file mode 100644 index 00000000..0b16d0c1 --- /dev/null +++ b/benches/linalg/schur.rs @@ -0,0 +1,51 @@ +use test::{self, Bencher}; +use na::{Matrix4, RealSchur}; + +#[bench] +fn schur_decompose_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(RealSchur::new(m.clone()))) +} + +#[bench] +fn schur_decompose_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(RealSchur::new(m.clone()))) +} + + +#[bench] +fn schur_decompose_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(RealSchur::new(m.clone()))) +} + +#[bench] +fn schur_decompose_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(RealSchur::new(m.clone()))) +} + +#[bench] +fn eigenvalues_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(m.complex_eigenvalues())) +} + +#[bench] +fn eigenvalues_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(m.complex_eigenvalues())) +} + +#[bench] +fn eigenvalues_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(m.complex_eigenvalues())) +} + +#[bench] +fn eigenvalues_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(m.complex_eigenvalues())) +} diff --git a/benches/linalg/solve.rs b/benches/linalg/solve.rs new file mode 100644 index 00000000..3362549a --- /dev/null +++ b/benches/linalg/solve.rs @@ -0,0 +1,82 @@ +use test::Bencher; +use na::{DMatrix, DVector}; + +#[bench] +fn solve_l_triangular_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.iter(|| { + let _ = m.solve_lower_triangular(&v); + }) +} + +#[bench] +fn solve_l_triangular_1000x1000(bh: &mut Bencher) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.iter(|| { + let _ = m.solve_lower_triangular(&v); + }) +} + +#[bench] +fn tr_solve_l_triangular_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.iter(|| { + let _ = m.tr_solve_lower_triangular(&v); + }) +} + +#[bench] +fn tr_solve_l_triangular_1000x1000(bh: &mut Bencher) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.iter(|| { + let _ = m.tr_solve_lower_triangular(&v); + }) +} + +#[bench] +fn solve_u_triangular_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.iter(|| { + let _ = m.solve_upper_triangular(&v); + }) +} + +#[bench] +fn solve_u_triangular_1000x1000(bh: &mut Bencher) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.iter(|| { + let _ = m.solve_upper_triangular(&v); + }) +} + +#[bench] +fn tr_solve_u_triangular_100x100(bh: &mut Bencher) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.iter(|| { + let _ = m.tr_solve_upper_triangular(&v); + }) +} + +#[bench] +fn tr_solve_u_triangular_1000x1000(bh: &mut Bencher) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.iter(|| { + let _ = m.tr_solve_upper_triangular(&v); + }) +} diff --git a/benches/linalg/svd.rs b/benches/linalg/svd.rs new file mode 100644 index 00000000..74cdd344 --- /dev/null +++ b/benches/linalg/svd.rs @@ -0,0 +1,99 @@ +use test::{self, Bencher}; +use na::{Matrix4, SVD}; + +#[bench] +fn svd_decompose_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) +} + +#[bench] +fn svd_decompose_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) +} + +#[bench] +fn svd_decompose_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) +} + +#[bench] +fn svd_decompose_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) +} + +#[bench] +fn rank_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(m.rank(1.0e-10))) +} + +#[bench] +fn rank_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(m.rank(1.0e-10))) +} + +#[bench] +fn rank_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(m.rank(1.0e-10))) +} + +#[bench] +fn rank_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(m.rank(1.0e-10))) +} + +#[bench] +fn singular_values_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(m.singular_values())) +} + +#[bench] +fn singular_values_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(m.singular_values())) +} + +#[bench] +fn singular_values_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(m.singular_values())) +} + +#[bench] +fn singular_values_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(m.singular_values())) +} + + +#[bench] +fn pseudo_inverse_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) +} + +#[bench] +fn pseudo_inverse_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) +} + +#[bench] +fn pseudo_inverse_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) +} + +#[bench] +fn pseudo_inverse_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) +} diff --git a/benches/linalg/symmetric_eigen.rs b/benches/linalg/symmetric_eigen.rs new file mode 100644 index 00000000..07e7b3f3 --- /dev/null +++ b/benches/linalg/symmetric_eigen.rs @@ -0,0 +1,27 @@ +use test::{self, Bencher}; +use na::{Matrix4, SymmetricEigen}; + +#[bench] +fn symmetric_eigen_decompose_4x4(bh: &mut Bencher) { + let m = Matrix4::::new_random(); + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) +} + +#[bench] +fn symmetric_eigen_decompose_10x10(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(10, 10); + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) +} + + +#[bench] +fn symmetric_eigen_decompose_100x100(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(100, 100); + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) +} + +#[bench] +fn symmetric_eigen_decompose_200x200(bh: &mut Bencher) { + let m = ::reproductible_dmatrix(200, 200); + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) +} diff --git a/benches/matrix.rs b/benches/matrix.rs deleted file mode 100644 index 8403b5b7..00000000 --- a/benches/matrix.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate rand; -extern crate nalgebra as na; - -use rand::{IsaacRng, Rng}; -use test::Bencher; -use na::{Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4}; -use std::ops::{Add, Sub, Mul, Div}; - -#[path="common/macros.rs"] -mod macros; - -bench_binop!(_bench_mat2_mul_m, Matrix2, Matrix2, mul); -bench_binop!(_bench_mat3_mul_m, Matrix3, Matrix3, mul); -bench_binop!(_bench_mat4_mul_m, Matrix4, Matrix4, mul); - -bench_binop_ref!(_bench_mat2_tr_mul_m, Matrix2, Matrix2, tr_mul); -bench_binop_ref!(_bench_mat3_tr_mul_m, Matrix3, Matrix3, tr_mul); -bench_binop_ref!(_bench_mat4_tr_mul_m, Matrix4, Matrix4, tr_mul); - -bench_binop!(_bench_mat2_add_m, Matrix2, Matrix2, add); -bench_binop!(_bench_mat3_add_m, Matrix3, Matrix3, add); -bench_binop!(_bench_mat4_add_m, Matrix4, Matrix4, add); - -bench_binop!(_bench_mat2_sub_m, Matrix2, Matrix2, sub); -bench_binop!(_bench_mat3_sub_m, Matrix3, Matrix3, sub); -bench_binop!(_bench_mat4_sub_m, Matrix4, Matrix4, sub); - -bench_binop!(_bench_mat2_mul_v, Matrix2, Vector2, mul); -bench_binop!(_bench_mat3_mul_v, Matrix3, Vector3, mul); -bench_binop!(_bench_mat4_mul_v, Matrix4, Vector4, mul); - -bench_binop_ref!(_bench_mat2_tr_mul_v, Matrix2, Vector2, tr_mul); -bench_binop_ref!(_bench_mat3_tr_mul_v, Matrix3, Vector3, tr_mul); -bench_binop_ref!(_bench_mat4_tr_mul_v, Matrix4, Vector4, tr_mul); - -bench_binop!(_bench_mat2_mul_s, Matrix2, f32, mul); -bench_binop!(_bench_mat3_mul_s, Matrix3, f32, mul); -bench_binop!(_bench_mat4_mul_s, Matrix4, f32, mul); - -bench_binop!(_bench_mat2_div_s, Matrix2, f32, div); -bench_binop!(_bench_mat3_div_s, Matrix3, f32, div); -bench_binop!(_bench_mat4_div_s, Matrix4, f32, div); - -bench_unop!(_bench_mat2_inv, Matrix2, try_inverse); -bench_unop!(_bench_mat3_inv, Matrix3, try_inverse); -bench_unop!(_bench_mat4_inv, Matrix4, try_inverse); - -bench_unop!(_bench_mat2_transpose, Matrix2, transpose); -bench_unop!(_bench_mat3_transpose, Matrix3, transpose); -bench_unop!(_bench_mat4_transpose, Matrix4, transpose); diff --git a/benches/quaternion.rs b/benches/quaternion.rs deleted file mode 100644 index f1c66ef5..00000000 --- a/benches/quaternion.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate rand; -extern crate nalgebra as na; - -use rand::{IsaacRng, Rng}; -use test::Bencher; -use na::{Quaternion, UnitQuaternion, Vector3}; -use std::ops::{Add, Sub, Mul, Div}; - -#[path="common/macros.rs"] -mod macros; - -bench_binop!(_bench_quaternion_add_q, Quaternion, Quaternion, add); -bench_binop!(_bench_quaternion_sub_q, Quaternion, Quaternion, sub); -bench_binop!(_bench_quaternion_mul_q, Quaternion, Quaternion, mul); - -bench_binop!(_bench_unit_quaternion_mul_v, UnitQuaternion, Vector3, mul); - -bench_binop!(_bench_quaternion_mul_s, Quaternion, f32, mul); -bench_binop!(_bench_quaternion_div_s, Quaternion, f32, div); - -bench_unop!(_bench_quaternion_inv, Quaternion, try_inverse); -bench_unop!(_bench_unit_quaternion_inv, UnitQuaternion, inverse); - -// bench_unop_self!(_bench_quaternion_conjugate, Quaternion, conjugate); -// bench_unop!(_bench_quaternion_normalize, Quaternion, normalize); diff --git a/benches/vector.rs b/benches/vector.rs deleted file mode 100644 index aa897145..00000000 --- a/benches/vector.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate rand; -extern crate nalgebra as na; - -use rand::{IsaacRng, Rng}; -use test::Bencher; -use na::{Vector2, Vector3, Vector4}; -use std::ops::{Add, Sub, Mul, Div}; - -#[path="common/macros.rs"] -mod macros; - -bench_binop!(_bench_vec2_add_v, Vector2, Vector2, add); -bench_binop!(_bench_vec3_add_v, Vector3, Vector3, add); -bench_binop!(_bench_vec4_add_v, Vector4, Vector4, add); - -bench_binop!(_bench_vec2_sub_v, Vector2, Vector2, sub); -bench_binop!(_bench_vec3_sub_v, Vector3, Vector3, sub); -bench_binop!(_bench_vec4_sub_v, Vector4, Vector4, sub); - -bench_binop!(_bench_vec2_mul_s, Vector2, f32, mul); -bench_binop!(_bench_vec3_mul_s, Vector3, f32, mul); -bench_binop!(_bench_vec4_mul_s, Vector4, f32, mul); - -bench_binop!(_bench_vec2_div_s, Vector2, f32, div); -bench_binop!(_bench_vec3_div_s, Vector3, f32, div); -bench_binop!(_bench_vec4_div_s, Vector4, f32, div); - -bench_binop_ref!(_bench_vec2_dot, Vector2, Vector2, dot); -bench_binop_ref!(_bench_vec3_dot, Vector3, Vector3, dot); -bench_binop_ref!(_bench_vec4_dot, Vector4, Vector4, dot); - -bench_binop_ref!(_bench_vec3_cross, Vector3, Vector3, cross); - -bench_unop!(_bench_vec2_norm, Vector2, norm); -bench_unop!(_bench_vec3_norm, Vector3, norm); -bench_unop!(_bench_vec4_norm, Vector4, norm); - -bench_unop!(_bench_vec2_normalize, Vector2, normalize); -bench_unop!(_bench_vec3_normalize, Vector3, normalize); -bench_unop!(_bench_vec4_normalize, Vector4, normalize); diff --git a/examples/dimensional_genericity.rs b/examples/dimensional_genericity.rs index df22b945..70a37a04 100644 --- a/examples/dimensional_genericity.rs +++ b/examples/dimensional_genericity.rs @@ -1,11 +1,10 @@ extern crate alga; extern crate nalgebra as na; -use alga::general::Real; use alga::linear::FiniteDimInnerSpace; -use na::{Unit, ColumnVector, OwnedColumnVector, Vector2, Vector3}; -use na::storage::Storage; -use na::dimension::{DimName, U1}; +use na::{Real, DefaultAllocator, Unit, VectorN, Vector2, Vector3}; +use na::allocator::Allocator; +use na::dimension::Dim; /// Reflects a vector wrt. the hyperplane with normal `plane_normal`. fn reflect_wrt_hyperplane_with_algebraic_genericity(plane_normal: &Unit, vector: &V) -> V @@ -16,12 +15,12 @@ fn reflect_wrt_hyperplane_with_algebraic_genericity(plane_normal: &Unit, v /// Reflects a vector wrt. the hyperplane with normal `plane_normal`. -fn reflect_wrt_hyperplane_with_structural_genericity(plane_normal: &Unit>, - vector: &ColumnVector) - -> OwnedColumnVector +fn reflect_wrt_hyperplane_with_dimensional_genericity(plane_normal: &Unit>, + vector: &VectorN) + -> VectorN where N: Real, - D: DimName, - S: Storage { + D: Dim, + DefaultAllocator: Allocator { let n = plane_normal.as_ref(); // Get the underlying V. vector - n * (n.dot(vector) * na::convert(2.0)) } @@ -57,8 +56,8 @@ fn main() { assert_eq!(reflect_wrt_hyperplane_with_algebraic_genericity(&plane2, &v2).y, -2.0); assert_eq!(reflect_wrt_hyperplane_with_algebraic_genericity(&plane3, &v3).y, -2.0); - assert_eq!(reflect_wrt_hyperplane_with_structural_genericity(&plane2, &v2).y, -2.0); - assert_eq!(reflect_wrt_hyperplane_with_structural_genericity(&plane3, &v3).y, -2.0); + assert_eq!(reflect_wrt_hyperplane_with_dimensional_genericity(&plane2, &v2).y, -2.0); + assert_eq!(reflect_wrt_hyperplane_with_dimensional_genericity(&plane3, &v3).y, -2.0); // Call each specific implementation depending on the dimension. assert_eq!(reflect_wrt_hyperplane2(&plane2, &v2).y, -2.0); diff --git a/src/core/alias.rs b/src/core/alias.rs index df296257..8fa29e5e 100644 --- a/src/core/alias.rs +++ b/src/core/alias.rs @@ -1,7 +1,7 @@ use core::Matrix; use core::dimension::{Dynamic, U1, U2, U3, U4, U5, U6}; -use core::matrix_array::MatrixArray; use core::matrix_vec::MatrixVec; +use core::storage::Owned; /* * @@ -10,14 +10,18 @@ use core::matrix_vec::MatrixVec; * * */ -/// A dynamically sized column-major matrix. -pub type DMatrix = Matrix>; +/// A staticaly sized column-major matrix with `R` rows and `C` columns. +#[deprecated(note = "This matrix name contains a typo. Use MatrixMN instead.")] +pub type MatrixNM = Matrix>; /// A staticaly sized column-major matrix with `R` rows and `C` columns. -pub type MatrixNM = Matrix>; +pub type MatrixMN = Matrix>; /// A staticaly sized column-major square matrix with `D` rows and columns. -pub type MatrixN = MatrixNM; +pub type MatrixN = MatrixMN; + +/// A dynamically sized column-major matrix. +pub type DMatrix = MatrixN; /// A stack-allocated, column-major, 1x1 square matrix. pub type Matrix1 = MatrixN; @@ -33,75 +37,75 @@ pub type Matrix5 = MatrixN; pub type Matrix6 = MatrixN; /// A stack-allocated, column-major, 1x2 square matrix. -pub type Matrix1x2 = MatrixNM; +pub type Matrix1x2 = MatrixMN; /// A stack-allocated, column-major, 1x3 square matrix. -pub type Matrix1x3 = MatrixNM; +pub type Matrix1x3 = MatrixMN; /// A stack-allocated, column-major, 1x4 square matrix. -pub type Matrix1x4 = MatrixNM; +pub type Matrix1x4 = MatrixMN; /// A stack-allocated, column-major, 1x5 square matrix. -pub type Matrix1x5 = MatrixNM; +pub type Matrix1x5 = MatrixMN; /// A stack-allocated, column-major, 1x6 square matrix. -pub type Matrix1x6 = MatrixNM; +pub type Matrix1x6 = MatrixMN; /// A stack-allocated, column-major, 2x3 square matrix. -pub type Matrix2x3 = MatrixNM; +pub type Matrix2x3 = MatrixMN; /// A stack-allocated, column-major, 2x4 square matrix. -pub type Matrix2x4 = MatrixNM; +pub type Matrix2x4 = MatrixMN; /// A stack-allocated, column-major, 2x5 square matrix. -pub type Matrix2x5 = MatrixNM; +pub type Matrix2x5 = MatrixMN; /// A stack-allocated, column-major, 2x6 square matrix. -pub type Matrix2x6 = MatrixNM; +pub type Matrix2x6 = MatrixMN; /// A stack-allocated, column-major, 3x4 square matrix. -pub type Matrix3x4 = MatrixNM; +pub type Matrix3x4 = MatrixMN; /// A stack-allocated, column-major, 3x5 square matrix. -pub type Matrix3x5 = MatrixNM; +pub type Matrix3x5 = MatrixMN; /// A stack-allocated, column-major, 3x6 square matrix. -pub type Matrix3x6 = MatrixNM; +pub type Matrix3x6 = MatrixMN; /// A stack-allocated, column-major, 4x5 square matrix. -pub type Matrix4x5 = MatrixNM; +pub type Matrix4x5 = MatrixMN; /// A stack-allocated, column-major, 4x6 square matrix. -pub type Matrix4x6 = MatrixNM; +pub type Matrix4x6 = MatrixMN; /// A stack-allocated, column-major, 5x6 square matrix. -pub type Matrix5x6 = MatrixNM; +pub type Matrix5x6 = MatrixMN; /// A stack-allocated, column-major, 2x1 square matrix. -pub type Matrix2x1 = MatrixNM; +pub type Matrix2x1 = MatrixMN; /// A stack-allocated, column-major, 3x1 square matrix. -pub type Matrix3x1 = MatrixNM; +pub type Matrix3x1 = MatrixMN; /// A stack-allocated, column-major, 4x1 square matrix. -pub type Matrix4x1 = MatrixNM; +pub type Matrix4x1 = MatrixMN; /// A stack-allocated, column-major, 5x1 square matrix. -pub type Matrix5x1 = MatrixNM; +pub type Matrix5x1 = MatrixMN; /// A stack-allocated, column-major, 6x1 square matrix. -pub type Matrix6x1 = MatrixNM; +pub type Matrix6x1 = MatrixMN; /// A stack-allocated, column-major, 3x2 square matrix. -pub type Matrix3x2 = MatrixNM; +pub type Matrix3x2 = MatrixMN; /// A stack-allocated, column-major, 4x2 square matrix. -pub type Matrix4x2 = MatrixNM; +pub type Matrix4x2 = MatrixMN; /// A stack-allocated, column-major, 5x2 square matrix. -pub type Matrix5x2 = MatrixNM; +pub type Matrix5x2 = MatrixMN; /// A stack-allocated, column-major, 6x2 square matrix. -pub type Matrix6x2 = MatrixNM; +pub type Matrix6x2 = MatrixMN; /// A stack-allocated, column-major, 4x3 square matrix. -pub type Matrix4x3 = MatrixNM; +pub type Matrix4x3 = MatrixMN; /// A stack-allocated, column-major, 5x3 square matrix. -pub type Matrix5x3 = MatrixNM; +pub type Matrix5x3 = MatrixMN; /// A stack-allocated, column-major, 6x3 square matrix. -pub type Matrix6x3 = MatrixNM; +pub type Matrix6x3 = MatrixMN; /// A stack-allocated, column-major, 5x4 square matrix. -pub type Matrix5x4 = MatrixNM; +pub type Matrix5x4 = MatrixMN; /// A stack-allocated, column-major, 6x4 square matrix. -pub type Matrix6x4 = MatrixNM; +pub type Matrix6x4 = MatrixMN; /// A stack-allocated, column-major, 6x5 square matrix. -pub type Matrix6x5 = MatrixNM; +pub type Matrix6x5 = MatrixMN; /* @@ -115,7 +119,7 @@ pub type Matrix6x5 = MatrixNM; pub type DVector = Matrix>; /// A statically sized D-dimensional column vector. -pub type VectorN = MatrixNM; +pub type VectorN = MatrixMN; /// A stack-allocated, 1-dimensional column vector. pub type Vector1 = VectorN; @@ -142,7 +146,7 @@ pub type Vector6 = VectorN; pub type RowDVector = Matrix>; /// A statically sized D-dimensional row vector. -pub type RowVectorN = MatrixNM; +pub type RowVectorN = MatrixMN; /// A stack-allocated, 1-dimensional row vector. pub type RowVector1 = RowVectorN; diff --git a/src/core/allocator.rs b/src/core/allocator.rs index d0c0a416..13d2de3c 100644 --- a/src/core/allocator.rs +++ b/src/core/allocator.rs @@ -2,10 +2,10 @@ use std::any::Any; -use core::Scalar; +use core::{DefaultAllocator, Scalar}; use core::constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint}; use core::dimension::{Dim, U1}; -use core::storage::{Storage, OwnedStorage}; +use core::storage::ContiguousStorageMut; /// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()` /// elements of type `N`. @@ -16,9 +16,9 @@ use core::storage::{Storage, OwnedStorage}; /// /// Every allocator must be both static and dynamic. Though not all implementations may share the /// same `Buffer` type. -pub trait Allocator: Any + Sized { +pub trait Allocator: Any + Sized { /// The type of buffer this allocator can instanciate. - type Buffer: OwnedStorage; + type Buffer: ContiguousStorageMut + Clone; /// Allocates a buffer with the given number of rows and columns without initializing its content. unsafe fn allocate_uninitialized(nrows: R, ncols: C) -> Self::Buffer; @@ -27,15 +27,20 @@ pub trait Allocator: Any + Sized { fn allocate_from_iterator>(nrows: R, ncols: C, iter: I) -> Self::Buffer; } -/// A matrix data allocator dedicated to the given owned matrix storage. -pub trait OwnedAllocator>: - Allocator { -} - -impl OwnedAllocator for T - where N: Scalar, R: Dim, C: Dim, - T: Allocator, - S: OwnedStorage { +/// A matrix reallocator. Changes the size of the memory buffer that initially contains (RFrom × +/// CFrom) elements to a smaller or larger size (RTo, CTo). +pub trait Reallocator: + Allocator + Allocator { + /// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer + /// `buf`. Data stored by `buf` are linearly copied to the output: + /// + /// * The copy is performed as if both were just arrays (without a matrix structure). + /// * If `buf` is larger than the output size, then extra elements of `buf` are truncated. + /// * If `buf` is smaller than the output size, then extra elements of the output are left + /// uninitialized. + unsafe fn reallocate_copy(nrows: RTo, ncols: CTo, + buf: >::Buffer) + -> >::Buffer; } /// The number of rows of the result of a componentwise operation on two matrices. @@ -45,45 +50,36 @@ pub type SameShapeR = >::Rep pub type SameShapeC = >::Representative; // FIXME: Bad name. -/// Restricts the given number of rows and columns to be respectively the same. Can only be used -/// when `Self = SA::Alloc`. -pub trait SameShapeAllocator: +/// Restricts the given number of rows and columns to be respectively the same. +pub trait SameShapeAllocator: Allocator + Allocator, SameShapeC> where R1: Dim, R2: Dim, C1: Dim, C2: Dim, N: Scalar, - SA: Storage, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { } -impl SameShapeAllocator for SA::Alloc +impl SameShapeAllocator for DefaultAllocator where R1: Dim, R2: Dim, C1: Dim, C2: Dim, N: Scalar, - SA: Storage, - SA::Alloc: - Allocator + - Allocator, SameShapeC>, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + DefaultAllocator: Allocator + Allocator, SameShapeC>, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { } // XXX: Bad name. -/// Restricts the given number of rows to be equal. Can only be used when `Self = SA::Alloc`. -pub trait SameShapeColumnVectorAllocator: - Allocator + - Allocator, U1> + - SameShapeAllocator +/// Restricts the given number of rows to be equal. +pub trait SameShapeVectorAllocator: + Allocator + + Allocator> + + SameShapeAllocator where R1: Dim, R2: Dim, N: Scalar, - SA: Storage, ShapeConstraint: SameNumberOfRows { } -impl SameShapeColumnVectorAllocator for SA::Alloc +impl SameShapeVectorAllocator for DefaultAllocator where R1: Dim, R2: Dim, N: Scalar, - SA: Storage, - SA::Alloc: - Allocator + - Allocator, U1>, - ShapeConstraint: SameNumberOfRows { + DefaultAllocator: Allocator + Allocator>, + ShapeConstraint: SameNumberOfRows { } diff --git a/src/core/blas.rs b/src/core/blas.rs new file mode 100644 index 00000000..19eeda7a --- /dev/null +++ b/src/core/blas.rs @@ -0,0 +1,458 @@ +use std::mem; +use num::{Zero, One, Signed}; +use matrixmultiply; +use alga::general::{ClosedMul, ClosedAdd}; + +use core::{Scalar, Matrix, Vector}; +use core::dimension::{Dim, U1, U2, U3, U4, Dynamic}; +use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable, DimEq}; +use core::storage::{Storage, StorageMut}; + + + +impl> Vector { + /// Computes the index of the vector component with the largest absolute value. + #[inline] + pub fn iamax(&self) -> usize { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0).abs() }; + let mut the_i = 0; + + for i in 1 .. self.nrows() { + let val = unsafe { self.vget_unchecked(i).abs() }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + the_i + } +} + +impl> Matrix { + /// Computes the index of the matrix component with the largest absolute value. + #[inline] + pub fn iamax_full(&self) -> (usize, usize) { + assert!(!self.is_empty(), "The input matrix must not be empty."); + + let mut the_max = unsafe { self.get_unchecked(0, 0).abs() }; + let mut the_ij = (0, 0); + + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + let val = unsafe { self.get_unchecked(i, j).abs() }; + + if val > the_max { + the_max = val; + the_ij = (i, j); + } + } + } + + the_ij + } +} + +impl> Matrix + where N: Scalar + Zero + ClosedAdd + ClosedMul { + /// The dot product between two matrices (seen as vectors). + /// + /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix + /// multiplication, use one of: `.gemm`, `mul_to`, `.mul`, `*`. + #[inline] + pub fn dot(&self, rhs: &Matrix) -> N + where SB: Storage, + ShapeConstraint: DimEq + DimEq { + assert!(self.nrows() == rhs.nrows(), "Dot product dimensions mismatch."); + + + // So we do some special cases for common fixed-size vectors of dimension lower than 8 + // because the `for` loop bellow won't be very efficient on those. + if (R::is::() || R2::is::()) && + (C::is::() || C2::is::()) { + unsafe { + let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0); + let b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0); + + return a + b; + } + } + if (R::is::() || R2::is::()) && + (C::is::() || C2::is::()) { + unsafe { + let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0); + let b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0); + let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0); + + return a + b + c; + } + } + if (R::is::() || R2::is::()) && + (C::is::() || C2::is::()) { + unsafe { + let mut a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0); + let mut b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0); + let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0); + let d = *self.get_unchecked(3, 0) * *rhs.get_unchecked(3, 0); + + a += c; + b += d; + + return a + b; + } + } + + + // All this is inspired from the "unrolled version" discussed in: + // http://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/ + // + // And this comment from bluss: + // https://users.rust-lang.org/t/how-to-zip-two-slices-efficiently/2048/12 + let mut res = N::zero(); + + // We have to define them outside of the loop (and not inside at first assignment) + // otherwize vectorization won't kick in for some reason. + let mut acc0; + let mut acc1; + let mut acc2; + let mut acc3; + let mut acc4; + let mut acc5; + let mut acc6; + let mut acc7; + + for j in 0 .. self.ncols() { + let mut i = 0; + + acc0 = N::zero(); + acc1 = N::zero(); + acc2 = N::zero(); + acc3 = N::zero(); + acc4 = N::zero(); + acc5 = N::zero(); + acc6 = N::zero(); + acc7 = N::zero(); + + while self.nrows() - i >= 8 { + acc0 += unsafe { *self.get_unchecked(i + 0, j) * *rhs.get_unchecked(i + 0, j) }; + acc1 += unsafe { *self.get_unchecked(i + 1, j) * *rhs.get_unchecked(i + 1, j) }; + acc2 += unsafe { *self.get_unchecked(i + 2, j) * *rhs.get_unchecked(i + 2, j) }; + acc3 += unsafe { *self.get_unchecked(i + 3, j) * *rhs.get_unchecked(i + 3, j) }; + acc4 += unsafe { *self.get_unchecked(i + 4, j) * *rhs.get_unchecked(i + 4, j) }; + acc5 += unsafe { *self.get_unchecked(i + 5, j) * *rhs.get_unchecked(i + 5, j) }; + acc6 += unsafe { *self.get_unchecked(i + 6, j) * *rhs.get_unchecked(i + 6, j) }; + acc7 += unsafe { *self.get_unchecked(i + 7, j) * *rhs.get_unchecked(i + 7, j) }; + i += 8; + } + + res += acc0 + acc4; + res += acc1 + acc5; + res += acc2 + acc6; + res += acc3 + acc7; + + for k in i .. self.nrows() { + res += unsafe { *self.get_unchecked(k, j) * *rhs.get_unchecked(k, j) } + } + } + + res + } + + /// The dot product between the transpose of `self` and `rhs`. + #[inline] + pub fn tr_dot(&self, rhs: &Matrix) -> N + where SB: Storage, + ShapeConstraint: DimEq + DimEq { + let (nrows, ncols) = self.shape(); + assert!((ncols, nrows) == rhs.shape(), "Transposed dot product dimension mismatch."); + + let mut res = N::zero(); + + for j in 0 .. self.nrows() { + for i in 0 .. self.ncols() { + res += unsafe { *self.get_unchecked(j, i) * *rhs.get_unchecked(i, j) } + } + } + + res + } +} + +fn array_axpy(y: &mut [N], a: N, x: &[N], beta: N, stride1: usize, stride2: usize, len: usize) + where N: Scalar + Zero + ClosedAdd + ClosedMul { + for i in 0 .. len { + unsafe { + let y = y.get_unchecked_mut(i * stride1); + *y = a * *x.get_unchecked(i * stride2) + beta * *y; + } + } +} + +fn array_ax(y: &mut [N], a: N, x: &[N], stride1: usize, stride2: usize, len: usize) + where N: Scalar + Zero + ClosedAdd + ClosedMul { + for i in 0 .. len { + unsafe { + *y.get_unchecked_mut(i * stride1) = a * *x.get_unchecked(i * stride2); + } + } +} + +impl Vector + where N: Scalar + Zero + ClosedAdd + ClosedMul, + S: StorageMut { + /// Computes `self = a * x + b * self`. + /// + /// If be is zero, `self` is never read from. + #[inline] + pub fn axpy(&mut self, a: N, x: &Vector, b: N) + where SB: Storage, + ShapeConstraint: DimEq { + + assert_eq!(self.nrows(), x.nrows(), "Axpy: mismatched vector shapes."); + + let rstride1 = self.strides().0; + let rstride2 = x.strides().0; + + let y = self.data.as_mut_slice(); + let x = x.data.as_slice(); + + if !b.is_zero() { + array_axpy(y, a, x, b, rstride1, rstride2, x.len()); + } + else { + array_ax(y, a, x, rstride1, rstride2, x.len()); + } + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is a matrix, `x` a vector, and + /// `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. + #[inline] + pub fn gemv(&mut self, + alpha: N, + a: &Matrix, + x: &Vector, + beta: N) + where N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + + AreMultipliable { + let dim1 = self.nrows(); + let (nrows2, ncols2) = a.shape(); + let dim3 = x.nrows(); + + assert!(ncols2 == dim3 && dim1 == nrows2, "Gemv: dimensions mismatch."); + + if ncols2 == 0 { + return; + } + + // FIXME: avoid bound checks. + let col2 = a.column(0); + let val = unsafe { *x.vget_unchecked(0) }; + self.axpy(alpha * val, &col2, beta); + + for j in 1 .. ncols2 { + let col2 = a.column(j); + let val = unsafe { *x.vget_unchecked(j) }; + + self.axpy(alpha * val, &col2, N::one()); + } + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a + /// vector, and `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part + /// (including the diagonal) is actually read. + #[inline] + pub fn gemv_symm(&mut self, + alpha: N, + a: &Matrix, + x: &Vector, + beta: N) + where N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + + AreMultipliable { + let dim1 = self.nrows(); + let dim2 = a.nrows(); + let dim3 = x.nrows(); + + assert!(a.is_square(), "Syetric gemv: the input matrix must be square."); + assert!(dim2 == dim3 && dim1 == dim2, "Symmetric gemv: dimensions mismatch."); + + if dim2 == 0 { + return; + } + + // FIXME: avoid bound checks. + let col2 = a.column(0); + let val = unsafe { *x.vget_unchecked(0) }; + self.axpy(alpha * val, &col2, beta); + self[0] += alpha * x.rows_range(1 ..).dot(&a.slice_range(1 .., 0)); + + for j in 1 .. dim2 { + let col2 = a.column(j); + let dot = x.rows_range(j ..).dot(&col2.rows_range(j ..)); + + let val; + unsafe { + val = *x.vget_unchecked(j); + *self.vget_unchecked_mut(j) += alpha * dot; + } + self.rows_range_mut(j + 1 ..).axpy(alpha * val, &col2.rows_range(j + 1 ..), N::one()); + } + } +} + +impl> Matrix + where N: Scalar + Zero + ClosedAdd + ClosedMul { + + /// Computes `self = alpha * x * y.transpose() + beta * self`. + /// + /// If `beta` is zero, `self` is never read. + #[inline] + pub fn ger(&mut self, alpha: N, x: &Vector, y: &Vector, beta: N) + where N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq { + let (nrows1, ncols1) = self.shape(); + let dim2 = x.nrows(); + let dim3 = y.nrows(); + + assert!(nrows1 == dim2 && ncols1 == dim3, "ger: dimensions mismatch."); + + for j in 0 .. ncols1 { + // FIXME: avoid bound checks. + let val = unsafe { *y.vget_unchecked(j) }; + self.column_mut(j).axpy(alpha * val, x, beta); + } + } + + /// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices. + /// `alpha` and `beta` are scalar. + /// + /// If `beta` is zero, `self` is never read. + #[inline] + pub fn gemm(&mut self, + alpha: N, + a: &Matrix, + b: &Matrix, + beta: N) + where N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable { + let (nrows1, ncols1) = self.shape(); + let (nrows2, ncols2) = a.shape(); + let (nrows3, ncols3) = b.shape(); + + assert_eq!(ncols2, nrows3, "gemm: dimensions mismatch for multiplication."); + assert_eq!((nrows1, ncols1), (nrows2, ncols3), "gemm: dimensions mismatch for addition."); + + // We assume large matrices will be Dynamic but small matrices static. + // We could use matrixmultiply for large statically-sized matrices but the performance + // threshold to activate it would be different from SMALL_DIM because our code optimizes + // better for statically-sized matrices. + let is_dynamic = R1::is::() || C1::is::() || + R2::is::() || C2::is::() || + R3::is::() || C3::is::(); + // Thershold determined ampirically. + const SMALL_DIM: usize = 5; + + if is_dynamic && + nrows1 > SMALL_DIM && ncols1 > SMALL_DIM && + nrows2 > SMALL_DIM && ncols2 > SMALL_DIM { + if N::is::() { + let (rsa, csa) = a.strides(); + let (rsb, csb) = b.strides(); + let (rsc, csc) = self.strides(); + + unsafe { + matrixmultiply::sgemm( + nrows2, + ncols2, + ncols3, + mem::transmute_copy(&alpha), + a.data.ptr() as *const f32, + rsa as isize, csa as isize, + b.data.ptr() as *const f32, + rsb as isize, csb as isize, + mem::transmute_copy(&beta), + self.data.ptr_mut() as *mut f32, + rsc as isize, csc as isize); + } + } + else if N::is::() { + let (rsa, csa) = a.strides(); + let (rsb, csb) = b.strides(); + let (rsc, csc) = self.strides(); + + unsafe { + matrixmultiply::dgemm( + nrows2, + ncols2, + ncols3, + mem::transmute_copy(&alpha), + a.data.ptr() as *const f64, + rsa as isize, csa as isize, + b.data.ptr() as *const f64, + rsb as isize, csb as isize, + mem::transmute_copy(&beta), + self.data.ptr_mut() as *mut f64, + rsc as isize, csc as isize); + } + } + } + else { + for j1 in 0 .. ncols1 { + // FIXME: avoid bound checks. + self.column_mut(j1).gemv(alpha, a, &b.column(j1), beta); + } + } + } +} + + +impl> Matrix + where N: Scalar + Zero + ClosedAdd + ClosedMul { + /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** + /// matrix. + /// + /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular + /// (including the diagonal) part of `self` is read/written. + #[inline] + pub fn ger_symm(&mut self, + alpha: N, + x: &Vector, + y: &Vector, + beta: N) + where N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq { + let dim1 = self.nrows(); + let dim2 = x.nrows(); + let dim3 = y.nrows(); + + assert!(self.is_square(), "Symmetric ger: the input matrix must be square."); + assert!(dim1 == dim2 && dim1 == dim3, "ger: dimensions mismatch."); + + for j in 0 .. dim1 { + // FIXME: avoid bound checks. + let val = unsafe { *y.vget_unchecked(j) }; + let subdim = Dynamic::new(dim1 - j); + self.generic_slice_mut((j, j), (subdim, U1)).axpy(alpha * val, &x.rows_range(j ..), beta); + } + } +} diff --git a/src/core/cg.rs b/src/core/cg.rs index e409d006..0ef8507b 100644 --- a/src/core/cg.rs +++ b/src/core/cg.rs @@ -7,20 +7,20 @@ use num::One; -use core::{Scalar, SquareMatrix, OwnedSquareMatrix, ColumnVector, Unit}; -use core::dimension::{DimName, DimNameSub, DimNameDiff, U1, U2, U3, U4}; -use core::storage::{Storage, StorageMut, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; -use geometry::{PointBase, OrthographicBase, PerspectiveBase, IsometryBase, OwnedRotation, OwnedPoint}; +use core::{DefaultAllocator, Scalar, SquareMatrix, Vector, Unit, + VectorN, MatrixN, Vector3, Matrix3, Matrix4}; +use core::dimension::{DimName, DimNameSub, DimNameDiff, U1}; +use core::storage::{Storage, StorageMut}; +use core::allocator::Allocator; +use geometry::{Point, Isometry, Point3, Rotation2, Rotation3, Orthographic3, Perspective3, IsometryMatrix3}; use alga::general::{Real, Field}; use alga::linear::Transformation; -impl SquareMatrix +impl MatrixN where N: Scalar + Field, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { /// Creates a new homogeneous matrix that applies the same scaling factor on each dimension. #[inline] pub fn new_scaling(scaling: N) -> Self { @@ -32,9 +32,9 @@ impl SquareMatrix /// Creates a new homogeneous matrix that applies a distinct scaling factor for each dimension. #[inline] - pub fn new_nonuniform_scaling(scaling: &ColumnVector, SB>) -> Self + pub fn new_nonuniform_scaling(scaling: &Vector, SB>) -> Self where D: DimNameSub, - SB: Storage, U1> { + SB: Storage> { let mut res = Self::one(); for i in 0 .. scaling.len() { res[(i, i)] = scaling[i]; @@ -45,10 +45,9 @@ impl SquareMatrix /// Creates a new homogeneous matrix that applies a pure translation. #[inline] - pub fn new_translation(translation: &ColumnVector, SB>) -> Self + pub fn new_translation(translation: &Vector, SB>) -> Self where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator, U1> { + SB: Storage> { let mut res = Self::one(); res.fixed_slice_mut::, U1>(0, D::dim() - 1).copy_from(translation); @@ -56,44 +55,30 @@ impl SquareMatrix } } -impl SquareMatrix - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Matrix3 { /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian. #[inline] - pub fn new_rotation(angle: N) -> Self - where S::Alloc: Allocator { - OwnedRotation::::new(angle).to_homogeneous() + pub fn new_rotation(angle: N) -> Self { + Rotation2::new(angle).to_homogeneous() } } -impl SquareMatrix - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { - +impl Matrix4 { /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// /// Returns the identity matrix if the given argument is zero. #[inline] - pub fn new_rotation(axisangle: ColumnVector) -> Self - where SB: Storage, - S::Alloc: Allocator { - OwnedRotation::::new(axisangle).to_homogeneous() + pub fn new_rotation(axisangle: Vector3) -> Self { + Rotation3::new(axisangle).to_homogeneous() } /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// /// Returns the identity matrix if the given argument is zero. #[inline] - pub fn new_rotation_wrt_point(axisangle: ColumnVector, pt: OwnedPoint) -> Self - where SB: Storage, - S::Alloc: Allocator + - Allocator + - Allocator { - let rot = OwnedRotation::::from_scaled_axis(axisangle); - IsometryBase::rotation_wrt_point(rot, pt).to_homogeneous() + pub fn new_rotation_wrt_point(axisangle: Vector3, pt: Point3) -> Self { + let rot = Rotation3::from_scaled_axis(axisangle); + Isometry::rotation_wrt_point(rot, pt).to_homogeneous() } /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). @@ -101,37 +86,32 @@ impl SquareMatrix /// Returns the identity matrix if the given argument is zero. /// This is identical to `Self::new_rotation`. #[inline] - pub fn from_scaled_axis(axisangle: ColumnVector) -> Self - where SB: Storage, - S::Alloc: Allocator { - OwnedRotation::::from_scaled_axis(axisangle).to_homogeneous() + pub fn from_scaled_axis(axisangle: Vector3) -> Self { + Rotation3::from_scaled_axis(axisangle).to_homogeneous() } /// Creates a new rotation from Euler angles. /// /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw. - pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self - where S::Alloc: Allocator { - OwnedRotation::::from_euler_angles(roll, pitch, yaw).to_homogeneous() + pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { + Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous() } /// Builds a 3D homogeneous rotation matrix from an axis and a rotation angle. - pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self - where SB: Storage, - S::Alloc: Allocator { - OwnedRotation::::from_axis_angle(axis, angle).to_homogeneous() + pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self { + Rotation3::from_axis_angle(axis, angle).to_homogeneous() } /// Creates a new homogeneous matrix for an orthographic projection. #[inline] pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self { - OrthographicBase::new(left, right, bottom, top, znear, zfar).unwrap() + Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap() } /// Creates a new homogeneous matrix for a perspective projection. #[inline] pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self { - PerspectiveBase::new(aspect, fovy, znear, zfar).unwrap() + Perspective3::new(aspect, fovy, znear, zfar).unwrap() } /// Creates an isometry that corresponds to the local frame of an observer standing at the @@ -140,57 +120,30 @@ impl SquareMatrix /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the /// `eye`. #[inline] - pub fn new_observer_frame(eye: &PointBase, - target: &PointBase, - up: &ColumnVector) - -> Self - where SB: OwnedStorage, - SB::Alloc: OwnedAllocator + - Allocator + - Allocator { - IsometryBase::> - ::new_observer_frame(eye, target, up).to_homogeneous() + pub fn new_observer_frame(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous() } /// Builds a right-handed look-at view matrix. #[inline] - pub fn look_at_rh(eye: &PointBase, - target: &PointBase, - up: &ColumnVector) - -> Self - where SB: OwnedStorage, - SB::Alloc: OwnedAllocator + - Allocator + - Allocator { - IsometryBase::> - ::look_at_rh(eye, target, up).to_homogeneous() + pub fn look_at_rh(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous() } /// Builds a left-handed look-at view matrix. #[inline] - pub fn look_at_lh(eye: &PointBase, - target: &PointBase, - up: &ColumnVector) - -> Self - where SB: OwnedStorage, - SB::Alloc: OwnedAllocator + - Allocator + - Allocator { - IsometryBase::> - ::look_at_lh(eye, target, up).to_homogeneous() + pub fn look_at_lh(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous() } } -impl SquareMatrix - where N: Scalar + Field, - S: Storage { - +impl> SquareMatrix { /// Computes the transformation equal to `self` followed by an uniform scaling factor. #[inline] - pub fn append_scaling(&self, scaling: N) -> OwnedSquareMatrix + pub fn append_scaling(&self, scaling: N) -> MatrixN where D: DimNameSub, - S::Alloc: Allocator, D> { + DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.append_scaling_mut(scaling); res @@ -198,9 +151,9 @@ impl SquareMatrix /// Computes the transformation equal to an uniform scaling factor followed by `self`. #[inline] - pub fn prepend_scaling(&self, scaling: N) -> OwnedSquareMatrix + pub fn prepend_scaling(&self, scaling: N) -> MatrixN where D: DimNameSub, - S::Alloc: Allocator> { + DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.prepend_scaling_mut(scaling); res @@ -208,11 +161,10 @@ impl SquareMatrix /// Computes the transformation equal to `self` followed by a non-uniform scaling factor. #[inline] - pub fn append_nonuniform_scaling(&self, scaling: &ColumnVector, SB>) - -> OwnedSquareMatrix - where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator { + pub fn append_nonuniform_scaling(&self, scaling: &Vector, SB>) -> MatrixN + where D: DimNameSub, + SB: Storage>, + DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.append_nonuniform_scaling_mut(scaling); res @@ -220,11 +172,10 @@ impl SquareMatrix /// Computes the transformation equal to a non-uniform scaling factor followed by `self`. #[inline] - pub fn prepend_nonuniform_scaling(&self, scaling: &ColumnVector, SB>) - -> OwnedSquareMatrix - where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator { + pub fn prepend_nonuniform_scaling(&self, scaling: &Vector, SB>) -> MatrixN + where D: DimNameSub, + SB: Storage>, + DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.prepend_nonuniform_scaling_mut(scaling); res @@ -232,11 +183,10 @@ impl SquareMatrix /// Computes the transformation equal to `self` followed by a translation. #[inline] - pub fn append_translation(&self, shift: &ColumnVector, SB>) - -> OwnedSquareMatrix + pub fn append_translation(&self, shift: &Vector, SB>) -> MatrixN where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator, U1> { + SB: Storage>, + DefaultAllocator: Allocator { let mut res = self.clone_owned(); res.append_translation_mut(shift); res @@ -244,28 +194,23 @@ impl SquareMatrix /// Computes the transformation equal to a translation followed by `self`. #[inline] - pub fn prepend_translation(&self, shift: &ColumnVector, SB>) - -> OwnedSquareMatrix + pub fn prepend_translation(&self, shift: &Vector, SB>) -> MatrixN where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator, U1> + - Allocator, DimNameDiff> + - Allocator> { + SB: Storage>, + DefaultAllocator: Allocator + + Allocator> { let mut res = self.clone_owned(); res.prepend_translation_mut(shift); res } } -impl SquareMatrix - where N: Scalar + Field, - S: StorageMut { +impl> SquareMatrix { /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor. #[inline] pub fn append_scaling_mut(&mut self, scaling: N) - where D: DimNameSub, - S::Alloc: Allocator, D> { + where D: DimNameSub { let mut to_scale = self.fixed_rows_mut::>(0); to_scale *= scaling; } @@ -273,18 +218,16 @@ impl SquareMatrix /// Computes in-place the transformation equal to an uniform scaling factor followed by `self`. #[inline] pub fn prepend_scaling_mut(&mut self, scaling: N) - where D: DimNameSub, - S::Alloc: Allocator> { + where D: DimNameSub { let mut to_scale = self.fixed_columns_mut::>(0); to_scale *= scaling; } /// Computes in-place the transformation equal to `self` followed by a non-uniform scaling factor. #[inline] - pub fn append_nonuniform_scaling_mut(&mut self, scaling: &ColumnVector, SB>) + pub fn append_nonuniform_scaling_mut(&mut self, scaling: &Vector, SB>) where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator { + SB: Storage> { for i in 0 .. scaling.len() { let mut to_scale = self.fixed_rows_mut::(i); to_scale *= scaling[i]; @@ -293,10 +236,9 @@ impl SquareMatrix /// Computes in-place the transformation equal to a non-uniform scaling factor followed by `self`. #[inline] - pub fn prepend_nonuniform_scaling_mut(&mut self, scaling: &ColumnVector, SB>) + pub fn prepend_nonuniform_scaling_mut(&mut self, scaling: &Vector, SB>) where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator { + SB: Storage> { for i in 0 .. scaling.len() { let mut to_scale = self.fixed_columns_mut::(i); to_scale *= scaling[i]; @@ -305,10 +247,9 @@ impl SquareMatrix /// Computes the transformation equal to `self` followed by a translation. #[inline] - pub fn append_translation_mut(&mut self, shift: &ColumnVector, SB>) + pub fn append_translation_mut(&mut self, shift: &Vector, SB>) where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator, U1> { + SB: Storage> { for i in 0 .. D::dim() { for j in 0 .. D::dim() - 1 { self[(j, i)] += shift[j] * self[(D::dim() - 1, i)]; @@ -318,12 +259,10 @@ impl SquareMatrix /// Computes the transformation equal to a translation followed by `self`. #[inline] - pub fn prepend_translation_mut(&mut self, shift: &ColumnVector, SB>) + pub fn prepend_translation_mut(&mut self, shift: &Vector, SB>) where D: DimNameSub, - SB: Storage, U1>, - S::Alloc: Allocator, U1> + - Allocator, DimNameDiff> + - Allocator> { + SB: Storage>, + DefaultAllocator: Allocator> { let scale = self.fixed_slice::>(D::dim() - 1, 0).tr_dot(&shift); let post_translation = self.fixed_slice::, DimNameDiff>(0, 0) * shift; @@ -335,19 +274,12 @@ impl SquareMatrix } -impl Transformation, SB>> for SquareMatrix - where N: Real, - D: DimNameSub, - SA: OwnedStorage, - SB: OwnedStorage, U1, Alloc = SA::Alloc>, - SA::Alloc: OwnedAllocator + - Allocator, DimNameDiff> + - Allocator, U1> + - Allocator>, - SB::Alloc: OwnedAllocator, U1, SB> { +impl> Transformation>> for MatrixN + where DefaultAllocator: Allocator + + Allocator> + + Allocator, DimNameDiff> { #[inline] - fn transform_vector(&self, v: &ColumnVector, SB>) - -> ColumnVector, SB> { + fn transform_vector(&self, v: &VectorN>) -> VectorN> { let transform = self.fixed_slice::, DimNameDiff>(0, 0); let normalizer = self.fixed_slice::>(D::dim() - 1, 0); let n = normalizer.tr_dot(&v); @@ -360,8 +292,7 @@ impl Transformation, SB>> for Squa } #[inline] - fn transform_point(&self, pt: &PointBase, SB>) - -> PointBase, SB> { + fn transform_point(&self, pt: &Point>) -> Point> { let transform = self.fixed_slice::, DimNameDiff>(0, 0); let translation = self.fixed_slice::, U1>(0, D::dim() - 1); let normalizer = self.fixed_slice::>(D::dim() - 1, 0); diff --git a/src/core/componentwise.rs b/src/core/componentwise.rs index e8fa857b..031af3de 100644 --- a/src/core/componentwise.rs +++ b/src/core/componentwise.rs @@ -4,21 +4,22 @@ use num::Signed; use alga::general::{ClosedMul, ClosedDiv}; -use core::{Scalar, Matrix, OwnedMatrix, MatrixSum}; +use core::{DefaultAllocator, Scalar, Matrix, MatrixMN, MatrixSum}; use core::dimension::Dim; use core::storage::{Storage, StorageMut}; -use core::allocator::SameShapeAllocator; +use core::allocator::{Allocator, SameShapeAllocator}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; /// The type of the result of a matrix componentwise operation. -pub type MatrixComponentOp = MatrixSum; +pub type MatrixComponentOp = MatrixSum; impl> Matrix { /// Computes the componentwise absolute value. #[inline] - pub fn abs(&self) -> OwnedMatrix - where N: Signed { + pub fn abs(&self) -> MatrixMN + where N: Signed, + DefaultAllocator: Allocator { let mut res = self.clone_owned(); for e in res.iter_mut() { @@ -33,27 +34,32 @@ impl> Matrix { macro_rules! component_binop_impl( ($($binop: ident, $binop_mut: ident, $Trait: ident . $binop_assign: ident, $desc:expr, $desc_mut:expr);* $(;)*) => {$( - impl> Matrix { + impl> Matrix { #[doc = $desc] #[inline] - pub fn $binop(&self, rhs: &Matrix) -> MatrixComponentOp + pub fn $binop(&self, rhs: &Matrix) -> MatrixComponentOp where N: $Trait, R2: Dim, C2: Dim, SB: Storage, - S::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); let mut res = self.clone_owned_sum(); - - for (res, rhs) in res.iter_mut().zip(rhs.iter()) { - res.$binop_assign(*rhs); + + for j in 0 .. res.ncols() { + for i in 0 .. res.nrows() { + unsafe { + res.get_unchecked_mut(i, j).$binop_assign(*rhs.get_unchecked(i, j)); + } + } } - + res } } - - impl> Matrix { + + impl> Matrix { #[doc = $desc_mut] #[inline] pub fn $binop_mut(&mut self, rhs: &Matrix) @@ -61,9 +67,16 @@ macro_rules! component_binop_impl( R2: Dim, C2: Dim, SB: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - for (me, rhs) in self.iter_mut().zip(rhs.iter()) { - me.$binop_assign(*rhs); + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + self.get_unchecked_mut(i, j).$binop_assign(*rhs.get_unchecked(i, j)); + } + } } } } diff --git a/src/core/constraint.rs b/src/core/constraint.rs index 0f017e5b..36867b18 100644 --- a/src/core/constraint.rs +++ b/src/core/constraint.rs @@ -6,8 +6,7 @@ use core::dimension::{Dim, DimName, Dynamic}; pub struct ShapeConstraint; /// Constraints `C1` and `R2` to be equivalent. -pub trait AreMultipliable { +pub trait AreMultipliable: DimEq { } @@ -15,11 +14,30 @@ impl AreMultipliable for Sha where ShapeConstraint: DimEq { } +/// Constraints `D1` and `D2` to be equivalent. +pub trait DimEq { + /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level + /// constant. + type Representative: Dim; +} + +impl DimEq for ShapeConstraint { + type Representative = D; +} + +impl DimEq for ShapeConstraint { + type Representative = D; +} + +impl DimEq for ShapeConstraint { + type Representative = D; +} + macro_rules! equality_trait_decl( ($($doc: expr, $Trait: ident),* $(,)*) => {$( // XXX: we can't do something like `DimEq for D2` because we would require a blancket impl… #[doc = $doc] - pub trait $Trait { + pub trait $Trait: DimEq + DimEq { /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level /// constant. type Representative: Dim; @@ -40,9 +58,6 @@ macro_rules! equality_trait_decl( ); equality_trait_decl!( - "Constraints `D1` and `D2` to be equivalent.", - DimEq, - "Constraints `D1` and `D2` to be equivalent. \ They are both assumed to be the number of \ rows of a matrix.", diff --git a/src/core/construction.rs b/src/core/construction.rs index 606f0a2f..48c055a0 100644 --- a/src/core/construction.rs +++ b/src/core/construction.rs @@ -1,5 +1,7 @@ #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; use std::iter; use num::{Zero, One, Bounded}; @@ -8,38 +10,44 @@ use typenum::{self, Cmp, Greater}; use alga::general::{ClosedAdd, ClosedMul}; -use core::{Scalar, Matrix, SquareMatrix, ColumnVector, Unit}; +use core::{DefaultAllocator, Scalar, Matrix, Vector, Unit, MatrixMN, MatrixN, VectorN}; use core::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6}; -use core::allocator::{Allocator, OwnedAllocator}; -use core::storage::{Storage, OwnedStorage}; +use core::allocator::Allocator; +use core::storage::Storage; /* * * Generic constructors. * */ -impl> Matrix - // XXX: needed because of a compiler bug. See the rust compiler issue #26026. - where S::Alloc: OwnedAllocator { +impl MatrixMN + where DefaultAllocator: Allocator { /// Creates a new uninitialized matrix. If the matrix has a compile-time dimension, this panics /// if `nrows != R::to_usize()` or `ncols != C::to_usize()`. #[inline] - pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> Matrix { - Matrix::from_data(S::Alloc::allocate_uninitialized(nrows, ncols)) + pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> Self { + Self::from_data(DefaultAllocator::allocate_uninitialized(nrows, ncols)) } /// Creates a matrix with all its elements set to `elem`. #[inline] - pub fn from_element_generic(nrows: R, ncols: C, elem: N) -> Matrix { + pub fn from_element_generic(nrows: R, ncols: C, elem: N) -> Self { let len = nrows.value() * ncols.value(); - Matrix::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len)) + Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len)) + } + + /// Creates a matrix with all its elements set to 0. + #[inline] + pub fn zeros_generic(nrows: R, ncols: C) -> Self + where N: Zero { + Self::from_element_generic(nrows, ncols, N::zero()) } /// Creates a matrix with all its elements filled by an iterator. #[inline] - pub fn from_iterator_generic(nrows: R, ncols: C, iter: I) -> Matrix + pub fn from_iterator_generic(nrows: R, ncols: C, iter: I) -> Self where I: IntoIterator { - Matrix::from_data(S::Alloc::allocate_from_iterator(nrows, ncols, iter)) + Self::from_data(DefaultAllocator::allocate_from_iterator(nrows, ncols, iter)) } /// Creates a matrix with its elements filled with the components provided by a slice in @@ -48,7 +56,7 @@ impl> Matrix /// The order of elements in the slice must follow the usual mathematic writing, i.e., /// row-by-row. #[inline] - pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Matrix { + pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Self { assert!(slice.len() == nrows.value() * ncols.value(), "Matrix init. error: the slice did not contain the right number of elements."); @@ -69,14 +77,14 @@ impl> Matrix /// Creates a matrix with its elements filled with the components provided by a slice. The /// components must have the same layout as the matrix data storage (i.e. row-major or column-major). #[inline] - pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Matrix { - Matrix::from_iterator_generic(nrows, ncols, slice.iter().cloned()) + pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Self { + Self::from_iterator_generic(nrows, ncols, slice.iter().cloned()) } /// Creates a matrix filled with the results of a function applied to each of its component /// coordinates. #[inline] - pub fn from_fn_generic(nrows: R, ncols: C, mut f: F) -> Matrix + pub fn from_fn_generic(nrows: R, ncols: C, mut f: F) -> Self where F: FnMut(usize, usize) -> N { let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) }; @@ -94,7 +102,7 @@ impl> Matrix /// If the matrix is not square, the largest square submatrix starting at index `(0, 0)` is set /// to the identity matrix. All other entries are set to zero. #[inline] - pub fn identity_generic(nrows: R, ncols: C) -> Matrix + pub fn identity_generic(nrows: R, ncols: C) -> Self where N: Zero + One { Self::from_diagonal_element_generic(nrows, ncols, N::one()) } @@ -104,10 +112,9 @@ impl> Matrix /// If the matrix is not square, the largest square submatrix starting at index `(0, 0)` is set /// to the identity matrix. All other entries are set to zero. #[inline] - pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: N) -> Matrix + pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: N) -> Self where N: Zero + One { - let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) }; - res.fill(N::zero()); + let mut res = Self::zeros_generic(nrows, ncols); for i in 0 .. ::min(nrows.value(), ncols.value()) { unsafe { *res.get_unchecked_mut(i, i) = elt } @@ -116,12 +123,29 @@ impl> Matrix res } + /// Creates a new matrix that may be rectangular. The first `elts.len()` diagonal elements are + /// filled with the content of `elts`. Others are set to 0. + /// + /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. + #[inline] + pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[N]) -> Self + where N: Zero { + let mut res = Self::zeros_generic(nrows, ncols); + assert!(elts.len() <= ::min(nrows.value(), ncols.value()), "Too many diagonal elements provided."); + + for (i, elt) in elts.iter().enumerate() { + unsafe { *res.get_unchecked_mut(i, i) = *elt } + } + + res + } + /// Builds a new matrix from its rows. /// /// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do /// not have the same dimensions. #[inline] - pub fn from_rows(rows: &[Matrix]) -> Matrix + pub fn from_rows(rows: &[Matrix]) -> Self where SB: Storage { assert!(rows.len() > 0, "At least one row must be given."); @@ -144,8 +168,8 @@ impl> Matrix /// Panics if not enough columns are provided (for statically-sized matrices), or if all /// columns do not have the same dimensions. #[inline] - pub fn from_columns(columns: &[ColumnVector]) -> Matrix - where SB: Storage { + pub fn from_columns(columns: &[Vector]) -> Self + where SB: Storage { assert!(columns.len() > 0, "At least one column must be given."); let ncols = C::try_to_usize().unwrap_or(columns.len()); @@ -160,31 +184,27 @@ impl> Matrix // FIXME: optimize that. Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| columns[j][i]) } -} -impl Matrix - where N: Scalar + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { /// Creates a matrix filled with random values. #[inline] - pub fn new_random_generic(nrows: R, ncols: C) -> Matrix { - Matrix::from_fn_generic(nrows, ncols, |_, _| rand::random()) + pub fn new_random_generic(nrows: R, ncols: C) -> Self + where N: Rand { + Self::from_fn_generic(nrows, ncols, |_, _| rand::random()) } } -impl SquareMatrix - where N: Scalar + Zero, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl MatrixN + where N: Scalar, + DefaultAllocator: Allocator { /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. #[inline] - pub fn from_diagonal>(diag: &ColumnVector) -> Self { + pub fn from_diagonal>(diag: &Vector) -> Self + where N: Zero { let (dim, _) = diag.data.shape(); - let mut res = Self::from_element_generic(dim, dim, N::zero()); + let mut res = Self::zeros_generic(dim, dim); for i in 0 .. diag.len() { - unsafe { *res.get_unchecked_mut(i, i) = *diag.get_unchecked(i, 0); } + unsafe { *res.get_unchecked_mut(i, i) = *diag.vget_unchecked(i); } } res @@ -199,25 +219,31 @@ impl SquareMatrix */ macro_rules! impl_constructors( ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { - impl Matrix - where S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl MatrixMN + where DefaultAllocator: Allocator { /// Creates a new uninitialized matrix. #[inline] - pub unsafe fn new_uninitialized($($args: usize),*) -> Matrix { + pub unsafe fn new_uninitialized($($args: usize),*) -> Self { Self::new_uninitialized_generic($($gargs),*) } /// Creates a matrix with all its elements set to `elem`. #[inline] - pub fn from_element($($args: usize,)* elem: N) -> Matrix { + pub fn from_element($($args: usize,)* elem: N) -> Self { Self::from_element_generic($($gargs, )* elem) } + /// Creates a matrix with all its elements set to `0`. + #[inline] + pub fn zeros($($args: usize),*) -> Self + where N: Zero { + Self::zeros_generic($($gargs),*) + } + /// Creates a matrix with all its elements filled by an iterator. #[inline] - pub fn from_iterator($($args: usize,)* iter: I) -> Matrix + pub fn from_iterator($($args: usize,)* iter: I) -> Self where I: IntoIterator { Self::from_iterator_generic($($gargs, )* iter) } @@ -228,14 +254,14 @@ macro_rules! impl_constructors( /// The order of elements in the slice must follow the usual mathematic writing, i.e., /// row-by-row. #[inline] - pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Matrix { + pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Self { Self::from_row_slice_generic($($gargs, )* slice) } /// Creates a matrix with its elements filled with the components provided by a slice /// in column-major order. #[inline] - pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Matrix { + pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Self { Self::from_column_slice_generic($($gargs, )* slice) } @@ -243,7 +269,7 @@ macro_rules! impl_constructors( /// component coordinates. // FIXME: don't take a dimension of the matrix is statically sized. #[inline] - pub fn from_fn($($args: usize,)* f: F) -> Matrix + pub fn from_fn($($args: usize,)* f: F) -> Self where F: FnMut(usize, usize) -> N { Self::from_fn_generic($($gargs, )* f) } @@ -252,7 +278,7 @@ macro_rules! impl_constructors( /// submatrix (starting at the first row and column) is set to the identity while all /// other entries are set to zero. #[inline] - pub fn identity($($args: usize,)*) -> Matrix + pub fn identity($($args: usize,)*) -> Self where N: Zero + One { Self::identity_generic($($gargs),* ) } @@ -260,19 +286,28 @@ macro_rules! impl_constructors( /// Creates a matrix filled with its diagonal filled with `elt` and all other /// components set to zero. #[inline] - pub fn from_diagonal_element($($args: usize,)* elt: N) -> Matrix + pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self where N: Zero + One { Self::from_diagonal_element_generic($($gargs, )* elt) } + + /// Creates a new matrix that may be rectangular. The first `elts.len()` diagonal + /// elements are filled with the content of `elts`. Others are set to 0. + /// + /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. + #[inline] + pub fn from_partial_diagonal($($args: usize,)* elts: &[N]) -> Self + where N: Zero { + Self::from_partial_diagonal_generic($($gargs, )* elts) + } } - impl Matrix - where S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl MatrixMN + where DefaultAllocator: Allocator { /// Creates a matrix filled with random values. #[inline] - pub fn new_random($($args: usize),*) -> Matrix { + pub fn new_random($($args: usize),*) -> Self { Self::new_random_generic($($gargs),*) } } @@ -305,10 +340,9 @@ impl_constructors!(Dynamic, Dynamic; * Zero, One, Rand traits. * */ -impl Zero for Matrix +impl Zero for MatrixMN where N: Scalar + Zero + ClosedAdd, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn zero() -> Self { Self::from_element(N::zero()) @@ -320,20 +354,18 @@ impl Zero for Matrix } } -impl One for Matrix +impl One for MatrixN where N: Scalar + Zero + One + ClosedMul + ClosedAdd, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn one() -> Self { Self::identity() } } -impl Bounded for Matrix +impl Bounded for MatrixMN where N: Scalar + Bounded, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn max_value() -> Self { Self::from_element(N::max_value()) @@ -345,9 +377,8 @@ impl Bounded for Matrix } } -impl Rand for Matrix - where S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for MatrixMN + where DefaultAllocator: Allocator { #[inline] fn rand(rng: &mut G) -> Self { let nrows = R::try_to_usize().unwrap_or(rng.gen_range(0, 10)); @@ -359,11 +390,11 @@ impl Rand for Matrix #[cfg(feature = "arbitrary")] -impl Arbitrary for Matrix +impl Arbitrary for MatrixMN where R: Dim, C: Dim, N: Scalar + Arbitrary + Send, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator, + Owned: Clone + Send { #[inline] fn arbitrary(g: &mut G) -> Self { let nrows = R::try_to_usize().unwrap_or(g.gen_range(0, 10)); @@ -381,13 +412,12 @@ impl Arbitrary for Matrix */ macro_rules! componentwise_constructors_impl( ($($R: ty, $C: ty, $($args: ident:($irow: expr,$icol: expr)),*);* $(;)*) => {$( - impl Matrix + impl MatrixMN where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { /// Initializes this matrix from its components. #[inline] - pub fn new($($args: N),*) -> Matrix { + pub fn new($($args: N),*) -> Self { unsafe { let mut res = Self::new_uninitialized(); $( *res.get_unchecked_mut($irow, $icol) = $args; )* @@ -549,16 +579,15 @@ componentwise_constructors_impl!( * Axis constructors. * */ -impl ColumnVector +impl VectorN where N: Scalar + Zero + One, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { /// The column vector with a 1 as its first component, and zero elsewhere. #[inline] pub fn x() -> Self where R::Value: Cmp { let mut res = Self::from_element(N::zero()); - unsafe { *res.get_unchecked_mut(0, 0) = N::one(); } + unsafe { *res.vget_unchecked_mut(0) = N::one(); } res } @@ -568,7 +597,7 @@ where N: Scalar + Zero + One, pub fn y() -> Self where R::Value: Cmp { let mut res = Self::from_element(N::zero()); - unsafe { *res.get_unchecked_mut(1, 0) = N::one(); } + unsafe { *res.vget_unchecked_mut(1) = N::one(); } res } @@ -578,7 +607,7 @@ where N: Scalar + Zero + One, pub fn z() -> Self where R::Value: Cmp { let mut res = Self::from_element(N::zero()); - unsafe { *res.get_unchecked_mut(2, 0) = N::one(); } + unsafe { *res.vget_unchecked_mut(2) = N::one(); } res } @@ -588,7 +617,7 @@ where N: Scalar + Zero + One, pub fn w() -> Self where R::Value: Cmp { let mut res = Self::from_element(N::zero()); - unsafe { *res.get_unchecked_mut(3, 0) = N::one(); } + unsafe { *res.vget_unchecked_mut(3) = N::one(); } res } @@ -598,7 +627,7 @@ where N: Scalar + Zero + One, pub fn a() -> Self where R::Value: Cmp { let mut res = Self::from_element(N::zero()); - unsafe { *res.get_unchecked_mut(4, 0) = N::one(); } + unsafe { *res.vget_unchecked_mut(4) = N::one(); } res } @@ -608,7 +637,7 @@ where N: Scalar + Zero + One, pub fn b() -> Self where R::Value: Cmp { let mut res = Self::from_element(N::zero()); - unsafe { *res.get_unchecked_mut(5, 0) = N::one(); } + unsafe { *res.vget_unchecked_mut(5) = N::one(); } res } diff --git a/src/core/conversion.rs b/src/core/conversion.rs index 7e8f40cb..738857d5 100644 --- a/src/core/conversion.rs +++ b/src/core/conversion.rs @@ -3,37 +3,35 @@ use std::mem; use std::convert::{From, Into, AsRef, AsMut}; use alga::general::{SubsetOf, SupersetOf}; -use core::{Scalar, Matrix}; +use core::{DefaultAllocator, Scalar, Matrix, MatrixMN}; use core::dimension::{Dim, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16 }; -use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; -use core::storage::{Storage, StorageMut, OwnedStorage}; use core::iter::{MatrixIter, MatrixIterMut}; -use core::allocator::{OwnedAllocator, SameShapeAllocator}; +use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; +use core::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; +use core::allocator::{Allocator, SameShapeAllocator}; // FIXME: too bad this won't work allo slice conversions. -impl SubsetOf> for Matrix +impl SubsetOf> for MatrixMN where R1: Dim, C1: Dim, R2: Dim, C2: Dim, N1: Scalar, N2: Scalar + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SB::Alloc: OwnedAllocator, - SA::Alloc: OwnedAllocator + - SameShapeAllocator, + DefaultAllocator: Allocator + + Allocator + + SameShapeAllocator, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { #[inline] - fn to_superset(&self) -> Matrix { + fn to_superset(&self) -> MatrixMN { let (nrows, ncols) = self.shape(); let nrows2 = R2::from_usize(nrows); let ncols2 = C2::from_usize(ncols); - let mut res = unsafe { Matrix::::new_uninitialized_generic(nrows2, ncols2) }; + let mut res = unsafe { MatrixMN::::new_uninitialized_generic(nrows2, ncols2) }; for i in 0 .. nrows { for j in 0 .. ncols { unsafe { @@ -46,12 +44,12 @@ impl SubsetOf> for Matrix } #[inline] - fn is_in_subset(m: &Matrix) -> bool { + fn is_in_subset(m: &MatrixMN) -> bool { m.iter().all(|e| e.is_in_subset()) } #[inline] - unsafe fn from_superset_unchecked(m: &Matrix) -> Self { + unsafe fn from_superset_unchecked(m: &MatrixMN) -> Self { let (nrows2, ncols2) = m.shape(); let nrows = R1::from_usize(nrows2); let ncols = C1::from_usize(ncols2); @@ -90,10 +88,9 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut> IntoIterator for &'a macro_rules! impl_from_into_asref_1D( ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$( - impl From<[N; $SZ]> for Matrix + impl From<[N; $SZ]> for MatrixMN where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn from(arr: [N; $SZ]) -> Self { unsafe { @@ -107,8 +104,7 @@ macro_rules! impl_from_into_asref_1D( impl Into<[N; $SZ]> for Matrix where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + S: ContiguousStorage { #[inline] fn into(self) -> [N; $SZ] { unsafe { @@ -122,8 +118,7 @@ macro_rules! impl_from_into_asref_1D( impl AsRef<[N; $SZ]> for Matrix where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + S: ContiguousStorage { #[inline] fn as_ref(&self) -> &[N; $SZ] { unsafe { @@ -134,8 +129,7 @@ macro_rules! impl_from_into_asref_1D( impl AsMut<[N; $SZ]> for Matrix where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + S: ContiguousStorageMut { #[inline] fn as_mut(&mut self) -> &mut [N; $SZ] { unsafe { @@ -165,10 +159,8 @@ impl_from_into_asref_1D!( macro_rules! impl_from_into_asref_2D( ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( - impl From<[[N; $SZRows]; $SZCols]> for Matrix - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl From<[[N; $SZRows]; $SZCols]> for MatrixMN + where DefaultAllocator: Allocator { #[inline] fn from(arr: [[N; $SZRows]; $SZCols]) -> Self { unsafe { @@ -180,10 +172,8 @@ macro_rules! impl_from_into_asref_2D( } } - impl Into<[[N; $SZRows]; $SZCols]> for Matrix - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl Into<[[N; $SZRows]; $SZCols]> for Matrix + where S: ContiguousStorage { #[inline] fn into(self) -> [[N; $SZRows]; $SZCols] { unsafe { @@ -195,10 +185,8 @@ macro_rules! impl_from_into_asref_2D( } } - impl AsRef<[[N; $SZRows]; $SZCols]> for Matrix - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl AsRef<[[N; $SZRows]; $SZCols]> for Matrix + where S: ContiguousStorage { #[inline] fn as_ref(&self) -> &[[N; $SZRows]; $SZCols] { unsafe { @@ -207,10 +195,8 @@ macro_rules! impl_from_into_asref_2D( } } - impl AsMut<[[N; $SZRows]; $SZCols]> for Matrix - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl AsMut<[[N; $SZRows]; $SZCols]> for Matrix + where S: ContiguousStorageMut { #[inline] fn as_mut(&mut self) -> &mut [[N; $SZRows]; $SZCols] { unsafe { @@ -222,7 +208,7 @@ macro_rules! impl_from_into_asref_2D( ); -// Implement for matrices with shape 2x2 .. 4x4. +// Implement for matrices with shape 2x2 .. 6x6. impl_from_into_asref_2D!( (U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6); (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6); diff --git a/src/core/coordinates.rs b/src/core/coordinates.rs index 63d81166..95fd3011 100644 --- a/src/core/coordinates.rs +++ b/src/core/coordinates.rs @@ -9,8 +9,7 @@ use std::ops::{Deref, DerefMut}; use core::{Scalar, Matrix}; use core::dimension::{U1, U2, U3, U4, U5, U6}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::storage::{ContiguousStorage, ContiguousStorageMut}; /* * @@ -35,22 +34,20 @@ macro_rules! coords_impl( macro_rules! deref_impl( ($R: ty, $C: ty; $Target: ident) => { impl Deref for Matrix - where S: OwnedStorage, - S::Alloc: OwnedAllocator { + where S: ContiguousStorage { type Target = $Target; #[inline] fn deref(&self) -> &Self::Target { - unsafe { mem::transmute(self) } + unsafe { mem::transmute(self.data.ptr()) } } } impl DerefMut for Matrix - where S: OwnedStorage, - S::Alloc: OwnedAllocator { + where S: ContiguousStorageMut { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { mem::transmute(self) } + unsafe { mem::transmute(self.data.ptr_mut()) } } } } diff --git a/src/core/decompositions.rs b/src/core/decompositions.rs deleted file mode 100644 index 41183fcb..00000000 --- a/src/core/decompositions.rs +++ /dev/null @@ -1,373 +0,0 @@ -use std::cmp; - -use alga::general::Real; -use core::{SquareMatrix, OwnedSquareMatrix, ColumnVector, OwnedColumnVector}; -use dimension::{Dim, Dynamic, U1}; -use storage::{Storage, OwnedStorage}; -use allocator::{Allocator, OwnedAllocator}; - - - -impl SquareMatrix - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { - /// Get the householder matrix corresponding to a reflexion to the hyperplane - /// defined by `vector`. It can be a reflexion contained in a subspace. - /// - /// # Arguments - /// * `dimension` - the dimension of the space the resulting matrix operates in - /// * `start` - the starting dimension of the subspace of the reflexion - /// * `vector` - the vector defining the reflection. - pub fn new_householder_generic(dimension: D, start: usize, vector: &ColumnVector) - -> OwnedSquareMatrix - where D2: Dim, - SB: Storage { - let mut qk = Self::identity_generic(dimension, dimension); - let subdim = vector.shape().0; - - let stop = subdim + start; - - assert!(dimension.value() >= stop, "Householder matrix creation: subspace dimension index out of bounds."); - - for j in start .. stop { - for i in start .. stop { - unsafe { - let vv = *vector.get_unchecked(i - start, 0) * *vector.get_unchecked(j - start, 0); - let qkij = *qk.get_unchecked(i, j); - *qk.get_unchecked_mut(i, j) = qkij - vv - vv; - } - } - } - - qk - } -} - - -impl> SquareMatrix { - /// QR decomposition using Householder reflections. - pub fn qr(self) -> (OwnedSquareMatrix, OwnedSquareMatrix) - where S::Alloc: Allocator + - Allocator { - - let (nrows, ncols) = self.data.shape(); - - // XXX: too restrictive. - assert!(nrows.value() >= ncols.value(), ""); - - let mut q = OwnedSquareMatrix::::identity_generic(nrows, ncols); - let mut r = self.into_owned(); - - // Temporary buffer that contains a column. - let mut col = unsafe { - OwnedColumnVector::::new_uninitialized_generic(nrows, U1) - }; - - for ite in 0 .. cmp::min(nrows.value() - 1, ncols.value()) { - let subdim = Dynamic::new(nrows.value() - ite); - let mut v = col.rows_mut(0, subdim.value()); - v.copy_from(&r.generic_slice((ite, ite), (subdim, U1))); - - let alpha = - if unsafe { *v.get_unchecked(ite, 0) } >= ::zero() { - -v.norm() - } - else { - v.norm() - }; - - unsafe { - let x = *v.get_unchecked(0, 0); - *v.get_unchecked_mut(0, 0) = x - alpha; - } - - if !v.normalize_mut().is_zero() { - let mut qk = OwnedSquareMatrix::::new_householder_generic(nrows, ite, &v); - r = &qk * r; - - // FIXME: add a method `q.mul_tr(qk) := q * qk.transpose` ? - qk.transpose_mut(); - q = q * qk; - } - } - - (q, r) - } - - /// Eigendecomposition of a square symmetric matrix. - pub fn eig(&self, eps: N, niter: usize) - -> (OwnedSquareMatrix, OwnedColumnVector) - where S::Alloc: Allocator + - Allocator { - - assert!(self.is_square(), - "Unable to compute the eigenvectors and eigenvalues of a non-square matrix."); - - let dim = self.data.shape().0; - - let (mut eigenvectors, mut eigenvalues) = self.hessenberg(); - - if dim.value() == 1 { - return (eigenvectors, eigenvalues.diagonal()); - } - - // Allocate arrays for Givens rotation components - let mut c = unsafe { OwnedColumnVector::::new_uninitialized_generic(dim, U1) }; - let mut s = unsafe { OwnedColumnVector::::new_uninitialized_generic(dim, U1) }; - - let mut iter = 0; - let mut curdim = dim.value() - 1; - - for _ in 0 .. dim.value() { - - let mut stop = false; - - while !stop && iter < niter { - - let lambda; - - unsafe { - let a = *eigenvalues.get_unchecked(curdim - 1, curdim - 1); - let b = *eigenvalues.get_unchecked(curdim - 1, curdim); - let c = *eigenvalues.get_unchecked(curdim, curdim - 1); - let d = *eigenvalues.get_unchecked(curdim, curdim); - - let trace = a + d; - let determinant = a * d - b * c; - - let constquarter: N = ::convert(0.25f64); - let consthalf: N = ::convert(0.5f64); - - let e = (constquarter * trace * trace - determinant).sqrt(); - - let lambda1 = consthalf * trace + e; - let lambda2 = consthalf * trace - e; - - if (lambda1 - d).abs() < (lambda2 - d).abs() { - lambda = lambda1; - } - else { - lambda = lambda2; - } - - } - - // Shift matrix - for k in 0 .. curdim + 1 { - unsafe { - let a = *eigenvalues.get_unchecked(k, k); - *eigenvalues.get_unchecked_mut(k, k) = a - lambda; - } - } - - - // Givens rotation from left - for k in 0 .. curdim { - let x_i = unsafe { *eigenvalues.get_unchecked(k, k) }; - let x_j = unsafe { *eigenvalues.get_unchecked(k + 1, k) }; - - let ctmp; - let stmp; - - if x_j.abs() < eps { - ctmp = N::one(); - stmp = N::zero(); - } - else if x_i.abs() < eps { - ctmp = N::zero(); - stmp = -N::one(); - } - else { - let r = x_i.hypot(x_j); - ctmp = x_i / r; - stmp = -x_j / r; - } - - c[k] = ctmp; - s[k] = stmp; - - for j in k .. (curdim + 1) { - unsafe { - let a = *eigenvalues.get_unchecked(k, j); - let b = *eigenvalues.get_unchecked(k + 1, j); - - *eigenvalues.get_unchecked_mut(k, j) = ctmp * a - stmp * b; - *eigenvalues.get_unchecked_mut(k + 1, j) = stmp * a + ctmp * b; - } - - } - } - - // Givens rotation from right applied to eigenvalues - for k in 0 .. curdim { - for i in 0 .. (k + 2) { - unsafe { - let a = *eigenvalues.get_unchecked(i, k); - let b = *eigenvalues.get_unchecked(i, k + 1); - - *eigenvalues.get_unchecked_mut(i, k) = c[k] * a - s[k] * b; - *eigenvalues.get_unchecked_mut(i, k + 1) = s[k] * a + c[k] * b; - } - } - } - - - // Shift back - for k in 0 .. curdim + 1 { - unsafe { - let a = *eigenvalues.get_unchecked(k, k); - *eigenvalues.get_unchecked_mut(k, k) = a + lambda; - } - } - - - // Givens rotation from right applied to eigenvectors - for k in 0 .. curdim { - for i in 0 .. dim.value() { - - unsafe { - let a = *eigenvectors.get_unchecked(i, k); - let b = *eigenvectors.get_unchecked(i, k + 1); - - *eigenvectors.get_unchecked_mut(i, k) = c[k] * a - s[k] * b; - *eigenvectors.get_unchecked_mut(i, k + 1) = s[k] * a + c[k] * b; - } - } - } - - iter = iter + 1; - stop = true; - - for j in 0 .. curdim { - // Check last row. - if unsafe { *eigenvalues.get_unchecked(curdim, j) }.abs() >= eps { - stop = false; - break; - } - - // Check last column. - if unsafe { *eigenvalues.get_unchecked(j, curdim) }.abs() >= eps { - stop = false; - break; - } - } - } - - - if stop { - if curdim > 1 { - curdim = curdim - 1; - } - else { - break; - } - } - } - - (eigenvectors, eigenvalues.diagonal()) - } - - /// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T - /// - /// Matrix symmetricness is not checked. Returns `None` if `self` is not definite positive. - #[inline] - pub fn cholesky(&self) -> Result, &'static str> { - let out = self.transpose(); - - if !out.relative_eq(self, N::default_epsilon(), N::default_max_relative()) { - return Err("Cholesky: Input matrix is not symmetric"); - } - - self.do_cholesky(out) - } - - /// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T - #[inline] - pub fn cholesky_unchecked(&self) -> Result, &'static str> { - let out = self.transpose(); - self.do_cholesky(out) - } - - #[inline(always)] - fn do_cholesky(&self, mut out: OwnedSquareMatrix) - -> Result, &'static str> { - assert!(self.is_square(), "The input matrix must be square."); - - for i in 0 .. out.nrows() { - for j in 0 .. (i + 1) { - - let mut sum = out[(i, j)]; - - for k in 0 .. j { - sum = sum - out[(i, k)] * out[(j, k)]; - } - - if i > j { - out[(i, j)] = sum / out[(j, j)]; - } - else if sum > N::zero() { - out[(i, i)] = sum.sqrt(); - } - else { - return Err("Cholesky: Input matrix is not positive definite to machine precision."); - } - } - } - - for i in 0 .. out.nrows() { - for j in i + 1 .. out.ncols() { - out[(i, j)] = N::zero(); - } - } - - Ok(out) - } - - /// Hessenberg - /// Returns the matrix `self` in Hessenberg form and the corresponding similarity transformation - /// - /// # Returns - /// The tuple (`q`, `h`) that `q * h * q^T = self` - pub fn hessenberg(&self) -> (OwnedSquareMatrix, OwnedSquareMatrix) - where S::Alloc: Allocator + Allocator { - - let (nrows, ncols) = self.data.shape(); - let mut h = self.clone_owned(); - - let mut q = OwnedSquareMatrix::::identity_generic(nrows, ncols); - - if ncols.value() <= 2 { - return (q, h); - } - - // Temporary buffer that contains a column. - let mut col = unsafe { - OwnedColumnVector::::new_uninitialized_generic(nrows, U1) - }; - - for ite in 0 .. (ncols.value() - 2) { - let subdim = Dynamic::new(nrows.value() - (ite + 1)); - let mut v = col.rows_mut(0, subdim.value()); - v.copy_from(&h.generic_slice((ite + 1, ite), (subdim, U1))); - - let alpha = v.norm(); - - unsafe { - let x = *v.get_unchecked(0, 0); - *v.get_unchecked_mut(0, 0) = x - alpha; - } - - if !v.normalize_mut().is_zero() { - // XXX: we output the householder matrix to a pre-allocated matrix instead of - // return a value to `p`. This would avoid allocation at each iteration. - let p = OwnedSquareMatrix::::new_householder_generic(nrows, ite + 1, &v); - - q = q * &p; - h = &p * h * p; - } - } - - (q, h) - } -} diff --git a/src/core/default_allocator.rs b/src/core/default_allocator.rs index acfbe97c..fd801d27 100644 --- a/src/core/default_allocator.rs +++ b/src/core/default_allocator.rs @@ -4,6 +4,8 @@ //! heap-allocated buffers for matrices with at least one dimension unknown at compile-time. use std::mem; +use std::ptr; +use std::cmp; use std::ops::Mul; use typenum::Prod; @@ -11,7 +13,8 @@ use generic_array::ArrayLength; use core::Scalar; use core::dimension::{Dim, DimName, Dynamic}; -use core::allocator::Allocator; +use core::allocator::{Allocator, Reallocator}; +use core::storage::{Storage, StorageMut}; use core::matrix_array::MatrixArray; use core::matrix_vec::MatrixVec; @@ -107,3 +110,110 @@ impl Allocator for DefaultAllocator { MatrixVec::new(nrows, ncols, res) } } + +/* + * + * Reallocator. + * + */ +// Anything -> Static × Static +impl Reallocator for DefaultAllocator + where RFrom: Dim, + CFrom: Dim, + RTo: DimName, + CTo: DimName, + Self: Allocator, + RTo::Value: Mul, + Prod: ArrayLength { + + #[inline] + unsafe fn reallocate_copy(rto: RTo, cto: CTo, buf: >::Buffer) -> MatrixArray { + let mut res = >::allocate_uninitialized(rto, cto); + + let (rfrom, cfrom) = buf.shape(); + + let len_from = rfrom.value() * cfrom.value(); + let len_to = rto.value() * cto.value(); + ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to)); + + res + } +} + + +// Static × Static -> Dynamic × Any +impl Reallocator for DefaultAllocator + where RFrom: DimName, + CFrom: DimName, + CTo: Dim, + RFrom::Value: Mul, + Prod: ArrayLength { + + #[inline] + unsafe fn reallocate_copy(rto: Dynamic, cto: CTo, buf: MatrixArray) -> MatrixVec { + let mut res = >::allocate_uninitialized(rto, cto); + + let (rfrom, cfrom) = buf.shape(); + + let len_from = rfrom.value() * cfrom.value(); + let len_to = rto.value() * cto.value(); + ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to)); + + res + } +} + +// Static × Static -> Static × Dynamic +impl Reallocator for DefaultAllocator + where RFrom: DimName, + CFrom: DimName, + RTo: DimName, + RFrom::Value: Mul, + Prod: ArrayLength { + + #[inline] + unsafe fn reallocate_copy(rto: RTo, cto: Dynamic, buf: MatrixArray) -> MatrixVec { + let mut res = >::allocate_uninitialized(rto, cto); + + let (rfrom, cfrom) = buf.shape(); + + let len_from = rfrom.value() * cfrom.value(); + let len_to = rto.value() * cto.value(); + ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to)); + + res + } +} + +// All conversion from a dynamic buffer to a dynamic buffer. +impl Reallocator for DefaultAllocator { + #[inline] + unsafe fn reallocate_copy(rto: Dynamic, cto: CTo, buf: MatrixVec) -> MatrixVec { + let new_buf = buf.resize(rto.value() * cto.value()); + MatrixVec::new(rto, cto, new_buf) + } +} + +impl Reallocator for DefaultAllocator { + #[inline] + unsafe fn reallocate_copy(rto: RTo, cto: Dynamic, buf: MatrixVec) -> MatrixVec { + let new_buf = buf.resize(rto.value() * cto.value()); + MatrixVec::new(rto, cto, new_buf) + } +} + +impl Reallocator for DefaultAllocator { + #[inline] + unsafe fn reallocate_copy(rto: Dynamic, cto: CTo, buf: MatrixVec) -> MatrixVec { + let new_buf = buf.resize(rto.value() * cto.value()); + MatrixVec::new(rto, cto, new_buf) + } +} + +impl Reallocator for DefaultAllocator { + #[inline] + unsafe fn reallocate_copy(rto: RTo, cto: Dynamic, buf: MatrixVec) -> MatrixVec { + let new_buf = buf.resize(rto.value() * cto.value()); + MatrixVec::new(rto, cto, new_buf) + } +} diff --git a/src/core/dimension.rs b/src/core/dimension.rs index ec8f3c57..f87eb2cf 100644 --- a/src/core/dimension.rs +++ b/src/core/dimension.rs @@ -3,9 +3,11 @@ //! Traits and tags for identifying the dimension of all algebraic entities. use std::fmt::Debug; -use std::any::Any; +use std::any::{TypeId, Any}; +use std::cmp; use std::ops::{Add, Sub, Mul, Div}; -use typenum::{self, Unsigned, UInt, B1, Bit, UTerm, Sum, Prod, Diff, Quot}; +use typenum::{self, Unsigned, UInt, B1, Bit, UTerm, Sum, Prod, Diff, Quot, + Min, Minimum, Max, Maximum}; #[cfg(feature = "serde-serialize")] use serde::{Serialize, Serializer, Deserialize, Deserializer}; @@ -55,6 +57,11 @@ impl IsNotStaticOne for Dynamic { } /// Trait implemented by any type that can be used as a dimension. This includes type-level /// integers and `Dynamic` (for dimensions not known at compile-time). pub trait Dim: Any + Debug + Copy + PartialEq + Send { + #[inline(always)] + fn is() -> bool { + TypeId::of::() == TypeId::of::() + } + /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self = /// Dynamic`. fn try_to_usize() -> Option; @@ -85,6 +92,24 @@ impl Dim for Dynamic { } } +impl Add for Dynamic { + type Output = Dynamic; + + #[inline] + fn add(self, rhs: usize) -> Dynamic { + Dynamic::new(self.value + rhs) + } +} + +impl Sub for Dynamic { + type Output = Dynamic; + + #[inline] + fn sub(self, rhs: usize) -> Dynamic { + Dynamic::new(self.value - rhs) + } +} + /* * * Operations. @@ -93,7 +118,7 @@ impl Dim for Dynamic { macro_rules! dim_ops( ($($DimOp: ident, $DimNameOp: ident, - $Op: ident, $op: ident, + $Op: ident, $op: ident, $op_path: path, $DimResOp: ident, $DimNameResOp: ident, $ResOp: ident);* $(;)*) => {$( pub type $DimResOp = >::Output; @@ -120,7 +145,7 @@ macro_rules! dim_ops( #[inline] fn $op(self, other: D) -> Dynamic { - Dynamic::new(self.value.$op(other.value())) + Dynamic::new($op_path(self.value, other.value())) } } @@ -129,7 +154,7 @@ macro_rules! dim_ops( #[inline] fn $op(self, other: Dynamic) -> Dynamic { - Dynamic::new(self.value().$op(other.value)) + Dynamic::new($op_path(self.value(), other.value)) } } @@ -155,10 +180,12 @@ macro_rules! dim_ops( ); dim_ops!( - DimAdd, DimNameAdd, Add, add, DimSum, DimNameSum, Sum; - DimMul, DimNameMul, Mul, mul, DimProd, DimNameProd, Prod; - DimSub, DimNameSub, Sub, sub, DimDiff, DimNameDiff, Diff; - DimDiv, DimNameDiv, Div, div, DimQuot, DimNameQuot, Quot; + DimAdd, DimNameAdd, Add, add, Add::add, DimSum, DimNameSum, Sum; + DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod; + DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff; + DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot; + DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameNimimum, Minimum; + DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum; ); diff --git a/src/core/edition.rs b/src/core/edition.rs new file mode 100644 index 00000000..23106484 --- /dev/null +++ b/src/core/edition.rs @@ -0,0 +1,539 @@ +use num::{Zero, One}; +use std::cmp; +use std::ptr; + +use core::{DefaultAllocator, Scalar, Matrix, DMatrix, MatrixMN, Vector}; +use core::dimension::{Dim, DimName, DimSub, DimDiff, DimAdd, DimSum, DimMin, DimMinimum, U1, Dynamic}; +use core::constraint::{ShapeConstraint, DimEq}; +use core::allocator::{Allocator, Reallocator}; +use core::storage::{Storage, StorageMut}; + +impl> Matrix { + /// Extracts the upper triangular part of this matrix (including the diagonal). + #[inline] + pub fn upper_triangle(&self) -> MatrixMN + where DefaultAllocator: Allocator { + let mut res = self.clone_owned(); + res.fill_lower_triangle(N::zero(), 1); + + res + } + + /// Extracts the upper triangular part of this matrix (including the diagonal). + #[inline] + pub fn lower_triangle(&self) -> MatrixMN + where DefaultAllocator: Allocator { + let mut res = self.clone_owned(); + res.fill_upper_triangle(N::zero(), 1); + + res + } +} + +impl> Matrix { + /// Sets all the elements of this matrix to `val`. + #[inline] + pub fn fill(&mut self, val: N) { + for e in self.iter_mut() { + *e = val + } + } + + /// Fills `self` with the identity matrix. + #[inline] + pub fn fill_with_identity(&mut self) + where N: Zero + One { + self.fill(N::zero()); + self.fill_diagonal(N::one()); + } + + /// Sets all the diagonal elements of this matrix to `val`. + #[inline] + pub fn fill_diagonal(&mut self, val: N) { + let (nrows, ncols) = self.shape(); + let n = cmp::min(nrows, ncols); + + for i in 0 .. n { + unsafe { *self.get_unchecked_mut(i, i) = val } + } + } + + /// Sets all the elements of the selected row to `val`. + #[inline] + pub fn fill_row(&mut self, i: usize, val: N) { + assert!(i < self.nrows(), "Row index out of bounds."); + for j in 0 .. self.ncols() { + unsafe { *self.get_unchecked_mut(i, j) = val } + } + } + + /// Sets all the elements of the selected column to `val`. + #[inline] + pub fn fill_column(&mut self, j: usize, val: N) { + assert!(j < self.ncols(), "Row index out of bounds."); + for i in 0 .. self.nrows() { + unsafe { *self.get_unchecked_mut(i, j) = val } + } + } + + /// Fills the diagonal of this matrix with the content of the given vector. + #[inline] + pub fn set_diagonal(&mut self, diag: &Vector) + where R: DimMin, + S2: Storage, + ShapeConstraint: DimEq, R2> { + let (nrows, ncols) = self.shape(); + let min_nrows_ncols = cmp::min(nrows, ncols); + assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions."); + + for i in 0 .. min_nrows_ncols { + unsafe { *self.get_unchecked_mut(i, i) = *diag.vget_unchecked(i) } + } + } + + /// Sets all the elements of the lower-triangular part of this matrix to `val`. + /// + /// The parameter `shift` allows some subdiagonals to be left untouched: + /// * If `shift = 0` then the diagonal is overwritten as well. + /// * If `shift = 1` then the diagonal is left untouched. + /// * If `shift > 1`, then the diagonal and the first `shift - 1` subdiagonals are left + /// untouched. + #[inline] + pub fn fill_lower_triangle(&mut self, val: N, shift: usize) { + for j in 0 .. self.ncols() { + for i in (j + shift) .. self.nrows() { + unsafe { *self.get_unchecked_mut(i, j) = val } + } + } + } + + /// Sets all the elements of the lower-triangular part of this matrix to `val`. + /// + /// The parameter `shift` allows some superdiagonals to be left untouched: + /// * If `shift = 0` then the diagonal is overwritten as well. + /// * If `shift = 1` then the diagonal is left untouched. + /// * If `shift > 1`, then the diagonal and the first `shift - 1` superdiagonals are left + /// untouched. + #[inline] + pub fn fill_upper_triangle(&mut self, val: N, shift: usize) { + for j in shift .. self.ncols() { + // FIXME: is there a more efficient way to avoid the min ? + // (necessary for rectangular matrices) + for i in 0 .. cmp::min(j + 1 - shift, self.nrows()) { + unsafe { *self.get_unchecked_mut(i, j) = val } + } + } + } + + /// Swaps two rows in-place. + #[inline] + pub fn swap_rows(&mut self, irow1: usize, irow2: usize) { + assert!(irow1 < self.nrows() && irow2 < self.nrows()); + + if irow1 != irow2 { + // FIXME: optimize that. + for i in 0 .. self.ncols() { + unsafe { self.swap_unchecked((irow1, i), (irow2, i)) } + } + } + // Otherwise do nothing. + } + + /// Swaps two columns in-place. + #[inline] + pub fn swap_columns(&mut self, icol1: usize, icol2: usize) { + assert!(icol1 < self.ncols() && icol2 < self.ncols()); + + if icol1 != icol2 { + // FIXME: optimize that. + for i in 0 .. self.nrows() { + unsafe { self.swap_unchecked((i, icol1), (i, icol2)) } + } + } + // Otherwise do nothing. + } +} + +impl> Matrix { + /// Copies the upper-triangle of this matrix to its lower-triangular part. + /// + /// This makes the matrix symmetric. Panics if the matrix is not square. + pub fn fill_lower_triangle_with_upper_triangle(&mut self) { + assert!(self.is_square(), "The input matrix should be square."); + + let dim = self.nrows(); + for j in 0 .. dim { + for i in j + 1 .. dim { + unsafe { + *self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i); + } + } + } + } + + /// Copies the upper-triangle of this matrix to its upper-triangular part. + /// + /// This makes the matrix symmetric. Panics if the matrix is not square. + pub fn fill_upper_triangle_with_lower_triangle(&mut self) { + assert!(self.is_square(), "The input matrix should be square."); + + for j in 1 .. self.ncols() { + for i in 0 .. j { + unsafe { + *self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i); + } + } + } + } +} + +/* + * + * FIXME: specialize all the following for slices. + * + */ +impl> Matrix { + /* + * + * Column removal. + * + */ + /// Removes the `i`-th column from this matrix. + #[inline] + pub fn remove_column(self, i: usize) -> MatrixMN> + where C: DimSub, + DefaultAllocator: Reallocator> { + self.remove_fixed_columns::(i) + } + + /// Removes a fixed number − `D::dim()` − of consecutive columns from this matrix, starting + /// with the `i`-th (included). + #[inline] + pub fn remove_fixed_columns(self, i: usize) -> MatrixMN> + where D: DimName, + C: DimSub, + DefaultAllocator: Reallocator> { + + self.remove_columns_generic(i, D::name()) + } + + /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included). + #[inline] + pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN + where C: DimSub, + DefaultAllocator: Reallocator { + + self.remove_columns_generic(i, Dynamic::new(n)) + } + + /// Removes `nremove.value()` columns from this matrix, starting with the `i`-th (included). + /// + /// This is the generic implementation of `.remove_columns(...)` and + /// `.remove_fixed_columns(...)` which have nicer API interfaces. + #[inline] + pub fn remove_columns_generic(self, i: usize, nremove: D) -> MatrixMN> + where D: Dim, + C: DimSub, + DefaultAllocator: Reallocator> { + + let mut m = self.into_owned(); + let (nrows, ncols) = m.data.shape(); + assert!(i + nremove.value() <= ncols.value(), "Column index out of range."); + + if nremove.value() != 0 && i + nremove.value() < ncols.value() { + // The first `deleted_i * nrows` are left untouched. + let copied_value_start = i + nremove.value(); + + unsafe { + let ptr_in = m.data.ptr().offset((copied_value_start * nrows.value()) as isize); + let ptr_out = m.data.ptr_mut().offset((i * nrows.value()) as isize); + + ptr::copy(ptr_in, ptr_out, (ncols.value() - copied_value_start) * nrows.value()); + } + } + + unsafe { + Matrix::from_data(DefaultAllocator::reallocate_copy(nrows, ncols.sub(nremove), m.data)) + } + } + + + /* + * + * Row removal. + * + */ + /// Removes the `i`-th row from this matrix. + #[inline] + pub fn remove_row(self, i: usize) -> MatrixMN, C> + where R: DimSub, + DefaultAllocator: Reallocator, C> { + self.remove_fixed_rows::(i) + } + + /// Removes a fixed number − `D::dim()` − of consecutive rows from this matrix, starting + /// with the `i`-th (included). + #[inline] + pub fn remove_fixed_rows(self, i: usize) -> MatrixMN, C> + where D: DimName, + R: DimSub, + DefaultAllocator: Reallocator, C> { + + self.remove_rows_generic(i, D::name()) + } + + /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included). + #[inline] + pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN + where R: DimSub, + DefaultAllocator: Reallocator { + + self.remove_rows_generic(i, Dynamic::new(n)) + } + + /// Removes `nremove.value()` rows from this matrix, starting with the `i`-th (included). + /// + /// This is the generic implementation of `.remove_rows(...)` and `.remove_fixed_rows(...)` + /// which have nicer API interfaces. + #[inline] + pub fn remove_rows_generic(self, i: usize, nremove: D) -> MatrixMN, C> + where D: Dim, + R: DimSub, + DefaultAllocator: Reallocator, C> { + let mut m = self.into_owned(); + let (nrows, ncols) = m.data.shape(); + assert!(i + nremove.value() <= nrows.value(), "Row index out of range."); + + if nremove.value() != 0 { + unsafe { + compress_rows(&mut m.data.as_mut_slice(), nrows.value(), ncols.value(), i, nremove.value()); + } + } + + unsafe { + Matrix::from_data(DefaultAllocator::reallocate_copy(nrows.sub(nremove), ncols, m.data)) + } + } + + /* + * + * Columns insertion. + * + */ + /// Inserts a column filled with `val` at the `i-th` position. + #[inline] + pub fn insert_column(self, i: usize, val: N) -> MatrixMN> + where C: DimAdd, + DefaultAllocator: Reallocator> { + self.insert_fixed_columns::(i, val) + } + + /// Inserts `D` column filled with `val` at the `i-th` position. + #[inline] + pub fn insert_fixed_columns(self, i: usize, val: N) -> MatrixMN> + where D: DimName, + C: DimAdd, + DefaultAllocator: Reallocator> { + let mut res = unsafe { self.insert_columns_generic_uninitialized(i, D::name()) }; + res.fixed_columns_mut::(i).fill(val); + res + } + + /// Inserts `n` column filled with `val` at the `i-th` position. + #[inline] + pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN + where C: DimAdd, + DefaultAllocator: Reallocator { + let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dynamic::new(n)) }; + res.columns_mut(i, n).fill(val); + res + } + + /// Inserts `ninsert.value()` columns at the `i-th` place of this matrix. + /// + /// The added column values are not initialized. + #[inline] + pub unsafe fn insert_columns_generic_uninitialized(self, i: usize, ninsert: D) + -> MatrixMN> + where D: Dim, + C: DimAdd, + DefaultAllocator: Reallocator> { + + let m = self.into_owned(); + let (nrows, ncols) = m.data.shape(); + let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(nrows, ncols.add(ninsert), m.data)); + + assert!(i <= ncols.value(), "Column insertion index out of range."); + + if ninsert.value() != 0 && i != ncols.value() { + let ptr_in = res.data.ptr().offset((i * nrows.value()) as isize); + let ptr_out = res.data.ptr_mut().offset(((i + ninsert.value()) * nrows.value()) as isize); + + ptr::copy(ptr_in, ptr_out, (ncols.value() - i) * nrows.value()) + } + + res + } + + /* + * + * Rows insertion. + * + */ + /// Inserts a row filled with `val` at the `i-th` position. + #[inline] + pub fn insert_row(self, i: usize, val: N) -> MatrixMN, C> + where R: DimAdd, + DefaultAllocator: Reallocator, C> { + self.insert_fixed_rows::(i, val) + } + + /// Inserts `D` row filled with `val` at the `i-th` position. + #[inline] + pub fn insert_fixed_rows(self, i: usize, val: N) -> MatrixMN, C> + where D: DimName, + R: DimAdd, + DefaultAllocator: Reallocator, C> { + let mut res = unsafe { self.insert_rows_generic_uninitialized(i, D::name()) }; + res.fixed_rows_mut::(i).fill(val); + res + } + + /// Inserts `n` rows filled with `val` at the `i-th` position. + #[inline] + pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN + where R: DimAdd, + DefaultAllocator: Reallocator { + let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dynamic::new(n)) }; + res.rows_mut(i, n).fill(val); + res + } + + /// Inserts `ninsert.value()` rows at the `i-th` place of this matrix. + /// + /// The added rows values are not initialized. + #[inline] + pub unsafe fn insert_rows_generic_uninitialized(self, i: usize, ninsert: D) + -> MatrixMN, C> + where D: Dim, + R: DimAdd, + DefaultAllocator: Reallocator, C> { + + let m = self.into_owned(); + let (nrows, ncols) = m.data.shape(); + let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(nrows.add(ninsert), ncols, m.data)); + + assert!(i <= nrows.value(), "Row insertion index out of range."); + + if ninsert.value() != 0 { + extend_rows(&mut res.data.as_mut_slice(), nrows.value(), ncols.value(), i, ninsert.value()); + } + + res + } + + /* + * + * Resizing. + * + */ + + pub fn resize(self, new_nrows: usize, new_ncols: usize, val: N) -> DMatrix + where DefaultAllocator: Reallocator { + + self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) + } + + pub fn fixed_resize(self, val: N) -> MatrixMN + where DefaultAllocator: Reallocator { + + self.resize_generic(R2::name(), C2::name(), val) + } + + /// Resizes `self` such that it has dimensions `new_nrows × now_ncols`. The values are copied + /// such that `self[(i, j)] == result[(i, j)]`. If the result has more rows and/or columns than + /// `self`, then the extra rows or columns are filled with `val`. + #[inline] + pub fn resize_generic(self, new_nrows: R2, new_ncols: C2, val: N) -> MatrixMN + where DefaultAllocator: Reallocator { + + let (nrows, ncols) = self.shape(); + let mut data = self.data.into_owned(); + + if new_nrows.value() == nrows { + let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data) }; + + Matrix::from_data(res) + } + else { + let mut res; + + unsafe { + if new_nrows.value() < nrows { + compress_rows(&mut data.as_mut_slice(), nrows, ncols, new_nrows.value(), nrows - new_nrows.value()); + res = Matrix::from_data(DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data)); + } + else { + res = Matrix::from_data(DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data)); + extend_rows(&mut res.data.as_mut_slice(), nrows, ncols, nrows, new_nrows.value() - nrows); + } + } + + if new_ncols.value() > ncols { + res.columns_range_mut(ncols ..).fill(val); + } + + if new_nrows.value() > nrows { + res.slice_range_mut(nrows .., .. cmp::min(ncols, new_ncols.value())).fill(val); + } + + res + } + } +} + + +unsafe fn compress_rows(data: &mut [N], nrows: usize, ncols: usize, i: usize, nremove: usize) { + let new_nrows = nrows - nremove; + let ptr_in = data.as_ptr(); + let ptr_out = data.as_mut_ptr(); + + let mut curr_i = i; + + for k in 0 .. ncols - 1 { + ptr::copy(ptr_in.offset((curr_i + (k + 1) * nremove) as isize), + ptr_out.offset(curr_i as isize), + new_nrows); + + curr_i += new_nrows; + } + + // Deal with the last column from which less values have to be copied. + let remaining_len = nrows - i - nremove; + ptr::copy(ptr_in.offset((nrows * ncols - remaining_len) as isize), + ptr_out.offset(curr_i as isize), + remaining_len); +} + + +unsafe fn extend_rows(data: &mut [N], nrows: usize, ncols: usize, i: usize, ninsert: usize) { + let new_nrows = nrows + ninsert; + let ptr_in = data.as_ptr(); + let ptr_out = data.as_mut_ptr(); + + let remaining_len = nrows - i; + let mut curr_i = new_nrows * ncols - remaining_len; + + // Deal with the last column from which less values have to be copied. + ptr::copy(ptr_in.offset((nrows * ncols - remaining_len) as isize), + ptr_out.offset(curr_i as isize), + remaining_len); + + for k in (0 .. ncols - 1).rev() { + curr_i -= new_nrows; + + ptr::copy(ptr_in.offset((k * nrows + i) as isize), + ptr_out.offset(curr_i as isize), + nrows); + } +} diff --git a/src/core/inverse.rs b/src/core/inverse.rs deleted file mode 100644 index 488c5b5b..00000000 --- a/src/core/inverse.rs +++ /dev/null @@ -1,203 +0,0 @@ -use approx::ApproxEq; - -use alga::general::Field; - -use core::{Scalar, Matrix, SquareMatrix, OwnedSquareMatrix}; -use core::dimension::Dim; -use core::storage::{Storage, StorageMut}; - - -impl SquareMatrix - where N: Scalar + Field + ApproxEq, - S: Storage { - /// Attempts to invert this matrix. - #[inline] - pub fn try_inverse(self) -> Option> { - let mut res = self.into_owned(); - - if res.shape().0 <= 3 { - if res.try_inverse_mut() { - Some(res) - } - else { - None - } - } - else { - gauss_jordan_inverse(res) - } - } -} - - -impl SquareMatrix - where N: Scalar + Field + ApproxEq, - S: StorageMut { - /// Attempts to invert this matrix in-place. Returns `false` and leaves `self` untouched if - /// inversion fails. - #[inline] - pub fn try_inverse_mut(&mut self) -> bool { - assert!(self.is_square(), "Unable to invert a non-square matrix."); - - let dim = self.shape().0; - - unsafe { - match dim { - 0 => true, - 1 => { - let determinant = self.get_unchecked(0, 0).clone(); - if determinant == N::zero() { - false - } - else { - *self.get_unchecked_mut(0, 0) = N::one() / determinant; - true - } - }, - 2 => { - let determinant = self.determinant(); - - if determinant == N::zero() { - false - } - else { - let m11 = *self.get_unchecked(0, 0); let m12 = *self.get_unchecked(0, 1); - let m21 = *self.get_unchecked(1, 0); let m22 = *self.get_unchecked(1, 1); - - *self.get_unchecked_mut(0, 0) = m22 / determinant; - *self.get_unchecked_mut(0, 1) = -m12 / determinant; - - *self.get_unchecked_mut(1, 0) = -m21 / determinant; - *self.get_unchecked_mut(1, 1) = m11 / determinant; - - true - } - }, - 3 => { - let m11 = *self.get_unchecked(0, 0); - let m12 = *self.get_unchecked(0, 1); - let m13 = *self.get_unchecked(0, 2); - - let m21 = *self.get_unchecked(1, 0); - let m22 = *self.get_unchecked(1, 1); - let m23 = *self.get_unchecked(1, 2); - - let m31 = *self.get_unchecked(2, 0); - let m32 = *self.get_unchecked(2, 1); - let m33 = *self.get_unchecked(2, 2); - - - let minor_m12_m23 = m22 * m33 - m32 * m23; - let minor_m11_m23 = m21 * m33 - m31 * m23; - let minor_m11_m22 = m21 * m32 - m31 * m22; - - let determinant = m11 * minor_m12_m23 - - m12 * minor_m11_m23 + - m13 * minor_m11_m22; - - if determinant == N::zero() { - false - } - else { - *self.get_unchecked_mut(0, 0) = minor_m12_m23 / determinant; - *self.get_unchecked_mut(0, 1) = (m13 * m32 - m33 * m12) / determinant; - *self.get_unchecked_mut(0, 2) = (m12 * m23 - m22 * m13) / determinant; - - *self.get_unchecked_mut(1, 0) = -minor_m11_m23 / determinant; - *self.get_unchecked_mut(1, 1) = (m11 * m33 - m31 * m13) / determinant; - *self.get_unchecked_mut(1, 2) = (m13 * m21 - m23 * m11) / determinant; - - *self.get_unchecked_mut(2, 0) = minor_m11_m22 / determinant; - *self.get_unchecked_mut(2, 1) = (m12 * m31 - m32 * m11) / determinant; - *self.get_unchecked_mut(2, 2) = (m11 * m22 - m21 * m12) / determinant; - - true - } - }, - _ => { - let oself = self.clone_owned(); - if let Some(res) = gauss_jordan_inverse(oself) { - self.copy_from(&res); - true - } - else { - false - } - } - } - } - } -} - - -/// Inverts the given matrix using Gauss-Jordan Ellimitation. -fn gauss_jordan_inverse(mut matrix: SquareMatrix) -> Option> - where D: Dim, - N: Scalar + Field + ApproxEq, - S: StorageMut { - - assert!(matrix.is_square(), "Unable to invert a non-square matrix."); - let dim = matrix.data.shape().0; - let mut res: OwnedSquareMatrix = Matrix::identity_generic(dim, dim); - let dim = dim.value(); - - unsafe { - for k in 0 .. dim { - // Search a non-zero value on the k-th column. - // FIXME: would it be worth it to spend some more time searching for the - // max instead? - - let mut n0 = k; // index of a non-zero entry. - - while n0 != dim { - if !matrix.get_unchecked(n0, k).is_zero() { - break; - } - - n0 += 1; - } - - if n0 == dim { - return None - } - - // Swap pivot line. - if n0 != k { - for j in 0 .. dim { - matrix.swap_unchecked((n0, j), (k, j)); - res.swap_unchecked((n0, j), (k, j)); - } - } - - let pivot = *matrix.get_unchecked(k, k); - - for j in k .. dim { - let selfval = *matrix.get_unchecked(k, j) / pivot; - *matrix.get_unchecked_mut(k, j) = selfval; - } - - for j in 0 .. dim { - let resval = *res.get_unchecked(k, j) / pivot; - *res.get_unchecked_mut(k, j) = resval; - } - - for l in 0 .. dim { - if l != k { - let normalizer = *matrix.get_unchecked(l, k); - - for j in k .. dim { - let selfval = *matrix.get_unchecked(l, j) - *matrix.get_unchecked(k, j) * normalizer; - *matrix.get_unchecked_mut(l, j) = selfval; - } - - for j in 0 .. dim { - let resval = *res.get_unchecked(l, j) - *res.get_unchecked(k, j) * normalizer; - *res.get_unchecked_mut(l, j) = resval; - } - } - } - } - - Some(res) - } -} diff --git a/src/core/iter.rs b/src/core/iter.rs index 3c99a4ae..c4cb515b 100644 --- a/src/core/iter.rs +++ b/src/core/iter.rs @@ -81,6 +81,13 @@ macro_rules! iterator { self.size_hint().0 } } + + impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + $Storage> ExactSizeIterator for $Name<'a, N, R, C, S> { + #[inline] + fn len(&self) -> usize { + self.size + } + } } } diff --git a/src/core/matrix.rs b/src/core/matrix.rs index 6deb899f..809611bb 100644 --- a/src/core/matrix.rs +++ b/src/core/matrix.rs @@ -1,4 +1,5 @@ use num::Zero; +use num_complex::Complex; use std::cmp::Ordering; use std::marker::PhantomData; @@ -12,54 +13,33 @@ use serde::{Serialize, Serializer, Deserialize, Deserializer}; use alga::general::{Ring, Real}; -use core::{Scalar, Unit}; +use core::{Scalar, DefaultAllocator, Unit, VectorN, MatrixMN}; use core::dimension::{Dim, DimAdd, DimSum, U1, U2}; -use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; +use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, DimEq}; use core::iter::{MatrixIter, MatrixIterMut}; -use core::allocator::{Allocator, OwnedAllocator, SameShapeAllocator, SameShapeR, SameShapeC}; -use core::storage::{Storage, StorageMut, Owned, OwnedStorage, MulStorage, TrMulStorage, SumStorage}; - -/// The type of the result of a matrix allocation by the allocator `A`. -pub type OwnedMatrix = Matrix>::Buffer>; +use core::allocator::{Allocator, SameShapeAllocator, SameShapeR, SameShapeC}; +use core::storage::{Storage, StorageMut, Owned, ContiguousStorage, ContiguousStorageMut, SameShapeStorage}; /// A square matrix. pub type SquareMatrix = Matrix; -/// The type of the result of a square matrix allocation by the allocator `A`. -pub type OwnedSquareMatrix = OwnedMatrix; - /// A matrix with one column and `D` rows. -pub type ColumnVector = Matrix; +pub type Vector = Matrix; -/// An owned matrix with one column and `D` rows. -pub type OwnedColumnVector = OwnedMatrix; - -/// A matrix with one row and `D` columns. +/// A matrix with one row and `D` columns . pub type RowVector = Matrix; -/// An owned matrix with one row and `D` columns. -pub type OwnedRowVector = OwnedMatrix; +/// The type of the result of a matrix sum. +pub type MatrixSum = + Matrix, SameShapeC, SameShapeStorage>; /// The type of the result of a matrix sum. -pub type MatrixSum = - Matrix, SameShapeC, SumStorage>; - -/// The type of the result of a matrix sum. -pub type ColumnVectorSum = - Matrix, U1, SumStorage>; +pub type VectorSum = + Matrix, U1, SameShapeStorage>; /// The type of the result of a matrix cross product. -pub type MatrixCross = MatrixSum; - -/// The type of the result of a matrix multiplication. -pub type MatrixMul = Matrix>; - -/// The type of the result of a matrix transpose-multiplication. -pub type MatrixTrMul = Matrix>; - -/// The matrix with storage `S` and scalar type changed from `NOld` to `NNew`. -pub type MatrixWithScalar = -Matrix>::Alloc as Allocator>::Buffer>; +pub type MatrixCross = + Matrix, SameShapeC, SameShapeStorage>; /// The most generic column-major matrix (and vector) type. /// @@ -89,7 +69,7 @@ Matrix>::Alloc as Allocator>: pub struct Matrix { /// The data storage that contains all the matrix components and informations about its number /// of rows and column (if needed). - pub data: S, + pub data: S, _phantoms: PhantomData<(N, R, C)> } @@ -143,65 +123,6 @@ impl> Matrix { } } - /// Moves this matrix into one that owns its data. - #[inline] - pub fn into_owned(self) -> OwnedMatrix { - Matrix::from_data(self.data.into_owned()) - } - - // FIXME: this could probably benefit from specialization. - // XXX: bad name. - /// Moves this matrix into one that owns its data. The actual type of the result depends on - /// matrix storage combination rules for addition. - #[inline] - pub fn into_owned_sum(self) -> MatrixSum - where R2: Dim, C2: Dim, - S::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - if TypeId::of::>() == TypeId::of::>() { - // We can just return `self.into_owned()`. - - unsafe { - // FIXME: check that those copies are optimized away by the compiler. - let owned = self.into_owned(); - let res = mem::transmute_copy(&owned); - mem::forget(owned); - res - } - } - else { - self.clone_owned_sum() - } - } - - /// Clones this matrix into one that owns its data. - #[inline] - pub fn clone_owned(&self) -> OwnedMatrix { - Matrix::from_data(self.data.clone_owned()) - } - - /// Clones this matrix into one that owns its data. The actual type of the result depends on - /// matrix storage combination rules for addition. - #[inline] - pub fn clone_owned_sum(&self) -> MatrixSum - where R2: Dim, C2: Dim, - S::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - let (nrows, ncols) = self.shape(); - let nrows: SameShapeR = Dim::from_usize(nrows); - let ncols: SameShapeC = Dim::from_usize(ncols); - - let mut res: MatrixSum = unsafe { - Matrix::new_uninitialized_generic(nrows, ncols) - }; - - for (r, s) in res.iter_mut().zip(self.iter()) { - *r = *s - } - - res - } - /// The total number of elements of this matrix. #[inline] pub fn len(&self) -> usize { @@ -264,6 +185,7 @@ impl> Matrix { /// bound-checking. #[inline] pub unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N { + debug_assert!(irow < self.nrows() && icol < self.ncols(), "Matrix index out of bounds."); self.data.get_unchecked(irow, icol) } @@ -283,8 +205,164 @@ impl> Matrix { assert!(self.shape() == other.shape()); self.iter().zip(other.iter()).all(|(a, b)| a.relative_eq(b, eps, max_relative)) } + + /// Tests whether `self` and `rhs` are exactly equal. + #[inline] + pub fn eq(&self, other: &Matrix) -> bool + where N: PartialEq, + R2: Dim, C2: Dim, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + assert!(self.shape() == other.shape()); + self.iter().zip(other.iter()).all(|(a, b)| *a == *b) + } + + /// Moves this matrix into one that owns its data. + #[inline] + pub fn into_owned(self) -> MatrixMN + where DefaultAllocator: Allocator { + Matrix::from_data(self.data.into_owned()) + } + + // FIXME: this could probably benefit from specialization. + // XXX: bad name. + /// Moves this matrix into one that owns its data. The actual type of the result depends on + /// matrix storage combination rules for addition. + #[inline] + pub fn into_owned_sum(self) -> MatrixSum + where R2: Dim, C2: Dim, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + if TypeId::of::>() == TypeId::of::>() { + // We can just return `self.into_owned()`. + + unsafe { + // FIXME: check that those copies are optimized away by the compiler. + let owned = self.into_owned(); + let res = mem::transmute_copy(&owned); + mem::forget(owned); + res + } + } + else { + self.clone_owned_sum() + } + } + + /// Clones this matrix into one that owns its data. + #[inline] + pub fn clone_owned(&self) -> MatrixMN + where DefaultAllocator: Allocator { + Matrix::from_data(self.data.clone_owned()) + } + + /// Clones this matrix into one that owns its data. The actual type of the result depends on + /// matrix storage combination rules for addition. + #[inline] + pub fn clone_owned_sum(&self) -> MatrixSum + where R2: Dim, C2: Dim, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + let (nrows, ncols) = self.shape(); + let nrows: SameShapeR = Dim::from_usize(nrows); + let ncols: SameShapeC = Dim::from_usize(ncols); + + let mut res: MatrixSum = unsafe { + Matrix::new_uninitialized_generic(nrows, ncols) + }; + + // FIXME: use copy_from + for j in 0 .. res.ncols() { + for i in 0 .. res.nrows() { + unsafe { *res.get_unchecked_mut(i, j) = *self.get_unchecked(i, j); } + } + } + + res + } + + /// Returns a matrix containing the result of `f` applied to each of its entries. + #[inline] + pub fn map N>(&self, mut f: F) -> MatrixMN + where DefaultAllocator: Allocator { + let (nrows, ncols) = self.data.shape(); + + let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) }; + + for j in 0 .. ncols.value() { + for i in 0 .. nrows.value() { + unsafe { + let a = *self.data.get_unchecked(i, j); + *res.data.get_unchecked_mut(i, j) = f(a) + } + } + } + + res + } + + /// Returns a matrix containing the result of `f` applied to each entries of `self` and + /// `rhs`. + #[inline] + pub fn zip_map N>(&self, rhs: &Matrix, mut f: F) -> MatrixMN + where DefaultAllocator: Allocator { + let (nrows, ncols) = self.data.shape(); + + let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) }; + + assert!((nrows.value(), ncols.value()) == rhs.shape(), "Matrix simultaneous traversal error: dimension mismatch."); + + for j in 0 .. ncols.value() { + for i in 0 .. nrows.value() { + unsafe { + let a = *self.data.get_unchecked(i, j); + let b = *rhs.data.get_unchecked(i, j); + *res.data.get_unchecked_mut(i, j) = f(a, b) + } + } + } + + res + } + + /// Transposes `self` and store the result into `out`. + #[inline] + pub fn transpose_to(&self, out: &mut Matrix) + where R2: Dim, C2: Dim, + SB: StorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + let (nrows, ncols) = self.shape(); + assert!((ncols, nrows) == out.shape(), "Incompatible shape for transpose-copy."); + + // FIXME: optimize that. + for i in 0 .. nrows { + for j in 0 .. ncols { + unsafe { + *out.get_unchecked_mut(j, i) = *self.get_unchecked(i, j); + } + } + } + } + + + /// Transposes `self`. + #[inline] + pub fn transpose(&self) -> MatrixMN + where DefaultAllocator: Allocator { + let (nrows, ncols) = self.data.shape(); + + unsafe { + let mut res = Matrix::new_uninitialized_generic(ncols, nrows); + self.transpose_to(&mut res); + + res + } + } } + impl> Matrix { /// Mutably iterates through this matrix coordinates. #[inline] @@ -295,12 +373,15 @@ impl> Matrix { /// Gets a mutable reference to the i-th element of this matrix. #[inline] pub unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut N { + debug_assert!(irow < self.nrows() && icol < self.ncols(), "Matrix index out of bounds."); self.data.get_unchecked_mut(irow, icol) } /// Swaps two entries without bound-checking. #[inline] pub unsafe fn swap_unchecked(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) { + debug_assert!(row_cols1.0 < self.nrows() && row_cols1.1 < self.ncols()); + debug_assert!(row_cols2.0 < self.nrows() && row_cols2.1 < self.ncols()); self.data.swap_unchecked(row_cols1, row_cols2) } @@ -321,16 +402,26 @@ impl> Matrix { ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { assert!(self.shape() == other.shape(), "Unable to copy from a matrix with a different shape."); - for (out, other) in self.iter_mut().zip(other.iter()) { - *out = *other + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { *self.get_unchecked_mut(i, j) = *other.get_unchecked(i, j); } + } } } - /// Sets all the entries of this matrix to `value`. + /// Fills this matrix with the content of the transpose another one. #[inline] - pub fn fill(&mut self, value: N) { - for e in self.iter_mut() { - *e = value + pub fn tr_copy_from(&mut self, other: &Matrix) + where R2: Dim, C2: Dim, + SB: Storage, + ShapeConstraint: DimEq + SameNumberOfColumns { + let (nrows, ncols) = self.shape(); + assert!((ncols, nrows) == other.shape(), "Unable to copy from a matrix with incompatible shape."); + + for j in 0 .. ncols { + for i in 0 .. nrows { + unsafe { *self.get_unchecked_mut(i, j) = *other.get_unchecked(j, i); } + } } } @@ -338,97 +429,54 @@ impl> Matrix { #[inline] pub fn set_row(&mut self, i: usize, row: &RowVector) where S2: Storage, - S::Alloc: Allocator, ShapeConstraint: SameNumberOfColumns { self.row_mut(i).copy_from(row); } /// Fills the selected column of this matrix with the content of the given vector. #[inline] - pub fn set_column(&mut self, i: usize, column: &ColumnVector) + pub fn set_column(&mut self, i: usize, column: &Vector) where S2: Storage, - S::Alloc: Allocator, ShapeConstraint: SameNumberOfRows { self.column_mut(i).copy_from(column); } } -impl> Matrix - // XXX: see the rust issue #26026 - where S::Alloc: OwnedAllocator { +impl> Vector { + /// Gets a reference to the i-th element of this column vector without bound checking. + #[inline] + pub unsafe fn vget_unchecked(&self, i: usize) -> &N { + debug_assert!(i < self.nrows(), "Vector index out of bounds."); + let i = i * self.strides().0; + self.data.get_unchecked_linear(i) + } +} - /// Extracts a slice containing the entire matrix entries orderd column-by-columns. +impl> Vector { + /// Gets a mutable reference to the i-th element of this column vector without bound checking. + #[inline] + pub unsafe fn vget_unchecked_mut(&mut self, i: usize) -> &mut N { + debug_assert!(i < self.nrows(), "Vector index out of bounds."); + let i = i * self.strides().0; + self.data.get_unchecked_linear_mut(i) + } +} + + +impl> Matrix { + /// Extracts a slice containing the entire matrix entries ordered column-by-columns. #[inline] pub fn as_slice(&self) -> &[N] { self.data.as_slice() } +} - /// Extracts a mutable slice containing the entire matrix entries orderd column-by-columns. +impl> Matrix { + /// Extracts a mutable slice containing the entire matrix entries ordered column-by-columns. #[inline] pub fn as_mut_slice(&mut self) -> &mut [N] { self.data.as_mut_slice() } - - /// Returns a matrix containing the result of `f` applied to each of its entries. - #[inline] - pub fn map N>(&self, mut f: F) -> Matrix { - let shape = self.data.shape(); - - let mut res: Matrix; - res = unsafe { Self::new_uninitialized_generic(shape.0, shape.1) }; - - for i in 0 .. shape.0.value() * shape.1.value() { - unsafe { - let a = *self.data.get_unchecked_linear(i); - *res.data.get_unchecked_linear_mut(i) = f(a) - } - } - - res - } - - /// Returns a matrix containing the result of `f` applied to each entries of `self` and - /// `rhs`. - #[inline] - pub fn zip_map N>(&self, rhs: &Matrix, mut f: F) -> Matrix { - let shape_generic = self.data.shape(); - let shape = self.shape(); - - let mut res: Matrix; - res = unsafe { Self::new_uninitialized_generic(shape_generic.0, shape_generic.1) }; - - assert!(shape == rhs.shape(), "Matrix simultaneous traversal error: dimension mismatch."); - - for i in 0 .. shape.0 * shape.1 { - unsafe { - let a = *self.data.get_unchecked_linear(i); - let b = *rhs.data.get_unchecked_linear(i); - *res.data.get_unchecked_linear_mut(i) = f(a, b) - } - } - - res - } -} - -impl> Matrix - where S::Alloc: Allocator { - /// Transposes `self`. - #[inline] - pub fn transpose(&self) -> OwnedMatrix { - let (nrows, ncols) = self.data.shape(); - - unsafe { - let mut res: OwnedMatrix = Matrix::new_uninitialized_generic(ncols, nrows); - for i in 0 .. nrows.value() { - for j in 0 .. ncols.value() { - *res.get_unchecked_mut(j, i) = *self.get_unchecked(i, j); - } - } - - res - } - } } impl> Matrix { @@ -446,20 +494,76 @@ impl> Matrix { } } -impl SquareMatrix - where N: Scalar, - S: Storage, - S::Alloc: Allocator { +impl, R, C>> Matrix, R, C, S> { + /// Takes the conjugate and transposes `self` and store the result into `out`. + #[inline] + pub fn conjugate_transpose_to(&self, out: &mut Matrix, R2, C2, SB>) + where R2: Dim, C2: Dim, + SB: StorageMut, R2, C2>, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + let (nrows, ncols) = self.shape(); + assert!((ncols, nrows) == out.shape(), "Incompatible shape for transpose-copy."); + + // FIXME: optimize that. + for i in 0 .. nrows { + for j in 0 .. ncols { + unsafe { + *out.get_unchecked_mut(j, i) = self.get_unchecked(i, j).conj(); + } + } + } + } + + /// The conjugate transposition of `self`. + #[inline] + pub fn conjugate_transpose(&self) -> MatrixMN, C, R> + where DefaultAllocator: Allocator, C, R> { + let (nrows, ncols) = self.data.shape(); + + unsafe { + let mut res: MatrixMN<_, C, R> = Matrix::new_uninitialized_generic(ncols, nrows); + self.conjugate_transpose_to(&mut res); + + res + } + } +} + +impl, D, D>> Matrix, D, D, S> { + /// Sets `self` to its conjugate transpose. + pub fn conjugate_transpose_mut(&mut self) { + assert!(self.is_square(), "Unable to transpose a non-square matrix in-place."); + + let dim = self.shape().0; + + for i in 1 .. dim { + for j in 0 .. i { + unsafe { + let ref_ij = self.get_unchecked_mut(i, j) as *mut Complex; + let ref_ji = self.get_unchecked_mut(j, i) as *mut Complex; + let conj_ij = (*ref_ij).conj(); + let conj_ji = (*ref_ji).conj(); + *ref_ij = conj_ji; + *ref_ji = conj_ij; + } + } + } + } +} + +impl> SquareMatrix { /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. #[inline] - pub fn diagonal(&self) -> OwnedColumnVector { - assert!(self.is_square(), "Unable to get the diagonal of a non-square."); + pub fn diagonal(&self) -> VectorN + where DefaultAllocator: Allocator { + assert!(self.is_square(), "Unable to get the diagonal of a non-square matrix."); let dim = self.data.shape().0; - let mut res = unsafe { OwnedColumnVector::::new_uninitialized_generic(dim, U1) }; + let mut res = unsafe { VectorN::new_uninitialized_generic(dim, U1) }; for i in 0 .. dim.value() { - unsafe { *res.get_unchecked_mut(i, 0) = *self.get_unchecked(i, i); } + unsafe { *res.vget_unchecked_mut(i) = *self.get_unchecked(i, i); } } res @@ -483,18 +587,16 @@ impl SquareMatrix } } -impl ColumnVector - where N: Scalar + Zero, - D: DimAdd, - S: Storage, - S::Alloc: Allocator, U1> { +impl, S: Storage> Vector { /// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its /// coordinates. #[inline] - pub fn to_homogeneous(&self) -> OwnedColumnVector, S::Alloc> { + pub fn to_homogeneous(&self) -> VectorN> + where DefaultAllocator: Allocator> { + let len = self.len(); let hnrows = DimSum::::from_usize(len + 1); - let mut res = unsafe { OwnedColumnVector::::new_uninitialized_generic(hnrows, U1) }; + let mut res = unsafe { VectorN::::new_uninitialized_generic(hnrows, U1) }; res.generic_slice_mut((0, 0), self.data.shape()).copy_from(self); res[(len, 0)] = N::zero(); @@ -504,8 +606,9 @@ impl ColumnVector /// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of /// `self`. Returns `None` if this last component is not zero. #[inline] - pub fn from_homogeneous(v: ColumnVector, SB>) -> Option> - where SB: Storage, U1, Alloc = S::Alloc> { + pub fn from_homogeneous(v: Vector, SB>) -> Option> + where SB: Storage>, + DefaultAllocator: Allocator { if v[v.len() - 1].is_zero() { let nrows = D::from_usize(v.len() - 1); Some(v.generic_slice((0, 0), (nrows, U1)).into_owned()) @@ -516,232 +619,6 @@ impl ColumnVector } } - -// // /* -// // * -// // * Conversions (AsRef, AsMut, From) -// // * -// // */ -// // impl FromIterator for Matrix -// // where N: Scalar + Rand, -// // R: Dim, -// // C: Dim, -// // A: Allocator { -// // #[inline] -// // fn from_iter>(iter: I) -> Matrix { -// // let mut iter = iter.into_iter(); -// // } -// // } -// // -// // impl AsRef<[[N; $dimension]; $dimension]> for $t { -// // #[inline] -// // fn as_ref(&self) -> &[[N; $dimension]; $dimension] { -// // unsafe { -// // mem::transmute(self) -// // } -// // } -// // } -// -// // impl AsMut<[[N; $dimension]; $dimension]> for $t { -// // #[inline] -// // fn as_mut(&mut self) -> &mut [[N; $dimension]; $dimension] { -// // unsafe { -// // mem::transmute(self) -// // } -// // } -// // } -// -// // impl<'a, N> From<&'a [[N; $dimension]; $dimension]> for &'a $t { -// // #[inline] -// // fn from(arr: &'a [[N; $dimension]; $dimension]) -> &'a $t { -// // unsafe { -// // mem::transmute(arr) -// // } -// // } -// // } -// -// // impl<'a, N> From<&'a mut [[N; $dimension]; $dimension]> for &'a mut $t { -// // #[inline] -// // fn from(arr: &'a mut [[N; $dimension]; $dimension]) -> &'a mut $t { -// // unsafe { -// // mem::transmute(arr) -// // } -// // } -// // } -// -// // impl<'a, N: Clone> From<&'a [[N; $dimension]; $dimension]> for $t { -// // #[inline] -// // fn from(arr: &'a [[N; $dimension]; $dimension]) -> $t { -// // let tref: &$t = From::from(arr); -// // tref.clone() -// // } -// // } -// -// // impl MatrixEdit for $t { -// // type RowSlice = $dvector; -// // type ColumnSlice = $dvector; -// // type MinorMatrix = $tsmaller; -// // -// // #[inline] -// // fn column_slice(&self, cid: usize, rstart: usize, rend: usize) -> Self::ColumnSlice { -// // let column = self.column(cid); -// // -// // $dvector::from_slice(rend - rstart, &column.as_ref()[rstart .. rend]) -// // } -// -// // #[inline] -// // fn row_slice(&self, rid: usize, cstart: usize, cend: usize) -> Self::RowSlice { -// // let row = self.row(rid); -// // -// // $dvector::from_slice(cend - cstart, &row.as_ref()[cstart .. cend]) -// // } -// -// // // FIXME: optimize that (+ this is a Copy/paste from dmatrix). -// // #[inline] -// // fn delete_row_column(&self, row_id: usize, column_id: usize) -> Self::MinorMatrix { -// // assert!(row_id < $dimension && column_id < $dimension); -// // -// // unsafe { -// // let mut res = $tsmaller::new_uninitialized_generic($dimension - 1, $dimension - 1); -// // -// // for irow in 0 .. row_id { -// // for icol in 0 .. column_id { -// // res.unsafe_set((irow, icol), self.unsafe_at((irow, icol))) -// // } -// // -// // for icol in column_id + 1 .. $dimension { -// // res.unsafe_set((irow, icol - 1), self.unsafe_at((irow, icol))) -// // } -// // } -// // -// // for irow in row_id + 1 .. $dimension { -// // for icol in 0 .. column_id { -// // res.unsafe_set((irow - 1, icol), self.unsafe_at((irow, icol))) -// // } -// // -// // for icol in column_id + 1 .. $dimension { -// // res.unsafe_set((irow - 1, icol - 1), self.unsafe_at((irow, icol))) -// // } -// // } -// // -// // res -// // } -// // } -// -// // // FIXME: optimize that (+ this is a Copy/paste from dmatrix). -// // #[inline] -// // fn swap_rows(&mut self, row_id1: usize, row_id2: usize) { -// // if row_id1 != row_id2 { -// // assert!(row_id1 < $dimension && row_id2 < $dimension); -// // -// // for icol in 0 .. $dimension { -// // self.swap((row_id1, icol), (row_id2, icol)) -// // } -// // } -// // } -// // -// // // FIXME: optimize that (+ this is a Copy/paste from dmatrix). -// // #[inline] -// // fn swap_columns(&mut self, column_id1: usize, column_id2: usize) { -// // if column_id1 != column_id2 { -// // assert!(column_id1 < $dimension && column_id2 < $dimension); -// // -// // for irow in 0 .. $dimension { -// // self.swap((irow, column_id1), (irow, column_id2)) -// // } -// // } -// // } -// // } -// // -// // /* -// // * -// // * Mean -// // * -// // */ -// // impl> Mean<$vector> for $t { -// // fn mean(&self) -> $vector { -// // let mut res: $vector = ::zero(); -// // let normalizer: N = ::convert(1.0f64 / $dimension as f64); -// // -// // for i in 0 .. $dimension { -// // for j in 0 .. $dimension { -// // unsafe { -// // let acc = res.unsafe_at(j) + self.unsafe_at((i, j)) * normalizer; -// // res.unsafe_set(j, acc); -// // } -// // } -// // } -// // -// // res -// // } -// // } -// // -// // /* -// // * -// // * Componentwise unary operations. -// // * -// // */ -// // componentwise_absolute!($t, $($compN),+); -// // ) -// // ); -// -// -// // FIXME: specialize for row-major/column major -// // -// -// // macro_rules! to_homogeneous_impl( -// // ($t: ident, $t2: ident, $dimension: expr, $dim2: expr) => ( -// // impl ToHomogeneous<$t2> for $t { -// // #[inline] -// // fn to_homogeneous(&self) -> $t2 { -// // let mut res: $t2 = ::one(); -// // -// // for i in 0 .. $dimension { -// // for j in 0 .. $dimension { -// // res[(i, j)] = self[(i, j)] -// // } -// // } -// // -// // res -// // } -// // } -// // ) -// // ); -// -// // macro_rules! from_homogeneous_impl( -// // ($t: ident, $t2: ident, $dimension: expr, $dim2: expr) => ( -// // impl FromHomogeneous<$t2> for $t { -// // #[inline] -// // fn from(m: &$t2) -> $t { -// // let mut res: $t = ::one(); -// // -// // for i in 0 .. $dimension { -// // for j in 0 .. $dimension { -// // res[(i, j)] = m[(i, j)] -// // } -// // } -// // -// // // FIXME: do we have to deal the lost components -// // // (like if the 1 is not a 1… do we have to divide?) -// // -// // res -// // } -// // } -// // ) -// // ); -// -// -// // macro_rules! eigen_qr_impl( -// // ($t: ident, $v: ident) => ( -// // impl EigenQR for $t { -// // fn eigen_qr(&self, eps: N, niter: usize) -> ($t, $v) { -// // linalg::eigen_qr(self, eps, niter) -// // } -// // } -// // ) -// // ); - - impl ApproxEq for Matrix where N: Scalar + ApproxEq, S: Storage, @@ -777,7 +654,7 @@ impl ApproxEq for Matrix impl PartialOrd for Matrix where N: Scalar + PartialOrd, - S: Storage { + S: Storage { #[inline] fn partial_cmp(&self, other: &Self) -> Option { assert!(self.shape() == other.shape(), "Matrix comparison error: dimensions mismatch."); @@ -855,107 +732,62 @@ impl PartialEq for Matrix } -// FIXME: the bounds are much too restrictive here! This won't even work for, e.g., -// integer-valued matrices... impl fmt::Display for Matrix - where N: Real + fmt::Display, + where N: Scalar + fmt::Display, S: Storage, - S::Alloc: Allocator { - // XXX: will not always work correctly due to rounding errors. + DefaultAllocator: Allocator { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fn integral_length(val: &N) -> usize { - let mut res = 1; - let mut curr: N = ::convert(10.0f64); - - while curr <= *val { - curr = curr * ::convert(10.0f64); - res += 1; - } - - if val.is_sign_negative() { - res + 1 - } - else { - res + fn val_width(val: N, f: &mut fmt::Formatter) -> usize { + match f.precision() { + Some(precision) => format!("{:.1$}", val, precision).chars().count(), + None => format!("{}", val).chars().count() } } let (nrows, ncols) = self.data.shape(); - let mut max_decimal_length = 0; - let mut decimal_lengths: MatrixWithScalar = - Matrix::from_element_generic(nrows, ncols, 0); + + if nrows.value() == 0 || ncols.value() == 0 { + return write!(f, "[ ]"); + } + + let mut max_length = 0; + let mut lengths: MatrixMN = Matrix::zeros_generic(nrows, ncols); let (nrows, ncols) = self.shape(); for i in 0 .. nrows { for j in 0 .. ncols { - decimal_lengths[(i, j)] = integral_length(&self[(i, j)]); - max_decimal_length = ::max(max_decimal_length, decimal_lengths[(i, j)]); + lengths[(i, j)] = val_width(self[(i, j)], f); + max_length = ::max(max_length, lengths[(i, j)]); } } - let precision = f.precision().unwrap_or(3); - let max_number_length = max_decimal_length + precision + 1; + let max_length_with_space = max_length + 1; - try!(writeln!(f, " ┌ {:>width$} ┐", "", width = max_number_length * ncols + ncols - 1)); + try!(writeln!(f, "")); + try!(writeln!(f, " ┌ {:>width$} ┐", "", width = max_length_with_space * ncols - 1)); for i in 0 .. nrows { try!(write!(f, " │")); for j in 0 .. ncols { - let number_length = decimal_lengths[(i, j)] + precision + 1; - let pad = max_number_length - number_length; + let number_length = lengths[(i, j)] + 1; + let pad = max_length_with_space - number_length; try!(write!(f, " {:>thepad$}", "", thepad = pad)); - try!(write!(f, "{:.*}", precision, (*self)[(i, j)])); + match f.precision() { + Some(precision) => try!(write!(f, "{:.1$}", (*self)[(i, j)], precision)), + None => try!(write!(f, "{}", (*self)[(i, j)])) + } } try!(writeln!(f, " │")); } - writeln!(f, " └ {:>width$} ┘", "", width = max_number_length * ncols + ncols - 1) + try!(writeln!(f, " └ {:>width$} ┘", "", width = max_length_with_space * ncols - 1)); + writeln!(f, "") } } -impl Matrix - where N: Scalar + Ring, - S: Storage { - /// The dot product between two matrices (seen as vectors). - #[inline] - pub fn dot(&self, other: &Matrix) -> N - where SB: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - assert!(self.shape() == other.shape(), "Dot product dimension mismatch."); - self.iter().zip(other.iter()).fold(N::zero(), |acc, (a, b)| acc + *a * *b) - } - - // FIXME: we could specialize this for when we only have vectors in which case we can just use - // `iter().zip(iter())` as for the regular `.dot` method. - /// The dot product between the transpose of `self` and `other`. - #[inline] - pub fn tr_dot(&self, other: &Matrix) -> N - where SB: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - let (nrows, ncols) = self.shape(); - assert!((ncols, nrows) == other.shape(), "Dot product dimension mismatch."); - - let mut res = N::zero(); - - for i in 0 .. nrows { - for j in 0 .. ncols { - unsafe { - res += *self.get_unchecked(i, j) * *other.get_unchecked(j, i); - } - } - } - - res - } - - - /// The squared L2 norm of this matrix. - #[inline] - pub fn norm_squared(&self) -> N { - self.dot(self) - } - +impl> Matrix { /// The perpendicular product between two 2D column vectors, i.e. `a.x * b.y - a.y * b.x`. #[inline] pub fn perp(&self, b: &Matrix) -> N @@ -979,10 +811,10 @@ impl Matrix /// Panics if the shape is not 3D vector. In the future, this will be implemented only for /// dynamically-sized matrices and statically-sized 3D matrices. #[inline] - pub fn cross(&self, b: &Matrix) -> MatrixCross + pub fn cross(&self, b: &Matrix) -> MatrixCross where R2: Dim, C2: Dim, SB: Storage, - S::Alloc: SameShapeAllocator, + DefaultAllocator: SameShapeAllocator, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { let shape = self.shape(); assert!(shape == b.shape(), "Vector cross product dimension mismatch."); @@ -1013,7 +845,7 @@ impl Matrix } else { unsafe { - // FIXME: soooo ugly! + // FIXME: ugly! let nrows = SameShapeR::::from_usize(1); let ncols = SameShapeC::::from_usize(3); let mut res = Matrix::new_uninitialized_generic(nrows, ncols); @@ -1036,14 +868,12 @@ impl Matrix } } -impl Matrix - where N: Real, - S: Storage { - /// The smallest angle between two matrices seen as vectors. +impl> Matrix { + /// The smallest angle between two vectors. #[inline] pub fn angle(&self, other: &Matrix) -> N where SB: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + ShapeConstraint: DimEq + DimEq { let prod = self.dot(other); let n1 = self.norm(); let n2 = other.norm(); @@ -1065,6 +895,21 @@ impl Matrix } } } +} + +impl> Matrix { + /// The squared L2 norm of this vector. + #[inline] + pub fn norm_squared(&self) -> N { + let mut res = N::zero(); + + for i in 0 .. self.ncols() { + let col = self.column(i); + res += col.dot(&col) + } + + res + } /// The L2 norm of this matrix. #[inline] @@ -1074,13 +919,15 @@ impl Matrix /// Returns a normalized version of this matrix. #[inline] - pub fn normalize(&self) -> OwnedMatrix { + pub fn normalize(&self) -> MatrixMN + where DefaultAllocator: Allocator { self / self.norm() } /// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`. #[inline] - pub fn try_normalize(&self, min_norm: N) -> Option> { + pub fn try_normalize(&self, min_norm: N) -> Option> + where DefaultAllocator: Allocator { let n = self.norm(); if n <= min_norm { @@ -1092,9 +939,7 @@ impl Matrix } } -impl Matrix - where N: Real, - S: StorageMut { +impl> Matrix { /// Normalizes this matrix in-place and returns its norm. #[inline] pub fn normalize_mut(&mut self) -> N { diff --git a/src/core/matrix_alga.rs b/src/core/matrix_alga.rs index ed0bad14..4fd5cff9 100644 --- a/src/core/matrix_alga.rs +++ b/src/core/matrix_alga.rs @@ -7,42 +7,39 @@ use alga::general::{AbstractMagma, AbstractGroupAbelian, AbstractGroup, Abstract ClosedAdd, ClosedNeg, ClosedMul}; use alga::linear::{VectorSpace, NormedSpace, InnerSpace, FiniteDimVectorSpace, FiniteDimInnerSpace}; -use core::{Scalar, Matrix, SquareMatrix}; +use core::{DefaultAllocator, Scalar, MatrixMN, MatrixN}; use core::dimension::{Dim, DimName}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::storage::{Storage, StorageMut}; +use core::allocator::Allocator; /* * * Additive structures. * */ -impl Identity for Matrix +impl Identity for MatrixMN where N: Scalar + Zero, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn identity() -> Self { Self::from_element(N::zero()) } } -impl AbstractMagma for Matrix +impl AbstractMagma for MatrixMN where N: Scalar + ClosedAdd, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn operate(&self, other: &Self) -> Self { self + other } } -impl Inverse for Matrix +impl Inverse for MatrixMN where N: Scalar + ClosedNeg, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] - fn inverse(&self) -> Matrix { + fn inverse(&self) -> MatrixMN { -self } @@ -54,10 +51,9 @@ impl Inverse for Matrix macro_rules! inherit_additive_structure( ($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$( - impl $marker<$operator> for Matrix + impl $marker<$operator> for MatrixMN where N: Scalar + $marker<$operator> $(+ $bounds)*, - S: OwnedStorage, - S::Alloc: OwnedAllocator { } + DefaultAllocator: Allocator { } )*} ); @@ -70,10 +66,9 @@ inherit_additive_structure!( AbstractGroupAbelian + Zero + ClosedAdd + ClosedNeg ); -impl AbstractModule for Matrix +impl AbstractModule for MatrixMN where N: Scalar + RingCommutative, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { type AbstractRing = N; #[inline] @@ -82,24 +77,21 @@ impl AbstractModule for Matrix } } -impl Module for Matrix +impl Module for MatrixMN where N: Scalar + RingCommutative, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { type Ring = N; } -impl VectorSpace for Matrix +impl VectorSpace for MatrixMN where N: Scalar + Field, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { type Field = N; } -impl FiniteDimVectorSpace for Matrix +impl FiniteDimVectorSpace for MatrixMN where N: Scalar + Field, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn dimension() -> usize { R::dim() * C::dim() @@ -131,10 +123,8 @@ impl FiniteDimVectorSpace for Matrix } } -impl NormedSpace for Matrix - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl NormedSpace for MatrixMN + where DefaultAllocator: Allocator { #[inline] fn norm_squared(&self) -> N { self.norm_squared() @@ -166,10 +156,8 @@ impl NormedSpace for Matrix } } -impl InnerSpace for Matrix - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl InnerSpace for MatrixMN + where DefaultAllocator: Allocator { type Real = N; #[inline] @@ -187,12 +175,10 @@ impl InnerSpace for Matrix // In particular: // − use `x()` instead of `::canonical_basis_element` // − use `::new(x, y, z)` instead of `::from_slice` -impl FiniteDimInnerSpace for Matrix - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl FiniteDimInnerSpace for MatrixMN + where DefaultAllocator: Allocator { #[inline] - fn orthonormalize(vs: &mut [Matrix]) -> usize { + fn orthonormalize(vs: &mut [MatrixMN]) -> usize { let mut nbasis_elements = 0; for i in 0 .. vs.len() { @@ -307,20 +293,18 @@ impl FiniteDimInnerSpace for Matrix * * */ -impl Identity for SquareMatrix +impl Identity for MatrixN where N: Scalar + Zero + One, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn identity() -> Self { Self::identity() } } -impl AbstractMagma for SquareMatrix - where N: Scalar + Zero + ClosedAdd + ClosedMul, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractMagma for MatrixN + where N: Scalar + Zero + One + ClosedAdd + ClosedMul, + DefaultAllocator: Allocator { #[inline] fn operate(&self, other: &Self) -> Self { self * other @@ -329,10 +313,9 @@ impl AbstractMagma for SquareMatrix macro_rules! impl_multiplicative_structure( ($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$( - impl $marker<$operator> for SquareMatrix - where N: Scalar + Zero + ClosedAdd + ClosedMul + $marker<$operator> $(+ $bounds)*, - S: OwnedStorage, - S::Alloc: OwnedAllocator { } + impl $marker<$operator> for MatrixN + where N: Scalar + Zero + One + ClosedAdd + ClosedMul + $marker<$operator> $(+ $bounds)*, + DefaultAllocator: Allocator { } )*} ); @@ -341,421 +324,24 @@ impl_multiplicative_structure!( AbstractMonoid + One ); -// // FIXME: Field too strong? -// impl Matrix for Matrix -// where N: Scalar + Field, -// S: Storage { -// type Field = N; -// type Row = OwnedMatrix, S::C, S::Alloc>; -// type Column = OwnedMatrix, S::Alloc>; -// type Transpose = OwnedMatrix; - -// #[inline] -// fn nrows(&self) -> usize { -// self.shape().0 -// } - -// #[inline] -// fn ncolumns(&self) -> usize { -// self.shape().1 -// } - -// #[inline] -// fn row(&self, row: usize) -> Self::Row { -// let mut res: Self::Row = ::zero(); - -// for (column, e) in res.iter_mut().enumerate() { -// *e = self[(row, column)]; -// } - -// res -// } - -// #[inline] -// fn column(&self, column: usize) -> Self::Column { -// let mut res: Self::Column = ::zero(); - -// for (row, e) in res.iter_mut().enumerate() { -// *e = self[(row, column)]; -// } - -// res -// } - -// #[inline] -// unsafe fn get_unchecked(&self, i: usize, j: usize) -> Self::Field { -// self.get_unchecked(i, j) -// } - -// #[inline] -// fn transpose(&self) -> Self::Transpose { -// self.transpose() -// } -// } - -// impl MatrixMut for Matrix -// where N: Scalar + Field, -// S: StorageMut { -// #[inline] -// fn set_row_mut(&mut self, irow: usize, row: &Self::Row) { -// assert!(irow < self.shape().0, "Row index out of bounds."); - -// for (icol, e) in row.iter().enumerate() { -// unsafe { self.set_unchecked(irow, icol, *e) } -// } -// } - -// #[inline] -// fn set_column_mut(&mut self, icol: usize, col: &Self::Column) { -// assert!(icol < self.shape().1, "Column index out of bounds."); -// for (irow, e) in col.iter().enumerate() { -// unsafe { self.set_unchecked(irow, icol, *e) } -// } -// } - -// #[inline] -// unsafe fn set_unchecked(&mut self, i: usize, j: usize, val: Self::Field) { -// *self.get_unchecked_mut(i, j) = val -// } -// } - -// // FIXME: Real is needed here only for invertibility... -// impl SquareMatrixMut for $t { -// #[inline] -// fn from_diagonal(diag: &Self::Coordinates) -> Self { -// let mut res: $t = ::zero(); -// res.set_diagonal_mut(diag); -// res -// } - -// #[inline] -// fn set_diagonal_mut(&mut self, diag: &Self::Coordinates) { -// for (i, e) in diag.iter().enumerate() { -// unsafe { self.set_unchecked(i, i, *e) } -// } -// } -// } - - - -// Specializations depending on the dimension. -// matrix_group_approx_impl!(common: $t, 1, $vector, $($compN),+); - -// // FIXME: Real is needed here only for invertibility... -// impl SquareMatrix for $t { -// type Vector = $vector; - -// #[inline] -// fn diagonal(&self) -> Self::Coordinates { -// $vector::new(self.m11) -// } - -// #[inline] -// fn determinant(&self) -> Self::Field { -// self.m11 -// } - -// #[inline] -// fn try_inverse(&self) -> Option { -// let mut res = *self; -// if res.try_inverse_mut() { -// Some(res) -// } -// else { -// None -// } -// } - -// #[inline] -// fn try_inverse_mut(&mut self) -> bool { -// if relative_eq!(&self.m11, &::zero()) { -// false -// } -// else { -// self.m11 = ::one::() / ::determinant(self); - -// true -// } -// } - -// #[inline] -// fn transpose_mut(&mut self) { -// // no-op -// } -// } - -// ident, 2, $vector: ident, $($compN: ident),+) => { -// matrix_group_approx_impl!(common: $t, 2, $vector, $($compN),+); - -// // FIXME: Real is needed only for inversion here. -// impl SquareMatrix for $t { -// type Vector = $vector; - -// #[inline] -// fn diagonal(&self) -> Self::Coordinates { -// $vector::new(self.m11, self.m22) -// } - -// #[inline] -// fn determinant(&self) -> Self::Field { -// self.m11 * self.m22 - self.m21 * self.m12 -// } - -// #[inline] -// fn try_inverse(&self) -> Option { -// let mut res = *self; -// if res.try_inverse_mut() { -// Some(res) -// } -// else { -// None -// } -// } - -// #[inline] -// fn try_inverse_mut(&mut self) -> bool { -// let determinant = ::determinant(self); - -// if relative_eq!(&determinant, &::zero()) { -// false -// } -// else { -// *self = Matrix2::new( -// self.m22 / determinant , -self.m12 / determinant, -// -self.m21 / determinant, self.m11 / determinant); - -// true -// } -// } - -// #[inline] -// fn transpose_mut(&mut self) { -// mem::swap(&mut self.m12, &mut self.m21) -// } -// } - -// ident, 3, $vector: ident, $($compN: ident),+) => { -// matrix_group_approx_impl!(common: $t, 3, $vector, $($compN),+); - -// // FIXME: Real is needed only for inversion here. -// impl SquareMatrix for $t { -// type Vector = $vector; - -// #[inline] -// fn diagonal(&self) -> Self::Coordinates { -// $vector::new(self.m11, self.m22, self.m33) -// } - -// #[inline] -// fn determinant(&self) -> Self::Field { -// 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; - -// self.m11 * minor_m12_m23 - self.m12 * minor_m11_m23 + self.m13 * minor_m11_m22 -// } - -// #[inline] -// fn try_inverse(&self) -> Option { -// let mut res = *self; -// if res.try_inverse_mut() { -// Some(res) -// } -// else { -// None -// } -// } - -// #[inline] -// fn try_inverse_mut(&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; - -// let determinant = self.m11 * minor_m12_m23 - -// self.m12 * minor_m11_m23 + -// self.m13 * minor_m11_m22; - -// if relative_eq!(&determinant, &::zero()) { -// false -// } -// else { -// *self = Matrix3::new( -// (minor_m12_m23 / determinant), -// ((self.m13 * self.m32 - self.m33 * self.m12) / determinant), -// ((self.m12 * self.m23 - self.m22 * self.m13) / determinant), - -// (-minor_m11_m23 / determinant), -// ((self.m11 * self.m33 - self.m31 * self.m13) / determinant), -// ((self.m13 * self.m21 - self.m23 * self.m11) / determinant), - -// (minor_m11_m22 / determinant), -// ((self.m12 * self.m31 - self.m32 * self.m11) / determinant), -// ((self.m11 * self.m22 - self.m21 * self.m12) / determinant) -// ); - -// true -// } -// } - -// #[inline] -// fn transpose_mut(&mut self) { -// mem::swap(&mut self.m12, &mut self.m21); -// mem::swap(&mut self.m13, &mut self.m31); -// mem::swap(&mut self.m23, &mut self.m32); -// } -// } - -// ident, $dimension: expr, $vector: ident, $($compN: ident),+) => { -// matrix_group_approx_impl!(common: $t, $dimension, $vector, $($compN),+); - -// // FIXME: Real is needed only for inversion here. -// impl SquareMatrix for $t { -// type Vector = $vector; - -// #[inline] -// fn diagonal(&self) -> Self::Coordinates { -// let mut diagonal: $vector = ::zero(); - -// for i in 0 .. $dimension { -// unsafe { diagonal.unsafe_set(i, self.get_unchecked(i, i)) } -// } - -// diagonal -// } - -// #[inline] -// fn determinant(&self) -> Self::Field { -// // FIXME: extremely naive implementation. -// let mut det = ::zero(); - -// for icol in 0 .. $dimension { -// let e = unsafe { self.unsafe_at((0, icol)) }; - -// if e != ::zero() { -// let minor_mat = self.delete_row_column(0, icol); -// let minor = minor_mat.determinant(); - -// if icol % 2 == 0 { -// det += minor; -// } -// else { -// det -= minor; -// } -// } -// } - -// det -// } - -// #[inline] -// fn try_inverse(&self) -> Option { -// let mut res = *self; -// if res.try_inverse_mut() { -// Some(res) -// } -// else { -// None -// } -// } - -// #[inline] -// fn try_inverse_mut(&mut self) -> bool { -// let mut res: $t = ::one(); - -// // Inversion using Gauss-Jordan elimination -// for k in 0 .. $dimension { -// // search a non-zero value on the k-th column -// // FIXME: would it be worth it to spend some more time searching for the -// // max instead? - -// let mut n0 = k; // index of a non-zero entry - -// while n0 != $dimension { -// if self[(n0, k)] != ::zero() { -// break; -// } - -// n0 = n0 + 1; -// } - -// if n0 == $dimension { -// return false -// } - -// // swap pivot line -// if n0 != k { -// for j in 0 .. $dimension { -// self.swap((n0, j), (k, j)); -// res.swap((n0, j), (k, j)); -// } -// } - -// let pivot = self[(k, k)]; - -// for j in k .. $dimension { -// let selfval = self[(k, j)] / pivot; -// self[(k, j)] = selfval; -// } - -// for j in 0 .. $dimension { -// let resval = res[(k, j)] / pivot; -// res[(k, j)] = resval; -// } - -// for l in 0 .. $dimension { -// if l != k { -// let normalizer = self[(l, k)]; - -// for j in k .. $dimension { -// let selfval = self[(l, j)] - self[(k, j)] * normalizer; -// self[(l, j)] = selfval; -// } - -// for j in 0 .. $dimension { -// let resval = res[(l, j)] - res[(k, j)] * normalizer; -// res[(l, j)] = resval; -// } -// } -// } -// } - -// *self = res; - -// true -// } - -// #[inline] -// fn transpose_mut(&mut self) { -// for i in 1 .. $dimension { -// for j in 0 .. i { -// self.swap((i, j), (j, i)) -// } -// } -// } - - - /* * * Ordering * */ -impl MeetSemilattice for Matrix +impl MeetSemilattice for MatrixMN where N: Scalar + MeetSemilattice, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn meet(&self, other: &Self) -> Self { self.zip_map(other, |a, b| a.meet(&b)) } } -impl JoinSemilattice for Matrix +impl JoinSemilattice for MatrixMN where N: Scalar + JoinSemilattice, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn join(&self, other: &Self) -> Self { self.zip_map(other, |a, b| a.join(&b)) @@ -763,10 +349,9 @@ impl JoinSemilattice for Matrix } -impl Lattice for Matrix +impl Lattice for MatrixMN where N: Scalar + Lattice, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn meet_join(&self, other: &Self) -> (Self, Self) { let shape = self.data.shape(); diff --git a/src/core/matrix_array.rs b/src/core/matrix_array.rs index 5acd67d3..cccb91c0 100644 --- a/src/core/matrix_array.rs +++ b/src/core/matrix_array.rs @@ -18,7 +18,7 @@ use generic_array::{ArrayLength, GenericArray}; use core::Scalar; use core::dimension::{DimName, U1}; -use core::storage::{Storage, StorageMut, Owned, OwnedStorage}; +use core::storage::{Storage, StorageMut, Owned, ContiguousStorage, ContiguousStorageMut}; use core::allocator::Allocator; use core::default_allocator::DefaultAllocator; @@ -136,22 +136,10 @@ unsafe impl Storage for MatrixArray R: DimName, C: DimName, R::Value: Mul, - Prod: ArrayLength { + Prod: ArrayLength, + DefaultAllocator: Allocator { type RStride = U1; type CStride = R; - type Alloc = DefaultAllocator; - - #[inline] - fn into_owned(self) -> Owned { - self - } - - #[inline] - fn clone_owned(&self) -> Owned { - let it = self.iter().cloned(); - - Self::Alloc::allocate_from_iterator(self.shape().0, self.shape().1, it) - } #[inline] fn ptr(&self) -> *const N { @@ -167,30 +155,44 @@ unsafe impl Storage for MatrixArray fn strides(&self) -> (Self::RStride, Self::CStride) { (Self::RStride::name(), Self::CStride::name()) } + + #[inline] + fn is_contiguous(&self) -> bool { + true + } + + #[inline] + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator { + self + } + + #[inline] + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator { + let it = self.iter().cloned(); + + DefaultAllocator::allocate_from_iterator(self.shape().0, self.shape().1, it) + } + + #[inline] + fn as_slice(&self) -> &[N] { + &self[..] + } } + unsafe impl StorageMut for MatrixArray where N: Scalar, R: DimName, C: DimName, R::Value: Mul, - Prod: ArrayLength { + Prod: ArrayLength, + DefaultAllocator: Allocator { #[inline] fn ptr_mut(&mut self) -> *mut N { self[..].as_mut_ptr() } -} - -unsafe impl OwnedStorage for MatrixArray - where N: Scalar, - R: DimName, - C: DimName, - R::Value: Mul, - Prod: ArrayLength { - #[inline] - fn as_slice(&self) -> &[N] { - &self[..] - } #[inline] fn as_mut_slice(&mut self) -> &mut [N] { @@ -198,6 +200,24 @@ unsafe impl OwnedStorage for MatrixArray } } +unsafe impl ContiguousStorage for MatrixArray + where N: Scalar, + R: DimName, + C: DimName, + R::Value: Mul, + Prod: ArrayLength, + DefaultAllocator: Allocator { +} + +unsafe impl ContiguousStorageMut for MatrixArray + where N: Scalar, + R: DimName, + C: DimName, + R::Value: Mul, + Prod: ArrayLength, + DefaultAllocator: Allocator { +} + /* * diff --git a/src/core/matrix_slice.rs b/src/core/matrix_slice.rs index 8a09fb5f..ec47615c 100644 --- a/src/core/matrix_slice.rs +++ b/src/core/matrix_slice.rs @@ -1,28 +1,31 @@ use std::marker::PhantomData; +use std::ops::{Range, RangeFrom, RangeTo, RangeFull}; +use std::slice; use core::{Scalar, Matrix}; use core::dimension::{Dim, DimName, Dynamic, DimMul, DimProd, U1}; use core::iter::MatrixIter; use core::storage::{Storage, StorageMut, Owned}; use core::allocator::Allocator; +use core::default_allocator::DefaultAllocator; macro_rules! slice_storage_impl( ($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { #[doc = $doc] - pub struct $T<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> { + #[derive(Debug)] + pub struct $T<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> { ptr: $Ptr, shape: (R, C), strides: (RStride, CStride), - _phantoms: PhantomData<($Ref, Alloc)>, + _phantoms: PhantomData<$Ref>, } - // Dynamic and () are arbitrary. It's just to be able to call the constructors with - // `Slice::` - impl<'a, N: Scalar, R: Dim, C: Dim> $T<'a, N, R, C, Dynamic, Dynamic, ()> { + // Dynamic is arbitrary. It's just to be able to call the constructors with `Slice::` + impl<'a, N: Scalar, R: Dim, C: Dim> $T<'a, N, R, C, Dynamic, Dynamic> { /// Create a new matrix slice without bound checking. #[inline] pub unsafe fn new_unchecked(storage: $SRef, start: (usize, usize), shape: (R, C)) - -> $T<'a, N, R, C, S::RStride, S::CStride, S::Alloc> + -> $T<'a, N, R, C, S::RStride, S::CStride> where RStor: Dim, CStor: Dim, S: $Storage { @@ -37,17 +40,29 @@ macro_rules! slice_storage_impl( start: (usize, usize), shape: (R, C), strides: (RStride, CStride)) - -> $T<'a, N, R, C, RStride, CStride, S::Alloc> + -> $T<'a, N, R, C, RStride, CStride> where RStor: Dim, CStor: Dim, S: $Storage, RStride: Dim, CStride: Dim { + $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides) + } + + /// Create a new matrix slice without bound checking and from a raw pointer. + #[inline] + pub unsafe fn from_raw_parts(ptr: $Ptr, + shape: (R, C), + strides: (RStride, CStride)) + -> $T<'a, N, R, C, RStride, CStride> + where RStride: Dim, + CStride: Dim { + $T { - ptr: storage.$get_addr(start.0, start.1), + ptr: ptr, shape: shape, - strides: (strides.0, strides.1), + strides: strides, _phantoms: PhantomData } } @@ -65,11 +80,11 @@ slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Onl ); -impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> Copy -for SliceStorage<'a, N, R, C, RStride, CStride, Alloc> { } +impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy +for SliceStorage<'a, N, R, C, RStride, CStride> { } -impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> Clone -for SliceStorage<'a, N, R, C, RStride, CStride, Alloc> { +impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone +for SliceStorage<'a, N, R, C, RStride, CStride> { #[inline] fn clone(&self) -> Self { SliceStorage { @@ -83,26 +98,11 @@ for SliceStorage<'a, N, R, C, RStride, CStride, Alloc> { macro_rules! storage_impl( ($($T: ident),* $(,)*) => {$( - unsafe impl<'a, N, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> Storage - for $T<'a, N, R, C, RStride, CStride, Alloc> - where N: Scalar, - Alloc: Allocator { + unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage + for $T<'a, N, R, C, RStride, CStride> { type RStride = RStride; type CStride = CStride; - type Alloc = Alloc; - - #[inline] - fn into_owned(self) -> Owned { - self.clone_owned() - } - - #[inline] - fn clone_owned(&self) -> Owned { - let (nrows, ncols) = self.shape(); - let it = MatrixIter::new(self).cloned(); - Alloc::allocate_from_iterator(nrows, ncols, it) - } #[inline] fn ptr(&self) -> *const N { @@ -118,20 +118,74 @@ macro_rules! storage_impl( fn strides(&self) -> (Self::RStride, Self::CStride) { self.strides } + + #[inline] + fn is_contiguous(&self) -> bool { + // Common cases that can be deduced at compile-time even if one of the dimensions + // is Dynamic. + if (RStride::is::() && C::is::()) || // Column vector. + (CStride::is::() && R::is::()) { // Row vector. + true + } + else { + let (nrows, _) = self.shape(); + let (srows, scols) = self.strides(); + + srows.value() == 1 && scols.value() == nrows.value() + } + } + + + + #[inline] + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator { + self.clone_owned() + } + + #[inline] + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator { + let (nrows, ncols) = self.shape(); + let it = MatrixIter::new(self).cloned(); + DefaultAllocator::allocate_from_iterator(nrows, ncols, it) + } + + #[inline] + fn as_slice(&self) -> &[N] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts(self.ptr, sz + 1) } + } + else { + unsafe { slice::from_raw_parts(self.ptr, 0) } + } + } } )*} ); storage_impl!(SliceStorage, SliceStorageMut); -unsafe impl<'a, N, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> StorageMut - for SliceStorageMut<'a, N, R, C, RStride, CStride, Alloc> - where N: Scalar, - Alloc: Allocator { +unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut + for SliceStorageMut<'a, N, R, C, RStride, CStride> { #[inline] fn ptr_mut(&mut self) -> *mut N { self.ptr } + + #[inline] + fn as_mut_slice(&mut self) -> &mut [N] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) } + } + else { + unsafe { slice::from_raw_parts_mut(self.ptr, 0) } + } + } } @@ -139,35 +193,44 @@ impl> Matrix { #[inline] fn assert_slice_index(&self, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) { let my_shape = self.shape(); - assert!(start.0 + (shape.0 - 1) * steps.0 <= my_shape.0, "Matrix slicing out of bounds."); - assert!(start.1 + (shape.1 - 1) * steps.1 <= my_shape.1, "Matrix slicing out of bounds."); + // NOTE: we previously did: (shape.0 - 1) * steps.0 + // which was wrong because underflow may occur for zero-sized matrices. + // Istead, we moved the subtraction into an addition on the right hand side. + assert!(start.0 + shape.0 * steps.0 <= my_shape.0 + steps.0, "Matrix slicing out of bounds."); + assert!(start.1 + shape.1 * steps.1 <= my_shape.1 + steps.1, "Matrix slicing out of bounds."); } } macro_rules! matrix_slice_impl( - ($me: ident: $Me: ty, $MatrixSlice: ident, $SliceStorage: ident, $Storage: ident, $data: expr; + ($me: ident: $Me: ty, $MatrixSlice: ident, $SliceStorage: ident, $Storage: ident.$get_addr: ident (), $data: expr; $row: ident, + $row_part: ident, $rows: ident, $rows_with_step: ident, $fixed_rows: ident, $fixed_rows_with_step: ident, $rows_generic: ident, + $rows_generic_with_step: ident, $column: ident, + $column_part: ident, $columns: ident, $columns_with_step: ident, $fixed_columns: ident, $fixed_columns_with_step: ident, $columns_generic: ident, + $columns_generic_with_step: ident, $slice: ident, $slice_with_steps: ident, $fixed_slice: ident, $fixed_slice_with_steps: ident, $generic_slice: ident, - $generic_slice_with_steps: ident) => { + $generic_slice_with_steps: ident, + $rows_range_pair: ident, + $columns_range_pair: ident) => { /// A matrix slice. - pub type $MatrixSlice<'a, N, R, C, RStride, CStride, Alloc> - = Matrix>; + pub type $MatrixSlice<'a, N, R, C, RStride, CStride> + = Matrix>; impl> Matrix { /* @@ -175,65 +238,75 @@ macro_rules! matrix_slice_impl( * Row slicing. * */ - /// Returns a slice containing the i-th column of this matrix. + /// Returns a slice containing the i-th row of this matrix. #[inline] - pub fn $row($me: $Me, i: usize) -> $MatrixSlice { + pub fn $row($me: $Me, i: usize) -> $MatrixSlice { $me.$fixed_rows::(i) } + /// Returns a slice containing the `n` first elements of the i-th row of this matrix. + #[inline] + pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixSlice { + $me.$generic_slice((i, 0), (U1, Dynamic::new(n))) + } + /// Extracts from this matrix a set of consecutive rows. #[inline] pub fn $rows($me: $Me, first_row: usize, nrows: usize) - -> $MatrixSlice { + -> $MatrixSlice { - let my_shape = $me.data.shape(); - $me.assert_slice_index((first_row, 0), (nrows, my_shape.1.value()), (1, 1)); - let shape = (Dynamic::new(nrows), my_shape.1); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (first_row, 0), shape); - Matrix::from_data_statically_unchecked(data) - } + $me.$rows_generic(first_row, Dynamic::new(nrows)) } /// Extracts from this matrix a set of consecutive rows regularly spaced by `step` rows. #[inline] pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) - -> $MatrixSlice { + -> $MatrixSlice { - $me.$rows_generic(first_row, Dynamic::new(nrows), Dynamic::new(step)) + $me.$rows_generic_with_step(first_row, Dynamic::new(nrows), Dynamic::new(step)) } /// Extracts a compile-time number of consecutive rows from this matrix. #[inline] pub fn $fixed_rows($me: $Me, first_row: usize) - -> $MatrixSlice + -> $MatrixSlice where RSlice: DimName { - let my_shape = $me.data.shape(); - $me.assert_slice_index((first_row, 0), (RSlice::dim(), my_shape.1.value()), (1, 1)); - let shape = (RSlice::name(), my_shape.1); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (first_row, 0), shape); - Matrix::from_data_statically_unchecked(data) - } + $me.$rows_generic(first_row, RSlice::name()) } /// Extracts from this matrix a compile-time number of rows regularly spaced by `step` rows. #[inline] pub fn $fixed_rows_with_step($me: $Me, first_row: usize, step: usize) - -> $MatrixSlice + -> $MatrixSlice where RSlice: DimName { - $me.$rows_generic(first_row, RSlice::name(), Dynamic::new(step)) + $me.$rows_generic_with_step(first_row, RSlice::name(), Dynamic::new(step)) } /// Extracts from this matrix `nrows` rows regularly spaced by `step` rows. Both argument may /// or may not be values known at compile-time. #[inline] - pub fn $rows_generic($me: $Me, row_start: usize, nrows: RSlice, step: RStep) - -> $MatrixSlice, S::CStride, S::Alloc> + pub fn $rows_generic($me: $Me, row_start: usize, nrows: RSlice) + -> $MatrixSlice + where RSlice: Dim { + + let my_shape = $me.data.shape(); + $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (1, 1)); + + let shape = (nrows, my_shape.1); + + unsafe { + let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Extracts from this matrix `nrows` rows regularly spaced by `step` rows. Both argument may + /// or may not be values known at compile-time. + #[inline] + pub fn $rows_generic_with_step($me: $Me, row_start: usize, nrows: RSlice, step: RStep) + -> $MatrixSlice, S::CStride> where RSlice: Dim, RStep: DimMul { @@ -257,66 +330,76 @@ macro_rules! matrix_slice_impl( */ /// Returns a slice containing the i-th column of this matrix. #[inline] - pub fn $column($me: $Me, i: usize) -> $MatrixSlice { + pub fn $column($me: $Me, i: usize) -> $MatrixSlice { $me.$fixed_columns::(i) } + /// Returns a slice containing the `n` first elements of the i-th column of this matrix. + #[inline] + pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixSlice { + $me.$generic_slice((0, i), (Dynamic::new(n), U1)) + } + /// Extracts from this matrix a set of consecutive columns. #[inline] pub fn $columns($me: $Me, first_col: usize, ncols: usize) - -> $MatrixSlice { + -> $MatrixSlice { - let my_shape = $me.data.shape(); - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols), (1, 1)); - let shape = (my_shape.0, Dynamic::new(ncols)); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); - Matrix::from_data_statically_unchecked(data) - } + $me.$columns_generic(first_col, Dynamic::new(ncols)) } /// Extracts from this matrix a set of consecutive columns regularly spaced by `step` columns. #[inline] pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) - -> $MatrixSlice { + -> $MatrixSlice { - $me.$columns_generic(first_col, Dynamic::new(ncols), Dynamic::new(step)) + $me.$columns_generic_with_step(first_col, Dynamic::new(ncols), Dynamic::new(step)) } /// Extracts a compile-time number of consecutive columns from this matrix. #[inline] pub fn $fixed_columns($me: $Me, first_col: usize) - -> $MatrixSlice + -> $MatrixSlice where CSlice: DimName { - let my_shape = $me.data.shape(); - $me.assert_slice_index((0, first_col), (my_shape.0.value(), CSlice::dim()), (1, 1)); - let shape = (my_shape.0, CSlice::name()); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); - Matrix::from_data_statically_unchecked(data) - } + $me.$columns_generic(first_col, CSlice::name()) } /// Extracts from this matrix a compile-time number of columns regularly spaced by `step` /// columns. #[inline] pub fn $fixed_columns_with_step($me: $Me, first_col: usize, step: usize) - -> $MatrixSlice + -> $MatrixSlice where CSlice: DimName { - $me.$columns_generic(first_col, CSlice::name(), Dynamic::new(step)) + $me.$columns_generic_with_step(first_col, CSlice::name(), Dynamic::new(step)) } + /// Extracts from this matrix `ncols` columns. The number of columns may or may not be + /// known at compile-time. + #[inline] + pub fn $columns_generic($me: $Me, first_col: usize, ncols: CSlice) + -> $MatrixSlice + where CSlice: Dim { + + let my_shape = $me.data.shape(); + $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (1, 1)); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Extracts from this matrix `ncols` columns regularly spaced by `step` columns. Both argument may /// or may not be values known at compile-time. #[inline] - pub fn $columns_generic($me: $Me, first_col: usize, ncols: CSlice, step: CStep) - -> $MatrixSlice, S::Alloc> + pub fn $columns_generic_with_step($me: $Me, first_col: usize, ncols: CSlice, step: CStep) + -> $MatrixSlice> where CSlice: Dim, - CStep: DimMul { + CStep: DimMul { let my_shape = $me.data.shape(); let my_strides = $me.data.strides(); @@ -341,7 +424,7 @@ macro_rules! matrix_slice_impl( /// consecutive elements. #[inline] pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) - -> $MatrixSlice { + -> $MatrixSlice { $me.assert_slice_index(start, shape, (1, 1)); let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); @@ -359,7 +442,7 @@ macro_rules! matrix_slice_impl( /// original matrix. #[inline] pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) - -> $MatrixSlice { + -> $MatrixSlice { let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); let steps = (Dynamic::new(steps.0), Dynamic::new(steps.1)); @@ -370,7 +453,7 @@ macro_rules! matrix_slice_impl( /// CSlice::dim())` consecutive components. #[inline] pub fn $fixed_slice($me: $Me, irow: usize, icol: usize) - -> $MatrixSlice + -> $MatrixSlice where RSlice: DimName, CSlice: DimName { @@ -389,7 +472,7 @@ macro_rules! matrix_slice_impl( /// the original matrix. #[inline] pub fn $fixed_slice_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) - -> $MatrixSlice + -> $MatrixSlice where RSlice: DimName, CSlice: DimName { let shape = (RSlice::name(), CSlice::name()); @@ -400,7 +483,7 @@ macro_rules! matrix_slice_impl( /// Creates a slice that may or may not have a fixed size and stride. #[inline] pub fn $generic_slice($me: $Me, start: (usize, usize), shape: (RSlice, CSlice)) - -> $MatrixSlice + -> $MatrixSlice where RSlice: Dim, CSlice: Dim { @@ -418,12 +501,13 @@ macro_rules! matrix_slice_impl( start: (usize, usize), shape: (RSlice, CSlice), steps: (RStep, CStep)) - -> $MatrixSlice, DimProd, S::Alloc> + -> $MatrixSlice, DimProd> where RSlice: Dim, CSlice: Dim, RStep: DimMul, CStep: DimMul { + assert!(steps.0.value() > 0 && steps.1.value() > 0, "Matrix slicing steps must not be zero."); $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (steps.0.value(), steps.1.value())); let my_strides = $me.data.strides(); @@ -434,49 +518,297 @@ macro_rules! matrix_slice_impl( Matrix::from_data_statically_unchecked(data) } } + + /* + * + * Splitting. + * + */ + /// Splits this NxM matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $rows_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixSlice, + $MatrixSlice) { + + let (nrows, ncols) = $me.data.shape(); + let strides = $me.data.strides(); + + let start1 = r1.begin(nrows); + let start2 = r2.begin(nrows); + + let end1 = r1.end(nrows); + let end2 = r2.end(nrows); + + let nrows1 = r1.size(nrows); + let nrows2 = r2.size(nrows); + + assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the slice ranges must not overlap."); + assert!(end2 <= nrows.value(), "Rows range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(start1, 0); + let ptr2 = $data.$get_addr(start2, 0); + + let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); + let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); + let slice1 = Matrix::from_data_statically_unchecked(data1); + let slice2 = Matrix::from_data_statically_unchecked(data2); + + (slice1, slice2) + } + } + + /// Splits this NxM matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $columns_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixSlice, + $MatrixSlice) { + + let (nrows, ncols) = $me.data.shape(); + let strides = $me.data.strides(); + + let start1 = r1.begin(ncols); + let start2 = r2.begin(ncols); + + let end1 = r1.end(ncols); + let end2 = r2.end(ncols); + + let ncols1 = r1.size(ncols); + let ncols2 = r2.size(ncols); + + assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the slice ranges must not overlap."); + assert!(end2 <= ncols.value(), "Columns range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(0, start1); + let ptr2 = $data.$get_addr(0, start2); + + let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); + let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); + let slice1 = Matrix::from_data_statically_unchecked(data1); + let slice2 = Matrix::from_data_statically_unchecked(data2); + + (slice1, slice2) + } + } } } ); matrix_slice_impl!( - self: &Self, MatrixSlice, SliceStorage, Storage, &self.data; + self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data; row, + row_part, rows, rows_with_step, fixed_rows, fixed_rows_with_step, rows_generic, + rows_generic_with_step, column, + column_part, columns, columns_with_step, fixed_columns, fixed_columns_with_step, columns_generic, + columns_generic_with_step, slice, slice_with_steps, fixed_slice, fixed_slice_with_steps, generic_slice, - generic_slice_with_steps); + generic_slice_with_steps, + rows_range_pair, + columns_range_pair); matrix_slice_impl!( - self: &mut Self, MatrixSliceMut, SliceStorageMut, StorageMut, &mut self.data; + self: &mut Self, MatrixSliceMut, SliceStorageMut, StorageMut.get_address_unchecked_mut(), &mut self.data; row_mut, + row_part_mut, rows_mut, rows_with_step_mut, fixed_rows_mut, fixed_rows_with_step_mut, rows_generic_mut, + rows_generic_with_step_mut, column_mut, + column_part_mut, columns_mut, columns_with_step_mut, fixed_columns_mut, fixed_columns_with_step_mut, columns_generic_mut, + columns_generic_with_step_mut, slice_mut, slice_with_steps_mut, fixed_slice_mut, fixed_slice_with_steps_mut, generic_slice_mut, - generic_slice_with_steps_mut); + generic_slice_with_steps_mut, + rows_range_pair_mut, + columns_range_pair_mut); + + +pub trait SliceRange { + type Size: Dim; + + fn begin(&self, shape: D) -> usize; + // NOTE: this is the index immediatly after the last index. + fn end(&self, shape: D) -> usize; + fn size(&self, shape: D) -> Self::Size; +} + +impl SliceRange for usize { + type Size = U1; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + *self + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + *self + 1 + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + U1 + } +} + +impl SliceRange for Range { + type Size = Dynamic; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + self.end + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dynamic::new(self.end - self.start) + } +} + +impl SliceRange for RangeFrom { + type Size = Dynamic; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn end(&self, dim: D) -> usize { + dim.value() + } + + #[inline(always)] + fn size(&self, dim: D) -> Self::Size { + Dynamic::new(dim.value() - self.start) + } +} + +impl SliceRange for RangeTo { + type Size = Dynamic; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + self.end + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dynamic::new(self.end) + } +} + +impl SliceRange for RangeFull { + type Size = D; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn end(&self, dim: D) -> usize { + dim.value() + } + + #[inline(always)] + fn size(&self, dim: D) -> Self::Size { + dim + } +} + + +impl> Matrix { + #[inline] + pub fn slice_range(&self, rows: RowRange, cols: ColRange) + -> MatrixSlice + where RowRange: SliceRange, + ColRange: SliceRange { + + let (nrows, ncols) = self.data.shape(); + self.generic_slice((rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols))) + } + + #[inline] + pub fn rows_range>(&self, rows: RowRange) + -> MatrixSlice { + + self.slice_range(rows, ..) + } + + #[inline] + pub fn columns_range>(&self, cols: ColRange) + -> MatrixSlice { + + self.slice_range(.., cols) + } +} + +impl> Matrix { + pub fn slice_range_mut(&mut self, rows: RowRange, cols: ColRange) + -> MatrixSliceMut + where RowRange: SliceRange, + ColRange: SliceRange { + + let (nrows, ncols) = self.data.shape(); + self.generic_slice_mut((rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols))) + } + + #[inline] + pub fn rows_range_mut>(&mut self, rows: RowRange) + -> MatrixSliceMut { + + self.slice_range_mut(rows, ..) + } + + #[inline] + pub fn columns_range_mut>(&mut self, cols: ColRange) + -> MatrixSliceMut { + + self.slice_range_mut(.., cols) + } +} diff --git a/src/core/matrix_vec.rs b/src/core/matrix_vec.rs index 51a02640..bfaccf8d 100644 --- a/src/core/matrix_vec.rs +++ b/src/core/matrix_vec.rs @@ -2,7 +2,8 @@ use std::ops::Deref; use core::Scalar; use core::dimension::{Dim, DimName, Dynamic, U1}; -use core::storage::{Storage, StorageMut, Owned, OwnedStorage}; +use core::storage::{Storage, StorageMut, Owned, ContiguousStorage, ContiguousStorageMut}; +use core::allocator::Allocator; use core::default_allocator::DefaultAllocator; /* @@ -45,6 +46,26 @@ impl MatrixVec { pub unsafe fn data_mut(&mut self) -> &mut Vec { &mut self.data } + + /// Resizes the undelying mutable data storage and unrwaps it. + /// + /// If `sz` is larger than the current size, additional elements are uninitialized. + /// If `sz` is smaller than the current size, additional elements are trucated. + #[inline] + pub unsafe fn resize(mut self, sz: usize) -> Vec{ + let len = self.len(); + + if sz < len { + self.data.set_len(sz); + self.data.shrink_to_fit(); + } + else { + self.data.reserve_exact(sz - len); + self.data.set_len(sz); + } + + self.data + } } impl Deref for MatrixVec { @@ -62,24 +83,14 @@ impl Deref for MatrixVec { * Dynamic − Dynamic * */ -unsafe impl Storage for MatrixVec { +unsafe impl Storage for MatrixVec + where DefaultAllocator: Allocator { type RStride = U1; type CStride = Dynamic; - type Alloc = DefaultAllocator; - - #[inline] - fn into_owned(self) -> Owned { - self - } - - #[inline] - fn clone_owned(&self) -> Owned { - self.clone() - } #[inline] fn ptr(&self) -> *const N { - self[..].as_ptr() + self.data.as_ptr() } #[inline] @@ -91,27 +102,39 @@ unsafe impl Storage for MatrixVec (Self::RStride, Self::CStride) { (Self::RStride::name(), self.nrows) } -} - - -unsafe impl Storage for MatrixVec { - type RStride = U1; - type CStride = R; - type Alloc = DefaultAllocator; #[inline] - fn into_owned(self) -> Owned { + fn is_contiguous(&self) -> bool { + true + } + + #[inline] + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator { self } #[inline] - fn clone_owned(&self) -> Owned { + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator { self.clone() } + #[inline] + fn as_slice(&self) -> &[N] { + &self[..] + } +} + + +unsafe impl Storage for MatrixVec + where DefaultAllocator: Allocator { + type RStride = U1; + type CStride = R; + #[inline] fn ptr(&self) -> *const N { - self[..].as_ptr() + self.data.as_ptr() } #[inline] @@ -123,6 +146,28 @@ unsafe impl Storage for MatrixVec (Self::RStride, Self::CStride) { (Self::RStride::name(), self.nrows) } + + #[inline] + fn is_contiguous(&self) -> bool { + true + } + + #[inline] + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator { + self + } + + #[inline] + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator { + self.clone() + } + + #[inline] + fn as_slice(&self) -> &[N] { + &self[..] + } } @@ -130,20 +175,14 @@ unsafe impl Storage for MatrixVec StorageMut for MatrixVec { +unsafe impl StorageMut for MatrixVec + where DefaultAllocator: Allocator { #[inline] fn ptr_mut(&mut self) -> *mut N { - self.as_mut_slice().as_mut_ptr() - } -} - -unsafe impl OwnedStorage for MatrixVec { - #[inline] - fn as_slice(&self) -> &[N] { - &self[..] + self.data.as_mut_ptr() } #[inline] @@ -152,18 +191,20 @@ unsafe impl OwnedStorage for MatrixVec StorageMut for MatrixVec { - #[inline] - fn ptr_mut(&mut self) -> *mut N { - self.as_mut_slice().as_mut_ptr() - } +unsafe impl ContiguousStorage for MatrixVec + where DefaultAllocator: Allocator { } -unsafe impl OwnedStorage for MatrixVec { +unsafe impl ContiguousStorageMut for MatrixVec + where DefaultAllocator: Allocator { +} + + +unsafe impl StorageMut for MatrixVec + where DefaultAllocator: Allocator { #[inline] - fn as_slice(&self) -> &[N] { - &self[..] + fn ptr_mut(&mut self) -> *mut N { + self.data.as_mut_ptr() } #[inline] @@ -171,3 +212,11 @@ unsafe impl OwnedStorage for MatrixVec ContiguousStorage for MatrixVec + where DefaultAllocator: Allocator { +} + +unsafe impl ContiguousStorageMut for MatrixVec + where DefaultAllocator: Allocator { +} diff --git a/src/core/mod.rs b/src/core/mod.rs index 356dd29d..e3532703 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -6,6 +6,7 @@ pub mod allocator; pub mod storage; pub mod coordinates; mod ops; +mod blas; pub mod iter; pub mod default_allocator; @@ -15,8 +16,6 @@ mod construction; mod properties; mod alias; mod matrix_alga; -mod determinant; -mod inverse; mod conversion; mod matrix_slice; mod matrix_array; @@ -24,8 +23,7 @@ mod matrix_vec; mod cg; mod unit; mod componentwise; - -mod decompositions; +mod edition; #[doc(hidden)] pub mod helper; diff --git a/src/core/ops.rs b/src/core/ops.rs index 98c0186f..28981128 100644 --- a/src/core/ops.rs +++ b/src/core/ops.rs @@ -1,15 +1,16 @@ use std::iter; use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg, Index, IndexMut}; -use num::{Zero, One}; +use std::cmp::PartialOrd; +use num::{Zero, One, Signed}; use alga::general::{ClosedMul, ClosedDiv, ClosedAdd, ClosedSub, ClosedNeg}; -use core::{Scalar, Matrix, OwnedMatrix, SquareMatrix, MatrixSum, MatrixMul, MatrixTrMul}; -use core::dimension::{Dim, DimMul, DimName, DimProd}; -use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable}; -use core::storage::{Storage, StorageMut, OwnedStorage}; -use core::allocator::{SameShapeAllocator, Allocator, OwnedAllocator}; +use core::{DefaultAllocator, Scalar, Matrix, MatrixN, MatrixMN, MatrixSum}; +use core::dimension::{Dim, DimName, DimProd, DimMul}; +use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable, DimEq}; +use core::storage::{Storage, StorageMut, ContiguousStorageMut}; +use core::allocator::{SameShapeAllocator, Allocator, SameShapeR, SameShapeC}; /* * @@ -70,8 +71,9 @@ impl IndexMut<(usize, usize)> for Matrix */ impl Neg for Matrix where N: Scalar + ClosedNeg, - S: Storage { - type Output = OwnedMatrix; + S: Storage, + DefaultAllocator: Allocator { + type Output = MatrixMN; #[inline] fn neg(self) -> Self::Output { @@ -83,8 +85,9 @@ impl Neg for Matrix impl<'a, N, R: Dim, C: Dim, S> Neg for &'a Matrix where N: Scalar + ClosedNeg, - S: Storage { - type Output = OwnedMatrix; + S: Storage, + DefaultAllocator: Allocator { + type Output = MatrixMN; #[inline] fn neg(self) -> Self::Output { @@ -109,33 +112,156 @@ impl Matrix * Addition & Substraction * */ + macro_rules! componentwise_binop_impl( ($Trait: ident, $method: ident, $bound: ident; - $TraitAssign: ident, $method_assign: ident) => { + $TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident, + $method_assign_statically_unchecked_rhs: ident; + $method_to: ident, $method_to_statically_unchecked: ident) => { + + impl> Matrix + where N: Scalar + $bound { + + /* + * + * Methods without dimension checking at compile-time. + * This is useful for code reuse because the sum representative system does not plays + * easily with static checks. + * + */ + #[inline] + fn $method_to_statically_unchecked(&self, + rhs: &Matrix, + out: &mut Matrix) + where SB: Storage, + SC: StorageMut { + assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + assert!(self.shape() == out.shape(), "Matrix addition/subtraction output dimensions mismatch."); + + // This is the most common case and should be deduced at compile-time. + // FIXME: use specialization instead? + if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() { + let arr1 = self.data.as_slice(); + let arr2 = rhs.data.as_slice(); + let mut out = out.data.as_mut_slice(); + for i in 0 .. arr1.len() { + unsafe { + *out.get_unchecked_mut(i) = arr1.get_unchecked(i).$method(*arr2.get_unchecked(i)); + } + } + } + else { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + let val = self.get_unchecked(i, j).$method(*rhs.get_unchecked(i, j)); + *out.get_unchecked_mut(i, j) = val; + } + } + } + } + } + + + #[inline] + fn $method_assign_statically_unchecked(&mut self, rhs: &Matrix) + where R2: Dim, + C2: Dim, + SA: StorageMut, + SB: Storage { + assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + + // This is the most common case and should be deduced at compile-time. + // FIXME: use specialization instead? + if self.data.is_contiguous() && rhs.data.is_contiguous() { + let mut arr1 = self.data.as_mut_slice(); + let arr2 = rhs.data.as_slice(); + for i in 0 .. arr2.len() { + unsafe { + arr1.get_unchecked_mut(i).$method_assign(*arr2.get_unchecked(i)); + } + } + } + else { + for j in 0 .. rhs.ncols() { + for i in 0 .. rhs.nrows() { + unsafe { + self.get_unchecked_mut(i, j).$method_assign(*rhs.get_unchecked(i, j)) + } + } + } + } + } + + + #[inline] + fn $method_assign_statically_unchecked_rhs(&self, rhs: &mut Matrix) + where R2: Dim, + C2: Dim, + SB: StorageMut { + assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + + // This is the most common case and should be deduced at compile-time. + // FIXME: use specialization instead? + if self.data.is_contiguous() && rhs.data.is_contiguous() { + let arr1 = self.data.as_slice(); + let mut arr2 = rhs.data.as_mut_slice(); + for i in 0 .. arr1.len() { + unsafe { + let res = arr1.get_unchecked(i).$method(*arr2.get_unchecked(i)); + *arr2.get_unchecked_mut(i) = res; + } + } + } + else { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + let mut r = rhs.get_unchecked_mut(i, j); + *r = self.get_unchecked(i, j).$method(*r) + } + } + } + } + } + + + /* + * + * Methods without dimension checking at compile-time. + * This is useful for code reuse because the sum representative system does not plays + * easily with static checks. + * + */ + /// Equivalent to `self + rhs` but stores the result into `out` to avoid allocations. + #[inline] + pub fn $method_to(&self, + rhs: &Matrix, + out: &mut Matrix) + where SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + + SameNumberOfRows + SameNumberOfColumns { + self.$method_to_statically_unchecked(rhs, out) + } + } + impl<'b, N, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix> for Matrix where R1: Dim, C1: Dim, R2: Dim, C2: Dim, N: Scalar + $bound, SA: Storage, SB: Storage, - SA::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - type Output = MatrixSum; + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; #[inline] - fn $method(self, right: &'b Matrix) -> Self::Output { - assert!(self.shape() == right.shape(), "Matrix addition/subtraction dimensions mismatch."); + fn $method(self, rhs: &'b Matrix) -> Self::Output { + assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); let mut res = self.into_owned_sum::(); - - // XXX: optimize our iterator! - // - // Using our own iterator prevents loop unrolling, wich breaks some optimization - // (like SIMD). On the other hand, using the slice iterator is 4x faster. - - // for (left, right) in res.iter_mut().zip(right.iter()) { - for (left, right) in res.as_mut_slice().iter_mut().zip(right.iter()) { - *left = left.$method(*right) - } - + res.$method_assign_statically_unchecked(rhs); res } } @@ -145,26 +271,16 @@ macro_rules! componentwise_binop_impl( N: Scalar + $bound, SA: Storage, SB: Storage, - SB::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - type Output = MatrixSum; + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; #[inline] - fn $method(self, right: Matrix) -> Self::Output { - assert!(self.shape() == right.shape(), "Matrix addition/subtraction dimensions mismatch."); - let mut res = right.into_owned_sum::(); - - // XXX: optimize our iterator! - // - // Using our own iterator prevents loop unrolling, wich breaks some optimization - // (like SIMD). On the other hand, using the slice iterator is 4x faster. - - // for (left, right) in self.iter().zip(res.iter_mut()) { - for (left, right) in self.iter().zip(res.as_mut_slice().iter_mut()) { - *right = left.$method(*right) - } - - res + fn $method(self, rhs: Matrix) -> Self::Output { + let mut rhs = rhs.into_owned_sum::(); + assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + self.$method_assign_statically_unchecked_rhs(&mut rhs); + rhs } } @@ -173,13 +289,13 @@ macro_rules! componentwise_binop_impl( N: Scalar + $bound, SA: Storage, SB: Storage, - SA::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - type Output = MatrixSum; + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; #[inline] - fn $method(self, right: Matrix) -> Self::Output { - self.$method(&right) + fn $method(self, rhs: Matrix) -> Self::Output { + self.$method(&rhs) } } @@ -188,13 +304,21 @@ macro_rules! componentwise_binop_impl( N: Scalar + $bound, SA: Storage, SB: Storage, - SA::Alloc: SameShapeAllocator, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - type Output = MatrixSum; + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; #[inline] - fn $method(self, right: &'b Matrix) -> Self::Output { - self.clone_owned().$method(right) + fn $method(self, rhs: &'b Matrix) -> Self::Output { + let mut res = unsafe { + let (nrows, ncols) = self.shape(); + let nrows: SameShapeR = Dim::from_usize(nrows); + let ncols: SameShapeC = Dim::from_usize(ncols); + Matrix::new_uninitialized_generic(nrows, ncols) + }; + + self.$method_to_statically_unchecked(rhs, &mut res); + res } } @@ -206,11 +330,8 @@ macro_rules! componentwise_binop_impl( ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { #[inline] - fn $method_assign(&mut self, right: &'b Matrix) { - assert!(self.shape() == right.shape(), "Matrix addition/subtraction dimensions mismatch."); - for (left, right) in self.iter_mut().zip(right.iter()) { - left.$method_assign(*right) - } + fn $method_assign(&mut self, rhs: &'b Matrix) { + self.$method_assign_statically_unchecked(rhs) } } @@ -222,32 +343,34 @@ macro_rules! componentwise_binop_impl( ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { #[inline] - fn $method_assign(&mut self, right: Matrix) { - self.$method_assign(&right) + fn $method_assign(&mut self, rhs: Matrix) { + self.$method_assign(&rhs) } } } ); -componentwise_binop_impl!(Add, add, ClosedAdd; AddAssign, add_assign); -componentwise_binop_impl!(Sub, sub, ClosedSub; SubAssign, sub_assign); +componentwise_binop_impl!(Add, add, ClosedAdd; + AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut; + add_to, add_to_statically_unchecked); +componentwise_binop_impl!(Sub, sub, ClosedSub; + SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut; + sub_to, sub_to_statically_unchecked); -impl iter::Sum for Matrix +impl iter::Sum for MatrixMN where N: Scalar + ClosedAdd + Zero, - S: OwnedStorage, - S::Alloc: OwnedAllocator + DefaultAllocator: Allocator { - fn sum>>(iter: I) -> Matrix { + fn sum>>(iter: I) -> MatrixMN { iter.fold(Matrix::zero(), |acc, x| acc + x) } } -impl<'a, N, R: DimName, C: DimName, S> iter::Sum<&'a Matrix> for Matrix +impl<'a, N, R: DimName, C: DimName> iter::Sum<&'a MatrixMN> for MatrixMN where N: Scalar + ClosedAdd + Zero, - S: OwnedStorage, - S::Alloc: OwnedAllocator + DefaultAllocator: Allocator { - fn sum>>(iter: I) -> Matrix { + fn sum>>(iter: I) -> MatrixMN { iter.fold(Matrix::zero(), |acc, x| acc + x) } } @@ -266,8 +389,9 @@ macro_rules! componentwise_scalarop_impl( $TraitAssign: ident, $method_assign: ident) => { impl $Trait for Matrix where N: Scalar + $bound, - S: Storage { - type Output = OwnedMatrix; + S: Storage, + DefaultAllocator: Allocator { + type Output = MatrixMN; #[inline] fn $method(self, rhs: N) -> Self::Output { @@ -289,8 +413,9 @@ macro_rules! componentwise_scalarop_impl( impl<'a, N, R: Dim, C: Dim, S> $Trait for &'a Matrix where N: Scalar + $bound, - S: Storage { - type Output = OwnedMatrix; + S: Storage, + DefaultAllocator: Allocator { + type Output = MatrixMN; #[inline] fn $method(self, rhs: N) -> Self::Output { @@ -302,9 +427,11 @@ macro_rules! componentwise_scalarop_impl( where N: Scalar + $bound, S: StorageMut { #[inline] - fn $method_assign(&mut self, right: N) { - for left in self.iter_mut() { - left.$method_assign(right) + fn $method_assign(&mut self, rhs: N) { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { self.get_unchecked_mut(i, j).$method_assign(rhs) }; + } } } } @@ -316,35 +443,35 @@ componentwise_scalarop_impl!(Div, div, ClosedDiv; DivAssign, div_assign); macro_rules! left_scalar_mul_impl( ($($T: ty),* $(,)*) => {$( - impl Mul> for $T - where S: Storage<$T, R, C> { - type Output = OwnedMatrix<$T, R, C, S::Alloc>; + impl> Mul> for $T + where DefaultAllocator: Allocator<$T, R, C> { + type Output = MatrixMN<$T, R, C>; #[inline] - fn mul(self, right: Matrix<$T, R, C, S>) -> Self::Output { - let mut res = right.into_owned(); + fn mul(self, rhs: Matrix<$T, R, C, S>) -> Self::Output { + let mut res = rhs.into_owned(); // XXX: optimize our iterator! // // Using our own iterator prevents loop unrolling, wich breaks some optimization // (like SIMD). On the other hand, using the slice iterator is 4x faster. - // for right in res.iter_mut() { - for right in res.as_mut_slice().iter_mut() { - *right = self * *right + // for rhs in res.iter_mut() { + for rhs in res.as_mut_slice().iter_mut() { + *rhs = self * *rhs } res } } - impl<'b, R: Dim, C: Dim, S> Mul<&'b Matrix<$T, R, C, S>> for $T - where S: Storage<$T, R, C> { - type Output = OwnedMatrix<$T, R, C, S::Alloc>; + impl<'b, R: Dim, C: Dim, S: Storage<$T, R, C>> Mul<&'b Matrix<$T, R, C, S>> for $T + where DefaultAllocator: Allocator<$T, R, C> { + type Output = MatrixMN<$T, R, C>; #[inline] - fn mul(self, right: &'b Matrix<$T, R, C, S>) -> Self::Output { - self * right.clone_owned() + fn mul(self, rhs: &'b Matrix<$T, R, C, S>) -> Self::Output { + self * rhs.clone_owned() } } )*} @@ -361,84 +488,66 @@ left_scalar_mul_impl!( // Matrix × Matrix impl<'a, 'b, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix> for &'a Matrix - where N: Scalar + Zero + ClosedAdd + ClosedMul, - SB: Storage, + where N: Scalar + Zero + One + ClosedAdd + ClosedMul, SA: Storage, - SA::Alloc: Allocator, - ShapeConstraint: AreMultipliable { - type Output = MatrixMul; + SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable { + type Output = MatrixMN; #[inline] - fn mul(self, right: &'b Matrix) -> Self::Output { - let (nrows1, ncols1) = self.shape(); - let (nrows2, ncols2) = right.shape(); - - assert!(ncols1 == nrows2, "Matrix multiplication dimensions mismatch."); - - let mut res: MatrixMul = unsafe { - Matrix::new_uninitialized_generic(self.data.shape().0, right.data.shape().1) + fn mul(self, rhs: &'b Matrix) -> Self::Output { + let mut res = unsafe { + Matrix::new_uninitialized_generic(self.data.shape().0, rhs.data.shape().1) }; - for i in 0 .. nrows1 { - for j in 0 .. ncols2 { - let mut acc = N::zero(); - - unsafe { - for k in 0 .. ncols1 { - acc = acc + *self.get_unchecked(i, k) * *right.get_unchecked(k, j); - } - - *res.get_unchecked_mut(i, j) = acc; - } - } - } - + self.mul_to(rhs, &mut res); res } } impl<'a, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul> for &'a Matrix - where N: Scalar + Zero + ClosedAdd + ClosedMul, + where N: Scalar + Zero + One + ClosedAdd + ClosedMul, SB: Storage, SA: Storage, - SA::Alloc: Allocator, - ShapeConstraint: AreMultipliable { - type Output = MatrixMul; + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable { + type Output = MatrixMN; #[inline] - fn mul(self, right: Matrix) -> Self::Output { - self * &right + fn mul(self, rhs: Matrix) -> Self::Output { + self * &rhs } } impl<'b, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix> for Matrix - where N: Scalar + Zero + ClosedAdd + ClosedMul, + where N: Scalar + Zero + One + ClosedAdd + ClosedMul, SB: Storage, SA: Storage, - SA::Alloc: Allocator, - ShapeConstraint: AreMultipliable { - type Output = MatrixMul; + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable { + type Output = MatrixMN; #[inline] - fn mul(self, right: &'b Matrix) -> Self::Output { - &self * right + fn mul(self, rhs: &'b Matrix) -> Self::Output { + &self * rhs } } impl Mul> for Matrix - where N: Scalar + Zero + ClosedAdd + ClosedMul, + where N: Scalar + Zero + One + ClosedAdd + ClosedMul, SB: Storage, SA: Storage, - SA::Alloc: Allocator, - ShapeConstraint: AreMultipliable { - type Output = MatrixMul; + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable { + type Output = MatrixMN; #[inline] - fn mul(self, right: Matrix) -> Self::Output { - &self * &right + fn mul(self, rhs: Matrix) -> Self::Output { + &self * &rhs } } @@ -447,84 +556,106 @@ for Matrix // − we can't use `a *= b` when C2 is not equal to C1. impl MulAssign> for Matrix where R1: Dim, C1: Dim, R2: Dim, - N: Scalar + Zero + ClosedAdd + ClosedMul, + N: Scalar + Zero + One + ClosedAdd + ClosedMul, SB: Storage, - SA: OwnedStorage, - ShapeConstraint: AreMultipliable, - SA::Alloc: OwnedAllocator { + SA: ContiguousStorageMut + Clone, + ShapeConstraint: AreMultipliable, + DefaultAllocator: Allocator { #[inline] - fn mul_assign(&mut self, right: Matrix) { - *self = &*self * right + fn mul_assign(&mut self, rhs: Matrix) { + *self = &*self * rhs } } impl<'b, N, R1, C1, R2, SA, SB> MulAssign<&'b Matrix> for Matrix where R1: Dim, C1: Dim, R2: Dim, - N: Scalar + Zero + ClosedAdd + ClosedMul, + N: Scalar + Zero + One + ClosedAdd + ClosedMul, SB: Storage, - SA: OwnedStorage, + SA: ContiguousStorageMut + Clone, ShapeConstraint: AreMultipliable, // FIXME: this is too restrictive. See comments for the non-ref version. - SA::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] - fn mul_assign(&mut self, right: &'b Matrix) { - *self = &*self * right + fn mul_assign(&mut self, rhs: &'b Matrix) { + *self = &*self * rhs } } // Transpose-multiplication. impl Matrix - where N: Scalar, + where N: Scalar + Zero + One + ClosedAdd + ClosedMul, SA: Storage { - /// Equivalent to `self.transpose() * right`. + /// Equivalent to `self.transpose() * rhs`. #[inline] - pub fn tr_mul(&self, right: &Matrix) -> MatrixTrMul - where N: Zero + ClosedAdd + ClosedMul, - SB: Storage, - SA::Alloc: Allocator, - ShapeConstraint: AreMultipliable { + pub fn tr_mul(&self, rhs: &Matrix) -> MatrixMN + where SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows { + + let mut res = unsafe { + Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1) + }; + + self.tr_mul_to(rhs, &mut res); + res + } + + /// Equivalent to `self.transpose() * rhs` but stores the result into `out` to avoid + /// allocations. + #[inline] + pub fn tr_mul_to(&self, + rhs: &Matrix, + out: &mut Matrix) + where SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + + DimEq + + DimEq { let (nrows1, ncols1) = self.shape(); - let (nrows2, ncols2) = right.shape(); + let (nrows2, ncols2) = rhs.shape(); + let (nrows3, ncols3) = out.shape(); assert!(nrows1 == nrows2, "Matrix multiplication dimensions mismatch."); - - let mut res: MatrixTrMul = unsafe { - Matrix::new_uninitialized_generic(self.data.shape().1, right.data.shape().1) - }; + assert!(nrows3 == ncols1 && ncols3 == ncols2, "Matrix multiplication output dimensions mismatch."); for i in 0 .. ncols1 { for j in 0 .. ncols2 { - let mut acc = N::zero(); - - unsafe { - for k in 0 .. nrows1 { - acc += *self.get_unchecked(k, i) * *right.get_unchecked(k, j); - } - - *res.get_unchecked_mut(i, j) = acc; - } + let dot = self.column(i).dot(&rhs.column(j)); + unsafe { *out.get_unchecked_mut(i, j) = dot }; } } + } - res + /// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations. + #[inline] + pub fn mul_to(&self, + rhs: &Matrix, + out: &mut Matrix) + where SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable { + out.gemm(N::one(), self, rhs, N::zero()); } /// The kronecker product of two matrices (aka. tensor product of the corresponding linear /// maps). pub fn kronecker(&self, rhs: &Matrix) - -> OwnedMatrix, DimProd, SA::Alloc> + -> MatrixMN, DimProd> where N: ClosedMul, R1: DimMul, C1: DimMul, SB: Storage, - SA::Alloc: Allocator, DimProd> { + DefaultAllocator: Allocator, DimProd> { let (nrows1, ncols1) = self.data.shape(); let (nrows2, ncols2) = rhs.data.shape(); - let mut res: OwnedMatrix<_, _, _, SA::Alloc> = - unsafe { Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2)) }; + let mut res = unsafe { Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2)) }; { let mut data_res = res.data.ptr_mut(); @@ -549,22 +680,76 @@ impl Matrix } } -impl iter::Product for SquareMatrix +impl> Matrix { + /// Adds a scalar to `self`. + #[inline] + pub fn add_scalar(&self, rhs: N) -> MatrixMN + where DefaultAllocator: Allocator { + let mut res = self.clone_owned(); + res.add_scalar_mut(rhs); + res + } + + /// Adds a scalar to `self` in-place. + #[inline] + pub fn add_scalar_mut(&mut self, rhs: N) + where S: StorageMut { + for e in self.iter_mut() { + *e += rhs + } + } +} + + +impl iter::Product for MatrixN where N: Scalar + Zero + One + ClosedMul + ClosedAdd, - S: OwnedStorage, - S::Alloc: OwnedAllocator + DefaultAllocator: Allocator { - fn product>>(iter: I) -> SquareMatrix { + fn product>>(iter: I) -> MatrixN { iter.fold(Matrix::one(), |acc, x| acc * x) } } -impl<'a, N, D: DimName, S> iter::Product<&'a SquareMatrix> for SquareMatrix +impl<'a, N, D: DimName> iter::Product<&'a MatrixN> for MatrixN where N: Scalar + Zero + One + ClosedMul + ClosedAdd, - S: OwnedStorage, - S::Alloc: OwnedAllocator + DefaultAllocator: Allocator { - fn product>>(iter: I) -> SquareMatrix { + fn product>>(iter: I) -> MatrixN { iter.fold(Matrix::one(), |acc, x| acc * x) } } + +impl> Matrix { + /// Returns the absolute value of the coefficient with the largest absolute value. + #[inline] + pub fn amax(&self) -> N { + let mut max = N::zero(); + + for e in self.iter() { + let ae = e.abs(); + + if ae > max { + max = ae; + } + } + + max + } + + /// Returns the absolute value of the coefficient with the smallest absolute value. + #[inline] + pub fn amin(&self) -> N { + let mut it = self.iter(); + let mut min = it.next().expect("amin: empty matrices not supported.").abs(); + + for e in it { + let ae = e.abs(); + + if ae < min { + min = ae; + } + } + + min + } +} diff --git a/src/core/properties.rs b/src/core/properties.rs index 77a28c73..be1fbc6f 100644 --- a/src/core/properties.rs +++ b/src/core/properties.rs @@ -2,33 +2,38 @@ use num::{Zero, One}; use approx::ApproxEq; -use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Field}; +use alga::general::{ClosedAdd, ClosedMul, Real}; -use core::{Scalar, Matrix, SquareMatrix}; -use core::dimension::Dim; +use core::{DefaultAllocator, Scalar, Matrix, SquareMatrix}; +use core::dimension::{Dim, DimMin}; use core::storage::Storage; +use core::allocator::Allocator; impl> Matrix { /// Indicates if this is a square matrix. #[inline] - pub fn is_square(&self) -> bool { - let shape = self.shape(); - shape.0 == shape.1 + pub fn is_empty(&self) -> bool { + let (nrows, ncols) = self.shape(); + nrows == 0 || ncols == 0 + } + + /// Indicates if this is a square matrix. + #[inline] + pub fn is_square(&self) -> bool { + let (nrows, ncols) = self.shape(); + nrows == ncols } -} -impl> Matrix // FIXME: ApproxEq prevents us from using those methods on integer matrices… - where N: ApproxEq, - N::Epsilon: Copy { /// Indicated if this is the identity matrix within a relative error of `eps`. /// /// If the matrix is diagonal, this checks that diagonal elements (i.e. at coordinates `(i, i)` /// for i from `0` to `min(R, C)`) are equal one; and that all other elements are zero. #[inline] pub fn is_identity(&self, eps: N::Epsilon) -> bool - where N: Zero + One { + where N: Zero + One + ApproxEq, + N::Epsilon: Copy { let (nrows, ncols) = self.shape(); let d; @@ -75,32 +80,35 @@ impl> Matrix true } -} - -impl> SquareMatrix - where N: Zero + One + ClosedAdd + ClosedMul, - N::Epsilon: Copy { - /// Checks that this matrix is orthogonal, i.e., that it is square and `M × Mᵀ = Id`. + /// Checks that `Mᵀ × M = Id`. /// /// In this definition `Id` is approximately equal to the identity matrix with a relative error /// equal to `eps`. #[inline] - pub fn is_orthogonal(&self, eps: N::Epsilon) -> bool { - self.is_square() && (self.tr_mul(self)).is_identity(eps) + pub fn is_orthogonal(&self, eps: N::Epsilon) -> bool + where N: Zero + One + ClosedAdd + ClosedMul + ApproxEq, + S: Storage, + N::Epsilon: Copy, + DefaultAllocator: Allocator { + (self.tr_mul(self)).is_identity(eps) } +} + +impl> SquareMatrix + where DefaultAllocator: Allocator { /// Checks that this matrix is orthogonal and has a determinant equal to 1. #[inline] - pub fn is_special_orthogonal(&self, eps: N::Epsilon) -> bool - where N: ClosedSub + PartialOrd { - self.is_orthogonal(eps) && self.determinant() > N::zero() + pub fn is_special_orthogonal(&self, eps: N) -> bool + where D: DimMin, + DefaultAllocator: Allocator<(usize, usize), D> { + self.is_square() && self.is_orthogonal(eps) && self.determinant() > N::zero() } /// Returns `true` if this matrix is invertible. #[inline] - pub fn is_invertible(&self) -> bool - where N: Field { + pub fn is_invertible(&self) -> bool { // FIXME: improve this? self.clone_owned().try_inverse().is_some() } diff --git a/src/core/scalar.rs b/src/core/scalar.rs index 9d2cb8c7..29e2c76d 100644 --- a/src/core/scalar.rs +++ b/src/core/scalar.rs @@ -1,3 +1,4 @@ +use std::any::TypeId; use std::fmt::Debug; use std::any::Any; @@ -5,5 +6,9 @@ use std::any::Any; /// /// This does not make any assumption on the algebraic properties of `Self`. pub trait Scalar: Copy + PartialEq + Debug + Any { + #[inline] + fn is() -> bool { + TypeId::of::() == TypeId::of::() + } } impl Scalar for T { } diff --git a/src/core/storage.rs b/src/core/storage.rs index d70e416c..6b25a807 100644 --- a/src/core/storage.rs +++ b/src/core/storage.rs @@ -1,39 +1,28 @@ //! Abstract definition of a matrix data storage. +use std::fmt::Debug; use std::mem; -use std::any::Any; use core::Scalar; -use dimension::Dim; -use allocator::{Allocator, SameShapeR, SameShapeC}; +use core::default_allocator::DefaultAllocator; +use core::dimension::{Dim, U1}; +use core::allocator::{Allocator, SameShapeR, SameShapeC}; /* - * Aliases for sum storage. + * Aliases for allocation results. */ /// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`. -pub type SumStorage = - <>::Alloc as Allocator, SameShapeC>>::Buffer; +pub type SameShapeStorage = , SameShapeC>>::Buffer; -/* - * Aliases for multiplication storage. - */ -/// The data storage for the multiplication of two matrices with dimensions `(R1, C1)` on the left -/// hand side, and with `C2` columns on the right hand side. -pub type MulStorage = - <>::Alloc as Allocator>::Buffer; - -/// The data storage for the multiplication of two matrices with dimensions `(R1, C1)` on the left -/// hand side, and with `C2` columns on the right hand side. The first matrix is implicitly -/// transposed. -pub type TrMulStorage = - <>::Alloc as Allocator>::Buffer; - -/* - * Alias for allocation result. - */ +// FIXME: better name than Owned ? /// The owned data storage that can be allocated from `S`. -pub type Owned = - >::Buffer; +pub type Owned = >::Buffer; + +/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`. +pub type RStride = <>::Buffer as Storage>::RStride; + +/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`. +pub type CStride = <>::Buffer as Storage>::CStride; /// The trait shared by all matrix data storage. @@ -45,22 +34,13 @@ pub type Owned = /// should **not** allow the user to modify the size of the underlying buffer with safe methods /// (for example the `MatrixVec::data_mut` method is unsafe because the user could change the /// vector's size so that it no longer contains enough elements: this will lead to UB. -pub unsafe trait Storage: Sized { +pub unsafe trait Storage: Debug + Sized { /// The static stride of this storage's rows. type RStride: Dim; /// The static stride of this storage's columns. type CStride: Dim; - /// The allocator for this family of storage. - type Alloc: Allocator; - - /// Builds a matrix data storage that does not contain any reference. - fn into_owned(self) -> Owned; - - /// Clones this data storage into one that does not contain any reference. - fn clone_owned(&self) -> Owned; - /// The matrix data pointer. fn ptr(&self) -> *const N; @@ -110,6 +90,24 @@ pub unsafe trait Storage: Sized { unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N { self.get_unchecked_linear(self.linear_index(irow, icol)) } + + /// Indicates whether this data buffer stores its elements contiguously. + #[inline] + fn is_contiguous(&self) -> bool; + + /// Retrieves the data buffer as a contiguous slice. + /// + /// The matrix components may not be stored in a contiguous way, depending on the strides. + #[inline] + fn as_slice(&self) -> &[N]; + + /// Builds a matrix data storage that does not contain any reference. + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator; + + /// Clones this data storage into one that does not contain any reference. + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator; } @@ -118,7 +116,7 @@ pub unsafe trait Storage: Sized { /// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable /// matrix slice can provide mutable access to its elements even if it does not own its data (it /// contains only an internal reference to them). -pub unsafe trait StorageMut: Storage { +pub unsafe trait StorageMut: Storage { /// The matrix mutable data pointer. fn ptr_mut(&mut self) -> *mut N; @@ -163,22 +161,24 @@ pub unsafe trait StorageMut: Storage { self.swap_unchecked_linear(lid1, lid2) } -} -/// A matrix storage that does not contain any reference and that is stored contiguously in memory. -/// -/// The storage requirement means that for any value of `i` in `[0, nrows * ncols[`, the value -/// `.get_unchecked_linear` succeeds. This trait is unsafe because failing to comply to this may -/// cause Undefined Behaviors. -pub unsafe trait OwnedStorage: StorageMut + Clone + Any - where Self::Alloc: Allocator { - // NOTE: We could auto-impl those two methods but we don't to make sure the user is aware that - // data must be contiguous. - /// Converts this data storage to a slice. - #[inline] - fn as_slice(&self) -> &[N]; - - /// Converts this data storage to a mutable slice. + /// Retrieves the mutable data buffer as a contiguous slice. + /// + /// Matrix components may not be contiguous, depending on its strides. #[inline] fn as_mut_slice(&mut self) -> &mut [N]; } + +/// A matrix storage that is stored contiguously in memory. +/// +/// The storage requirement means that for any value of `i` in `[0, nrows * ncols[`, the value +/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because +/// failing to comply to this may cause Undefined Behaviors. +pub unsafe trait ContiguousStorage: Storage { } + +/// A mutable matrix storage that is stored contiguously in memory. +/// +/// The storage requirement means that for any value of `i` in `[0, nrows * ncols[`, the value +/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because +/// failing to comply to this may cause Undefined Behaviors. +pub unsafe trait ContiguousStorageMut: ContiguousStorage + StorageMut { } diff --git a/src/debug/mod.rs b/src/debug/mod.rs new file mode 100644 index 00000000..57a16dfd --- /dev/null +++ b/src/debug/mod.rs @@ -0,0 +1,8 @@ +//! Various tools useful for testing/debugging/benchmarking. + + +mod random_orthogonal; +mod random_sdp; + +pub use self::random_orthogonal::*; +pub use self::random_sdp::*; diff --git a/src/debug/random_orthogonal.rs b/src/debug/random_orthogonal.rs new file mode 100644 index 00000000..819bb21b --- /dev/null +++ b/src/debug/random_orthogonal.rs @@ -0,0 +1,51 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; + +use num_complex::Complex; +use alga::general::Real; +use core::{DefaultAllocator, MatrixN}; +use core::dimension::{Dim, Dynamic, U2}; +use core::allocator::Allocator; +use geometry::UnitComplex; + +/// A random orthogonal matrix. +#[derive(Clone, Debug)] +pub struct RandomOrthogonal + where DefaultAllocator: Allocator { + m: MatrixN +} + + +impl RandomOrthogonal + where DefaultAllocator: Allocator { + /// Retrieve the generated matrix. + pub fn unwrap(self) -> MatrixN { + self.m + } + + /// Creates a new random orthogonal matrix from its dimension and a random reals generators. + pub fn new N>(dim: D, mut rand: Rand) -> Self { + let mut res = MatrixN::identity_generic(dim, dim); + + // Create an orthogonal matrix by compositing planar 2D rotations. + for i in 0 .. dim.value() - 1 { + let c = Complex::new(rand(), rand()); + let rot: UnitComplex = UnitComplex::from_complex(c); + rot.rotate(&mut res.fixed_rows_mut::(i)); + } + + RandomOrthogonal { m: res } + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for RandomOrthogonal + where DefaultAllocator: Allocator, + Owned: Clone + Send { + fn arbitrary(g: &mut G) -> Self { + let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50)); + Self::new(D::from_usize(dim), || N::arbitrary(g)) + } +} diff --git a/src/debug/random_sdp.rs b/src/debug/random_sdp.rs new file mode 100644 index 00000000..d193b3c8 --- /dev/null +++ b/src/debug/random_sdp.rs @@ -0,0 +1,54 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; + +use alga::general::Real; +use core::{DefaultAllocator, MatrixN}; +use core::dimension::{Dim, Dynamic}; +use core::allocator::Allocator; + +use debug::RandomOrthogonal; + + +/// A random, well-conditioned, symmetric definite-positive matrix. +#[derive(Clone, Debug)] +pub struct RandomSDP + where DefaultAllocator: Allocator { + m: MatrixN +} + + +impl RandomSDP + where DefaultAllocator: Allocator { + + /// Retrieve the generated matrix. + pub fn unwrap(self) -> MatrixN { + self.m + } + + /// Creates a new well conditioned symmetric definite-positive matrix from its dimension and a + /// random reals generators. + pub fn new N>(dim: D, mut rand: Rand) -> Self { + let mut m = RandomOrthogonal::new(dim, || rand()).unwrap(); + let mt = m.transpose(); + + for i in 0 .. dim.value() { + let mut col = m.column_mut(i); + let eigenval = N::one() + rand().abs(); + col *= eigenval; + } + + RandomSDP { m: m * mt } + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for RandomSDP + where DefaultAllocator: Allocator, + Owned: Clone + Send { + fn arbitrary(g: &mut G) -> Self { + let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50)); + Self::new(D::from_usize(dim), || N::arbitrary(g)) + } +} diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 67d2e7e8..fd60a16d 100644 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -1,30 +1,40 @@ use std::fmt; +use std::hash; use std::marker::PhantomData; use approx::ApproxEq; +#[cfg(feature = "serde-serialize")] +use serde; + use alga::general::{Real, SubsetOf}; use alga::linear::Rotation; -use core::{Scalar, OwnedSquareMatrix}; +use core::{DefaultAllocator, MatrixN}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; -use core::storage::{Storage, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; -use geometry::{TranslationBase, PointBase}; - - -/// An isometry that uses a data storage deduced from the allocator `A`. -pub type OwnedIsometryBase = - IsometryBase>::Buffer, R>; +use core::storage::Owned; +use core::allocator::Allocator; +use geometry::{Translation, Point}; /// A direct isometry, i.e., a rotation followed by a translation. #[repr(C)] -#[derive(Hash, Debug, Clone, Copy)] +#[derive(Debug)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -pub struct IsometryBase { +#[cfg_attr(feature = "serde-serialize", + serde(bound( + serialize = "R: serde::Serialize, + DefaultAllocator: Allocator, + Owned: serde::Serialize")))] +#[cfg_attr(feature = "serde-serialize", + serde(bound( + deserialize = "R: serde::Deserialize<'de>, + DefaultAllocator: Allocator, + Owned: serde::Deserialize<'de>")))] +pub struct Isometry + where DefaultAllocator: Allocator { /// The pure rotational part of this isometry. pub rotation: R, /// The pure translational part of this isometry. - pub translation: TranslationBase, + pub translation: Translation, // One dummy private field just to prevent explicit construction. @@ -32,15 +42,34 @@ pub struct IsometryBase { _noconstruct: PhantomData } -impl IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl hash::Hash for Isometry + where DefaultAllocator: Allocator, + Owned: hash::Hash { + fn hash(&self, state: &mut H) { + self.translation.hash(state); + self.rotation.hash(state); + } +} + +impl> + Copy> Copy for Isometry + where DefaultAllocator: Allocator, + Owned: Copy { +} + +impl> + Clone> Clone for Isometry + where DefaultAllocator: Allocator { + #[inline] + fn clone(&self) -> Self { + Isometry::from_parts(self.translation.clone(), self.rotation.clone()) + } +} + +impl>> Isometry + where DefaultAllocator: Allocator { /// Creates a new isometry from its rotational and translational parts. #[inline] - pub fn from_parts(translation: TranslationBase, rotation: R) -> IsometryBase { - IsometryBase { + pub fn from_parts(translation: Translation, rotation: R) -> Isometry { + Isometry { rotation: rotation, translation: translation, _noconstruct: PhantomData @@ -49,7 +78,7 @@ impl IsometryBase /// Inverts `self`. #[inline] - pub fn inverse(&self) -> IsometryBase { + pub fn inverse(&self) -> Isometry { let mut res = self.clone(); res.inverse_mut(); res @@ -65,7 +94,7 @@ impl IsometryBase /// Appends to `self` the given translation in-place. #[inline] - pub fn append_translation_mut(&mut self, t: &TranslationBase) { + pub fn append_translation_mut(&mut self, t: &Translation) { self.translation.vector += &t.vector } @@ -79,7 +108,7 @@ impl IsometryBase /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that /// lets `p` invariant. #[inline] - pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &PointBase) { + pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point) { self.translation.vector -= &p.coords; self.append_rotation_mut(r); self.translation.vector += &p.coords; @@ -89,7 +118,7 @@ impl IsometryBase /// `self.translation`. #[inline] pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { - let center = PointBase::from_coordinates(self.translation.vector.clone()); + let center = Point::from_coordinates(self.translation.vector.clone()); self.append_rotation_wrt_point_mut(r, ¢er) } } @@ -98,16 +127,15 @@ impl IsometryBase // and makes it hard to use it, e.g., for Transform × Isometry implementation. // This is OK since all constructors of the isometry enforce the Rotation bound already (and // explicit struct construction is prevented by the dummy ZST field). -impl IsometryBase - where N: Scalar, - S: Storage { +impl Isometry + where DefaultAllocator: Allocator { /// Converts this isometry into its equivalent homogeneous transformation matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix, S::Alloc> + pub fn to_homogeneous(&self) -> MatrixN> where D: DimNameAdd, - R: SubsetOf, S::Alloc>>, - S::Alloc: Allocator, DimNameSum> { - let mut res: OwnedSquareMatrix = ::convert_ref(&self.rotation); + R: SubsetOf>>, + DefaultAllocator: Allocator, DimNameSum> { + let mut res: MatrixN = ::convert_ref(&self.rotation); res.fixed_slice_mut::(0, D::dim()).copy_from(&self.translation.vector); res @@ -115,30 +143,24 @@ impl IsometryBase } -impl Eq for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation> + Eq, - S::Alloc: OwnedAllocator { +impl Eq for Isometry + where R: Rotation> + Eq, + DefaultAllocator: Allocator { } -impl PartialEq for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation> + PartialEq, - S::Alloc: OwnedAllocator { +impl PartialEq for Isometry + where R: Rotation> + PartialEq, + DefaultAllocator: Allocator { #[inline] - fn eq(&self, right: &IsometryBase) -> bool { + fn eq(&self, right: &Isometry) -> bool { self.translation == right.translation && self.rotation == right.rotation } } -impl ApproxEq for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation> + ApproxEq, - S::Alloc: OwnedAllocator, +impl ApproxEq for Isometry + where R: Rotation> + ApproxEq, + DefaultAllocator: Allocator, N::Epsilon: Copy { type Epsilon = N::Epsilon; @@ -175,32 +197,16 @@ impl ApproxEq for IsometryBase * Display * */ -impl fmt::Display for IsometryBase - where N: Real + fmt::Display, - S: OwnedStorage, - R: fmt::Display, - S::Alloc: OwnedAllocator + Allocator { +impl fmt::Display for Isometry + where R: fmt::Display, + DefaultAllocator: Allocator + + Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "IsometryBase {{")); + try!(writeln!(f, "Isometry {{")); try!(write!(f, "{:.*}", precision, self.translation)); try!(write!(f, "{:.*}", precision, self.rotation)); writeln!(f, "}}") } } - - -// /* -// * -// * Absolute -// * -// */ -// impl Absolute for $t { -// type AbsoluteValue = $submatrix; -// -// #[inline] -// fn abs(m: &$t) -> $submatrix { -// Absolute::abs(&m.submatrix) -// } -// } diff --git a/src/geometry/isometry_alga.rs b/src/geometry/isometry_alga.rs index 8728d9ac..8e3a6453 100644 --- a/src/geometry/isometry_alga.rs +++ b/src/geometry/isometry_alga.rs @@ -1,14 +1,14 @@ use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id}; -use alga::linear::{Transformation, Similarity, AffineTransformation, DirectIsometry, Isometry, +use alga::linear::{Transformation, Similarity, AffineTransformation, DirectIsometry, Rotation, ProjectiveTransformation}; +use alga::linear::Isometry as AlgaIsometry; -use core::ColumnVector; -use core::dimension::{DimName, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::{DefaultAllocator, VectorN}; +use core::dimension::DimName; +use core::allocator::Allocator; -use geometry::{IsometryBase, TranslationBase, PointBase}; +use geometry::{Isometry, Translation, Point}; /* @@ -16,22 +16,18 @@ use geometry::{IsometryBase, TranslationBase, PointBase}; * Algebraic structures. * */ -impl Identity for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Identity for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] fn identity() -> Self { Self::identity() } } -impl Inverse for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Inverse for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] fn inverse(&self) -> Self { self.inverse() @@ -43,11 +39,9 @@ impl Inverse for IsometryBase } } -impl AbstractMagma for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl AbstractMagma for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs @@ -56,11 +50,9 @@ impl AbstractMagma for IsometryBase),* $(,)*) => {$( - impl $marker<$operator> for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { } + impl $marker<$operator> for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { } )*} ); @@ -77,49 +69,43 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Transformation> for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] - fn transform_point(&self, pt: &PointBase) -> PointBase { + fn transform_point(&self, pt: &Point) -> Point { self * pt } #[inline] - fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn transform_vector(&self, v: &VectorN) -> VectorN { self * v } } -impl ProjectiveTransformation> for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl ProjectiveTransformation> for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] - fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { + fn inverse_transform_point(&self, pt: &Point) -> Point { self.rotation.inverse_transform_point(&(pt - &self.translation.vector)) } #[inline] - fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { self.rotation.inverse_transform_vector(v) } } -impl AffineTransformation> for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl AffineTransformation> for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { type Rotation = R; type NonUniformScaling = Id; - type Translation = TranslationBase; + type Translation = Translation; #[inline] - fn decompose(&self) -> (TranslationBase, R, Id, R) { + fn decompose(&self) -> (Translation, R, Id, R) { (self.translation.clone(), self.rotation.clone(), Id::new(), R::identity()) } @@ -136,7 +122,7 @@ impl AffineTransformation> for IsometryB #[inline] fn append_rotation(&self, r: &Self::Rotation) -> Self { let shift = r.transform_vector(&self.translation.vector); - IsometryBase::from_parts(TranslationBase::from_vector(shift), r.clone() * self.rotation.clone()) + Isometry::from_parts(Translation::from_vector(shift), r.clone() * self.rotation.clone()) } #[inline] @@ -155,22 +141,20 @@ impl AffineTransformation> for IsometryB } #[inline] - fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &PointBase) -> Option { + fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &Point) -> Option { let mut res = self.clone(); res.append_rotation_wrt_point_mut(r, p); Some(res) } } -impl Similarity> for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Similarity> for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { type Scaling = Id; #[inline] - fn translation(&self) -> TranslationBase { + fn translation(&self) -> Translation { self.translation.clone() } @@ -187,12 +171,10 @@ impl Similarity> for IsometryBase {$( - impl $Trait> for IsometryBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { } + impl $Trait> for Isometry + where R: Rotation>, + DefaultAllocator: Allocator { } )*} ); -marker_impl!(Isometry, DirectIsometry); +marker_impl!(AlgaIsometry, DirectIsometry); diff --git a/src/geometry/isometry_alias.rs b/src/geometry/isometry_alias.rs index 0bf44b4a..b9db1c63 100644 --- a/src/geometry/isometry_alias.rs +++ b/src/geometry/isometry_alias.rs @@ -1,19 +1,16 @@ -use core::MatrixArray; -use core::dimension::{U1, U2, U3}; +use core::dimension::{U2, U3}; -use geometry::{Rotation, IsometryBase, UnitQuaternion, UnitComplex}; +use geometry::{Isometry, Rotation2, Rotation3, UnitQuaternion, UnitComplex}; -/// A D-dimensional isometry. -pub type Isometry = IsometryBase, Rotation>; /// A 2-dimensional isometry using a unit complex number for its rotational part. -pub type Isometry2 = IsometryBase, UnitComplex>; +pub type Isometry2 = Isometry>; /// A 3-dimensional isometry using a unit quaternion for its rotational part. -pub type Isometry3 = IsometryBase, UnitQuaternion>; +pub type Isometry3 = Isometry>; -/// A 2-dimensional isometry using a rotation matrix for its rotation part. -pub type IsometryMatrix2 = Isometry; +/// A 2-dimensional isometry using a rotation matrix for its rotational part. +pub type IsometryMatrix2 = Isometry>; -/// A 3-dimensional isometry using a rotation matrix for its rotation part. -pub type IsometryMatrix3 = Isometry; +/// A 3-dimensional isometry using a rotation matrix for its rotational part. +pub type IsometryMatrix3 = Isometry>; diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index 9eb3a42f..27ac5169 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -1,5 +1,7 @@ #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; use num::One; use rand::{Rng, Rand}; @@ -7,31 +9,33 @@ use rand::{Rng, Rand}; use alga::general::Real; use alga::linear::Rotation as AlgaRotation; -use core::ColumnVector; -use core::dimension::{DimName, U1, U2, U3, U4}; -use core::allocator::{OwnedAllocator, Allocator}; -use core::storage::OwnedStorage; +use core::{DefaultAllocator, Vector2, Vector3}; +use core::dimension::{DimName, U2, U3}; +use core::allocator::Allocator; -use geometry::{PointBase, TranslationBase, RotationBase, IsometryBase, UnitQuaternionBase, UnitComplex}; +use geometry::{Point, Translation, Rotation, Isometry, UnitQuaternion, UnitComplex, + Point3, Rotation2, Rotation3}; -impl IsometryBase - where N: Real, - S: OwnedStorage, - R: AlgaRotation>, - S::Alloc: OwnedAllocator { +impl>> Isometry + where DefaultAllocator: Allocator { /// Creates a new identity isometry. #[inline] pub fn identity() -> Self { - Self::from_parts(TranslationBase::identity(), R::identity()) + Self::from_parts(Translation::identity(), R::identity()) + } + + /// The isometry that applies the rotation `r` with its axis passing through the point `p`. + /// This effectively lets `p` invariant. + #[inline] + pub fn rotation_wrt_point(r: R, p: Point) -> Self { + let shift = r.transform_vector(&-&p.coords); + Self::from_parts(Translation::from_vector(shift + p.coords), r) } } -impl One for IsometryBase - where N: Real, - S: OwnedStorage, - R: AlgaRotation>, - S::Alloc: OwnedAllocator { +impl>> One for Isometry + where DefaultAllocator: Allocator { /// Creates a new identity isometry. #[inline] fn one() -> Self { @@ -39,37 +43,21 @@ impl One for IsometryBase } } -impl Rand for IsometryBase - where N: Real + Rand, - S: OwnedStorage, - R: AlgaRotation> + Rand, - S::Alloc: OwnedAllocator { +impl Rand for Isometry + where R: AlgaRotation> + Rand, + DefaultAllocator: Allocator { #[inline] fn rand(rng: &mut G) -> Self { Self::from_parts(rng.gen(), rng.gen()) } } -impl IsometryBase - where N: Real, - S: OwnedStorage, - R: AlgaRotation>, - S::Alloc: OwnedAllocator { - /// The isometry that applies the rotation `r` with its axis passing through the point `p`. - /// This effectively lets `p` invariant. - #[inline] - pub fn rotation_wrt_point(r: R, p: PointBase) -> Self { - let shift = r.transform_vector(&-&p.coords); - Self::from_parts(TranslationBase::from_vector(shift + p.coords), r) - } -} - #[cfg(feature = "arbitrary")] -impl Arbitrary for IsometryBase +impl Arbitrary for Isometry where N: Real + Arbitrary + Send, - S: OwnedStorage + Send, - R: AlgaRotation> + Arbitrary + Send, - S::Alloc: OwnedAllocator { + R: AlgaRotation> + Arbitrary + Send, + Owned: Send, + DefaultAllocator: Allocator { #[inline] fn arbitrary(rng: &mut G) -> Self { Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng)) @@ -83,45 +71,31 @@ impl Arbitrary for IsometryBase */ // 2D rotation. -impl IsometryBase> - where N: Real, - S: OwnedStorage, - SR: OwnedStorage, - S::Alloc: OwnedAllocator, - SR::Alloc: OwnedAllocator { +impl Isometry> { /// Creates a new isometry from a translation and a rotation angle. #[inline] - pub fn new(translation: ColumnVector, angle: N) -> Self { - Self::from_parts(TranslationBase::from_vector(translation), RotationBase::::new(angle)) + pub fn new(translation: Vector2, angle: N) -> Self { + Self::from_parts(Translation::from_vector(translation), Rotation::::new(angle)) } } -impl IsometryBase> - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Isometry> { /// Creates a new isometry from a translation and a rotation angle. #[inline] - pub fn new(translation: ColumnVector, angle: N) -> Self { - Self::from_parts(TranslationBase::from_vector(translation), UnitComplex::from_angle(angle)) + pub fn new(translation: Vector2, angle: N) -> Self { + Self::from_parts(Translation::from_vector(translation), UnitComplex::from_angle(angle)) } } // 3D rotation. macro_rules! isometry_construction_impl( ($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => { - impl IsometryBase> - where N: Real, - S: OwnedStorage, - SR: OwnedStorage, - S::Alloc: OwnedAllocator, - SR::Alloc: OwnedAllocator + - Allocator { + impl Isometry> { /// Creates a new isometry from a translation and a rotation axis-angle. #[inline] - pub fn new(translation: ColumnVector, axisangle: ColumnVector) -> Self { + pub fn new(translation: Vector3, axisangle: Vector3) -> Self { Self::from_parts( - TranslationBase::from_vector(translation), + Translation::from_vector(translation), $RotId::<$($RotParams),*>::from_scaled_axis(axisangle)) } @@ -137,12 +111,12 @@ macro_rules! isometry_construction_impl( /// * up - Vertical direction. The only requirement of this parameter is to not be collinear /// to `eye - at`. Non-collinearity is not checked. #[inline] - pub fn new_observer_frame(eye: &PointBase, - target: &PointBase, - up: &ColumnVector) + pub fn new_observer_frame(eye: &Point3, + target: &Point3, + up: &Vector3) -> Self { Self::from_parts( - TranslationBase::from_vector(eye.coords.clone()), + Translation::from_vector(eye.coords.clone()), $RotId::new_observer_frame(&(target - eye), up)) } @@ -157,14 +131,14 @@ macro_rules! isometry_construction_impl( /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_rh(eye: &PointBase, - target: &PointBase, - up: &ColumnVector) + pub fn look_at_rh(eye: &Point3, + target: &Point3, + up: &Vector3) -> Self { let rotation = $RotId::look_at_rh(&(target - eye), up); let trans = &rotation * (-eye); - Self::from_parts(TranslationBase::from_vector(trans.coords), rotation) + Self::from_parts(Translation::from_vector(trans.coords), rotation) } /// Builds a left-handed look-at view matrix. @@ -178,18 +152,18 @@ macro_rules! isometry_construction_impl( /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_lh(eye: &PointBase, - target: &PointBase, - up: &ColumnVector) + pub fn look_at_lh(eye: &Point3, + target: &Point3, + up: &Vector3) -> Self { let rotation = $RotId::look_at_lh(&(target - eye), up); let trans = &rotation * (-eye); - Self::from_parts(TranslationBase::from_vector(trans.coords), rotation) + Self::from_parts(Translation::from_vector(trans.coords), rotation) } } } ); -isometry_construction_impl!(RotationBase, U3, U3); -isometry_construction_impl!(UnitQuaternionBase, U4, U1); +isometry_construction_impl!(Rotation3, U3, U3); +isometry_construction_impl!(UnitQuaternion, U4, U1); diff --git a/src/geometry/isometry_conversion.rs b/src/geometry/isometry_conversion.rs index c71b7289..01aa55db 100644 --- a/src/geometry/isometry_conversion.rs +++ b/src/geometry/isometry_conversion.rs @@ -1,50 +1,47 @@ use alga::general::{Real, SubsetOf, SupersetOf}; use alga::linear::Rotation; -use core::{SquareMatrix, OwnedSquareMatrix}; -use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; +use core::{DefaultAllocator, MatrixN}; +use core::dimension::{DimName, DimNameAdd, DimNameSum, DimMin, U1}; +use core::allocator::Allocator; -use geometry::{PointBase, TranslationBase, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; +use geometry::{Point, Translation, Isometry, Similarity, Transform, SuperTCategoryOf, TAffine}; /* * This file provides the following conversions: * ============================================= * - * IsometryBase -> IsometryBase - * IsometryBase -> SimilarityBase - * IsometryBase -> TransformBase - * IsometryBase -> Matrix (homogeneous) + * Isometry -> Isometry + * Isometry -> Similarity + * Isometry -> Transform + * Isometry -> Matrix (homogeneous) */ -impl SubsetOf> for IsometryBase +impl SubsetOf> for Isometry where N1: Real, N2: Real + SupersetOf, - R1: Rotation> + SubsetOf, - R2: Rotation>, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R1: Rotation> + SubsetOf, + R2: Rotation>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> IsometryBase { - IsometryBase::from_parts( + fn to_superset(&self) -> Isometry { + Isometry::from_parts( self.translation.to_superset(), self.rotation.to_superset() ) } #[inline] - fn is_in_subset(iso: &IsometryBase) -> bool { - ::is_convertible::<_, TranslationBase>(&iso.translation) && + fn is_in_subset(iso: &Isometry) -> bool { + ::is_convertible::<_, Translation>(&iso.translation) && ::is_convertible::<_, R1>(&iso.rotation) } #[inline] - unsafe fn from_superset_unchecked(iso: &IsometryBase) -> Self { - IsometryBase::from_parts( + unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { + Isometry::from_parts( iso.translation.to_subset_unchecked(), iso.rotation.to_subset_unchecked() ) @@ -52,95 +49,91 @@ impl SubsetOf> f } -impl SubsetOf> for IsometryBase +impl SubsetOf> for Isometry where N1: Real, N2: Real + SupersetOf, - R1: Rotation> + SubsetOf, - R2: Rotation>, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R1: Rotation> + SubsetOf, + R2: Rotation>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> SimilarityBase { - SimilarityBase::from_isometry( + fn to_superset(&self) -> Similarity { + Similarity::from_isometry( self.to_superset(), N2::one() ) } #[inline] - fn is_in_subset(sim: &SimilarityBase) -> bool { - ::is_convertible::<_, IsometryBase>(&sim.isometry) && + fn is_in_subset(sim: &Similarity) -> bool { + ::is_convertible::<_, Isometry>(&sim.isometry) && sim.scaling() == N2::one() } #[inline] - unsafe fn from_superset_unchecked(sim: &SimilarityBase) -> Self { + unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { ::convert_ref_unchecked(&sim.isometry) } } -impl SubsetOf> for IsometryBase +impl SubsetOf> for Isometry where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, C: SuperTCategoryOf, - R: Rotation> + - SubsetOf, SA::Alloc>> + // needed by: .to_homogeneous() - SubsetOf, SB>>, // needed by: ::convert_unchecked(mm) - D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator + // needed by R - Allocator, DimNameSum> + // needed by: .to_homogeneous() - Allocator, DimNameSum>, // needed by R - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + // needed by: mm.fixed_slice_mut - Allocator + // needed by: m.fixed_slice - Allocator { // needed by: m.fixed_slice + R: Rotation> + + SubsetOf>> + + SubsetOf>>, + D: DimNameAdd + + DimMin, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator + + Allocator + // needed by R + Allocator, DimNameSum> + // needed by: .to_homogeneous() + Allocator, DimNameSum> + // needed by R + Allocator, DimNameSum> + + Allocator<(usize, usize), D> + // needed by .is_special_orthogonal() + Allocator + + Allocator { #[inline] - fn to_superset(&self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] - fn is_in_subset(t: &TransformBase) -> bool { + fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] - unsafe fn from_superset_unchecked(t: &TransformBase) -> Self { + unsafe fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } -impl SubsetOf, SB>> for IsometryBase +impl SubsetOf>> for Isometry where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, - R: Rotation> + - SubsetOf, SA::Alloc>> + // needed by: .to_homogeneous() - SubsetOf, SB>>, // needed by: ::convert_unchecked(mm) - D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator + // needed by R - Allocator, DimNameSum> + // needed by: .to_homogeneous() - Allocator, DimNameSum>, // needed by R - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + // needed by: mm.fixed_slice_mut - Allocator + // needed by: m.fixed_slice - Allocator { // needed by: m.fixed_slice + R: Rotation> + + SubsetOf>> + + SubsetOf>>, + D: DimNameAdd + + DimMin, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator + + Allocator + // needed by R + Allocator, DimNameSum> + // needed by: .to_homogeneous() + Allocator, DimNameSum> + // needed by R + Allocator, DimNameSum> + + Allocator<(usize, usize), D> + // needed by .is_special_orthogonal() + Allocator + + Allocator { #[inline] - fn to_superset(&self) -> SquareMatrix, SB> { + fn to_superset(&self) -> MatrixN> { self.to_homogeneous().to_superset() } #[inline] - fn is_in_subset(m: &SquareMatrix, SB>) -> bool { + fn is_in_subset(m: &MatrixN>) -> bool { let rot = m.fixed_slice::(0, 0); let bottom = m.fixed_slice::(D::dim(), 0); @@ -154,9 +147,9 @@ impl SubsetOf, SB>> for } #[inline] - unsafe fn from_superset_unchecked(m: &SquareMatrix, SB>) -> Self { + unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let t = m.fixed_slice::(0, D::dim()).into_owned(); - let t = TranslationBase::from_vector(::convert_unchecked(t)); + let t = Translation::from_vector(::convert_unchecked(t)); Self::from_parts(t, ::convert_unchecked(m.clone_owned())) } diff --git a/src/geometry/isometry_ops.rs b/src/geometry/isometry_ops.rs index 0ca1bca8..02b89590 100644 --- a/src/geometry/isometry_ops.rs +++ b/src/geometry/isometry_ops.rs @@ -1,14 +1,13 @@ use std::ops::{Mul, MulAssign, Div, DivAssign}; use alga::general::Real; -use alga::linear::Rotation; +use alga::linear::Rotation as AlgaRotation; -use core::ColumnVector; +use core::{DefaultAllocator, VectorN}; use core::dimension::{DimName, U1, U3, U4}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::allocator::Allocator; -use geometry::{PointBase, RotationBase, IsometryBase, TranslationBase, UnitQuaternionBase}; +use geometry::{Point, Rotation, Isometry, Translation, UnitQuaternion}; // FIXME: there are several cloning of rotations that we could probably get rid of (but we didn't // yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` @@ -22,41 +21,41 @@ use geometry::{PointBase, RotationBase, IsometryBase, TranslationBase, UnitQuate * * (Operators) * - * IsometryBase × IsometryBase - * IsometryBase × R + * Isometry × Isometry + * Isometry × R * * - * IsometryBase ÷ IsometryBase - * IsometryBase ÷ R + * Isometry ÷ Isometry + * Isometry ÷ R * - * IsometryBase × PointBase - * IsometryBase × ColumnVector + * Isometry × Point + * Isometry × Vector * * - * IsometryBase × TranslationBase - * TranslationBase × IsometryBase - * TranslationBase × R -> IsometryBase + * Isometry × Translation + * Translation × Isometry + * Translation × R -> Isometry * - * NOTE: The following are provided explicitly because we can't have R × IsometryBase. - * RotationBase × IsometryBase - * UnitQuaternion × IsometryBase + * NOTE: The following are provided explicitly because we can't have R × Isometry. + * Rotation × Isometry + * UnitQuaternion × Isometry * - * RotationBase ÷ IsometryBase - * UnitQuaternion ÷ IsometryBase + * Rotation ÷ Isometry + * UnitQuaternion ÷ Isometry * - * RotationBase × TranslationBase -> IsometryBase - * UnitQuaternion × TranslationBase -> IsometryBase + * Rotation × Translation -> Isometry + * UnitQuaternion × Translation -> Isometry * * * (Assignment Operators) * - * IsometryBase ×= TranslationBase + * Isometry ×= Translation * - * IsometryBase ×= IsometryBase - * IsometryBase ×= R + * Isometry ×= Isometry + * Isometry ×= R * - * IsometryBase ÷= IsometryBase - * IsometryBase ÷= R + * Isometry ÷= Isometry + * Isometry ÷= R * */ @@ -65,11 +64,9 @@ macro_rules! isometry_binop_impl( ($Op: ident, $op: ident; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N, D: DimName, S, R> $Op<$Rhs> for $Lhs - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { + impl<$($lives ,)* N: Real, D: DimName, R> $Op<$Rhs> for $Lhs + where R: AlgaRotation>, + DefaultAllocator: Allocator { type Output = $Output; #[inline] @@ -114,22 +111,18 @@ macro_rules! isometry_binop_assign_impl_all( $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; [val] => $action_val: expr; [ref] => $action_ref: expr;) => { - impl $OpAssign<$Rhs> for $Lhs - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { + impl $OpAssign<$Rhs> for $Lhs + where R: AlgaRotation>, + DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: $Rhs) { $action_val } } - impl<'b, N, D: DimName, S, R> $OpAssign<&'b $Rhs> for $Lhs - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { + impl<'b, N: Real, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs + where R: AlgaRotation>, + DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { $action_ref @@ -138,18 +131,18 @@ macro_rules! isometry_binop_assign_impl_all( } ); -// IsometryBase × IsometryBase -// IsometryBase ÷ IsometryBase +// Isometry × Isometry +// Isometry ÷ Isometry isometry_binop_impl_all!( Mul, mul; - self: IsometryBase, rhs: IsometryBase, Output = IsometryBase; + self: Isometry, rhs: Isometry, Output = Isometry; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => { let shift = self.rotation.transform_vector(&rhs.translation.vector); - IsometryBase::from_parts(TranslationBase::from_vector(&self.translation.vector + shift), + Isometry::from_parts(Translation::from_vector(&self.translation.vector + shift), self.rotation.clone() * rhs.rotation.clone()) // FIXME: too bad we have to clone. }; ); @@ -157,7 +150,7 @@ isometry_binop_impl_all!( isometry_binop_impl_all!( Div, div; - self: IsometryBase, rhs: IsometryBase, Output = IsometryBase; + self: Isometry, rhs: Isometry, Output = Isometry; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); @@ -165,10 +158,10 @@ isometry_binop_impl_all!( ); -// IsometryBase ×= TranslationBase +// Isometry ×= Translation isometry_binop_assign_impl_all!( MulAssign, mul_assign; - self: IsometryBase, rhs: TranslationBase; + self: Isometry, rhs: Translation; [val] => *self *= &rhs; [ref] => { let shift = self.rotation.transform_vector(&rhs.vector); @@ -176,11 +169,11 @@ isometry_binop_assign_impl_all!( }; ); -// IsometryBase ×= IsometryBase -// IsometryBase ÷= IsometryBase +// Isometry ×= Isometry +// Isometry ÷= Isometry isometry_binop_assign_impl_all!( MulAssign, mul_assign; - self: IsometryBase, rhs: IsometryBase; + self: Isometry, rhs: Isometry; [val] => *self *= &rhs; [ref] => { let shift = self.rotation.transform_vector(&rhs.translation.vector); @@ -191,66 +184,68 @@ isometry_binop_assign_impl_all!( isometry_binop_assign_impl_all!( DivAssign, div_assign; - self: IsometryBase, rhs: IsometryBase; + self: Isometry, rhs: Isometry; [val] => *self /= &rhs; [ref] => *self *= rhs.inverse(); ); -// IsometryBase ×= R -// IsometryBase ÷= R +// Isometry ×= R +// Isometry ÷= R isometry_binop_assign_impl_all!( MulAssign, mul_assign; - self: IsometryBase, rhs: R; + self: Isometry, rhs: R; [val] => self.rotation *= rhs; [ref] => self.rotation *= rhs.clone(); ); isometry_binop_assign_impl_all!( DivAssign, div_assign; - self: IsometryBase, rhs: R; + self: Isometry, rhs: R; // FIXME: don't invert explicitly? [val] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse(); ); -// IsometryBase × R -// IsometryBase ÷ R +// Isometry × R +// Isometry ÷ R isometry_binop_impl_all!( Mul, mul; - self: IsometryBase, rhs: R, Output = IsometryBase; - [val val] => IsometryBase::from_parts(self.translation, self.rotation * rhs); - [ref val] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. - [val ref] => IsometryBase::from_parts(self.translation, self.rotation * rhs.clone()); - [ref ref] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); + self: Isometry, rhs: R, Output = Isometry; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); ); isometry_binop_impl_all!( Div, div; - self: IsometryBase, rhs: R, Output = IsometryBase; - [val val] => IsometryBase::from_parts(self.translation, self.rotation / rhs); - [ref val] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() / rhs); - [val ref] => IsometryBase::from_parts(self.translation, self.rotation / rhs.clone()); - [ref ref] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); + self: Isometry, rhs: R, Output = Isometry; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); ); -// IsometryBase × PointBase +// Isometry × Point isometry_binop_impl_all!( Mul, mul; - self: IsometryBase, right: PointBase, Output = PointBase; - [val val] => self.translation * self.rotation.transform_point(&right); + self: Isometry, right: Point, Output = Point; + [val val] => self.translation * self.rotation.transform_point(&right); [ref val] => &self.translation * self.rotation.transform_point(&right); - [val ref] => self.translation * self.rotation.transform_point(right); + [val ref] => self.translation * self.rotation.transform_point(right); [ref ref] => &self.translation * self.rotation.transform_point(right); ); -// IsometryBase × Vector +// Isometry × Vector isometry_binop_impl_all!( Mul, mul; - self: IsometryBase, right: ColumnVector, Output = ColumnVector; + // FIXME: because of `transform_vector`, we cant use a generic storage type for the rhs vector, + // i.e., right: Vector where S: Storage. + self: Isometry, right: VectorN, Output = VectorN; [val val] => self.rotation.transform_vector(&right); [ref val] => self.rotation.transform_vector(&right); [val ref] => self.rotation.transform_vector(right); @@ -258,38 +253,38 @@ isometry_binop_impl_all!( ); -// IsometryBase × TranslationBase +// Isometry × Translation isometry_binop_impl_all!( Mul, mul; - self: IsometryBase, right: TranslationBase, Output = IsometryBase; + self: Isometry, right: Translation, Output = Isometry; [val val] => &self * &right; [ref val] => self * &right; [val ref] => &self * right; [ref ref] => { let new_tr = &self.translation.vector + self.rotation.transform_vector(&right.vector); - IsometryBase::from_parts(TranslationBase::from_vector(new_tr), self.rotation.clone()) + Isometry::from_parts(Translation::from_vector(new_tr), self.rotation.clone()) }; ); -// TranslationBase × IsometryBase +// Translation × Isometry isometry_binop_impl_all!( Mul, mul; - self: TranslationBase, right: IsometryBase, Output = IsometryBase; - [val val] => IsometryBase::from_parts(self * right.translation, right.rotation); - [ref val] => IsometryBase::from_parts(self * &right.translation, right.rotation); - [val ref] => IsometryBase::from_parts(self * &right.translation, right.rotation.clone()); - [ref ref] => IsometryBase::from_parts(self * &right.translation, right.rotation.clone()); + self: Translation, right: Isometry, Output = Isometry; + [val val] => Isometry::from_parts(self * right.translation, right.rotation); + [ref val] => Isometry::from_parts(self * &right.translation, right.rotation); + [val ref] => Isometry::from_parts(self * &right.translation, right.rotation.clone()); + [ref ref] => Isometry::from_parts(self * &right.translation, right.rotation.clone()); ); -// TranslationBase × R +// Translation × R isometry_binop_impl_all!( Mul, mul; - self: TranslationBase, right: R, Output = IsometryBase; - [val val] => IsometryBase::from_parts(self, right); - [ref val] => IsometryBase::from_parts(self.clone(), right); - [val ref] => IsometryBase::from_parts(self, right.clone()); - [ref ref] => IsometryBase::from_parts(self.clone(), right.clone()); + self: Translation, right: R, Output = Isometry; + [val val] => Isometry::from_parts(self, right); + [ref val] => Isometry::from_parts(self.clone(), right); + [val ref] => Isometry::from_parts(self, right.clone()); + [ref ref] => Isometry::from_parts(self.clone(), right.clone()); ); @@ -300,12 +295,9 @@ macro_rules! isometry_from_composition_impl( ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(for $Dims: ident: $DimsBound: ident),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + impl<$($lives ,)* N: Real $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + where DefaultAllocator: Allocator + + Allocator { type Output = $Output; #[inline] @@ -352,51 +344,51 @@ macro_rules! isometry_from_composition_impl_all( ); -// RotationBase × TranslationBase +// Rotation × Translation isometry_from_composition_impl_all!( Mul, mul; (D, D), (D, U1) for D: DimName; - self: RotationBase, right: TranslationBase, Output = IsometryBase>; - [val val] => IsometryBase::from_parts(TranslationBase::from_vector(&self * right.vector), self); - [ref val] => IsometryBase::from_parts(TranslationBase::from_vector(self * right.vector), self.clone()); - [val ref] => IsometryBase::from_parts(TranslationBase::from_vector(&self * &right.vector), self); - [ref ref] => IsometryBase::from_parts(TranslationBase::from_vector(self * &right.vector), self.clone()); + self: Rotation, right: Translation, Output = Isometry>; + [val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self); + [ref val] => Isometry::from_parts(Translation::from_vector(self * right.vector), self.clone()); + [val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self); + [ref ref] => Isometry::from_parts(Translation::from_vector(self * &right.vector), self.clone()); ); -// UnitQuaternionBase × TranslationBase +// UnitQuaternion × Translation isometry_from_composition_impl_all!( Mul, mul; (U4, U1), (U3, U1); - self: UnitQuaternionBase, right: TranslationBase, - Output = IsometryBase>; - [val val] => IsometryBase::from_parts(TranslationBase::from_vector(&self * right.vector), self); - [ref val] => IsometryBase::from_parts(TranslationBase::from_vector( self * right.vector), self.clone()); - [val ref] => IsometryBase::from_parts(TranslationBase::from_vector(&self * &right.vector), self); - [ref ref] => IsometryBase::from_parts(TranslationBase::from_vector( self * &right.vector), self.clone()); + self: UnitQuaternion, right: Translation, + Output = Isometry>; + [val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self); + [ref val] => Isometry::from_parts(Translation::from_vector( self * right.vector), self.clone()); + [val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self); + [ref ref] => Isometry::from_parts(Translation::from_vector( self * &right.vector), self.clone()); ); -// RotationBase × IsometryBase +// Rotation × Isometry isometry_from_composition_impl_all!( Mul, mul; (D, D), (D, U1) for D: DimName; - self: RotationBase, right: IsometryBase>, - Output = IsometryBase>; + self: Rotation, right: Isometry>, + Output = Isometry>; [val val] => &self * &right; [ref val] => self * &right; [val ref] => &self * right; [ref ref] => { let shift = self * &right.translation.vector; - IsometryBase::from_parts(TranslationBase::from_vector(shift), self * &right.rotation) + Isometry::from_parts(Translation::from_vector(shift), self * &right.rotation) }; ); -// RotationBase ÷ IsometryBase +// Rotation ÷ Isometry isometry_from_composition_impl_all!( Div, div; (D, D), (D, U1) for D: DimName; - self: RotationBase, right: IsometryBase>, - Output = IsometryBase>; + self: Rotation, right: Isometry>, + Output = Isometry>; // FIXME: don't call iverse explicitly? [val val] => self * right.inverse(); [ref val] => self * right.inverse(); @@ -405,28 +397,28 @@ isometry_from_composition_impl_all!( ); -// UnitQuaternion × IsometryBase +// UnitQuaternion × Isometry isometry_from_composition_impl_all!( Mul, mul; (U4, U1), (U3, U1); - self: UnitQuaternionBase, right: IsometryBase>, - Output = IsometryBase>; + self: UnitQuaternion, right: Isometry>, + Output = Isometry>; [val val] => &self * &right; [ref val] => self * &right; [val ref] => &self * right; [ref ref] => { let shift = self * &right.translation.vector; - IsometryBase::from_parts(TranslationBase::from_vector(shift), self * &right.rotation) + Isometry::from_parts(Translation::from_vector(shift), self * &right.rotation) }; ); -// UnitQuaternion ÷ IsometryBase +// UnitQuaternion ÷ Isometry isometry_from_composition_impl_all!( Div, div; (U4, U1), (U3, U1); - self: UnitQuaternionBase, right: IsometryBase>, - Output = IsometryBase>; + self: UnitQuaternion, right: Isometry>, + Output = Isometry>; // FIXME: don't call inverse explicitly? [val val] => self * right.inverse(); [ref val] => self * right.inverse(); diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index d99e82cb..f125f9ed 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -14,7 +14,7 @@ mod point_coordinates; mod rotation; mod rotation_construction; mod rotation_ops; -mod rotation_alga; // FIXME: implement RotationBase methods. +mod rotation_alga; // FIXME: implement Rotation methods. mod rotation_conversion; mod rotation_alias; mod rotation_specialization; @@ -23,9 +23,8 @@ mod quaternion; mod quaternion_construction; mod quaternion_ops; mod quaternion_alga; -mod quaternion_alias; -mod quaternion_coordinates; mod quaternion_conversion; +mod quaternion_coordinates; mod unit_complex; mod unit_complex_construction; @@ -61,6 +60,8 @@ mod transform_alga; mod transform_conversion; mod transform_alias; +mod reflection; + mod orthographic; mod perspective; @@ -71,7 +72,6 @@ pub use self::rotation::*; pub use self::rotation_alias::*; pub use self::quaternion::*; -pub use self::quaternion_alias::*; pub use self::unit_complex::*; @@ -87,5 +87,7 @@ pub use self::similarity_alias::*; pub use self::transform::*; pub use self::transform_alias::*; -pub use self::orthographic::{OrthographicBase, Orthographic3}; -pub use self::perspective::{PerspectiveBase, Perspective3}; +pub use self::reflection::*; + +pub use self::orthographic::Orthographic3; +pub use self::perspective::Perspective3; diff --git a/src/geometry/op_macros.rs b/src/geometry/op_macros.rs index c81fd452..112b2649 100644 --- a/src/geometry/op_macros.rs +++ b/src/geometry/op_macros.rs @@ -8,7 +8,7 @@ macro_rules! md_impl( // Operator, operator method, and calar bounds. $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; // Storage dimensions, and dimension bounds. - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$BoundParam: ty>)*),+ + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+ // [Optional] Extra allocator bounds. $(where $ConstraintType: ty: $ConstraintBound: ident<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*> )*; // Argument identifiers and types + output. @@ -17,10 +17,11 @@ macro_rules! md_impl( $action: expr; // Lifetime. $($lives: tt),*) => { - impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$BoundParam>)*)*, SA, SB> $Op<$Rhs> for $Lhs - where N: Scalar + Zero + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, - SA: Storage, - SB: Storage, + impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where N: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, + DefaultAllocator: Allocator + + Allocator + + Allocator, $( $ConstraintType: $ConstraintBound<$( $ConstraintBoundParams $( = $EqBound )*),*> ),* { type Output = $Result; @@ -41,7 +42,7 @@ macro_rules! md_impl_all( // Operator, operator method, and calar bounds. $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; // Storage dimensions, and dimension bounds. - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$BoundParam: ty>)*),+ + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+ // [Optional] Extra allocator bounds. $(where $ConstraintType: ty: $ConstraintBound: ident<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*> )*; // Argument identifiers and types + output. @@ -54,28 +55,28 @@ macro_rules! md_impl_all( md_impl!( $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$BoundParam>)*),+ + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*; $lhs: $Lhs, $rhs: $Rhs, Output = $Result; $action_val_val; ); md_impl!( $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$BoundParam>)*),+ + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*; $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Result; $action_ref_val; 'a); md_impl!( $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$BoundParam>)*),+ + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*; $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Result; $action_val_ref; 'b); md_impl!( $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$BoundParam>)*),+ + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*; $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Result; $action_ref_ref; 'a, 'b); @@ -89,19 +90,18 @@ macro_rules! md_assign_impl( // Operator, operator method, and scalar bounds. $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; // Storage dimensions, and dimension bounds. - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$BoundParam: ty>)*),+ + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+ // [Optional] Extra allocator bounds. - $(where $ConstraintType: ty: $ConstraintBound: ident<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*> )*; + $(where $ConstraintType: ty: $ConstraintBound: ident $(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)* )*; // Argument identifiers and types. $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; // Actual implementation and lifetimes. $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$BoundParam>)*)*, SA, SB> $Op<$Rhs> for $Lhs - where N: Scalar + Zero + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, - SA: OwnedStorage, // FIXME: this is too restrictive. - SB: Storage, - SA::Alloc: OwnedAllocator, - $( $ConstraintType: $ConstraintBound<$( $ConstraintBoundParams $( = $EqBound )*),*> ),* + impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where N: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, + DefaultAllocator: Allocator + + Allocator, + $( $ConstraintType: $ConstraintBound $(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),* { #[inline] fn $op(&mut $lhs, $rhs: $Rhs) { @@ -118,9 +118,9 @@ macro_rules! md_assign_impl_all( // Operator, operator method, and scalar bounds. $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; // Storage dimensions, and dimension bounds. - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$BoundParam: ty>)*),+ + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+ // [Optional] Extra allocator bounds. - $(where $ConstraintType: ty: $ConstraintBound: ident<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*> )*; + $(where $ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)* )*; // Argument identifiers and types. $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; // Actual implementation and lifetimes. @@ -128,15 +128,15 @@ macro_rules! md_assign_impl_all( [ref] => $action_ref: expr;) => { md_assign_impl!( $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$BoundParam>)*),+ - $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*; + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ + $(where $ConstraintType: $ConstraintBound $(<$($ConstraintBoundParams $( = $EqBound )*),*>)*)*; $lhs: $Lhs, $rhs: $Rhs; $action_val; ); md_assign_impl!( $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$BoundParam>)*),+ - $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*; + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ + $(where $ConstraintType: $ConstraintBound $(<$($ConstraintBoundParams $( = $EqBound )*),*>)*)*; $lhs: $Lhs, $rhs: &'b $Rhs; $action_ref; 'b); } @@ -146,14 +146,14 @@ macro_rules! md_assign_impl_all( /// Macro for the implementation of addition and subtraction. macro_rules! add_sub_impl( ($Op: ident, $op: ident, $bound: ident; - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(-> ($RRes: ty))* for $($Dims: ident: $DimsBound: ident),+; + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(-> ($RRes: ty))* for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs - where N: Scalar + $bound, - SA: Storage, - SB: Storage, - SA::Alloc: SameShapeAllocator, + impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where N: Scalar + $bound, + DefaultAllocator: Allocator + + Allocator + + SameShapeAllocator, ShapeConstraint: SameNumberOfRows<$R1, $R2 $(, Representative = $RRes)*> + SameNumberOfColumns<$C1, $C2> { type Output = $Result; @@ -173,11 +173,10 @@ macro_rules! add_sub_assign_impl( ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident),+; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs - where N: Scalar + $bound, - SA: OwnedStorage, // FIXME: this is too restrictive. - SB: Storage, - SA::Alloc: OwnedAllocator, + impl<$($lives ,)* N $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + where N: Scalar + $bound, + DefaultAllocator: Allocator + + Allocator, ShapeConstraint: SameNumberOfRows<$R1, $R2> + SameNumberOfColumns<$C1, $C2> { #[inline] fn $op(&mut $lhs, $rhs: $Rhs) { diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index c907de6a..b74ef66e 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -1,70 +1,65 @@ #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; use rand::{Rand, Rng}; - #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; +use std::fmt; use alga::general::Real; -use core::{Scalar, SquareMatrix, OwnedSquareMatrix, ColumnVector, OwnedColumnVector, MatrixArray}; -use core::dimension::{U1, U3, U4}; -use core::storage::{OwnedStorage, Storage, StorageMut}; -use core::allocator::OwnedAllocator; +use core::{Matrix4, Vector, Vector3}; +use core::dimension::U3; +use core::storage::Storage; use core::helper; -use geometry::{PointBase, OwnedPoint}; +use geometry::Point3; /// A 3D orthographic projection stored as an homogeneous 4x4 matrix. -#[derive(Debug, Clone, Copy)] // FIXME: Hash -pub struct OrthographicBase> { - matrix: SquareMatrix +pub struct Orthographic3 { + matrix: Matrix4 } -#[cfg(feature = "serde-serialize")] -impl Serialize for OrthographicBase - where N: Scalar, - S: Storage, - SquareMatrix: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.matrix.serialize(serializer) +impl Copy for Orthographic3 { } + +impl Clone for Orthographic3 { + #[inline] + fn clone(&self) -> Self { + Orthographic3::from_matrix_unchecked(self.matrix.clone()) } } -#[cfg(feature = "serde-serialize")] -impl<'de, N, S> Deserialize<'de> for OrthographicBase - where N: Scalar, - S: Storage, - SquareMatrix: Deserialize<'de>, -{ - fn deserialize(deserializer: T) -> Result - where T: Deserializer<'de> - { - SquareMatrix::deserialize(deserializer).map(|x| OrthographicBase { matrix: x }) +impl fmt::Debug for Orthographic3 { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.matrix.fmt(f) } } -/// A 3D orthographic projection stored as a static homogeneous 4x4 matrix. -pub type Orthographic3 = OrthographicBase>; - -impl Eq for OrthographicBase - where N: Scalar + Eq, - S: Storage { } - -impl> PartialEq for OrthographicBase { +impl PartialEq for Orthographic3 { #[inline] fn eq(&self, right: &Self) -> bool { self.matrix == right.matrix } } -impl OrthographicBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +#[cfg(feature = "serde-serialize")] +impl serde::Serialize for Orthographic3 { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.matrix.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize")] +impl<'a, N: Real + serde::Deserialize<'a>> serde::Deserialize<'a> for Orthographic3 { + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let matrix = Matrix4::::deserialize(deserializer)?; + + Ok(Orthographic3::from_matrix_unchecked(matrix)) + } +} + +impl Orthographic3 { /// Creates a new orthographic projection matrix. #[inline] pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self { @@ -72,7 +67,7 @@ impl OrthographicBase assert!(bottom < top, "The top corner must be higher than the bottom corner."); assert!(znear < zfar, "The far plane must be farther than the near plane."); - let matrix = SquareMatrix::::identity(); + let matrix = Matrix4::::identity(); let mut res = Self::from_matrix_unchecked(matrix); res.set_left_and_right(left, right); @@ -87,8 +82,8 @@ impl OrthographicBase /// It is not checked whether or not the given matrix actually represents an orthographic /// projection. #[inline] - pub fn from_matrix_unchecked(matrix: SquareMatrix) -> Self { - OrthographicBase { + pub fn from_matrix_unchecked(matrix: Matrix4) -> Self { + Orthographic3 { matrix: matrix } } @@ -105,24 +100,10 @@ impl OrthographicBase Self::new(-width * half, width * half, -height * half, height * half, znear, zfar) } -} - -impl> OrthographicBase { - /// A reference to the underlying homogeneous transformation matrix. - #[inline] - pub fn as_matrix(&self) -> &SquareMatrix { - &self.matrix - } - - /// Retrieves the underlying homogeneous matrix. - #[inline] - pub fn unwrap(self) -> SquareMatrix { - self.matrix - } /// Retrieves the inverse of the underlying homogeneous matrix. #[inline] - pub fn inverse(&self) -> OwnedSquareMatrix { + pub fn inverse(&self) -> Matrix4 { let mut res = self.to_homogeneous(); let inv_m11 = N::one() / self.matrix[(0, 0)]; @@ -142,10 +123,22 @@ impl> OrthographicBase { /// Computes the corresponding homogeneous matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix { + pub fn to_homogeneous(&self) -> Matrix4 { self.matrix.clone_owned() } + /// A reference to the underlying homogeneous transformation matrix. + #[inline] + pub fn as_matrix(&self) -> &Matrix4 { + &self.matrix + } + + /// Retrieves the underlying homogeneous matrix. + #[inline] + pub fn unwrap(self) -> Matrix4 { + self.matrix + } + /// The smallest x-coordinate of the view cuboid. #[inline] pub fn left(&self) -> N { @@ -185,10 +178,8 @@ impl> OrthographicBase { // FIXME: when we get specialization, specialize the Mul impl instead. /// Projects a point. Faster than matrix multiplication. #[inline] - pub fn project_point(&self, p: &PointBase) -> OwnedPoint - where SB: Storage { - - OwnedPoint::::new( + pub fn project_point(&self, p: &Point3) -> Point3 { + Point3::new( self.matrix[(0, 0)] * p[0] + self.matrix[(0, 3)], self.matrix[(1, 1)] * p[1] + self.matrix[(1, 3)], self.matrix[(2, 2)] * p[2] + self.matrix[(2, 3)] @@ -197,10 +188,9 @@ impl> OrthographicBase { /// Un-projects a point. Faster than multiplication by the underlying matrix inverse. #[inline] - pub fn unproject_point(&self, p: &PointBase) -> OwnedPoint - where SB: Storage { + pub fn unproject_point(&self, p: &Point3) -> Point3 { - OwnedPoint::::new( + Point3::new( (p[0] - self.matrix[(0, 3)]) / self.matrix[(0, 0)], (p[1] - self.matrix[(1, 3)]) / self.matrix[(1, 1)], (p[2] - self.matrix[(2, 3)]) / self.matrix[(2, 2)] @@ -210,18 +200,16 @@ impl> OrthographicBase { // FIXME: when we get specialization, specialize the Mul impl instead. /// Projects a vector. Faster than matrix multiplication. #[inline] - pub fn project_vector(&self, p: &ColumnVector) -> OwnedColumnVector - where SB: Storage { + pub fn project_vector(&self, p: &Vector) -> Vector3 + where SB: Storage { - OwnedColumnVector::::new( + Vector3::new( self.matrix[(0, 0)] * p[0], self.matrix[(1, 1)] * p[1], self.matrix[(2, 2)] * p[2] ) } -} -impl> OrthographicBase { /// Sets the smallest x-coordinate of the view cuboid. #[inline] pub fn set_left(&mut self, left: N) { @@ -289,10 +277,7 @@ impl> OrthographicBase { } } -impl Rand for OrthographicBase - where N: Real + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for Orthographic3 { fn rand(r: &mut R) -> Self { let left = Rand::rand(r); let right = helper::reject_rand(r, |x: &N| *x > left); @@ -306,10 +291,8 @@ impl Rand for OrthographicBase } #[cfg(feature="arbitrary")] -impl Arbitrary for OrthographicBase - where N: Real + Arbitrary, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { +impl Arbitrary for Orthographic3 + where Matrix4: Send { fn arbitrary(g: &mut G) -> Self { let left = Arbitrary::arbitrary(g); let right = helper::reject(g, |x: &N| *x > left); diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index ba1eced4..3193549f 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -3,77 +3,71 @@ use quickcheck::{Arbitrary, Gen}; use rand::{Rand, Rng}; #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; +use std::fmt; use alga::general::Real; -use core::{Scalar, SquareMatrix, OwnedSquareMatrix, ColumnVector, OwnedColumnVector, MatrixArray}; -use core::dimension::{U1, U3, U4}; -use core::storage::{OwnedStorage, Storage, StorageMut}; -use core::allocator::OwnedAllocator; +use core::{Scalar, Matrix4, Vector, Vector3}; +use core::dimension::U3; +use core::storage::Storage; use core::helper; -use geometry::{PointBase, OwnedPoint}; +use geometry::Point3; /// A 3D perspective projection stored as an homogeneous 4x4 matrix. -#[derive(Debug, Clone, Copy)] // FIXME: Hash -pub struct PerspectiveBase> { - matrix: SquareMatrix +pub struct Perspective3 { + matrix: Matrix4 } -#[cfg(feature = "serde-serialize")] -impl Serialize for PerspectiveBase - where N: Scalar, - S: Storage, - SquareMatrix: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.matrix.serialize(serializer) +impl Copy for Perspective3 { } + +impl Clone for Perspective3 { + #[inline] + fn clone(&self) -> Self { + Perspective3::from_matrix_unchecked(self.matrix.clone()) } } -#[cfg(feature = "serde-serialize")] -impl<'de, N, S> Deserialize<'de> for PerspectiveBase - where N: Scalar, - S: Storage, - SquareMatrix: Deserialize<'de>, -{ - fn deserialize(deserializer: T) -> Result - where T: Deserializer<'de> - { - SquareMatrix::deserialize(deserializer).map(|x| PerspectiveBase { matrix: x }) +impl fmt::Debug for Perspective3 { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.matrix.fmt(f) } } -/// A 3D perspective projection stored as a static homogeneous 4x4 matrix. -pub type Perspective3 = PerspectiveBase>; - -impl Eq for PerspectiveBase - where N: Scalar + Eq, - S: Storage { } - -impl PartialEq for PerspectiveBase - where N: Scalar, - S: Storage { +impl PartialEq for Perspective3 { #[inline] fn eq(&self, right: &Self) -> bool { self.matrix == right.matrix } } -impl PerspectiveBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +#[cfg(feature = "serde-serialize")] +impl serde::Serialize for Perspective3 { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.matrix.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize")] +impl<'a, N: Real + serde::Deserialize<'a>> serde::Deserialize<'a> for Perspective3 { + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let matrix = Matrix4::::deserialize(deserializer)?; + + Ok(Perspective3::from_matrix_unchecked(matrix)) + } +} + +impl Perspective3 { /// Creates a new perspective matrix from the aspect ratio, y field of view, and near/far planes. pub fn new(aspect: N, fovy: N, znear: N, zfar: N) -> Self { assert!(!relative_eq!(zfar - znear, N::zero()), "The near-plane and far-plane must not be superimposed."); assert!(!relative_eq!(aspect, N::zero()), "The apsect ratio must not be zero."); - let matrix = SquareMatrix::::identity(); - let mut res = PerspectiveBase::from_matrix_unchecked(matrix); + let matrix = Matrix4::identity(); + let mut res = Perspective3::from_matrix_unchecked(matrix); res.set_fovy(fovy); res.set_aspect(aspect); @@ -91,32 +85,15 @@ impl PerspectiveBase /// It is not checked whether or not the given matrix actually represents an orthographic /// projection. #[inline] - pub fn from_matrix_unchecked(matrix: SquareMatrix) -> Self { - PerspectiveBase { + pub fn from_matrix_unchecked(matrix: Matrix4) -> Self { + Perspective3 { matrix: matrix } } -} - -impl PerspectiveBase - where N: Real, - S: Storage { - - /// A reference to the underlying homogeneous transformation matrix. - #[inline] - pub fn as_matrix(&self) -> &SquareMatrix { - &self.matrix - } - - /// Retrieves the underlying homogeneous matrix. - #[inline] - pub fn unwrap(self) -> SquareMatrix { - self.matrix - } /// Retrieves the inverse of the underlying homogeneous matrix. #[inline] - pub fn inverse(&self) -> OwnedSquareMatrix { + pub fn inverse(&self) -> Matrix4 { let mut res = self.to_homogeneous(); res[(0, 0)] = N::one() / self.matrix[(0, 0)]; @@ -135,10 +112,22 @@ impl PerspectiveBase /// Computes the corresponding homogeneous matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix { + pub fn to_homogeneous(&self) -> Matrix4 { self.matrix.clone_owned() } + /// A reference to the underlying homogeneous transformation matrix. + #[inline] + pub fn as_matrix(&self) -> &Matrix4 { + &self.matrix + } + + /// Retrieves the underlying homogeneous matrix. + #[inline] + pub fn unwrap(self) -> Matrix4 { + self.matrix + } + /// Gets the `width / height` aspect ratio of the view frustrum. #[inline] pub fn aspect(&self) -> N { @@ -174,11 +163,9 @@ impl PerspectiveBase // FIXME: when we get specialization, specialize the Mul impl instead. /// Projects a point. Faster than matrix multiplication. #[inline] - pub fn project_point(&self, p: &PointBase) -> OwnedPoint - where SB: Storage { - + pub fn project_point(&self, p: &Point3) -> Point3 { let inverse_denom = -N::one() / p[2]; - OwnedPoint::::new( + Point3::new( self.matrix[(0, 0)] * p[0] * inverse_denom, self.matrix[(1, 1)] * p[1] * inverse_denom, (self.matrix[(2, 2)] * p[2] + self.matrix[(2, 3)]) * inverse_denom @@ -187,12 +174,10 @@ impl PerspectiveBase /// Un-projects a point. Faster than multiplication by the matrix inverse. #[inline] - pub fn unproject_point(&self, p: &PointBase) -> OwnedPoint - where SB: Storage { - + pub fn unproject_point(&self, p: &Point3) -> Point3 { let inverse_denom = self.matrix[(2, 3)] / (p[2] + self.matrix[(2, 2)]); - OwnedPoint::::new( + Point3::new( p[0] * inverse_denom / self.matrix[(0, 0)], p[1] * inverse_denom / self.matrix[(1, 1)], -inverse_denom @@ -202,22 +187,17 @@ impl PerspectiveBase // FIXME: when we get specialization, specialize the Mul impl instead. /// Projects a vector. Faster than matrix multiplication. #[inline] - pub fn project_vector(&self, p: &ColumnVector) -> OwnedColumnVector - where SB: Storage { + pub fn project_vector(&self, p: &Vector) -> Vector3 + where SB: Storage { let inverse_denom = -N::one() / p[2]; - OwnedColumnVector::::new( + Vector3::new( self.matrix[(0, 0)] * p[0] * inverse_denom, self.matrix[(1, 1)] * p[1] * inverse_denom, self.matrix[(2, 2)] ) } -} - -impl PerspectiveBase - where N: Real, - S: StorageMut { /// Updates this perspective matrix with a new `width / height` aspect ratio of the view /// frustrum. #[inline] @@ -256,10 +236,7 @@ impl PerspectiveBase } } -impl Rand for PerspectiveBase - where N: Real + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for Perspective3 { fn rand(r: &mut R) -> Self { let znear = Rand::rand(r); let zfar = helper::reject_rand(r, |&x: &N| !(x - znear).is_zero()); @@ -270,10 +247,7 @@ impl Rand for PerspectiveBase } #[cfg(feature="arbitrary")] -impl Arbitrary for PerspectiveBase - where N: Real + Arbitrary, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { +impl Arbitrary for Perspective3 { fn arbitrary(g: &mut G) -> Self { let znear = Arbitrary::arbitrary(g); let zfar = helper::reject(g, |&x: &N| !(x - znear).is_zero()); diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 53f914a2..8b7aea7c 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -1,101 +1,103 @@ use num::One; +use std::hash; use std::fmt; use std::cmp::Ordering; use approx::ApproxEq; #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; -use core::{Scalar, ColumnVector, OwnedColumnVector}; +use core::{DefaultAllocator, Scalar, VectorN}; use core::iter::{MatrixIter, MatrixIterMut}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; -use core::storage::{Storage, StorageMut, MulStorage}; -use core::allocator::{Allocator, SameShapeR}; - -// XXX Bad name: we can't even add points… -/// The type of the result of the sum of a point with a vector. -pub type PointSum = - PointBase, - <>::Alloc as Allocator, U1>>::Buffer>; - -/// The type of the result of the multiplication of a point by a matrix. -pub type PointMul = PointBase>; - -/// A point with an owned storage. -pub type OwnedPoint = PointBase>::Buffer>; +use core::allocator::Allocator; /// A point in a n-dimensional euclidean space. #[repr(C)] -#[derive(Hash, Debug)] -pub struct PointBase> { +#[derive(Debug)] +pub struct Point + where DefaultAllocator: Allocator { /// The coordinates of this point, i.e., the shift from the origin. - pub coords: ColumnVector + pub coords: VectorN } -impl Copy for PointBase - where N: Scalar, - D: DimName, - S: Storage + Copy { } +impl hash::Hash for Point + where DefaultAllocator: Allocator, + >::Buffer: hash::Hash { + fn hash(&self, state: &mut H) { + self.coords.hash(state) + } +} -impl Clone for PointBase - where N: Scalar, - D: DimName, - S: Storage + Clone { +impl Copy for Point + where DefaultAllocator: Allocator, + >::Buffer: Copy { } + +impl Clone for Point + where DefaultAllocator: Allocator, + >::Buffer: Clone { #[inline] fn clone(&self) -> Self { - PointBase::from_coordinates(self.coords.clone()) + Point::from_coordinates(self.coords.clone()) } } #[cfg(feature = "serde-serialize")] -impl Serialize for PointBase - where N: Scalar, - D: DimName, - S: Storage, - ColumnVector: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.coords.serialize(serializer) - } -} +impl serde::Serialize for Point +where DefaultAllocator: Allocator, + >::Buffer: serde::Serialize { -#[cfg(feature = "serde-serialize")] -impl<'de, N, D, S> Deserialize<'de> for PointBase - where N: Scalar, - D: DimName, - S: Storage, - ColumnVector: Deserialize<'de>, -{ - fn deserialize(deserializer: T) -> Result - where T: Deserializer<'de> - { - ColumnVector::deserialize(deserializer).map(|x| PointBase { coords: x }) - } -} - -impl> PointBase { - /// Creates a new point with the given coordinates. - #[inline] - pub fn from_coordinates(coords: ColumnVector) -> PointBase { - PointBase { - coords: coords + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.coords.serialize(serializer) } - } } -impl> PointBase { - /// Moves this point into one that owns its data. - #[inline] - pub fn into_owned(self) -> OwnedPoint { - PointBase::from_coordinates(self.coords.into_owned()) - } +#[cfg(feature = "serde-serialize")] +impl<'a, N: Scalar, D: DimName> serde::Deserialize<'a> for Point +where DefaultAllocator: Allocator, + >::Buffer: serde::Deserialize<'a> { + + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let coords = VectorN::::deserialize(deserializer)?; + + Ok(Point::from_coordinates(coords)) + } +} + +impl Point + where DefaultAllocator: Allocator { /// Clones this point into one that owns its data. #[inline] - pub fn clone_owned(&self) -> OwnedPoint { - PointBase::from_coordinates(self.coords.clone_owned()) + pub fn clone(&self) -> Point { + Point::from_coordinates(self.coords.clone_owned()) + } + + /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the + /// end of it. + #[inline] + pub fn to_homogeneous(&self) -> VectorN> + where N: One, + D: DimNameAdd, + DefaultAllocator: Allocator> { + + let mut res = unsafe { + VectorN::<_, DimNameSum>::new_uninitialized() + }; + res.fixed_slice_mut::(0, 0).copy_from(&self.coords); + res[(D::dim(), 0)] = N::one(); + + res + } + + /// Creates a new point with the given coordinates. + #[inline] + pub fn from_coordinates(coords: VectorN) -> Point { + Point { + coords: coords + } } /// The dimension of this point. @@ -113,44 +115,26 @@ impl> PointBase { /// Iterates through this point coordinates. #[inline] - pub fn iter(&self) -> MatrixIter { + pub fn iter(&self) -> MatrixIter>::Buffer> { self.coords.iter() } /// Gets a reference to i-th element of this point without bound-checking. #[inline] pub unsafe fn get_unchecked(&self, i: usize) -> &N { - self.coords.get_unchecked(i, 0) + self.coords.vget_unchecked(i) } - - /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the - /// end of it. - #[inline] - pub fn to_homogeneous(&self) -> OwnedColumnVector, S::Alloc> - where N: One, - D: DimNameAdd, - S::Alloc: Allocator, U1> { - - let mut res = unsafe { OwnedColumnVector::::new_uninitialized() }; - res.fixed_slice_mut::(0, 0).copy_from(&self.coords); - res[(D::dim(), 0)] = N::one(); - - res - } -} - -impl> PointBase { /// Mutably iterates through this point coordinates. #[inline] - pub fn iter_mut(&mut self) -> MatrixIterMut { + pub fn iter_mut(&mut self) -> MatrixIterMut>::Buffer> { self.coords.iter_mut() } /// Gets a mutable reference to i-th element of this point without bound-checking. #[inline] pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut N { - self.coords.get_unchecked_mut(i, 0) + self.coords.vget_unchecked_mut(i) } /// Swaps two entries without bound-checking. @@ -160,9 +144,8 @@ impl> PointBase { } } -impl ApproxEq for PointBase - where N: Scalar + ApproxEq, - S: Storage, +impl ApproxEq for Point + where DefaultAllocator: Allocator, N::Epsilon: Copy { type Epsilon = N::Epsilon; @@ -192,22 +175,19 @@ impl ApproxEq for PointBase } } -impl Eq for PointBase - where N: Scalar + Eq, - S: Storage { } +impl Eq for Point + where DefaultAllocator: Allocator { } -impl PartialEq for PointBase - where N: Scalar, - S: Storage { +impl PartialEq for Point + where DefaultAllocator: Allocator { #[inline] fn eq(&self, right: &Self) -> bool { self.coords == right.coords } } -impl PartialOrd for PointBase - where N: Scalar + PartialOrd, - S: Storage { +impl PartialOrd for Point + where DefaultAllocator: Allocator { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.coords.partial_cmp(&other.coords) @@ -239,9 +219,8 @@ impl PartialOrd for PointBase * Display * */ -impl fmt::Display for PointBase - where N: Scalar + fmt::Display, - S: Storage { +impl fmt::Display for Point + where DefaultAllocator: Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); diff --git a/src/geometry/point_alga.rs b/src/geometry/point_alga.rs index d237af64..7d5962ab 100644 --- a/src/geometry/point_alga.rs +++ b/src/geometry/point_alga.rs @@ -1,26 +1,22 @@ use alga::general::{Field, Real, MeetSemilattice, JoinSemilattice, Lattice}; use alga::linear::{AffineSpace, EuclideanSpace}; -use core::{ColumnVector, Scalar}; -use core::dimension::{DimName, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::{DefaultAllocator, Scalar, VectorN}; +use core::dimension::DimName; +use core::allocator::Allocator; -use geometry::PointBase; +use geometry::Point; -impl AffineSpace for PointBase +impl AffineSpace for Point where N: Scalar + Field, - S: OwnedStorage, - S::Alloc: OwnedAllocator { - type Translation = ColumnVector; + DefaultAllocator: Allocator { + type Translation = VectorN; } -impl EuclideanSpace for PointBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { - type Coordinates = ColumnVector; +impl EuclideanSpace for Point + where DefaultAllocator: Allocator { + type Coordinates = VectorN; type Real = N; #[inline] @@ -49,35 +45,32 @@ impl EuclideanSpace for PointBase * Ordering * */ -impl MeetSemilattice for PointBase +impl MeetSemilattice for Point where N: Scalar + MeetSemilattice, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn meet(&self, other: &Self) -> Self { - PointBase::from_coordinates(self.coords.meet(&other.coords)) + Point::from_coordinates(self.coords.meet(&other.coords)) } } -impl JoinSemilattice for PointBase +impl JoinSemilattice for Point where N: Scalar + JoinSemilattice, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn join(&self, other: &Self) -> Self { - PointBase::from_coordinates(self.coords.join(&other.coords)) + Point::from_coordinates(self.coords.join(&other.coords)) } } -impl Lattice for PointBase +impl Lattice for Point where N: Scalar + Lattice, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn meet_join(&self, other: &Self) -> (Self, Self) { let (meet, join) = self.coords.meet_join(&other.coords); - (PointBase::from_coordinates(meet), PointBase::from_coordinates(join)) + (Point::from_coordinates(meet), Point::from_coordinates(join)) } } diff --git a/src/geometry/point_alias.rs b/src/geometry/point_alias.rs index 20cce1bc..c779e57d 100644 --- a/src/geometry/point_alias.rs +++ b/src/geometry/point_alias.rs @@ -1,10 +1,6 @@ -use core::MatrixArray; use core::dimension::{U1, U2, U3, U4, U5, U6}; -use geometry::PointBase; - -/// A statically sized D-dimensional column point. -pub type Point = PointBase>; +use geometry::Point; /// A statically sized 1-dimensional column point. pub type Point1 = Point; diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index 5a3d6e93..1f1fffa7 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -5,28 +5,25 @@ use rand::{Rand, Rng}; use num::{Zero, One, Bounded}; use alga::general::ClosedDiv; -use core::{Scalar, ColumnVector}; -use core::storage::{Storage, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; +use core::{DefaultAllocator, Scalar, VectorN}; +use core::allocator::Allocator; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3, U4, U5, U6}; -use geometry::PointBase; +use geometry::Point; -impl PointBase - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Point + where DefaultAllocator: Allocator { /// Creates a new point with uninitialized coordinates. #[inline] pub unsafe fn new_uninitialized() -> Self { - Self::from_coordinates(ColumnVector::<_, D, _>::new_uninitialized()) + Self::from_coordinates(VectorN::new_uninitialized()) } /// Creates a new point with all coordinates equal to zero. #[inline] pub fn origin() -> Self where N: Zero { - Self::from_coordinates(ColumnVector::<_, D, _>::from_element(N::zero())) + Self::from_coordinates(VectorN::from_element(N::zero())) } /// Creates a new point from its homogeneous vector representation. @@ -34,11 +31,10 @@ impl PointBase /// In practice, this builds a D-dimensional points with the same first D component as `v` /// divided by the last component of `v`. Returns `None` if this divisor is zero. #[inline] - pub fn from_homogeneous(v: ColumnVector, SB>) -> Option - where N: Scalar + Zero + One + ClosedDiv, - D: DimNameAdd, - SB: Storage, U1, Alloc = S::Alloc>, - S::Alloc: Allocator, U1> { + pub fn from_homogeneous(v: VectorN>) -> Option + where N: Scalar + Zero + One + ClosedDiv, + D: DimNameAdd, + DefaultAllocator: Allocator> { if !v[D::dim()].is_zero() { let coords = v.fixed_slice::(0, 0) / v[D::dim()]; @@ -56,39 +52,34 @@ impl PointBase * Traits that buid points. * */ -impl Bounded for PointBase - where N: Scalar + Bounded, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Bounded for Point + where DefaultAllocator: Allocator { #[inline] fn max_value() -> Self { - Self::from_coordinates(ColumnVector::max_value()) + Self::from_coordinates(VectorN::max_value()) } #[inline] fn min_value() -> Self { - Self::from_coordinates(ColumnVector::min_value()) + Self::from_coordinates(VectorN::min_value()) } } -impl Rand for PointBase - where N: Scalar + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for Point + where DefaultAllocator: Allocator { #[inline] fn rand(rng: &mut G) -> Self { - PointBase::from_coordinates(rng.gen()) + Point::from_coordinates(rng.gen()) } } #[cfg(feature="arbitrary")] -impl Arbitrary for PointBase - where N: Scalar + Arbitrary + Send, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { +impl Arbitrary for Point + where DefaultAllocator: Allocator, + >::Buffer: Send { #[inline] fn arbitrary(g: &mut G) -> Self { - PointBase::from_coordinates(ColumnVector::arbitrary(g)) + Point::from_coordinates(VectorN::arbitrary(g)) } } @@ -99,13 +90,11 @@ impl Arbitrary for PointBase */ macro_rules! componentwise_constructors_impl( ($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$( - impl PointBase - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl Point + where DefaultAllocator: Allocator { /// Initializes this matrix from its components. #[inline] - pub fn new($($args: N),*) -> PointBase { + pub fn new($($args: N),*) -> Point { unsafe { let mut res = Self::new_uninitialized(); $( *res.get_unchecked_mut($irow) = $args; )* diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index 2b463c72..f22a9689 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -1,72 +1,67 @@ use num::{One, Zero}; use alga::general::{SubsetOf, SupersetOf, ClosedDiv}; -use core::{Scalar, Matrix, ColumnVector, OwnedColumnVector}; +use core::{DefaultAllocator, Scalar, Matrix, VectorN}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; +use core::allocator::Allocator; -use geometry::{PointBase, OwnedPoint}; +use geometry::Point; /* * This file provides the following conversions: * ============================================= * - * PointBase -> PointBase - * PointBase -> ColumnVector (homogeneous) + * Point -> Point + * Point -> Vector (homogeneous) */ -impl SubsetOf> for PointBase +impl SubsetOf> for Point where D: DimName, N1: Scalar, N2: Scalar + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SB::Alloc: OwnedAllocator, - SA::Alloc: OwnedAllocator { + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> PointBase { - PointBase::from_coordinates(self.coords.to_superset()) + fn to_superset(&self) -> Point { + Point::from_coordinates(self.coords.to_superset()) } #[inline] - fn is_in_subset(m: &PointBase) -> bool { + fn is_in_subset(m: &Point) -> bool { // FIXME: is there a way to reuse the `.is_in_subset` from the matrix implementation of // SubsetOf? m.iter().all(|e| e.is_in_subset()) } #[inline] - unsafe fn from_superset_unchecked(m: &PointBase) -> Self { - PointBase::from_coordinates(Matrix::from_superset_unchecked(&m.coords)) + unsafe fn from_superset_unchecked(m: &Point) -> Self { + Point::from_coordinates(Matrix::from_superset_unchecked(&m.coords)) } } -impl SubsetOf, SB>> for PointBase +impl SubsetOf>> for Point where D: DimNameAdd, N1: Scalar, N2: Scalar + Zero + One + ClosedDiv + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, U1>, - SA::Alloc: OwnedAllocator + - Allocator, U1>, - SB::Alloc: OwnedAllocator, U1, SB> + - Allocator { + DefaultAllocator: Allocator + + Allocator> + + Allocator> + + Allocator { #[inline] - fn to_superset(&self) -> ColumnVector, SB> { - let p: OwnedPoint = self.to_superset(); + fn to_superset(&self) -> VectorN> { + let p: Point = self.to_superset(); p.to_homogeneous() } #[inline] - fn is_in_subset(v: &ColumnVector, SB>) -> bool { - ::is_convertible::<_, OwnedColumnVector, SA::Alloc>>(v) && + fn is_in_subset(v: &VectorN>) -> bool { + ::is_convertible::<_, VectorN>>(v) && !v[D::dim()].is_zero() } #[inline] - unsafe fn from_superset_unchecked(v: &ColumnVector, SB>) -> Self { + unsafe fn from_superset_unchecked(v: &VectorN>) -> Self { let coords = v.fixed_slice::(0, 0) / v[D::dim()]; Self::from_coordinates(::convert_unchecked(coords)) } diff --git a/src/geometry/point_coordinates.rs b/src/geometry/point_coordinates.rs index 5eaf15cc..3e22a578 100644 --- a/src/geometry/point_coordinates.rs +++ b/src/geometry/point_coordinates.rs @@ -1,25 +1,23 @@ use std::mem; use std::ops::{Deref, DerefMut}; -use core::Scalar; +use core::{DefaultAllocator, Scalar}; use core::dimension::{U1, U2, U3, U4, U5, U6}; use core::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; -use core::allocator::OwnedAllocator; -use core::storage::OwnedStorage; +use core::allocator::Allocator; -use geometry::PointBase; +use geometry::Point; /* * - * Give coordinates to PointBase{1 .. 6} + * Give coordinates to Point{1 .. 6} * */ macro_rules! deref_impl( ($D: ty, $Target: ident $(, $comps: ident)*) => { - impl Deref for PointBase - where S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl Deref for Point + where DefaultAllocator: Allocator { type Target = $Target; #[inline] @@ -28,9 +26,8 @@ macro_rules! deref_impl( } } - impl DerefMut for PointBase - where S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl DerefMut for Point + where DefaultAllocator: Allocator { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { mem::transmute(self) } diff --git a/src/geometry/point_ops.rs b/src/geometry/point_ops.rs index 4a9deb7f..fdabe34e 100644 --- a/src/geometry/point_ops.rs +++ b/src/geometry/point_ops.rs @@ -1,15 +1,15 @@ use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Index, IndexMut}; -use num::Zero; +use num::{Zero, One}; use alga::general::{ClosedNeg, ClosedAdd, ClosedSub, ClosedMul, ClosedDiv}; -use core::{Scalar, ColumnVector, Matrix, ColumnVectorSum}; +use core::{DefaultAllocator, Scalar, Vector, Matrix, VectorSum}; use core::dimension::{Dim, DimName, U1}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable}; -use core::storage::{Storage, StorageMut}; +use core::storage::Storage; use core::allocator::{SameShapeAllocator, Allocator}; -use geometry::{PointBase, OwnedPoint, PointMul}; +use geometry::Point; /* @@ -17,9 +17,8 @@ use geometry::{PointBase, OwnedPoint, PointMul}; * Indexing. * */ -impl Index for PointBase - where N: Scalar, - S: Storage { +impl Index for Point + where DefaultAllocator: Allocator { type Output = N; #[inline] @@ -28,9 +27,8 @@ impl Index for PointBase } } -impl IndexMut for PointBase - where N: Scalar, - S: StorageMut { +impl IndexMut for Point + where DefaultAllocator: Allocator { #[inline] fn index_mut(&mut self, i: usize) -> &mut Self::Output { &mut self.coords[i] @@ -38,28 +36,27 @@ impl IndexMut for PointBase } /* + * * Neg. * */ -impl Neg for PointBase - where N: Scalar + ClosedNeg, - S: Storage { - type Output = OwnedPoint; +impl Neg for Point + where DefaultAllocator: Allocator { + type Output = Point; #[inline] fn neg(self) -> Self::Output { - PointBase::from_coordinates(-self.coords) + Point::from_coordinates(-self.coords) } } -impl<'a, N, D: DimName, S> Neg for &'a PointBase - where N: Scalar + ClosedNeg, - S: Storage { - type Output = OwnedPoint; +impl<'a, N: Scalar + ClosedNeg, D: DimName> Neg for &'a Point + where DefaultAllocator: Allocator { + type Output = Point; #[inline] fn neg(self) -> Self::Output { - PointBase::from_coordinates(-&self.coords) + Point::from_coordinates(-&self.coords) } } @@ -69,94 +66,94 @@ impl<'a, N, D: DimName, S> Neg for &'a PointBase * */ -// PointBase - PointBase +// Point - Point add_sub_impl!(Sub, sub, ClosedSub; (D, U1), (D, U1) for D: DimName; - self: &'a PointBase, right: &'b PointBase, Output = ColumnVectorSum; + self: &'a Point, right: &'b Point, Output = VectorSum; &self.coords - &right.coords; 'a, 'b); add_sub_impl!(Sub, sub, ClosedSub; (D, U1), (D, U1) for D: DimName; - self: &'a PointBase, right: PointBase, Output = ColumnVectorSum; + self: &'a Point, right: Point, Output = VectorSum; &self.coords - right.coords; 'a); add_sub_impl!(Sub, sub, ClosedSub; (D, U1), (D, U1) for D: DimName; - self: PointBase, right: &'b PointBase, Output = ColumnVectorSum; + self: Point, right: &'b Point, Output = VectorSum; self.coords - &right.coords; 'b); add_sub_impl!(Sub, sub, ClosedSub; (D, U1), (D, U1) for D: DimName; - self: PointBase, right: PointBase, Output = ColumnVectorSum; + self: Point, right: Point, Output = VectorSum; self.coords - right.coords; ); -// PointBase - Vector +// Point - Vector add_sub_impl!(Sub, sub, ClosedSub; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: &'a PointBase, right: &'b ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: &'a Point, right: &'b Vector, Output = Point; Self::Output::from_coordinates(&self.coords - right); 'a, 'b); add_sub_impl!(Sub, sub, ClosedSub; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: &'a PointBase, right: ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: &'a Point, right: Vector, Output = Point; Self::Output::from_coordinates(&self.coords - &right); 'a); // FIXME: should not be a ref to `right`. add_sub_impl!(Sub, sub, ClosedSub; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: PointBase, right: &'b ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: Point, right: &'b Vector, Output = Point; Self::Output::from_coordinates(self.coords - right); 'b); add_sub_impl!(Sub, sub, ClosedSub; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: PointBase, right: ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: Point, right: Vector, Output = Point; Self::Output::from_coordinates(self.coords - right); ); -// PointBase + Vector +// Point + Vector add_sub_impl!(Add, add, ClosedAdd; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: &'a PointBase, right: &'b ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: &'a Point, right: &'b Vector, Output = Point; Self::Output::from_coordinates(&self.coords + right); 'a, 'b); add_sub_impl!(Add, add, ClosedAdd; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: &'a PointBase, right: ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: &'a Point, right: Vector, Output = Point; Self::Output::from_coordinates(&self.coords + &right); 'a); // FIXME: should not be a ref to `right`. add_sub_impl!(Add, add, ClosedAdd; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: PointBase, right: &'b ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: Point, right: &'b Vector, Output = Point; Self::Output::from_coordinates(self.coords + right); 'b); add_sub_impl!(Add, add, ClosedAdd; - (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; - self: PointBase, right: ColumnVector, Output = OwnedPoint; + (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage; + self: Point, right: Vector, Output = Point; Self::Output::from_coordinates(self.coords + right); ); // XXX: replace by the shared macro: add_sub_assign_impl macro_rules! op_assign_impl( ($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$( - impl<'b, N, D1: DimName, D2: Dim, SA, SB> $TraitAssign<&'b ColumnVector> for PointBase - where N: Scalar + $bound, - SA: StorageMut, - SB: Storage, + impl<'b, N, D1: DimName, D2: Dim, SB> $TraitAssign<&'b Vector> for Point + where N: Scalar + $bound, + SB: Storage, + DefaultAllocator: Allocator, ShapeConstraint: SameNumberOfRows { #[inline] - fn $method_assign(&mut self, right: &'b ColumnVector) { + fn $method_assign(&mut self, right: &'b Vector) { self.coords.$method_assign(right) } } - impl $TraitAssign> for PointBase - where N: Scalar + $bound, - SA: StorageMut, - SB: Storage, + impl $TraitAssign> for Point + where N: Scalar + $bound, + SB: Storage, + DefaultAllocator: Allocator, ShapeConstraint: SameNumberOfRows { #[inline] - fn $method_assign(&mut self, right: ColumnVector) { + fn $method_assign(&mut self, right: Vector) { self.coords.$method_assign(right) } } @@ -171,56 +168,52 @@ op_assign_impl!( /* * - * Matrix × PointBase + * Matrix × Point * */ md_impl_all!( Mul, mul; - (R1, C1), (D2, U1) for R1: DimName, C1: Dim, D2: DimName - where SA::Alloc: Allocator + (R1, C1), (D2, U1) for R1: DimName, C1: Dim, D2: DimName, SA: Storage where ShapeConstraint: AreMultipliable; - self: Matrix, right: PointBase, Output = PointMul; - [val val] => PointBase::from_coordinates(self * right.coords); - [ref val] => PointBase::from_coordinates(self * right.coords); - [val ref] => PointBase::from_coordinates(self * &right.coords); - [ref ref] => PointBase::from_coordinates(self * &right.coords); + self: Matrix, right: Point, Output = Point; + [val val] => Point::from_coordinates(self * right.coords); + [ref val] => Point::from_coordinates(self * right.coords); + [val ref] => Point::from_coordinates(self * &right.coords); + [ref ref] => Point::from_coordinates(self * &right.coords); ); /* * - * PointBase ×/÷ Scalar + * Point ×/÷ Scalar * */ macro_rules! componentwise_scalarop_impl( ($Trait: ident, $method: ident, $bound: ident; $TraitAssign: ident, $method_assign: ident) => { - impl $Trait for PointBase - where N: Scalar + $bound, - S: Storage { - type Output = OwnedPoint; + impl $Trait for Point + where DefaultAllocator: Allocator { + type Output = Point; #[inline] fn $method(self, right: N) -> Self::Output { - PointBase::from_coordinates(self.coords.$method(right)) + Point::from_coordinates(self.coords.$method(right)) } } - impl<'a, N, D: DimName, S> $Trait for &'a PointBase - where N: Scalar + $bound, - S: Storage { - type Output = OwnedPoint; + impl<'a, N: Scalar + $bound, D: DimName> $Trait for &'a Point + where DefaultAllocator: Allocator { + type Output = Point; #[inline] fn $method(self, right: N) -> Self::Output { - PointBase::from_coordinates((&self.coords).$method(right)) + Point::from_coordinates((&self.coords).$method(right)) } } - impl $TraitAssign for PointBase - where N: Scalar + $bound, - S: StorageMut { + impl $TraitAssign for Point + where DefaultAllocator: Allocator { #[inline] fn $method_assign(&mut self, right: N) { self.coords.$method_assign(right) @@ -234,23 +227,23 @@ componentwise_scalarop_impl!(Div, div, ClosedDiv; DivAssign, div_assign); macro_rules! left_scalar_mul_impl( ($($T: ty),* $(,)*) => {$( - impl Mul> for $T - where S: Storage<$T, D, U1> { - type Output = OwnedPoint<$T, D, S::Alloc>; + impl Mul> for $T + where DefaultAllocator: Allocator<$T, D> { + type Output = Point<$T, D>; #[inline] - fn mul(self, right: PointBase<$T, D, S>) -> Self::Output { - PointBase::from_coordinates(self * right.coords) + fn mul(self, right: Point<$T, D>) -> Self::Output { + Point::from_coordinates(self * right.coords) } } - impl<'b, D: DimName, S> Mul<&'b PointBase<$T, D, S>> for $T - where S: Storage<$T, D, U1> { - type Output = OwnedPoint<$T, D, S::Alloc>; + impl<'b, D: DimName> Mul<&'b Point<$T, D>> for $T + where DefaultAllocator: Allocator<$T, D> { + type Output = Point<$T, D>; #[inline] - fn mul(self, right: &'b PointBase<$T, D, S>) -> Self::Output { - PointBase::from_coordinates(self * &right.coords) + fn mul(self, right: &'b Point<$T, D>) -> Self::Output { + Point::from_coordinates(self * &right.coords) } } )*} diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 4a99acc3..6bc0db2f 100644 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -1,70 +1,34 @@ use std::fmt; +use std::hash; use num::Zero; use approx::ApproxEq; #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; +#[cfg(feature = "serde-serialize")] +use core::storage::Owned; use alga::general::Real; -use core::{Unit, ColumnVector, OwnedColumnVector, MatrixSlice, MatrixSliceMut, SquareMatrix, - OwnedSquareMatrix}; -use core::storage::{Storage, StorageMut}; -use core::allocator::Allocator; +use core::{Unit, Vector3, Vector4, MatrixSlice, MatrixSliceMut, SquareMatrix, MatrixN}; use core::dimension::{U1, U3, U4}; +use core::storage::{RStride, CStride}; -use geometry::{RotationBase, OwnedRotation}; +use geometry::Rotation; -/// A quaternion with an owned storage allocated by `A`. -pub type OwnedQuaternionBase = QuaternionBase>::Buffer>; - -/// A unit quaternion with an owned storage allocated by `A`. -pub type OwnedUnitQuaternionBase = UnitQuaternionBase>::Buffer>; - -/// A quaternion. See the type alias `UnitQuaternionBase = Unit` for a quaternion +/// A quaternion. See the type alias `UnitQuaternion = Unit` for a quaternion /// that may be used as a rotation. #[repr(C)] -#[derive(Hash, Debug, Copy, Clone)] -pub struct QuaternionBase> { +#[derive(Debug)] +pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. - pub coords: ColumnVector + pub coords: Vector4 } -#[cfg(feature = "serde-serialize")] -impl Serialize for QuaternionBase - where N: Real, - S: Storage, - ColumnVector: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.coords.serialize(serializer) - } +impl Eq for Quaternion { } -#[cfg(feature = "serde-serialize")] -impl<'de, N, S> Deserialize<'de> for QuaternionBase - where N: Real, - S: Storage, - ColumnVector: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> - { - ColumnVector::deserialize(deserializer).map(|x| QuaternionBase { coords: x }) - } -} - - -impl Eq for QuaternionBase - where N: Real + Eq, - S: Storage { -} - -impl PartialEq for QuaternionBase - where N: Real, - S: Storage { +impl PartialEq for Quaternion { fn eq(&self, rhs: &Self) -> bool { self.coords == rhs.coords || // Account for the double-covering of S², i.e. q = -q @@ -72,24 +36,91 @@ impl PartialEq for QuaternionBase } } -impl QuaternionBase - where N: Real, - S: Storage { - /// Moves this quaternion into one that owns its data. +impl hash::Hash for Quaternion { + fn hash(&self, state: &mut H) { + self.coords.hash(state) + } +} + +impl Copy for Quaternion { } + +impl Clone for Quaternion { #[inline] - pub fn into_owned(self) -> OwnedQuaternionBase { - QuaternionBase::from_vector(self.coords.into_owned()) + fn clone(&self) -> Self { + Quaternion::from_vector(self.coords.clone()) + } +} + +#[cfg(feature = "serde-serialize")] +impl serde::Serialize for Quaternion +where Owned: serde::Serialize { + + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.coords.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize")] +impl<'a, N: Real> serde::Deserialize<'a> for Quaternion +where Owned: serde::Deserialize<'a> { + + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let coords = Vector4::::deserialize(deserializer)?; + + Ok(Quaternion::from_vector(coords)) + } +} + +impl Quaternion { + /// Moves this unit quaternion into one that owns its data. + #[inline] + pub fn into_owned(self) -> Quaternion { + self } - /// Clones this quaternion into one that owns its data. + /// Clones this unit quaternion into one that owns its data. #[inline] - pub fn clone_owned(&self) -> OwnedQuaternionBase { - QuaternionBase::from_vector(self.coords.clone_owned()) + pub fn clone_owned(&self) -> Quaternion { + Quaternion::from_vector(self.coords.clone_owned()) + } + + /// Normalizes this quaternion. + #[inline] + pub fn normalize(&self) -> Quaternion { + Quaternion::from_vector(self.coords.normalize()) + } + + /// Compute the conjugate of this quaternion. + #[inline] + pub fn conjugate(&self) -> Quaternion { + let v = Vector4::new(-self.coords[0], -self.coords[1], -self.coords[2], self.coords[3]); + Quaternion::from_vector(v) + } + + /// Inverts this quaternion if it is not zero. + #[inline] + pub fn try_inverse(&self) -> Option> { + let mut res = Quaternion::from_vector(self.coords.clone_owned()); + + if res.try_inverse_mut() { + Some(res) + } + else { + None + } + } + + /// Linear interpolation between two quaternion. + #[inline] + pub fn lerp(&self, other: &Quaternion, t: N) -> Quaternion { + self * (N::one() - t) + other * t } /// The vector part `(i, j, k)` of this quaternion. #[inline] - pub fn vector(&self) -> MatrixSlice { + pub fn vector(&self) -> MatrixSlice, CStride> { self.coords.fixed_rows::(0) } @@ -101,7 +132,7 @@ impl QuaternionBase /// Reinterprets this quaternion as a 4D vector. #[inline] - pub fn as_vector(&self) -> &ColumnVector { + pub fn as_vector(&self) -> &Vector4 { &self.coords } @@ -117,53 +148,11 @@ impl QuaternionBase self.coords.norm_squared() } - /// Normalizes this quaternion. - #[inline] - pub fn normalize(&self) -> OwnedQuaternionBase { - QuaternionBase::from_vector(self.coords.normalize()) - } - - /// Compute the conjugate of this quaternion. - #[inline] - pub fn conjugate(&self) -> OwnedQuaternionBase { - let v = OwnedColumnVector::::new(-self.coords[0], - -self.coords[1], - -self.coords[2], - self.coords[3]); - QuaternionBase::from_vector(v) - } - - /// Inverts this quaternion if it is not zero. - #[inline] - pub fn try_inverse(&self) -> Option> { - let mut res = QuaternionBase::from_vector(self.coords.clone_owned()); - - if res.try_inverse_mut() { - Some(res) - } - else { - None - } - } - - /// Linear interpolation between two quaternion. - #[inline] - pub fn lerp(&self, other: &QuaternionBase, t: N) -> OwnedQuaternionBase - where S2: Storage { - self * (N::one() - t) + other * t - } -} - - -impl QuaternionBase - where N: Real, - S: Storage, - S::Alloc: Allocator { /// The polar decomposition of this quaternion. /// /// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation /// axis. If the rotation angle is zero, the rotation axis is set to `None`. - pub fn polar_decomposition(&self) -> (N, N, Option>>) { + pub fn polar_decomposition(&self) -> (N, N, Option>>) { if let Some((q, n)) = Unit::try_new_and_get(self.clone_owned(), N::zero()) { if let Some(axis) = Unit::try_new(self.vector().clone_owned(), N::zero()) { let angle = q.angle() / ::convert(2.0f64); @@ -181,51 +170,47 @@ impl QuaternionBase /// Compute the exponential of a quaternion. #[inline] - pub fn exp(&self) -> OwnedQuaternionBase { + pub fn exp(&self) -> Quaternion { let v = self.vector(); let nn = v.norm_squared(); if relative_eq!(nn, N::zero()) { - QuaternionBase::identity() + Quaternion::identity() } else { let w_exp = self.scalar().exp(); let n = nn.sqrt(); let nv = v * (w_exp * n.sin() / n); - QuaternionBase::from_parts(n.cos(), nv) + Quaternion::from_parts(n.cos(), nv) } } /// Compute the natural logarithm of a quaternion. #[inline] - pub fn ln(&self) -> OwnedQuaternionBase { + pub fn ln(&self) -> Quaternion { let n = self.norm(); let v = self.vector(); let s = self.scalar(); - QuaternionBase::from_parts(n.ln(), v.normalize() * (s / n).acos()) + Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos()) } /// Raise the quaternion to a given floating power. #[inline] - pub fn powf(&self, n: N) -> OwnedQuaternionBase { + pub fn powf(&self, n: N) -> Quaternion { (self.ln() * n).exp() } -} -impl QuaternionBase - where N: Real, - S: StorageMut { /// Transforms this quaternion into its 4D vector form (Vector part, Scalar part). #[inline] - pub fn as_vector_mut(&mut self) -> &mut ColumnVector { + pub fn as_vector_mut(&mut self) -> &mut Vector4 { &mut self.coords } /// The mutable vector part `(i, j, k)` of this quaternion. #[inline] - pub fn vector_mut(&mut self) -> MatrixSliceMut { + pub fn vector_mut(&mut self) -> MatrixSliceMut, CStride> { self.coords.fixed_rows_mut::(0) } @@ -260,9 +245,7 @@ impl QuaternionBase } } -impl ApproxEq for QuaternionBase - where N: Real + ApproxEq, - S: Storage { +impl> ApproxEq for Quaternion { type Epsilon = N; #[inline] @@ -296,9 +279,7 @@ impl ApproxEq for QuaternionBase } -impl fmt::Display for QuaternionBase - where N: Real + fmt::Display, - S: Storage { +impl fmt::Display for Quaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Quaternion {} − ({}, {}, {})", self[3], self[0], self[1], self[2]) } @@ -325,118 +306,115 @@ impl fmt::Display for QuaternionBase /// fn angle(&self) -> N /// ///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

///

-pub type UnitQuaternionBase = Unit>; +pub type UnitQuaternion = Unit>; - -impl UnitQuaternionBase - where N: Real, - S: Storage { +impl UnitQuaternion { /// Moves this unit quaternion into one that owns its data. #[inline] - pub fn into_owned(self) -> OwnedUnitQuaternionBase { - UnitQuaternionBase::new_unchecked(self.unwrap().into_owned()) + pub fn into_owned(self) -> UnitQuaternion { + self } /// Clones this unit quaternion into one that owns its data. #[inline] - pub fn clone_owned(&self) -> OwnedUnitQuaternionBase { - UnitQuaternionBase::new_unchecked(self.as_ref().clone_owned()) + pub fn clone_owned(&self) -> UnitQuaternion { + UnitQuaternion::new_unchecked(self.as_ref().clone_owned()) } /// The rotation angle in [0; pi] of this unit quaternion. @@ -457,26 +435,25 @@ impl UnitQuaternionBase /// /// Same as `self.as_ref()`. #[inline] - pub fn quaternion(&self) -> &QuaternionBase { + pub fn quaternion(&self) -> &Quaternion { self.as_ref() } /// Compute the conjugate of this unit quaternion. #[inline] - pub fn conjugate(&self) -> OwnedUnitQuaternionBase { - UnitQuaternionBase::new_unchecked(self.as_ref().conjugate()) + pub fn conjugate(&self) -> UnitQuaternion { + UnitQuaternion::new_unchecked(self.as_ref().conjugate()) } /// Inverts this quaternion if it is not zero. #[inline] - pub fn inverse(&self) -> OwnedUnitQuaternionBase { + pub fn inverse(&self) -> UnitQuaternion { self.conjugate() } /// The rotation angle needed to make `self` and `other` coincide. #[inline] - pub fn angle_to(&self, other: &UnitQuaternionBase) -> N - where S2: Storage { + pub fn angle_to(&self, other: &UnitQuaternion) -> N { let delta = self.rotation_to(other); delta.angle() } @@ -485,8 +462,7 @@ impl UnitQuaternionBase /// /// The result is such that: `self.rotation_to(other) * self == other`. #[inline] - pub fn rotation_to(&self, other: &UnitQuaternionBase) -> OwnedUnitQuaternionBase - where S2: Storage { + pub fn rotation_to(&self, other: &UnitQuaternion) -> UnitQuaternion { other / self } @@ -494,19 +470,17 @@ impl UnitQuaternionBase /// /// The result is not normalized. #[inline] - pub fn lerp(&self, other: &UnitQuaternionBase, t: N) -> OwnedQuaternionBase - where S2: Storage { + pub fn lerp(&self, other: &UnitQuaternion, t: N) -> Quaternion { self.as_ref().lerp(other.as_ref(), t) } /// Normalized linear interpolation between two unit quaternions. #[inline] - pub fn nlerp(&self, other: &UnitQuaternionBase, t: N) -> OwnedUnitQuaternionBase - where S2: Storage { + pub fn nlerp(&self, other: &UnitQuaternion, t: N) -> UnitQuaternion { let mut res = self.lerp(other, t); let _ = res.normalize_mut(); - UnitQuaternionBase::new_unchecked(res) + UnitQuaternion::new_unchecked(res) } /// Spherical linear interpolation between two unit quaternions. @@ -514,8 +488,7 @@ impl UnitQuaternionBase /// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation /// is not well-defined). #[inline] - pub fn slerp(&self, other: &UnitQuaternionBase, t: N) -> OwnedUnitQuaternionBase - where S2: Storage { + pub fn slerp(&self, other: &UnitQuaternion, t: N) -> UnitQuaternion { self.try_slerp(other, t, N::zero()).expect( "Unable to perform a spherical quaternion interpolation when they \ are 180 degree apart (the result is not unique).") @@ -532,9 +505,7 @@ impl UnitQuaternionBase /// * `epsilon`: the value bellow which the sinus of the angle separating both quaternion /// must be to return `None`. #[inline] - pub fn try_slerp(&self, other: &UnitQuaternionBase, t: N, epsilon: N) - -> Option> - where S2: Storage { + pub fn try_slerp(&self, other: &UnitQuaternion, t: N, epsilon: N) -> Option> { let c_hang = self.coords.dot(&other.coords); @@ -555,14 +526,10 @@ impl UnitQuaternionBase let tb = (t * hang).sin() / s_hang; let res = self.as_ref() * ta + other.as_ref() * tb; - Some(UnitQuaternionBase::new_unchecked(res)) + Some(UnitQuaternion::new_unchecked(res)) } } -} -impl UnitQuaternionBase - where N: Real, - S: StorageMut { /// Compute the conjugate of this unit quaternion in-place. #[inline] pub fn conjugate_mut(&mut self) { @@ -574,15 +541,10 @@ impl UnitQuaternionBase pub fn inverse_mut(&mut self) { self.as_mut_unchecked().conjugate_mut() } -} -impl UnitQuaternionBase - where N: Real, - S: Storage, - S::Alloc: Allocator { /// The rotation axis of this unit quaternion or `None` if the rotation is zero. #[inline] - pub fn axis(&self) -> Option>> { + pub fn axis(&self) -> Option>> { let v = if self.quaternion().scalar() >= N::zero() { self.as_ref().vector().clone_owned() @@ -597,35 +559,35 @@ impl UnitQuaternionBase /// The rotation axis of this unit quaternion multiplied by the rotation agle. #[inline] - pub fn scaled_axis(&self) -> OwnedColumnVector { + pub fn scaled_axis(&self) -> Vector3 { if let Some(axis) = self.axis() { axis.unwrap() * self.angle() } else { - ColumnVector::zero() + Vector3::zero() } } /// Compute the exponential of a quaternion. /// - /// Note that this function yields a `QuaternionBase` because it looses the unit property. + /// Note that this function yields a `Quaternion` because it looses the unit property. #[inline] - pub fn exp(&self) -> OwnedQuaternionBase { + pub fn exp(&self) -> Quaternion { self.as_ref().exp() } /// Compute the natural logarithm of a quaternion. /// - /// Note that this function yields a `QuaternionBase` because it looses the unit property. + /// Note that this function yields a `Quaternion` because it looses the unit property. /// The vector part of the return value corresponds to the axis-angle representation (divided /// by 2.0) of this unit quaternion. #[inline] - pub fn ln(&self) -> OwnedQuaternionBase { + pub fn ln(&self) -> Quaternion { if let Some(v) = self.axis() { - QuaternionBase::from_parts(N::zero(), v.unwrap() * self.angle()) + Quaternion::from_parts(N::zero(), v.unwrap() * self.angle()) } else { - QuaternionBase::zero() + Quaternion::zero() } } @@ -634,23 +596,18 @@ impl UnitQuaternionBase /// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and /// angle `self.angle() × n`. #[inline] - pub fn powf(&self, n: N) -> OwnedUnitQuaternionBase { + pub fn powf(&self, n: N) -> UnitQuaternion { if let Some(v) = self.axis() { - UnitQuaternionBase::from_axis_angle(&v, self.angle() * n) + UnitQuaternion::from_axis_angle(&v, self.angle() * n) } else { - UnitQuaternionBase::identity() + UnitQuaternion::identity() } } -} -impl UnitQuaternionBase - where N: Real, - S: Storage, - S::Alloc: Allocator { /// Builds a rotation matrix from this unit quaternion. #[inline] - pub fn to_rotation_matrix(&self) -> OwnedRotation { + pub fn to_rotation_matrix(&self) -> Rotation { let i = self.as_ref()[0]; let j = self.as_ref()[1]; let k = self.as_ref()[2]; @@ -667,7 +624,7 @@ impl UnitQuaternionBase let jk = j * k * ::convert(2.0f64); let wi = w * i * ::convert(2.0f64); - RotationBase::from_matrix_unchecked( + Rotation::from_matrix_unchecked( SquareMatrix::<_, U3, _>::new( ww + ii - jj - kk, ij - wk, wj + ik, wk + ij, ww - ii + jj - kk, jk - wi, @@ -678,17 +635,13 @@ impl UnitQuaternionBase /// Converts this unit quaternion into its equivalent homogeneous transformation matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix - where S::Alloc: Allocator { + pub fn to_homogeneous(&self) -> MatrixN { self.to_rotation_matrix().to_homogeneous() } } -impl fmt::Display for UnitQuaternionBase - where N: Real + fmt::Display, - S: Storage, - S::Alloc: Allocator { +impl fmt::Display for UnitQuaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(axis) = self.axis() { let axis = axis.unwrap(); @@ -700,9 +653,7 @@ impl fmt::Display for UnitQuaternionBase } } -impl ApproxEq for UnitQuaternionBase - where N: Real + ApproxEq, - S: Storage { +impl> ApproxEq for UnitQuaternion { type Epsilon = N; #[inline] diff --git a/src/geometry/quaternion_alga.rs b/src/geometry/quaternion_alga.rs index 16cd03f3..5bb52dee 100644 --- a/src/geometry/quaternion_alga.rs +++ b/src/geometry/quaternion_alga.rs @@ -7,57 +7,39 @@ use alga::linear::{Transformation, AffineTransformation, Similarity, Isometry, D OrthogonalTransformation, VectorSpace, FiniteDimVectorSpace, NormedSpace, Rotation, ProjectiveTransformation}; -use core::ColumnVector; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; -use core::dimension::{U1, U3, U4}; -use geometry::{PointBase, QuaternionBase, UnitQuaternionBase}; +use core::{Vector3, Vector4}; +use geometry::{Point3, Quaternion, UnitQuaternion}; -impl Identity for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Identity for Quaternion { #[inline] fn identity() -> Self { Self::identity() } } -impl Identity for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Identity for Quaternion { #[inline] fn identity() -> Self { Self::zero() } } -impl AbstractMagma for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractMagma for Quaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } -impl AbstractMagma for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractMagma for Quaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self + rhs } } -impl Inverse for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Inverse for Quaternion { #[inline] fn inverse(&self) -> Self { -self @@ -66,15 +48,12 @@ impl Inverse for QuaternionBase macro_rules! impl_structures( ($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for $Quaternion - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { } + impl $marker<$operator> for $Quaternion { } )*} ); impl_structures!( - QuaternionBase; + Quaternion; AbstractSemigroup, AbstractMonoid, @@ -92,10 +71,7 @@ impl_structures!( * Vector space. * */ -impl AbstractModule for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractModule for Quaternion { type AbstractRing = N; #[inline] @@ -104,24 +80,15 @@ impl AbstractModule for QuaternionBase } } -impl Module for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Module for Quaternion { type Ring = N; } -impl VectorSpace for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl VectorSpace for Quaternion { type Field = N; } -impl FiniteDimVectorSpace for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl FiniteDimVectorSpace for Quaternion { #[inline] fn dimension() -> usize { 4 @@ -129,7 +96,7 @@ impl FiniteDimVectorSpace for QuaternionBase #[inline] fn canonical_basis_element(i: usize) -> Self { - Self::from_vector(ColumnVector::canonical_basis_element(i)) + Self::from_vector(Vector4::canonical_basis_element(i)) } #[inline] @@ -148,10 +115,7 @@ impl FiniteDimVectorSpace for QuaternionBase } } -impl NormedSpace for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl NormedSpace for Quaternion { #[inline] fn norm_squared(&self) -> N { self.coords.norm_squared() @@ -191,33 +155,24 @@ impl NormedSpace for QuaternionBase /* * - * Implementations for UnitQuaternionBase. + * Implementations for UnitQuaternion. * */ -impl Identity for UnitQuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Identity for UnitQuaternion { #[inline] fn identity() -> Self { Self::identity() } } -impl AbstractMagma for UnitQuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractMagma for UnitQuaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } -impl Inverse for UnitQuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Inverse for UnitQuaternion { #[inline] fn inverse(&self) -> Self { self.inverse() @@ -230,7 +185,7 @@ impl Inverse for UnitQuaternionBase } impl_structures!( - UnitQuaternionBase; + UnitQuaternion; AbstractSemigroup, AbstractQuasigroup, AbstractMonoid, @@ -238,48 +193,33 @@ impl_structures!( AbstractGroup ); -impl Transformation> for UnitQuaternionBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl Transformation> for UnitQuaternion { #[inline] - fn transform_point(&self, pt: &PointBase) -> PointBase { + fn transform_point(&self, pt: &Point3) -> Point3 { self * pt } #[inline] - fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn transform_vector(&self, v: &Vector3) -> Vector3 { self * v } } -impl ProjectiveTransformation> for UnitQuaternionBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl ProjectiveTransformation> for UnitQuaternion { #[inline] - fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { + fn inverse_transform_point(&self, pt: &Point3) -> Point3 { // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement // the inverse transformation explicitly here) ? self.inverse() * pt } #[inline] - fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { self.inverse() * v } } -impl AffineTransformation> for UnitQuaternionBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl AffineTransformation> for UnitQuaternion { type Rotation = Self; type NonUniformScaling = Id; type Translation = Id; @@ -320,12 +260,7 @@ impl AffineTransformation> for UnitQuaternionBas } } -impl Similarity> for UnitQuaternionBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl Similarity> for UnitQuaternion { type Scaling = Id; #[inline] @@ -346,12 +281,7 @@ impl Similarity> for UnitQuaternionBase macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for UnitQuaternionBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { } + impl $Trait> for UnitQuaternion { } )*} ); @@ -359,24 +289,19 @@ marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); -impl Rotation> for UnitQuaternionBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator + Allocator, - SB::Alloc: OwnedAllocator { +impl Rotation> for UnitQuaternion { #[inline] fn powf(&self, n: N) -> Option { Some(self.powf(n)) } #[inline] - fn rotation_between(a: &ColumnVector, b: &ColumnVector) -> Option { + fn rotation_between(a: &Vector3, b: &Vector3) -> Option { Self::rotation_between(a, b) } #[inline] - fn scaled_rotation_between(a: &ColumnVector, b: &ColumnVector, s: N) -> Option { + fn scaled_rotation_between(a: &Vector3, b: &Vector3, s: N) -> Option { Self::scaled_rotation_between(a, b, s) } } diff --git a/src/geometry/quaternion_alias.rs b/src/geometry/quaternion_alias.rs deleted file mode 100644 index 36427e92..00000000 --- a/src/geometry/quaternion_alias.rs +++ /dev/null @@ -1,10 +0,0 @@ -use core::MatrixArray; -use core::dimension::{U1, U4}; - -use geometry::{QuaternionBase, UnitQuaternionBase}; - -/// A statically-allocated quaternion. -pub type Quaternion = QuaternionBase>; - -/// A statically-allocated unit quaternion. -pub type UnitQuaternion = UnitQuaternionBase>; diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 2a627d93..2951e8b1 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -1,42 +1,38 @@ #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; +#[cfg(feature = "arbitrary")] +use core::dimension::U4; use rand::{Rand, Rng}; use num::{Zero, One}; use alga::general::Real; -use core::{Unit, ColumnVector, Vector3}; -use core::storage::{Storage, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; -use core::dimension::{U1, U3, U4}; +use core::{Unit, Vector, Vector4, Vector3}; +use core::storage::Storage; +use core::dimension::U3; -use geometry::{QuaternionBase, UnitQuaternionBase, RotationBase, OwnedRotation}; +use geometry::{Quaternion, UnitQuaternion, Rotation}; -impl QuaternionBase - where N: Real, - S: Storage { +impl Quaternion { /// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w` /// vector component. #[inline] - pub fn from_vector(vector: ColumnVector) -> Self { - QuaternionBase { + pub fn from_vector(vector: Vector4) -> Self { + Quaternion { coords: vector } } -} -impl QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { /// Creates a new quaternion from its individual components. Note that the arguments order does /// **not** follow the storage order. /// /// The storage order is `[ x, y, z, w ]`. #[inline] pub fn new(w: N, x: N, y: N, z: N) -> Self { - let v = ColumnVector::::new(x, y, z, w); + let v = Vector4::::new(x, y, z, w); Self::from_vector(v) } @@ -46,8 +42,8 @@ impl QuaternionBase /// The storage order is [ vector, scalar ]. #[inline] // FIXME: take a reference to `vector`? - pub fn from_parts(scalar: N, vector: ColumnVector) -> Self - where SB: Storage { + pub fn from_parts(scalar: N, vector: Vector) -> Self + where SB: Storage { Self::new(scalar, vector[0], vector[1], vector[2]) } @@ -56,9 +52,9 @@ impl QuaternionBase /// /// Note that `axis` is assumed to be a unit vector. // FIXME: take a reference to `axis`? - pub fn from_polar_decomposition(scale: N, theta: N, axis: Unit>) -> Self - where SB: Storage { - let rot = UnitQuaternionBase::::from_axis_angle(&axis, theta * ::convert(2.0f64)); + pub fn from_polar_decomposition(scale: N, theta: N, axis: Unit>) -> Self + where SB: Storage { + let rot = UnitQuaternion::::from_axis_angle(&axis, theta * ::convert(2.0f64)); rot.unwrap() * scale } @@ -70,20 +66,14 @@ impl QuaternionBase } } -impl One for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl One for Quaternion { #[inline] fn one() -> Self { Self::identity() } } -impl Zero for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Zero for Quaternion { #[inline] fn zero() -> Self { Self::new(N::zero(), N::zero(), N::zero(), N::zero()) @@ -95,46 +85,38 @@ impl Zero for QuaternionBase } } -impl Rand for QuaternionBase - where N: Real + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for Quaternion { #[inline] fn rand(rng: &mut R) -> Self { - QuaternionBase::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()) + Quaternion::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()) } } #[cfg(feature="arbitrary")] -impl Arbitrary for QuaternionBase - where N: Real + Arbitrary, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { +impl Arbitrary for Quaternion + where Owned: Send { #[inline] fn arbitrary(g: &mut G) -> Self { - QuaternionBase::new(N::arbitrary(g), N::arbitrary(g), + Quaternion::new(N::arbitrary(g), N::arbitrary(g), N::arbitrary(g), N::arbitrary(g)) } } -impl UnitQuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl UnitQuaternion { /// The quaternion multiplicative identity. #[inline] pub fn identity() -> Self { - Self::new_unchecked(QuaternionBase::identity()) + Self::new_unchecked(Quaternion::identity()) } /// Creates a new quaternion from a unit vector (the rotation axis) and an angle /// (the rotation angle). #[inline] - pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self - where SB: Storage { + pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self + where SB: Storage { let (sang, cang) = (angle / ::convert(2.0f64)).sin_cos(); - let q = QuaternionBase::from_parts(cang, axis.as_ref() * sang); + let q = Quaternion::from_parts(cang, axis.as_ref() * sang); Self::new_unchecked(q) } @@ -142,7 +124,7 @@ impl UnitQuaternionBase /// /// The input quaternion will be normalized. #[inline] - pub fn from_quaternion(q: QuaternionBase) -> Self { + pub fn from_quaternion(q: Quaternion) -> Self { Self::new_normalize(q) } @@ -155,7 +137,7 @@ impl UnitQuaternionBase let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos(); let (sy, cy) = (yaw * ::convert(0.5f64)).sin_cos(); - let q = QuaternionBase::new( + let q = Quaternion::new( cr * cp * cy + sr * sp * sy, sr * cp * cy - cr * sp * sy, cr * sp * cy + sr * cp * sy, @@ -166,10 +148,7 @@ impl UnitQuaternionBase /// Builds an unit quaternion from a rotation matrix. #[inline] - pub fn from_rotation_matrix(rotmat: &RotationBase) -> Self - where SB: Storage, - SB::Alloc: Allocator { - + pub fn from_rotation_matrix(rotmat: &Rotation) -> Self { // Robust matrix to quaternion transformation. // See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)]; @@ -179,28 +158,28 @@ impl UnitQuaternionBase if tr > N::zero() { let denom = (tr + N::one()).sqrt() * ::convert(2.0); - res = QuaternionBase::new(_0_25 * denom, + res = Quaternion::new(_0_25 * denom, (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom); } else if rotmat[(0, 0)] > rotmat[(1, 1)] && rotmat[(0, 0)] > rotmat[(2, 2)] { let denom = (N::one() + rotmat[(0, 0)] - rotmat[(1, 1)] - rotmat[(2, 2)]).sqrt() * ::convert(2.0); - res = QuaternionBase::new((rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, + res = Quaternion::new((rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, _0_25 * denom, (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom); } else if rotmat[(1, 1)] > rotmat[(2, 2)] { let denom = (N::one() + rotmat[(1, 1)] - rotmat[(0, 0)] - rotmat[(2, 2)]).sqrt() * ::convert(2.0); - res = QuaternionBase::new((rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, + res = Quaternion::new((rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, _0_25 * denom, (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom); } else { let denom = (N::one() + rotmat[(2, 2)] - rotmat[(0, 0)] - rotmat[(1, 1)]).sqrt() * ::convert(2.0); - res = QuaternionBase::new((rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, + res = Quaternion::new((rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom, (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom, _0_25 * denom); @@ -212,19 +191,22 @@ impl UnitQuaternionBase /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same /// direction. #[inline] - pub fn rotation_between(a: &ColumnVector, b: &ColumnVector) -> Option - where SB: Storage, - SC: Storage { + pub fn rotation_between(a: &Vector, b: &Vector) -> Option + where SB: Storage, + SC: Storage { Self::scaled_rotation_between(a, b, N::one()) } /// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// direction, raised to the power `s`. #[inline] - pub fn scaled_rotation_between(a: &ColumnVector, b: &ColumnVector, s: N) -> Option - where SB: Storage, - SC: Storage { - // FIXME: code duplication with RotationBase. + pub fn scaled_rotation_between(a: &Vector, + b: &Vector, + s: N) + -> Option + where SB: Storage, + SC: Storage { + // FIXME: code duplication with Rotation. if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) { let c = na.cross(&nb); @@ -257,12 +239,10 @@ impl UnitQuaternionBase /// collinear /// to `dir`. Non-collinearity is not checked. #[inline] - pub fn new_observer_frame(dir: &ColumnVector, up: &ColumnVector) -> Self - where SB: Storage, - SC: Storage, - S::Alloc: Allocator + - Allocator { - Self::from_rotation_matrix(&OwnedRotation::::new_observer_frame(dir, up)) + pub fn new_observer_frame(dir: &Vector, up: &Vector) -> Self + where SB: Storage, + SC: Storage { + Self::from_rotation_matrix(&Rotation::::new_observer_frame(dir, up)) } @@ -277,11 +257,9 @@ impl UnitQuaternionBase /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_rh(dir: &ColumnVector, up: &ColumnVector) -> Self - where SB: Storage, - SC: Storage, - S::Alloc: Allocator + - Allocator { + pub fn look_at_rh(dir: &Vector, up: &Vector) -> Self + where SB: Storage, + SC: Storage { Self::new_observer_frame(&-dir, up).inverse() } @@ -296,28 +274,20 @@ impl UnitQuaternionBase /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_lh(dir: &ColumnVector, up: &ColumnVector) -> Self - where SB: Storage, - SC: Storage, - S::Alloc: Allocator + - Allocator { + pub fn look_at_lh(dir: &Vector, up: &Vector) -> Self + where SB: Storage, + SC: Storage { Self::new_observer_frame(dir, up).inverse() } -} -impl UnitQuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator + - Allocator { /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. /// /// If `axisangle` is zero, this returns the indentity rotation. #[inline] - pub fn new(axisangle: ColumnVector) -> Self - where SB: Storage { + pub fn new(axisangle: Vector) -> Self + where SB: Storage { let two: N = ::convert(2.0f64); - let q = QuaternionBase::::from_parts(N::zero(), axisangle / two).exp(); + let q = Quaternion::::from_parts(N::zero(), axisangle / two).exp(); Self::new_unchecked(q) } @@ -326,44 +296,35 @@ impl UnitQuaternionBase /// If `axisangle` is zero, this returns the indentity rotation. /// Same as `Self::new(axisangle)`. #[inline] - pub fn from_scaled_axis(axisangle: ColumnVector) -> Self - where SB: Storage { + pub fn from_scaled_axis(axisangle: Vector) -> Self + where SB: Storage { Self::new(axisangle) } } -impl One for UnitQuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl One for UnitQuaternion { #[inline] fn one() -> Self { Self::identity() } } -impl Rand for UnitQuaternionBase - where N: Real + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator + - Allocator { +impl Rand for UnitQuaternion { #[inline] fn rand(rng: &mut R) -> Self { let axisangle = Vector3::rand(rng); - UnitQuaternionBase::from_scaled_axis(axisangle) + UnitQuaternion::from_scaled_axis(axisangle) } } #[cfg(feature="arbitrary")] -impl Arbitrary for UnitQuaternionBase - where N: Real + Arbitrary, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator + - Allocator { +impl Arbitrary for UnitQuaternion + where Owned: Send, + Owned: Send { #[inline] fn arbitrary(g: &mut G) -> Self { let axisangle = Vector3::arbitrary(g); - UnitQuaternionBase::from_scaled_axis(axisangle) + UnitQuaternion::from_scaled_axis(axisangle) } } diff --git a/src/geometry/quaternion_conversion.rs b/src/geometry/quaternion_conversion.rs index da70cda0..7ac90eed 100644 --- a/src/geometry/quaternion_conversion.rs +++ b/src/geometry/quaternion_conversion.rs @@ -3,12 +3,11 @@ use num::Zero; use alga::general::{SubsetOf, SupersetOf, Real}; use alga::linear::Rotation as AlgaRotation; -use core::{ColumnVector, SquareMatrix}; -use core::dimension::{U1, U3, U4}; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; -use geometry::{PointBase, QuaternionBase, UnitQuaternionBase, OwnedUnitQuaternionBase, RotationBase, - OwnedRotation, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine, TranslationBase}; +use core::{Vector4, Matrix4}; +use core::dimension::U3; +use geometry::{Quaternion, UnitQuaternion, Rotation, Isometry, Similarity, + Transform, SuperTCategoryOf, TAffine, Translation, + Rotation3, Point3}; /* * This file provides the following conversions: @@ -16,197 +15,154 @@ use geometry::{PointBase, QuaternionBase, UnitQuaternionBase, OwnedUnitQuaternio * * Quaternion -> Quaternion * UnitQuaternion -> UnitQuaternion - * UnitQuaternion -> RotationBase - * UnitQuaternion -> IsometryBase - * UnitQuaternion -> SimilarityBase - * UnitQuaternion -> TransformBase + * UnitQuaternion -> Rotation + * UnitQuaternion -> Isometry + * UnitQuaternion -> Similarity + * UnitQuaternion -> Transform * UnitQuaternion -> Matrix (homogeneous) * * NOTE: * UnitQuaternion -> Quaternion is already provided by: Unit -> T */ -impl SubsetOf> for QuaternionBase +impl SubsetOf> for Quaternion where N1: Real, - N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + N2: Real + SupersetOf { #[inline] - fn to_superset(&self) -> QuaternionBase { - QuaternionBase::from_vector(self.coords.to_superset()) + fn to_superset(&self) -> Quaternion { + Quaternion::from_vector(self.coords.to_superset()) } #[inline] - fn is_in_subset(q: &QuaternionBase) -> bool { - ::is_convertible::<_, ColumnVector>(&q.coords) + fn is_in_subset(q: &Quaternion) -> bool { + ::is_convertible::<_, Vector4>(&q.coords) } #[inline] - unsafe fn from_superset_unchecked(q: &QuaternionBase) -> Self { + unsafe fn from_superset_unchecked(q: &Quaternion) -> Self { Self::from_vector(q.coords.to_subset_unchecked()) } } -impl SubsetOf> for UnitQuaternionBase +impl SubsetOf> for UnitQuaternion where N1: Real, - N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + N2: Real + SupersetOf { #[inline] - fn to_superset(&self) -> UnitQuaternionBase { - UnitQuaternionBase::new_unchecked(self.as_ref().to_superset()) + fn to_superset(&self) -> UnitQuaternion { + UnitQuaternion::new_unchecked(self.as_ref().to_superset()) } #[inline] - fn is_in_subset(uq: &UnitQuaternionBase) -> bool { - ::is_convertible::<_, QuaternionBase>(uq.as_ref()) + fn is_in_subset(uq: &UnitQuaternion) -> bool { + ::is_convertible::<_, Quaternion>(uq.as_ref()) } #[inline] - unsafe fn from_superset_unchecked(uq: &UnitQuaternionBase) -> Self { + unsafe fn from_superset_unchecked(uq: &UnitQuaternion) -> Self { Self::new_unchecked(::convert_ref_unchecked(uq.as_ref())) } } -impl SubsetOf> for UnitQuaternionBase +impl SubsetOf> for UnitQuaternion where N1: Real, - N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator + - Allocator, - SB::Alloc: OwnedAllocator + - Allocator + - Allocator { + N2: Real + SupersetOf { #[inline] - fn to_superset(&self) -> RotationBase { - let q: OwnedUnitQuaternionBase = self.to_superset(); + fn to_superset(&self) -> Rotation3 { + let q: UnitQuaternion = self.to_superset(); q.to_rotation_matrix() } #[inline] - fn is_in_subset(rot: &RotationBase) -> bool { - ::is_convertible::<_, OwnedRotation>(rot) + fn is_in_subset(rot: &Rotation3) -> bool { + ::is_convertible::<_, Rotation3>(rot) } #[inline] - unsafe fn from_superset_unchecked(rot: &RotationBase) -> Self { - let q = OwnedUnitQuaternionBase::::from_rotation_matrix(rot); + unsafe fn from_superset_unchecked(rot: &Rotation3) -> Self { + let q = UnitQuaternion::::from_rotation_matrix(rot); ::convert_unchecked(q) } } -impl SubsetOf> for UnitQuaternionBase +impl SubsetOf> for UnitQuaternion where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - R: AlgaRotation> + SupersetOf>, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R: AlgaRotation> + SupersetOf> { #[inline] - fn to_superset(&self) -> IsometryBase { - IsometryBase::from_parts(TranslationBase::identity(), ::convert_ref(self)) + fn to_superset(&self) -> Isometry { + Isometry::from_parts(Translation::identity(), ::convert_ref(self)) } #[inline] - fn is_in_subset(iso: &IsometryBase) -> bool { + fn is_in_subset(iso: &Isometry) -> bool { iso.translation.vector.is_zero() } #[inline] - unsafe fn from_superset_unchecked(iso: &IsometryBase) -> Self { + unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { ::convert_ref_unchecked(&iso.rotation) } } -impl SubsetOf> for UnitQuaternionBase +impl SubsetOf> for UnitQuaternion where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - R: AlgaRotation> + SupersetOf>, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R: AlgaRotation> + SupersetOf> { #[inline] - fn to_superset(&self) -> SimilarityBase { - SimilarityBase::from_isometry(::convert_ref(self), N2::one()) + fn to_superset(&self) -> Similarity { + Similarity::from_isometry(::convert_ref(self), N2::one()) } #[inline] - fn is_in_subset(sim: &SimilarityBase) -> bool { + fn is_in_subset(sim: &Similarity) -> bool { sim.isometry.translation.vector.is_zero() && sim.scaling() == N2::one() } #[inline] - unsafe fn from_superset_unchecked(sim: &SimilarityBase) -> Self { + unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { ::convert_ref_unchecked(&sim.isometry) } } -impl SubsetOf> for UnitQuaternionBase +impl SubsetOf> for UnitQuaternion where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - C: SuperTCategoryOf, - SA::Alloc: OwnedAllocator + - Allocator + - Allocator + - Allocator, - SB::Alloc: OwnedAllocator + - Allocator + - Allocator { + C: SuperTCategoryOf { #[inline] - fn to_superset(&self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] - fn is_in_subset(t: &TransformBase) -> bool { + fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] - unsafe fn from_superset_unchecked(t: &TransformBase) -> Self { + unsafe fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } -impl SubsetOf> for UnitQuaternionBase - where N1: Real, - N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator + - Allocator + - Allocator + - Allocator, - SB::Alloc: OwnedAllocator + - Allocator + - Allocator { +impl> SubsetOf> for UnitQuaternion { #[inline] - fn to_superset(&self) -> SquareMatrix { + fn to_superset(&self) -> Matrix4 { self.to_homogeneous().to_superset() } #[inline] - fn is_in_subset(m: &SquareMatrix) -> bool { - ::is_convertible::<_, OwnedRotation>(m) + fn is_in_subset(m: &Matrix4) -> bool { + ::is_convertible::<_, Rotation3>(m) } #[inline] - unsafe fn from_superset_unchecked(m: &SquareMatrix) -> Self { - let rot: OwnedRotation = ::convert_ref_unchecked(m); + unsafe fn from_superset_unchecked(m: &Matrix4) -> Self { + let rot: Rotation3 = ::convert_ref_unchecked(m); Self::from_rotation_matrix(&rot) } } diff --git a/src/geometry/quaternion_coordinates.rs b/src/geometry/quaternion_coordinates.rs index fdf4169c..cdfb39cd 100644 --- a/src/geometry/quaternion_coordinates.rs +++ b/src/geometry/quaternion_coordinates.rs @@ -4,17 +4,11 @@ use std::ops::{Deref, DerefMut}; use alga::general::Real; use core::coordinates::IJKW; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; -use core::dimension::{U1, U4}; -use geometry::QuaternionBase; +use geometry::Quaternion; -impl Deref for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Deref for Quaternion { type Target = IJKW; #[inline] @@ -23,10 +17,7 @@ impl Deref for QuaternionBase } } -impl DerefMut for QuaternionBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl DerefMut for Quaternion { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { mem::transmute(self) } diff --git a/src/geometry/quaternion_ops.rs b/src/geometry/quaternion_ops.rs index ce577176..af1650a2 100644 --- a/src/geometry/quaternion_ops.rs +++ b/src/geometry/quaternion_ops.rs @@ -17,17 +17,17 @@ * * (Unit Quaternion) * UnitQuaternion × UnitQuaternion - * UnitQuaternion × RotationBase -> UnitQuaternion - * RotationBase × UnitQuaternion -> UnitQuaternion + * UnitQuaternion × Rotation -> UnitQuaternion + * Rotation × UnitQuaternion -> UnitQuaternion * * UnitQuaternion ÷ UnitQuaternion - * UnitQuaternion ÷ RotationBase -> UnitQuaternion - * RotationBase ÷ UnitQuaternion -> UnitQuaternion + * UnitQuaternion ÷ Rotation -> UnitQuaternion + * Rotation ÷ UnitQuaternion -> UnitQuaternion * * - * UnitQuaternion × PointBase - * UnitQuaternion × ColumnVector - * UnitQuaternion × Unit + * UnitQuaternion × Point + * UnitQuaternion × Vector + * UnitQuaternion × Unit * * NOTE: -UnitQuaternion is already provided by `Unit`. * @@ -40,31 +40,28 @@ * Quaternion -= Quaternion * * UnitQuaternion ×= UnitQuaternion - * UnitQuaternion ×= RotationBase + * UnitQuaternion ×= Rotation * * UnitQuaternion ÷= UnitQuaternion - * UnitQuaternion ÷= RotationBase + * UnitQuaternion ÷= Rotation * - * FIXME: RotationBase ×= UnitQuaternion - * FIXME: RotationBase ÷= UnitQuaternion + * FIXME: Rotation ×= UnitQuaternion + * FIXME: Rotation ÷= UnitQuaternion * */ -use std::ops::{Index, IndexMut, Neg, Add, AddAssign, Mul, MulAssign, Div, DivAssign, Sub, SubAssign}; +use std::ops::{Index, IndexMut, Neg, Add, AddAssign, Mul, MulAssign, Sub, SubAssign, Div, DivAssign}; use alga::general::Real; -use core::{ColumnVector, OwnedColumnVector, Unit}; -use core::storage::{Storage, StorageMut}; +use core::{DefaultAllocator, Vector, Vector3, Unit}; +use core::storage::Storage; use core::allocator::Allocator; use core::dimension::{U1, U3, U4}; -use geometry::{QuaternionBase, OwnedQuaternionBase, UnitQuaternionBase, OwnedUnitQuaternionBase, - PointBase, OwnedPoint, RotationBase}; +use geometry::{Quaternion, UnitQuaternion, Point3, Rotation}; -impl Index for QuaternionBase - where N: Real, - S: Storage { +impl Index for Quaternion { type Output = N; #[inline] @@ -73,10 +70,7 @@ impl Index for QuaternionBase } } -impl IndexMut for QuaternionBase - where N: Real, - S: StorageMut { - +impl IndexMut for Quaternion { #[inline] fn index_mut(&mut self, i: usize) -> &mut N { &mut self.coords[i] @@ -85,15 +79,13 @@ impl IndexMut for QuaternionBase macro_rules! quaternion_op_impl( ($Op: ident, $op: ident; - ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident); + ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident) + $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty $(=> $VDimA: ty, $VDimB: ty)*; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N, SA, SB> $Op<$Rhs> for $Lhs - where N: Real, - SA: Storage, - SB: Storage, - $(SA::Alloc: Allocator, - SB::Alloc: Allocator)* { + impl<$($lives ,)* N: Real $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where DefaultAllocator: Allocator + + Allocator { type Output = $Result; #[inline] @@ -109,29 +101,29 @@ macro_rules! quaternion_op_impl( quaternion_op_impl!( Add, add; (U4, U1), (U4, U1); - self: &'a QuaternionBase, rhs: &'b QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(&self.coords + &rhs.coords); + self: &'a Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from_vector(&self.coords + &rhs.coords); 'a, 'b); quaternion_op_impl!( Add, add; (U4, U1), (U4, U1); - self: &'a QuaternionBase, rhs: QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(&self.coords + rhs.coords); + self: &'a Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from_vector(&self.coords + rhs.coords); 'a); quaternion_op_impl!( Add, add; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: &'b QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(self.coords + &rhs.coords); + self: Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from_vector(self.coords + &rhs.coords); 'b); quaternion_op_impl!( Add, add; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(self.coords + rhs.coords); + self: Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from_vector(self.coords + rhs.coords); ); @@ -139,29 +131,29 @@ quaternion_op_impl!( quaternion_op_impl!( Sub, sub; (U4, U1), (U4, U1); - self: &'a QuaternionBase, rhs: &'b QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(&self.coords - &rhs.coords); + self: &'a Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from_vector(&self.coords - &rhs.coords); 'a, 'b); quaternion_op_impl!( Sub, sub; (U4, U1), (U4, U1); - self: &'a QuaternionBase, rhs: QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(&self.coords - rhs.coords); + self: &'a Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from_vector(&self.coords - rhs.coords); 'a); quaternion_op_impl!( Sub, sub; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: &'b QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(self.coords - &rhs.coords); + self: Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from_vector(self.coords - &rhs.coords); 'b); quaternion_op_impl!( Sub, sub; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::from_vector(self.coords - rhs.coords); + self: Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from_vector(self.coords - rhs.coords); ); @@ -169,8 +161,8 @@ quaternion_op_impl!( quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: &'a QuaternionBase, rhs: &'b QuaternionBase, Output = OwnedQuaternionBase; - QuaternionBase::new( + self: &'a Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::new( self[3] * rhs[3] - self[0] * rhs[0] - self[1] * rhs[1] - self[2] * rhs[2], self[3] * rhs[0] + self[0] * rhs[3] + self[1] * rhs[2] - self[2] * rhs[1], self[3] * rhs[1] - self[0] * rhs[2] + self[1] * rhs[3] + self[2] * rhs[0], @@ -180,21 +172,21 @@ quaternion_op_impl!( quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: &'a QuaternionBase, rhs: QuaternionBase, Output = OwnedQuaternionBase; + self: &'a Quaternion, rhs: Quaternion, Output = Quaternion; self * &rhs; 'a); quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: &'b QuaternionBase, Output = OwnedQuaternionBase; + self: Quaternion, rhs: &'b Quaternion, Output = Quaternion; &self * rhs; 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: QuaternionBase, Output = OwnedQuaternionBase; + self: Quaternion, rhs: Quaternion, Output = Quaternion; &self * &rhs; ); @@ -202,28 +194,28 @@ quaternion_op_impl!( quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: &'a UnitQuaternionBase, rhs: &'b UnitQuaternionBase, Output = OwnedUnitQuaternionBase; - UnitQuaternionBase::new_unchecked(self.quaternion() * rhs.quaternion()); + self: &'a UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; + UnitQuaternion::new_unchecked(self.quaternion() * rhs.quaternion()); 'a, 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: &'a UnitQuaternionBase, rhs: UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: &'a UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; self * &rhs; 'a); quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: &'b UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; &self * rhs; 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; &self * &rhs; ); @@ -231,173 +223,173 @@ quaternion_op_impl!( quaternion_op_impl!( Div, div; (U4, U1), (U4, U1); - self: &'a UnitQuaternionBase, rhs: &'b UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: &'a UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; self * rhs.inverse(); 'a, 'b); quaternion_op_impl!( Div, div; (U4, U1), (U4, U1); - self: &'a UnitQuaternionBase, rhs: UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: &'a UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; self / &rhs; 'a); quaternion_op_impl!( Div, div; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: &'b UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; &self / rhs; 'b); quaternion_op_impl!( Div, div; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: UnitQuaternionBase, Output = OwnedUnitQuaternionBase; + self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; &self / &rhs; ); -// UnitQuaternion × RotationBase +// UnitQuaternion × Rotation quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U3); - self: &'a UnitQuaternionBase, rhs: &'b RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; + self: &'a UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion => U3, U3; // FIXME: can we avoid the conversion from a rotation matrix? - self * OwnedUnitQuaternionBase::::from_rotation_matrix(rhs); + self * UnitQuaternion::::from_rotation_matrix(rhs); 'a, 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U3); - self: &'a UnitQuaternionBase, rhs: RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; - self * OwnedUnitQuaternionBase::::from_rotation_matrix(&rhs); + self: &'a UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion => U3, U3; + self * UnitQuaternion::::from_rotation_matrix(&rhs); 'a); quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: &'b RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; - self * OwnedUnitQuaternionBase::::from_rotation_matrix(rhs); + self: UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion => U3, U3; + self * UnitQuaternion::::from_rotation_matrix(rhs); 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; - self * OwnedUnitQuaternionBase::::from_rotation_matrix(&rhs); + self: UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion => U3, U3; + self * UnitQuaternion::::from_rotation_matrix(&rhs); ); -// UnitQuaternion ÷ RotationBase +// UnitQuaternion ÷ Rotation quaternion_op_impl!( Div, div; (U4, U1), (U3, U3); - self: &'a UnitQuaternionBase, rhs: &'b RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; + self: &'a UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion => U3, U3; // FIXME: can we avoid the conversion to a rotation matrix? - self / OwnedUnitQuaternionBase::::from_rotation_matrix(rhs); + self / UnitQuaternion::::from_rotation_matrix(rhs); 'a, 'b); quaternion_op_impl!( Div, div; (U4, U1), (U3, U3); - self: &'a UnitQuaternionBase, rhs: RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; - self / OwnedUnitQuaternionBase::::from_rotation_matrix(&rhs); + self: &'a UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion => U3, U3; + self / UnitQuaternion::::from_rotation_matrix(&rhs); 'a); quaternion_op_impl!( Div, div; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: &'b RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; - self / OwnedUnitQuaternionBase::::from_rotation_matrix(rhs); + self: UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion => U3, U3; + self / UnitQuaternion::::from_rotation_matrix(rhs); 'b); quaternion_op_impl!( Div, div; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: RotationBase, - Output = OwnedUnitQuaternionBase => U3, U3; - self / OwnedUnitQuaternionBase::::from_rotation_matrix(&rhs); + self: UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion => U3, U3; + self / UnitQuaternion::::from_rotation_matrix(&rhs); ); -// RotationBase × UnitQuaternion +// Rotation × UnitQuaternion quaternion_op_impl!( Mul, mul; (U3, U3), (U4, U1); - self: &'a RotationBase, rhs: &'b UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; + self: &'a Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion => U3, U3; // FIXME: can we avoid the conversion from a rotation matrix? - OwnedUnitQuaternionBase::::from_rotation_matrix(self) * rhs; + UnitQuaternion::::from_rotation_matrix(self) * rhs; 'a, 'b); quaternion_op_impl!( Mul, mul; (U3, U3), (U4, U1); - self: &'a RotationBase, rhs: UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; - OwnedUnitQuaternionBase::::from_rotation_matrix(self) * rhs; + self: &'a Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion => U3, U3; + UnitQuaternion::::from_rotation_matrix(self) * rhs; 'a); quaternion_op_impl!( Mul, mul; (U3, U3), (U4, U1); - self: RotationBase, rhs: &'b UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; - OwnedUnitQuaternionBase::::from_rotation_matrix(&self) * rhs; + self: Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion => U3, U3; + UnitQuaternion::::from_rotation_matrix(&self) * rhs; 'b); quaternion_op_impl!( Mul, mul; (U3, U3), (U4, U1); - self: RotationBase, rhs: UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; - OwnedUnitQuaternionBase::::from_rotation_matrix(&self) * rhs; + self: Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion => U3, U3; + UnitQuaternion::::from_rotation_matrix(&self) * rhs; ); -// RotationBase ÷ UnitQuaternion +// Rotation ÷ UnitQuaternion quaternion_op_impl!( Div, div; (U3, U3), (U4, U1); - self: &'a RotationBase, rhs: &'b UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; + self: &'a Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion => U3, U3; // FIXME: can we avoid the conversion from a rotation matrix? - OwnedUnitQuaternionBase::::from_rotation_matrix(self) / rhs; + UnitQuaternion::::from_rotation_matrix(self) / rhs; 'a, 'b); quaternion_op_impl!( Div, div; (U3, U3), (U4, U1); - self: &'a RotationBase, rhs: UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; - OwnedUnitQuaternionBase::::from_rotation_matrix(self) / rhs; + self: &'a Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion => U3, U3; + UnitQuaternion::::from_rotation_matrix(self) / rhs; 'a); quaternion_op_impl!( Div, div; (U3, U3), (U4, U1); - self: RotationBase, rhs: &'b UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; - OwnedUnitQuaternionBase::::from_rotation_matrix(&self) / rhs; + self: Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion => U3, U3; + UnitQuaternion::::from_rotation_matrix(&self) / rhs; 'b); quaternion_op_impl!( Div, div; (U3, U3), (U4, U1); - self: RotationBase, rhs: UnitQuaternionBase, - Output = OwnedUnitQuaternionBase => U3, U3; - OwnedUnitQuaternionBase::::from_rotation_matrix(&self) / rhs; + self: Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion => U3, U3; + UnitQuaternion::::from_rotation_matrix(&self) / rhs; ); // UnitQuaternion × Vector quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: &'a UnitQuaternionBase, rhs: &'b ColumnVector, - Output = OwnedColumnVector => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitQuaternion, rhs: &'b Vector, + Output = Vector3 => U3, U4; { let two: N = ::convert(2.0f64); let t = self.as_ref().vector().cross(rhs) * two; @@ -409,91 +401,91 @@ quaternion_op_impl!( quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: &'a UnitQuaternionBase, rhs: ColumnVector, - Output = OwnedColumnVector => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitQuaternion, rhs: Vector, + Output = Vector3 => U3, U4; self * &rhs; 'a); quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: UnitQuaternionBase, rhs: &'b ColumnVector, - Output = OwnedColumnVector => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitQuaternion, rhs: &'b Vector, + Output = Vector3 => U3, U4; &self * rhs; 'b); quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: UnitQuaternionBase, rhs: ColumnVector, - Output = OwnedColumnVector => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitQuaternion, rhs: Vector, + Output = Vector3 => U3, U4; &self * &rhs; ); -// UnitQuaternion × PointBase +// UnitQuaternion × Point quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U1); - self: &'a UnitQuaternionBase, rhs: &'b PointBase, - Output = OwnedPoint => U3, U4; - PointBase::from_coordinates(self * &rhs.coords); + self: &'a UnitQuaternion, rhs: &'b Point3, + Output = Point3 => U3, U4; + Point3::from_coordinates(self * &rhs.coords); 'a, 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U1); - self: &'a UnitQuaternionBase, rhs: PointBase, - Output = OwnedPoint => U3, U4; - PointBase::from_coordinates(self * rhs.coords); + self: &'a UnitQuaternion, rhs: Point3, + Output = Point3 => U3, U4; + Point3::from_coordinates(self * rhs.coords); 'a); quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U1); - self: UnitQuaternionBase, rhs: &'b PointBase, - Output = OwnedPoint => U3, U4; - PointBase::from_coordinates(self * &rhs.coords); + self: UnitQuaternion, rhs: &'b Point3, + Output = Point3 => U3, U4; + Point3::from_coordinates(self * &rhs.coords); 'b); quaternion_op_impl!( Mul, mul; (U4, U1), (U3, U1); - self: UnitQuaternionBase, rhs: PointBase, - Output = OwnedPoint => U3, U4; - PointBase::from_coordinates(self * rhs.coords); + self: UnitQuaternion, rhs: Point3, + Output = Point3 => U3, U4; + Point3::from_coordinates(self * rhs.coords); ); // UnitQuaternion × Unit quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: &'a UnitQuaternionBase, rhs: &'b Unit>, - Output = Unit> => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitQuaternion, rhs: &'b Unit>, + Output = Unit> => U3, U4; Unit::new_unchecked(self * rhs.as_ref()); 'a, 'b); quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: &'a UnitQuaternionBase, rhs: Unit>, - Output = Unit> => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitQuaternion, rhs: Unit>, + Output = Unit> => U3, U4; Unit::new_unchecked(self * rhs.unwrap()); 'a); quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: UnitQuaternionBase, rhs: &'b Unit>, - Output = Unit> => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitQuaternion, rhs: &'b Unit>, + Output = Unit> => U3, U4; Unit::new_unchecked(self * rhs.as_ref()); 'b); quaternion_op_impl!( Mul, mul; - (U4, U1), (U3, U1); - self: UnitQuaternionBase, rhs: Unit>, - Output = Unit> => U3, U4; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitQuaternion, rhs: Unit>, + Output = Unit> => U3, U4; Unit::new_unchecked(self * rhs.unwrap()); ); @@ -501,31 +493,25 @@ quaternion_op_impl!( macro_rules! scalar_op_impl( ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$( - impl $Op for QuaternionBase - where N: Real, - S: Storage { - type Output = OwnedQuaternionBase; + impl $Op for Quaternion { + type Output = Quaternion; #[inline] fn $op(self, n: N) -> Self::Output { - QuaternionBase::from_vector(self.coords.$op(n)) + Quaternion::from_vector(self.coords.$op(n)) } } - impl<'a, N, S> $Op for &'a QuaternionBase - where N: Real, - S: Storage { - type Output = OwnedQuaternionBase; + impl<'a, N: Real> $Op for &'a Quaternion { + type Output = Quaternion; #[inline] fn $op(self, n: N) -> Self::Output { - QuaternionBase::from_vector((&self.coords).$op(n)) + Quaternion::from_vector((&self.coords).$op(n)) } } - impl $OpAssign for QuaternionBase - where N: Real, - S: StorageMut { + impl $OpAssign for Quaternion { #[inline] fn $op_assign(&mut self, n: N) { @@ -542,23 +528,21 @@ scalar_op_impl!( macro_rules! left_scalar_mul_impl( ($($T: ty),* $(,)*) => {$( - impl Mul> for $T - where S: Storage<$T, U4, U1> { - type Output = OwnedQuaternionBase<$T, S::Alloc>; + impl Mul> for $T { + type Output = Quaternion<$T>; #[inline] - fn mul(self, right: QuaternionBase<$T, S>) -> Self::Output { - QuaternionBase::from_vector(self * right.coords) + fn mul(self, right: Quaternion<$T>) -> Self::Output { + Quaternion::from_vector(self * right.coords) } } - impl<'b, S> Mul<&'b QuaternionBase<$T, S>> for $T - where S: Storage<$T, U4, U1> { - type Output = OwnedQuaternionBase<$T, S::Alloc>; + impl<'b> Mul<&'b Quaternion<$T>> for $T { + type Output = Quaternion<$T>; #[inline] - fn mul(self, right: &'b QuaternionBase<$T, S>) -> Self::Output { - QuaternionBase::from_vector(self * &right.coords) + fn mul(self, right: &'b Quaternion<$T>) -> Self::Output { + Quaternion::from_vector(self * &right.coords) } } )*} @@ -566,25 +550,21 @@ macro_rules! left_scalar_mul_impl( left_scalar_mul_impl!(f32, f64); -impl Neg for QuaternionBase - where N: Real, - S: Storage { - type Output = OwnedQuaternionBase; +impl Neg for Quaternion { + type Output = Quaternion; #[inline] fn neg(self) -> Self::Output { - QuaternionBase::from_vector(-self.coords) + Quaternion::from_vector(-self.coords) } } -impl<'a, N, S> Neg for &'a QuaternionBase - where N: Real, - S: Storage { - type Output = OwnedQuaternionBase; +impl<'a, N: Real> Neg for &'a Quaternion { + type Output = Quaternion; #[inline] fn neg(self) -> Self::Output { - QuaternionBase::from_vector(-&self.coords) + Quaternion::from_vector(-&self.coords) } } @@ -593,17 +573,9 @@ macro_rules! quaternion_op_impl( ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident); $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N, SA, SB> $OpAssign<$Rhs> for $Lhs - where N: Real, - SA: StorageMut, - SB: Storage, - $(SA::Alloc: Allocator + Allocator, - // ^^^^^^^^^^^^^^^^^^^^ - // XXX: For some reasons, the compiler needs - // this bound to compile UnitQuat *= RotationBase. - // Though in theory this bound is already - // inherited from `SA: StorageMut`… - SB::Alloc: Allocator)* { + impl<$($lives ,)* N: Real> $OpAssign<$Rhs> for $Lhs + where DefaultAllocator: Allocator + + Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: $Rhs) { @@ -617,14 +589,14 @@ macro_rules! quaternion_op_impl( quaternion_op_impl!( AddAssign, add_assign; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: &'b QuaternionBase; + self: Quaternion, rhs: &'b Quaternion; self.coords += &rhs.coords; 'b); quaternion_op_impl!( AddAssign, add_assign; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: QuaternionBase; + self: Quaternion, rhs: Quaternion; self.coords += rhs.coords; ); @@ -632,21 +604,21 @@ quaternion_op_impl!( quaternion_op_impl!( SubAssign, sub_assign; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: &'b QuaternionBase; + self: Quaternion, rhs: &'b Quaternion; self.coords -= &rhs.coords; 'b); quaternion_op_impl!( SubAssign, sub_assign; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: QuaternionBase; + self: Quaternion, rhs: Quaternion; self.coords -= rhs.coords; ); // Quaternion ×= Quaternion quaternion_op_impl!( MulAssign, mul_assign; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: &'b QuaternionBase; + self: Quaternion, rhs: &'b Quaternion; { let res = &*self * rhs; // FIXME: will this be optimized away? @@ -657,14 +629,14 @@ quaternion_op_impl!( quaternion_op_impl!( MulAssign, mul_assign; (U4, U1), (U4, U1); - self: QuaternionBase, rhs: QuaternionBase; + self: Quaternion, rhs: Quaternion; *self *= &rhs; ); // UnitQuaternion ×= UnitQuaternion quaternion_op_impl!( MulAssign, mul_assign; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: &'b UnitQuaternionBase; + self: UnitQuaternion, rhs: &'b UnitQuaternion; { let res = &*self * rhs; self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); @@ -674,14 +646,14 @@ quaternion_op_impl!( quaternion_op_impl!( MulAssign, mul_assign; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: UnitQuaternionBase; + self: UnitQuaternion, rhs: UnitQuaternion; *self *= &rhs; ); // UnitQuaternion ÷= UnitQuaternion quaternion_op_impl!( DivAssign, div_assign; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: &'b UnitQuaternionBase; + self: UnitQuaternion, rhs: &'b UnitQuaternion; { let res = &*self / rhs; self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); @@ -691,14 +663,14 @@ quaternion_op_impl!( quaternion_op_impl!( DivAssign, div_assign; (U4, U1), (U4, U1); - self: UnitQuaternionBase, rhs: UnitQuaternionBase; + self: UnitQuaternion, rhs: UnitQuaternion; *self /= &rhs; ); -// UnitQuaternion ×= RotationBase +// UnitQuaternion ×= Rotation quaternion_op_impl!( MulAssign, mul_assign; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: &'b RotationBase => U3, U3; + self: UnitQuaternion, rhs: &'b Rotation => U3, U3; { let res = &*self * rhs; self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); @@ -708,14 +680,14 @@ quaternion_op_impl!( quaternion_op_impl!( MulAssign, mul_assign; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: RotationBase => U3, U3; + self: UnitQuaternion, rhs: Rotation => U3, U3; *self *= &rhs; ); -// UnitQuaternion ÷= RotationBase +// UnitQuaternion ÷= Rotation quaternion_op_impl!( DivAssign, div_assign; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: &'b RotationBase => U3, U3; + self: UnitQuaternion, rhs: &'b Rotation => U3, U3; { let res = &*self / rhs; self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); @@ -725,5 +697,5 @@ quaternion_op_impl!( quaternion_op_impl!( DivAssign, div_assign; (U4, U1), (U3, U3); - self: UnitQuaternionBase, rhs: RotationBase => U3, U3; + self: UnitQuaternion, rhs: Rotation => U3, U3; *self /= &rhs; ); diff --git a/src/geometry/reflection.rs b/src/geometry/reflection.rs new file mode 100644 index 00000000..72d87005 --- /dev/null +++ b/src/geometry/reflection.rs @@ -0,0 +1,72 @@ +use alga::general::Real; +use core::{DefaultAllocator, Scalar, Unit, Matrix, Vector}; +use core::constraint::{ShapeConstraint, SameNumberOfRows, DimEq, AreMultipliable}; +use core::allocator::Allocator; +use dimension::{Dim, DimName, U1}; +use storage::{Storage, StorageMut}; + +use geometry::Point; + +/// A reflection wrt. a plane. +pub struct Reflection> { + axis: Vector, + bias: N +} + +impl> Reflection { + /// Creates a new reflection wrt the plane orthogonal to the given axis and bias. + /// + /// The bias is the position of the plane on the axis. In particular, a bias equal to zero + /// represents a plane that passes through the origin. + pub fn new(axis: Unit>, bias: N) -> Reflection { + Reflection { axis: axis.unwrap(), bias: bias } + } + + /// Creates a new reflection wrt. the plane orthogonal to the given axis and that contains the + /// point `pt`. + pub fn new_containing_point(axis: Unit>, pt: &Point) -> Reflection + where D: DimName, + DefaultAllocator: Allocator { + let bias = pt.coords.dot(axis.as_ref()); + Self::new(axis, bias) + } + + /// The reflexion axis. + pub fn axis(&self) -> &Vector { + &self.axis + } + + // FIXME: naming convension: reflect_to, reflect_assign ? + /// Applies the reflection to the columns of `rhs`. + pub fn reflect(&self, rhs: &mut Matrix) + where S2: StorageMut, + ShapeConstraint: SameNumberOfRows { + + for i in 0 .. rhs.ncols() { + // NOTE: we borrow the column twice here. First it is borrowed immutably for the + // dot product, and then mutably. Somehow, this allows significantly + // better optimizations of the dot product from the compiler. + let m_two: N = ::convert(-2.0f64); + let factor = (rhs.column(i).dot(&self.axis) - self.bias) * m_two; + rhs.column_mut(i).axpy(factor, &self.axis, N::one()); + } + } + + /// Applies the reflection to the rows of `rhs`. + pub fn reflect_rows(&self, + rhs: &mut Matrix, + work: &mut Vector) + where S2: StorageMut, + S3: StorageMut, + ShapeConstraint: DimEq + AreMultipliable { + + rhs.mul_to(&self.axis, work); + + if !self.bias.is_zero() { + work.add_scalar_mut(-self.bias); + } + + let m_two: N = ::convert(-2.0f64); + rhs.ger(m_two, &work, &self.axis, N::one()); + } +} diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 1429830a..c04e1eb1 100644 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -1,60 +1,79 @@ use num::{Zero, One}; +use std::hash; use std::fmt; use approx::ApproxEq; #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; + +#[cfg(feature = "serde-serialize")] +use core::storage::Owned; use alga::general::Real; -use core::{SquareMatrix, Scalar, OwnedSquareMatrix}; +use core::{DefaultAllocator, Scalar, MatrixN}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; -use core::storage::{Storage, StorageMut}; use core::allocator::Allocator; -/// A rotation matrix with an owned storage. -pub type OwnedRotation = RotationBase>::Buffer>; - /// A rotation matrix. #[repr(C)] -#[derive(Hash, Debug, Clone, Copy)] -pub struct RotationBase { - matrix: SquareMatrix +#[derive(Debug)] +pub struct Rotation + where DefaultAllocator: Allocator { + matrix: MatrixN } -#[cfg(feature = "serde-serialize")] -impl Serialize for RotationBase - where N: Scalar, - D: DimName, - SquareMatrix: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.matrix.serialize(serializer) +impl hash::Hash for Rotation + where DefaultAllocator: Allocator, + >::Buffer: hash::Hash { + fn hash(&self, state: &mut H) { + self.matrix.hash(state) + } +} + +impl Copy for Rotation + where DefaultAllocator: Allocator, + >::Buffer: Copy { } + +impl Clone for Rotation + where DefaultAllocator: Allocator, + >::Buffer: Clone { + #[inline] + fn clone(&self) -> Self { + Rotation::from_matrix_unchecked(self.matrix.clone()) } } #[cfg(feature = "serde-serialize")] -impl<'de, N, D, S> Deserialize<'de> for RotationBase - where N: Scalar, - D: DimName, - SquareMatrix: Deserialize<'de>, -{ - fn deserialize(deserializer: T) -> Result - where T: Deserializer<'de> - { - SquareMatrix::deserialize(deserializer).map(|x| RotationBase { matrix: x }) - } +impl serde::Serialize for Rotation +where DefaultAllocator: Allocator, + Owned: serde::Serialize { + + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.matrix.serialize(serializer) + } } -impl> RotationBase - where N: Scalar, - S: Storage { +#[cfg(feature = "serde-serialize")] +impl<'a, N: Scalar, D: DimName> serde::Deserialize<'a> for Rotation +where DefaultAllocator: Allocator, + Owned: serde::Deserialize<'a> { + + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let matrix = MatrixN::::deserialize(deserializer)?; + + Ok(Rotation::from_matrix_unchecked(matrix)) + } +} + +impl Rotation + where DefaultAllocator: Allocator { /// A reference to the underlying matrix representation of this rotation. #[inline] - pub fn matrix(&self) -> &SquareMatrix { + pub fn matrix(&self) -> &MatrixN { &self.matrix } @@ -64,57 +83,52 @@ impl> RotationBase /// non-square, non-inversible, or non-orthonormal. If one of those properties is broken, /// subsequent method calls may be UB. #[inline] - pub unsafe fn matrix_mut(&mut self) -> &mut SquareMatrix { + pub unsafe fn matrix_mut(&mut self) -> &mut MatrixN { &mut self.matrix } /// Unwraps the underlying matrix. #[inline] - pub fn unwrap(self) -> SquareMatrix { + pub fn unwrap(self) -> MatrixN { self.matrix } /// Converts this rotation into its equivalent homogeneous transformation matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix, S::Alloc> + pub fn to_homogeneous(&self) -> MatrixN> where N: Zero + One, D: DimNameAdd, - S::Alloc: Allocator, DimNameSum> { - let mut res = OwnedSquareMatrix::::identity(); + DefaultAllocator: Allocator, DimNameSum> { + let mut res = MatrixN::>::identity(); res.fixed_slice_mut::(0, 0).copy_from(&self.matrix); res } -} -impl> RotationBase { /// Creates a new rotation from the given square matrix. /// /// The matrix squareness is checked but not its orthonormality. #[inline] - pub fn from_matrix_unchecked(matrix: SquareMatrix) -> RotationBase { + pub fn from_matrix_unchecked(matrix: MatrixN) -> Rotation { assert!(matrix.is_square(), "Unable to create a rotation from a non-square matrix."); - RotationBase { + Rotation { matrix: matrix } } /// Transposes `self`. #[inline] - pub fn transpose(&self) -> OwnedRotation { - RotationBase::from_matrix_unchecked(self.matrix.transpose()) + pub fn transpose(&self) -> Rotation { + Rotation::from_matrix_unchecked(self.matrix.transpose()) } /// Inverts `self`. #[inline] - pub fn inverse(&self) -> OwnedRotation { + pub fn inverse(&self) -> Rotation { self.transpose() } -} - -impl> RotationBase { /// Transposes `self` in-place. #[inline] pub fn transpose_mut(&mut self) { @@ -128,18 +142,20 @@ impl> RotationBase { } } -impl> Eq for RotationBase { } +impl Eq for Rotation + where DefaultAllocator: Allocator { } -impl> PartialEq for RotationBase { +impl PartialEq for Rotation + where DefaultAllocator: Allocator { #[inline] - fn eq(&self, right: &RotationBase) -> bool { + fn eq(&self, right: &Rotation) -> bool { self.matrix == right.matrix } } -impl ApproxEq for RotationBase +impl ApproxEq for Rotation where N: Scalar + ApproxEq, - S: Storage, + DefaultAllocator: Allocator, N::Epsilon: Copy { type Epsilon = N::Epsilon; @@ -174,14 +190,14 @@ impl ApproxEq for RotationBase * Display * */ -impl fmt::Display for RotationBase +impl fmt::Display for Rotation where N: Real + fmt::Display, - S: Storage, - S::Alloc: Allocator { + DefaultAllocator: Allocator + + Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "RotationBase matrix {{")); + try!(writeln!(f, "Rotation matrix {{")); try!(write!(f, "{:.*}", precision, self.matrix)); writeln!(f, "}}") } diff --git a/src/geometry/rotation_alga.rs b/src/geometry/rotation_alga.rs index de226095..b982aef2 100644 --- a/src/geometry/rotation_alga.rs +++ b/src/geometry/rotation_alga.rs @@ -1,14 +1,13 @@ use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id}; -use alga::linear::{Transformation, Similarity, AffineTransformation, Isometry, DirectIsometry, - OrthogonalTransformation, ProjectiveTransformation, Rotation}; +use alga::linear::{self, Transformation, Similarity, AffineTransformation, Isometry, + DirectIsometry, OrthogonalTransformation, ProjectiveTransformation}; -use core::ColumnVector; -use core::dimension::{DimName, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::{DefaultAllocator, VectorN}; +use core::dimension::DimName; +use core::allocator::Allocator; -use geometry::{RotationBase, PointBase}; +use geometry::{Rotation, Point}; @@ -17,20 +16,16 @@ use geometry::{RotationBase, PointBase}; * Algebraic structures. * */ -impl Identity for RotationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Identity for Rotation + where DefaultAllocator: Allocator { #[inline] fn identity() -> Self { Self::identity() } } -impl Inverse for RotationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Inverse for Rotation + where DefaultAllocator: Allocator { #[inline] fn inverse(&self) -> Self { self.transpose() @@ -42,10 +37,8 @@ impl Inverse for RotationBase } } -impl AbstractMagma for RotationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractMagma for Rotation + where DefaultAllocator: Allocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs @@ -54,10 +47,8 @@ impl AbstractMagma for RotationBase macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for RotationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { } + impl $marker<$operator> for Rotation + where DefaultAllocator: Allocator { } )*} ); @@ -74,46 +65,37 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for RotationBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl Transformation> for Rotation + where DefaultAllocator: Allocator + + Allocator { #[inline] - fn transform_point(&self, pt: &PointBase) -> PointBase { + fn transform_point(&self, pt: &Point) -> Point { self * pt } #[inline] - fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn transform_vector(&self, v: &VectorN) -> VectorN { self * v } } -impl ProjectiveTransformation> for RotationBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl ProjectiveTransformation> for Rotation + where DefaultAllocator: Allocator + + Allocator { #[inline] - fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { - PointBase::from_coordinates(self.inverse_transform_vector(&pt.coords)) + fn inverse_transform_point(&self, pt: &Point) -> Point { + Point::from_coordinates(self.inverse_transform_vector(&pt.coords)) } #[inline] - fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { self.matrix().tr_mul(v) } } -impl AffineTransformation> for RotationBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl AffineTransformation> for Rotation + where DefaultAllocator: Allocator + + Allocator { type Rotation = Self; type NonUniformScaling = Id; type Translation = Id; @@ -155,12 +137,9 @@ impl AffineTransformation> for Rotati } -impl Similarity> for RotationBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl Similarity> for Rotation + where DefaultAllocator: Allocator + + Allocator { type Scaling = Id; #[inline] @@ -181,12 +160,9 @@ impl Similarity> for RotationBase {$( - impl $Trait> for RotationBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { } + impl $Trait> for Rotation + where DefaultAllocator: Allocator + + Allocator { } )*} ); @@ -194,12 +170,9 @@ marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); /// Subgroups of the n-dimensional rotation group `SO(n)`. -impl Rotation> for RotationBase - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { +impl linear::Rotation> for Rotation + where DefaultAllocator: Allocator + + Allocator { #[inline] fn powf(&self, _: N) -> Option { // XXX: Add the general case. @@ -208,14 +181,14 @@ impl Rotation> for RotationBase, _: &ColumnVector) -> Option { + fn rotation_between(_: &VectorN, _: &VectorN) -> Option { // XXX: Add the general case. // XXX: Use specialization for 2D and 3D. unimplemented!() } #[inline] - fn scaled_rotation_between(_: &ColumnVector, _: &ColumnVector, _: N) -> Option { + fn scaled_rotation_between(_: &VectorN, _: &VectorN, _: N) -> Option { // XXX: Add the general case. // XXX: Use specialization for 2D and 3D. unimplemented!() @@ -223,7 +196,7 @@ impl Rotation> for RotationBase Matrix for RotationBase { +impl Matrix for Rotation { type Field = N; type Row = Matrix; type Column = Matrix; @@ -261,11 +234,11 @@ impl Matrix for RotationBase { #[inline] fn transpose(&self) -> Self::Transpose { - RotationBase::from_matrix_unchecked(self.submatrix.transpose()) + Rotation::from_matrix_unchecked(self.submatrix.transpose()) } } -impl SquareMatrix for RotationBase { +impl SquareMatrix for Rotation { type Vector = Matrix; #[inline] @@ -295,7 +268,7 @@ impl SquareMatrix for RotationBase { } } -impl InversibleSquareMatrix for RotationBase { } +impl InversibleSquareMatrix for Rotation { } */ diff --git a/src/geometry/rotation_alias.rs b/src/geometry/rotation_alias.rs index 50523aa7..7e8edbaa 100644 --- a/src/geometry/rotation_alias.rs +++ b/src/geometry/rotation_alias.rs @@ -1,10 +1,6 @@ -use core::MatrixArray; use core::dimension::{U2, U3}; -use geometry::RotationBase; - -/// A D-dimensional rotation matrix. -pub type Rotation = RotationBase>; +use geometry::Rotation; /// A 2-dimensional rotation matrix. pub type Rotation2 = Rotation; diff --git a/src/geometry/rotation_construction.rs b/src/geometry/rotation_construction.rs index 50473d33..4eb526e5 100644 --- a/src/geometry/rotation_construction.rs +++ b/src/geometry/rotation_construction.rs @@ -2,28 +2,25 @@ use num::{Zero, One}; use alga::general::{ClosedAdd, ClosedMul}; -use core::{SquareMatrix, Scalar}; +use core::{DefaultAllocator, MatrixN, Scalar}; use core::dimension::DimName; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::allocator::Allocator; -use geometry::RotationBase; +use geometry::Rotation; -impl RotationBase +impl Rotation where N: Scalar + Zero + One, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { /// Creates a new square identity rotation of the given `dimension`. #[inline] - pub fn identity() -> RotationBase { - Self::from_matrix_unchecked(SquareMatrix::::identity()) + pub fn identity() -> Rotation { + Self::from_matrix_unchecked(MatrixN::::identity()) } } -impl One for RotationBase +impl One for Rotation where N: Scalar + Zero + One + ClosedAdd + ClosedMul, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + DefaultAllocator: Allocator { #[inline] fn one() -> Self { Self::identity() diff --git a/src/geometry/rotation_conversion.rs b/src/geometry/rotation_conversion.rs index fc1c8be8..df839062 100644 --- a/src/geometry/rotation_conversion.rs +++ b/src/geometry/rotation_conversion.rs @@ -3,178 +3,186 @@ use num::Zero; use alga::general::{Real, SubsetOf, SupersetOf}; use alga::linear::Rotation as AlgaRotation; -use core::{Matrix, SquareMatrix}; -use core::dimension::{DimName, DimNameSum, DimNameAdd, U1, U3, U4}; -use core::storage::OwnedStorage; -use core::allocator::{OwnedAllocator, Allocator}; +use core::{DefaultAllocator, MatrixN}; +use core::dimension::{DimName, DimNameSum, DimNameAdd, DimMin, U1}; +use core::allocator::Allocator; -use geometry::{PointBase, TranslationBase, RotationBase, UnitQuaternionBase, OwnedUnitQuaternionBase, IsometryBase, - SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; +use geometry::{Point, Translation, Rotation, UnitQuaternion, UnitComplex, Isometry, + Similarity, Transform, SuperTCategoryOf, TAffine, + Rotation2, Rotation3}; /* * This file provides the following conversions: * ============================================= * - * RotationBase -> RotationBase + * Rotation -> Rotation * Rotation3 -> UnitQuaternion - * RotationBase -> IsometryBase - * RotationBase -> SimilarityBase - * RotationBase -> TransformBase - * RotationBase -> Matrix (homogeneous) + * Rotation2 -> UnitComplex + * Rotation -> Isometry + * Rotation -> Similarity + * Rotation -> Transform + * Rotation -> Matrix (homogeneous) */ -impl SubsetOf> for RotationBase +impl SubsetOf> for Rotation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> RotationBase { - RotationBase::from_matrix_unchecked(self.matrix().to_superset()) + fn to_superset(&self) -> Rotation { + Rotation::from_matrix_unchecked(self.matrix().to_superset()) } #[inline] - fn is_in_subset(rot: &RotationBase) -> bool { - ::is_convertible::<_, Matrix>(rot.matrix()) + fn is_in_subset(rot: &Rotation) -> bool { + ::is_convertible::<_, MatrixN>(rot.matrix()) } #[inline] - unsafe fn from_superset_unchecked(rot: &RotationBase) -> Self { - RotationBase::from_matrix_unchecked(rot.matrix().to_subset_unchecked()) + unsafe fn from_superset_unchecked(rot: &Rotation) -> Self { + Rotation::from_matrix_unchecked(rot.matrix().to_subset_unchecked()) } } -impl SubsetOf> for RotationBase +impl SubsetOf> for Rotation3 where N1: Real, - N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator + - Allocator + - Allocator, - SB::Alloc: OwnedAllocator + - Allocator { + N2: Real + SupersetOf { #[inline] - fn to_superset(&self) -> UnitQuaternionBase { - let q = OwnedUnitQuaternionBase::::from_rotation_matrix(self); + fn to_superset(&self) -> UnitQuaternion { + let q = UnitQuaternion::::from_rotation_matrix(self); q.to_superset() } #[inline] - fn is_in_subset(q: &UnitQuaternionBase) -> bool { - ::is_convertible::<_, OwnedUnitQuaternionBase>(q) + fn is_in_subset(q: &UnitQuaternion) -> bool { + ::is_convertible::<_, UnitQuaternion>(q) } #[inline] - unsafe fn from_superset_unchecked(q: &UnitQuaternionBase) -> Self { - let q: OwnedUnitQuaternionBase = ::convert_ref_unchecked(q); + unsafe fn from_superset_unchecked(q: &UnitQuaternion) -> Self { + let q: UnitQuaternion = ::convert_ref_unchecked(q); + q.to_rotation_matrix() + } +} + +impl SubsetOf> for Rotation2 + where N1: Real, + N2: Real + SupersetOf { + #[inline] + fn to_superset(&self) -> UnitComplex { + let q = UnitComplex::::from_rotation_matrix(self); + q.to_superset() + } + + #[inline] + fn is_in_subset(q: &UnitComplex) -> bool { + ::is_convertible::<_, UnitComplex>(q) + } + + #[inline] + unsafe fn from_superset_unchecked(q: &UnitComplex) -> Self { + let q: UnitComplex = ::convert_ref_unchecked(q); q.to_rotation_matrix() } } -impl SubsetOf> for RotationBase + +impl SubsetOf> for Rotation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - R: AlgaRotation> + SupersetOf>, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R: AlgaRotation> + SupersetOf>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> IsometryBase { - IsometryBase::from_parts(TranslationBase::identity(), ::convert_ref(self)) + fn to_superset(&self) -> Isometry { + Isometry::from_parts(Translation::identity(), ::convert_ref(self)) } #[inline] - fn is_in_subset(iso: &IsometryBase) -> bool { + fn is_in_subset(iso: &Isometry) -> bool { iso.translation.vector.is_zero() } #[inline] - unsafe fn from_superset_unchecked(iso: &IsometryBase) -> Self { + unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { ::convert_ref_unchecked(&iso.rotation) } } -impl SubsetOf> for RotationBase +impl SubsetOf> for Rotation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - R: AlgaRotation> + SupersetOf>, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R: AlgaRotation> + SupersetOf>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> SimilarityBase { - SimilarityBase::from_parts(TranslationBase::identity(), ::convert_ref(self), N2::one()) + fn to_superset(&self) -> Similarity { + Similarity::from_parts(Translation::identity(), ::convert_ref(self), N2::one()) } #[inline] - fn is_in_subset(sim: &SimilarityBase) -> bool { + fn is_in_subset(sim: &Similarity) -> bool { sim.isometry.translation.vector.is_zero() && sim.scaling() == N2::one() } #[inline] - unsafe fn from_superset_unchecked(sim: &SimilarityBase) -> Self { + unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { ::convert_ref_unchecked(&sim.isometry.rotation) } } -impl SubsetOf> for RotationBase +impl SubsetOf> for Rotation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, C: SuperTCategoryOf, - D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator, DimNameSum>, - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + - Allocator { + D: DimNameAdd + + DimMin, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator + + Allocator + + Allocator, DimNameSum> + + Allocator, DimNameSum> + + Allocator<(usize, usize), D> { // needed by .is_special_orthogonal() #[inline] - fn to_superset(&self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] - fn is_in_subset(t: &TransformBase) -> bool { + fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] - unsafe fn from_superset_unchecked(t: &TransformBase) -> Self { + unsafe fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } -impl SubsetOf, SB>> for RotationBase +impl SubsetOf>> for Rotation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, - D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator, DimNameSum>, - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + - Allocator { + D: DimNameAdd + + DimMin, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator + + Allocator + + Allocator, DimNameSum> + + Allocator, DimNameSum> + + Allocator<(usize, usize), D> { // needed by .is_special_orthogonal() #[inline] - fn to_superset(&self) -> SquareMatrix, SB> { + fn to_superset(&self) -> MatrixN> { self.to_homogeneous().to_superset() } #[inline] - fn is_in_subset(m: &SquareMatrix, SB>) -> bool { + fn is_in_subset(m: &MatrixN>) -> bool { let rot = m.fixed_slice::(0, 0); let bottom = m.fixed_slice::(D::dim(), 0); @@ -188,7 +196,7 @@ impl SubsetOf, SB>> for Ro } #[inline] - unsafe fn from_superset_unchecked(m: &SquareMatrix, SB>) -> Self { + unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let r = m.fixed_slice::(0, 0); Self::from_matrix_unchecked(::convert_unchecked(r.into_owned())) } diff --git a/src/geometry/rotation_ops.rs b/src/geometry/rotation_ops.rs index ca9b907b..53236b64 100644 --- a/src/geometry/rotation_ops.rs +++ b/src/geometry/rotation_ops.rs @@ -4,33 +4,34 @@ * * Index<(usize, usize)> * - * RotationBase × RotationBase - * RotationBase ÷ RotationBase - * RotationBase × Matrix - * Matrix × RotationBase - * Matrix ÷ RotationBase - * RotationBase × PointBase + * Rotation × Rotation + * Rotation ÷ Rotation + * Rotation × Matrix + * Matrix × Rotation + * Matrix ÷ Rotation + * Rotation × Point * * - * RotationBase ×= RotationBase - * Matrix ×= RotationBase + * Rotation ×= Rotation + * Matrix ×= Rotation */ use std::ops::{Mul, MulAssign, Div, DivAssign, Index}; -use num::Zero; +use num::{Zero, One}; use alga::general::{ClosedMul, ClosedAdd}; -use core::{Scalar, Matrix, MatrixMul}; +use core::{DefaultAllocator, Scalar, Matrix, MatrixMN}; use core::dimension::{Dim, DimName, U1}; use core::constraint::{ShapeConstraint, AreMultipliable}; -use core::storage::{OwnedStorage, Storage}; -use core::allocator::{OwnedAllocator, Allocator}; +use core::storage::Storage; +use core::allocator::Allocator; -use geometry::{PointBase, PointMul, RotationBase, OwnedRotation}; +use geometry::{Point, Rotation}; -impl> Index<(usize, usize)> for RotationBase { +impl Index<(usize, usize)> for Rotation + where DefaultAllocator: Allocator { type Output = N; #[inline] @@ -39,62 +40,62 @@ impl> Index<(usize, usize)> for Rotat } } -// RotationBase × RotationBase +// Rotation × Rotation md_impl_all!( Mul, mul; (D, D), (D, D) for D: DimName; - self: RotationBase, right: RotationBase, Output = OwnedRotation; - [val val] => RotationBase::from_matrix_unchecked(self.unwrap() * right.unwrap()); - [ref val] => RotationBase::from_matrix_unchecked(self.matrix() * right.unwrap()); - [val ref] => RotationBase::from_matrix_unchecked(self.unwrap() * right.matrix()); - [ref ref] => RotationBase::from_matrix_unchecked(self.matrix() * right.matrix()); + self: Rotation, right: Rotation, Output = Rotation; + [val val] => Rotation::from_matrix_unchecked(self.unwrap() * right.unwrap()); + [ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.unwrap()); + [val ref] => Rotation::from_matrix_unchecked(self.unwrap() * right.matrix()); + [ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix()); ); -// RotationBase ÷ RotationBase +// Rotation ÷ Rotation // FIXME: instead of calling inverse explicitely, could we just add a `mul_tr` or `mul_inv` method? md_impl_all!( Div, div; (D, D), (D, D) for D: DimName; - self: RotationBase, right: RotationBase, Output = OwnedRotation; + self: Rotation, right: Rotation, Output = Rotation; [val val] => self * right.inverse(); [ref val] => self * right.inverse(); [val ref] => self * right.inverse(); [ref ref] => self * right.inverse(); ); -// RotationBase × Matrix +// Rotation × Matrix md_impl_all!( Mul, mul; - (D1, D1), (R2, C2) for D1: DimName, R2: Dim, C2: Dim - where SA::Alloc: Allocator + (D1, D1), (R2, C2) for D1: DimName, R2: Dim, C2: Dim, SB: Storage + where DefaultAllocator: Allocator where ShapeConstraint: AreMultipliable; - self: RotationBase, right: Matrix, Output = MatrixMul; + self: Rotation, right: Matrix, Output = MatrixMN; [val val] => self.unwrap() * right; [ref val] => self.matrix() * right; [val ref] => self.unwrap() * right; [ref ref] => self.matrix() * right; ); -// Matrix × RotationBase +// Matrix × Rotation md_impl_all!( Mul, mul; - (R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName - where SA::Alloc: Allocator - where ShapeConstraint: AreMultipliable; - self: Matrix, right: RotationBase, Output = MatrixMul; + (R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName, SA: Storage + where DefaultAllocator: Allocator + where ShapeConstraint: AreMultipliable; + self: Matrix, right: Rotation, Output = MatrixMN; [val val] => self * right.unwrap(); [ref val] => self * right.unwrap(); [val ref] => self * right.matrix(); [ref ref] => self * right.matrix(); ); -// Matrix ÷ RotationBase +// Matrix ÷ Rotation md_impl_all!( Div, div; - (R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName - where SA::Alloc: Allocator + (R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName, SA: Storage + where DefaultAllocator: Allocator where ShapeConstraint: AreMultipliable; - self: Matrix, right: RotationBase, Output = MatrixMul; + self: Matrix, right: Rotation, Output = MatrixMN; [val val] => self * right.inverse(); [ref val] => self * right.inverse(); [val ref] => self * right.inverse(); @@ -102,15 +103,15 @@ md_impl_all!( ); -// RotationBase × PointBase +// Rotation × Point // FIXME: we don't handle properly non-zero origins here. Do we want this to be the intended // behavior? md_impl_all!( Mul, mul; (D, D), (D, U1) for D: DimName - where SA::Alloc: Allocator - where ShapeConstraint: AreMultipliable; - self: RotationBase, right: PointBase, Output = PointMul; + where DefaultAllocator: Allocator + where ShapeConstraint: AreMultipliable; + self: Rotation, right: Point, Output = Point; [val val] => self.unwrap() * right; [ref val] => self.matrix() * right; [val ref] => self.unwrap() * right; @@ -118,13 +119,13 @@ md_impl_all!( ); -// RotationBase ×= RotationBase +// Rotation ×= Rotation // FIXME: try not to call `inverse()` explicitly. md_assign_impl_all!( MulAssign, mul_assign; (D, D), (D, D) for D: DimName; - self: RotationBase, right: RotationBase; + self: Rotation, right: Rotation; [val] => unsafe { self.matrix_mut().mul_assign(right.unwrap()) }; [ref] => unsafe { self.matrix_mut().mul_assign(right.matrix()) }; ); @@ -133,12 +134,12 @@ md_assign_impl_all!( md_assign_impl_all!( DivAssign, div_assign; (D, D), (D, D) for D: DimName; - self: RotationBase, right: RotationBase; + self: Rotation, right: Rotation; [val] => unsafe { self.matrix_mut().mul_assign(right.inverse().unwrap()) }; [ref] => unsafe { self.matrix_mut().mul_assign(right.inverse().matrix()) }; ); -// Matrix *= RotationBase +// Matrix *= Rotation // FIXME: try not to call `inverse()` explicitly. // FIXME: this shares the same limitations as for the current impl. of MulAssign for matrices. // (In particular the number of matrix column must be equal to the number of rotation columns, @@ -147,7 +148,7 @@ md_assign_impl_all!( md_assign_impl_all!( MulAssign, mul_assign; (R1, C1), (C1, C1) for R1: DimName, C1: DimName; - self: Matrix, right: RotationBase; + self: MatrixMN, right: Rotation; [val] => self.mul_assign(right.unwrap()); [ref] => self.mul_assign(right.matrix()); ); @@ -156,7 +157,7 @@ md_assign_impl_all!( md_assign_impl_all!( DivAssign, div_assign; (R1, C1), (C1, C1) for R1: DimName, C1: DimName; - self: Matrix, right: RotationBase; + self: MatrixMN, right: Rotation; [val] => self.mul_assign(right.inverse().unwrap()); [ref] => self.mul_assign(right.inverse().matrix()); ); diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 9c0f13bb..abe3066f 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -1,39 +1,37 @@ #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; use std::ops::Neg; use num::Zero; use rand::{Rand, Rng}; use alga::general::Real; -use core::{Unit, ColumnVector, SquareMatrix, OwnedSquareMatrix, OwnedColumnVector, Vector3}; +use core::{Unit, Vector, MatrixN, VectorN, Vector3}; use core::dimension::{U1, U2, U3}; -use core::storage::{Storage, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; +use core::storage::Storage; -use geometry::{RotationBase, OwnedRotation, UnitComplex}; +use geometry::{UnitComplex, Rotation2, Rotation3}; /* * - * 2D RotationBase matrix. + * 2D Rotation matrix. * */ -impl RotationBase -where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rotation2 { /// Builds a 2 dimensional rotation matrix from an angle in radian. pub fn new(angle: N) -> Self { let (sia, coa) = angle.sin_cos(); - Self::from_matrix_unchecked(SquareMatrix::::new(coa, -sia, sia, coa)) + Self::from_matrix_unchecked(MatrixN::::new(coa, -sia, sia, coa)) } /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector. /// /// Equivalent to `Self::new(axisangle[0])`. #[inline] - pub fn from_scaled_axis>(axisangle: ColumnVector) -> Self { + pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::new(axisangle[0]) } @@ -41,25 +39,23 @@ where N: Real, /// /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. #[inline] - pub fn rotation_between(a: &ColumnVector, b: &ColumnVector) -> Self - where SB: Storage, - SC: Storage { + pub fn rotation_between(a: &Vector, b: &Vector) -> Self + where SB: Storage, + SC: Storage { ::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix()) } /// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// direction, raised to the power `s`. #[inline] - pub fn scaled_rotation_between(a: &ColumnVector, b: &ColumnVector, s: N) -> Self - where SB: Storage, - SC: Storage { + pub fn scaled_rotation_between(a: &Vector, b: &Vector, s: N) -> Self + where SB: Storage, + SC: Storage { ::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) } } -impl RotationBase -where N: Real, - S: Storage { +impl Rotation2 { /// The rotation angle. #[inline] pub fn angle(&self) -> N { @@ -68,7 +64,7 @@ where N: Real, /// The rotation angle needed to make `self` and `other` coincide. #[inline] - pub fn angle_to>(&self, other: &RotationBase) -> N { + pub fn angle_to(&self, other: &Rotation2) -> N { self.rotation_to(other).angle() } @@ -76,30 +72,25 @@ where N: Real, /// /// The result is such that: `self.rotation_to(other) * self == other`. #[inline] - pub fn rotation_to(&self, other: &RotationBase) -> OwnedRotation - where SB: Storage { + pub fn rotation_to(&self, other: &Rotation2) -> Rotation2 { other * self.inverse() } /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// of `self` multiplied by `n`. #[inline] - pub fn powf(&self, n: N) -> OwnedRotation { - OwnedRotation::<_, _, S::Alloc>::new(self.angle() * n) + pub fn powf(&self, n: N) -> Rotation2 { + Self::new(self.angle() * n) } /// The rotation angle returned as a 1-dimensional vector. #[inline] - pub fn scaled_axis(&self) -> OwnedColumnVector - where S::Alloc: Allocator { - ColumnVector::<_, U1, _>::new(self.angle()) + pub fn scaled_axis(&self) -> VectorN { + Vector::<_, U1, _>::new(self.angle()) } } -impl Rand for RotationBase -where N: Real + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for Rotation2 { #[inline] fn rand(rng: &mut R) -> Self { Self::new(rng.gen()) @@ -107,10 +98,8 @@ where N: Real + Rand, } #[cfg(feature="arbitrary")] -impl Arbitrary for RotationBase -where N: Real + Arbitrary, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { +impl Arbitrary for Rotation2 +where Owned: Send { #[inline] fn arbitrary(g: &mut G) -> Self { Self::new(N::arbitrary(g)) @@ -120,32 +109,29 @@ where N: Real + Arbitrary, /* * - * 3D RotationBase matrix. + * 3D Rotation matrix. * */ -impl RotationBase -where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { - +impl Rotation3 { /// 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 new>(axisangle: ColumnVector) -> Self { - let (axis, angle) = Unit::new_and_get(axisangle.into_owned()); + pub fn new>(axisangle: Vector) -> Self { + let axisangle = axisangle.into_owned(); + let (axis, angle) = Unit::new_and_get(axisangle); Self::from_axis_angle(&axis, angle) } /// Builds a 3D rotation matrix from an axis scaled by the rotation angle. - pub fn from_scaled_axis>(axisangle: ColumnVector) -> Self { + pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::new(axisangle) } /// Builds a 3D rotation matrix from an axis and a rotation angle. - pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self - where SB: Storage { + pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self + where SB: Storage { if angle.is_zero() { Self::identity() } @@ -160,7 +146,7 @@ where N: Real, let one_m_cos = N::one() - cos; Self::from_matrix_unchecked( - SquareMatrix::::new( + MatrixN::::new( (sqx + (N::one() - sqx) * cos), (ux * uy * one_m_cos - uz * sin), (ux * uz * one_m_cos + uy * sin), @@ -184,7 +170,7 @@ where N: Real, let (sy, cy) = yaw.sin_cos(); Self::from_matrix_unchecked( - SquareMatrix::::new( + MatrixN::::new( cy * cp, cy * sp * sr - sy * cr, cy * sp * cr + sy * sr, sy * cp, sy * sp * sr + cy * cr, sy * sp * cr - cy * sr, -sp, cp * sr, cp * cr) @@ -202,14 +188,14 @@ where N: Real, /// collinear /// to `dir`. Non-collinearity is not checked. #[inline] - pub fn new_observer_frame(dir: &ColumnVector, up: &ColumnVector) -> Self - where SB: Storage, - SC: Storage { + pub fn new_observer_frame(dir: &Vector, up: &Vector) -> Self + where SB: Storage, + SC: Storage { let zaxis = dir.normalize(); let xaxis = up.cross(&zaxis).normalize(); let yaxis = zaxis.cross(&xaxis).normalize(); - Self::from_matrix_unchecked(SquareMatrix::::new( + Self::from_matrix_unchecked(MatrixN::::new( xaxis.x, yaxis.x, zaxis.x, xaxis.y, yaxis.y, zaxis.y, xaxis.z, yaxis.z, zaxis.z)) @@ -227,9 +213,9 @@ where N: Real, /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_rh(dir: &ColumnVector, up: &ColumnVector) -> Self - where SB: Storage, - SC: Storage { + pub fn look_at_rh(dir: &Vector, up: &Vector) -> Self + where SB: Storage, + SC: Storage { Self::new_observer_frame(&dir.neg(), up).inverse() } @@ -244,9 +230,9 @@ where N: Real, /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_lh(dir: &ColumnVector, up: &ColumnVector) -> Self - where SB: Storage, - SC: Storage { + pub fn look_at_lh(dir: &Vector, up: &Vector) -> Self + where SB: Storage, + SC: Storage { Self::new_observer_frame(dir, up).inverse() } @@ -254,20 +240,20 @@ where N: Real, /// /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. #[inline] - pub fn rotation_between(a: &ColumnVector, b: &ColumnVector) -> Option - where SB: Storage, - SC: Storage { + pub fn rotation_between(a: &Vector, b: &Vector) -> Option + where SB: Storage, + SC: Storage { Self::scaled_rotation_between(a, b, N::one()) } /// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// direction, raised to the power `s`. #[inline] - pub fn scaled_rotation_between(a: &ColumnVector, b: &ColumnVector, n: N) + pub fn scaled_rotation_between(a: &Vector, b: &Vector, n: N) -> Option - where SB: Storage, - SC: Storage { - // FIXME: code duplication with RotationBase. + where SB: Storage, + SC: Storage { + // FIXME: code duplication with Rotation. if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) { let c = na.cross(&nb); @@ -287,26 +273,17 @@ where N: Real, Some(Self::identity()) } -} -impl RotationBase -where N: Real, - S: Storage { /// The rotation angle. #[inline] pub fn angle(&self) -> N { ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) / ::convert(2.0)).acos() } -} -impl RotationBase -where N: Real, - S: Storage, - S::Alloc: Allocator { /// The rotation axis. Returns `None` if the rotation angle is zero or PI. #[inline] - pub fn axis(&self) -> Option>> { - let axis = OwnedColumnVector::::new( + pub fn axis(&self) -> Option>> { + let axis = VectorN::::new( self.matrix()[(2, 1)] - self.matrix()[(1, 2)], self.matrix()[(0, 2)] - self.matrix()[(2, 0)], self.matrix()[(1, 0)] - self.matrix()[(0, 1)]); @@ -316,18 +293,18 @@ where N: Real, /// The rotation axis multiplied by the rotation angle. #[inline] - pub fn scaled_axis(&self) -> OwnedColumnVector { + pub fn scaled_axis(&self) -> Vector3 { if let Some(axis) = self.axis() { axis.unwrap() * self.angle() } else { - ColumnVector::zero() + Vector::zero() } } /// The rotation angle needed to make `self` and `other` coincide. #[inline] - pub fn angle_to>(&self, other: &RotationBase) -> N { + pub fn angle_to(&self, other: &Rotation3) -> N { self.rotation_to(other).angle() } @@ -335,47 +312,40 @@ where N: Real, /// /// The result is such that: `self.rotation_to(other) * self == other`. #[inline] - pub fn rotation_to(&self, other: &RotationBase) -> OwnedRotation - where SB: Storage { + pub fn rotation_to(&self, other: &Rotation3) -> Rotation3 { other * self.inverse() } /// Raise the quaternion to a given floating power, i.e., returns the rotation with the same /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`. #[inline] - pub fn powf(&self, n: N) -> OwnedRotation { + pub fn powf(&self, n: N) -> Rotation3 { if let Some(axis) = self.axis() { - OwnedRotation::<_, _, S::Alloc>::from_axis_angle(&axis, self.angle() * n) + Self::from_axis_angle(&axis, self.angle() * n) } else if self.matrix()[(0, 0)] < N::zero() { - let minus_id = OwnedSquareMatrix::::from_diagonal_element(-N::one()); - OwnedRotation::<_, _, S::Alloc>::from_matrix_unchecked(minus_id) + let minus_id = MatrixN::::from_diagonal_element(-N::one()); + Self::from_matrix_unchecked(minus_id) } else { - OwnedRotation::<_, _, S::Alloc>::identity() + Self::identity() } } } -impl Rand for RotationBase -where N: Real + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator + - Allocator { +impl Rand for Rotation3 { #[inline] fn rand(rng: &mut R) -> Self { - Self::new(Vector3::rand(rng)) + Self::new(VectorN::rand(rng)) } } #[cfg(feature="arbitrary")] -impl Arbitrary for RotationBase -where N: Real + Arbitrary, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator + - Allocator { +impl Arbitrary for Rotation3 +where Owned: Send, + Owned: Send { #[inline] fn arbitrary(g: &mut G) -> Self { - Self::new(Vector3::arbitrary(g)) + Self::new(VectorN::arbitrary(g)) } } diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 43e4ec1f..00d3220a 100644 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -1,47 +1,80 @@ use std::fmt; +use std::hash; use approx::ApproxEq; -use alga::general::{ClosedMul, Real, SubsetOf}; +#[cfg(feature = "serde-serialize")] +use serde; + +use alga::general::{Real, SubsetOf}; use alga::linear::Rotation; -use core::{Scalar, OwnedSquareMatrix}; +use core::{DefaultAllocator, MatrixN}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; -use core::storage::{Storage, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; -use geometry::{PointBase, TranslationBase, IsometryBase}; +use core::storage::Owned; +use core::allocator::Allocator; +use geometry::{Point, Translation, Isometry}; -/// A similarity that uses a data storage deduced from the allocator `A`. -pub type OwnedSimilarityBase = - SimilarityBase>::Buffer, R>; - /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. #[repr(C)] -#[derive(Hash, Debug, Clone, Copy)] +#[derive(Debug)] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -pub struct SimilarityBase { +#[cfg_attr(feature = "serde-serialize", + serde(bound( + serialize = "N: serde::Serialize, + R: serde::Serialize, + DefaultAllocator: Allocator, + Owned: serde::Serialize")))] +#[cfg_attr(feature = "serde-serialize", + serde(bound( + deserialize = "N: serde::Deserialize<'de>, + R: serde::Deserialize<'de>, + DefaultAllocator: Allocator, + Owned: serde::Deserialize<'de>")))] +pub struct Similarity + where DefaultAllocator: Allocator { /// The part of this similarity that does not include the scaling factor. - pub isometry: IsometryBase, + pub isometry: Isometry, scaling: N } -impl SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl hash::Hash for Similarity + where DefaultAllocator: Allocator, + Owned: hash::Hash { + fn hash(&self, state: &mut H) { + self.isometry.hash(state); + self.scaling.hash(state); + } +} + +impl> + Copy> Copy for Similarity + where DefaultAllocator: Allocator, + Owned: Copy { +} + +impl> + Clone> Clone for Similarity + where DefaultAllocator: Allocator { + #[inline] + fn clone(&self) -> Self { + Similarity::from_isometry(self.isometry.clone(), self.scaling) + } +} + +impl Similarity + where R: Rotation>, + DefaultAllocator: Allocator { /// Creates a new similarity from its rotational and translational parts. #[inline] - pub fn from_parts(translation: TranslationBase, rotation: R, scaling: N) -> SimilarityBase { - SimilarityBase::from_isometry(IsometryBase::from_parts(translation, rotation), scaling) + pub fn from_parts(translation: Translation, rotation: R, scaling: N) -> Similarity { + Similarity::from_isometry(Isometry::from_parts(translation, rotation), scaling) } /// Creates a new similarity from its rotational and translational parts. #[inline] - pub fn from_isometry(isometry: IsometryBase, scaling: N) -> SimilarityBase { + pub fn from_isometry(isometry: Isometry, scaling: N) -> Similarity { assert!(!relative_eq!(scaling, N::zero()), "The scaling factor must not be zero."); - SimilarityBase { + Similarity { isometry: isometry, scaling: scaling } @@ -49,13 +82,13 @@ impl SimilarityBase /// Creates a new similarity that applies only a scaling factor. #[inline] - pub fn from_scaling(scaling: N) -> SimilarityBase { - Self::from_isometry(IsometryBase::identity(), scaling) + pub fn from_scaling(scaling: N) -> Similarity { + Self::from_isometry(Isometry::identity(), scaling) } /// Inverts `self`. #[inline] - pub fn inverse(&self) -> SimilarityBase { + pub fn inverse(&self) -> Similarity { let mut res = self.clone(); res.inverse_mut(); res @@ -77,6 +110,12 @@ impl SimilarityBase self.scaling = scaling; } + /// The scaling factor of this similarity transformation. + #[inline] + pub fn scaling(&self) -> N { + self.scaling + } + /// The similarity transformation that applies a scaling factor `scaling` before `self`. #[inline] pub fn prepend_scaling(&self, scaling: N) -> Self { @@ -91,7 +130,7 @@ impl SimilarityBase assert!(!relative_eq!(scaling, N::zero()), "The similarity scaling factor must not be zero."); Self::from_parts( - TranslationBase::from_vector(&self.isometry.translation.vector * scaling), + Translation::from_vector(&self.isometry.translation.vector * scaling), self.isometry.rotation.clone(), self.scaling * scaling) } @@ -115,7 +154,7 @@ impl SimilarityBase /// Appends to `self` the given translation in-place. #[inline] - pub fn append_translation_mut(&mut self, t: &TranslationBase) { + pub fn append_translation_mut(&mut self, t: &Translation) { self.isometry.append_translation_mut(t) } @@ -128,7 +167,7 @@ impl SimilarityBase /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that /// lets `p` invariant. #[inline] - pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &PointBase) { + pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point) { self.isometry.append_rotation_wrt_point_mut(r, p) } @@ -145,16 +184,14 @@ impl SimilarityBase // and makes it harde to use it, e.g., for Transform × Isometry implementation. // This is OK since all constructors of the isometry enforce the Rotation bound already (and // explicit struct construction is prevented by the private scaling factor). -impl SimilarityBase - where N: Scalar + ClosedMul, - S: Storage { +impl Similarity + where DefaultAllocator: Allocator { /// Converts this similarity into its equivalent homogeneous transformation matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix, S::Alloc> + pub fn to_homogeneous(&self) -> MatrixN> where D: DimNameAdd, - R: SubsetOf, S::Alloc>>, - S::Alloc: Allocator + - Allocator, DimNameSum> { + R: SubsetOf>>, + DefaultAllocator: Allocator, DimNameSum> { let mut res = self.isometry.to_homogeneous(); for e in res.fixed_slice_mut::(0, 0).iter_mut() { @@ -163,38 +200,26 @@ impl SimilarityBase res } - - /// The scaling factor of this similarity transformation. - #[inline] - pub fn scaling(&self) -> N { - self.scaling - } } -impl Eq for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation> + Eq, - S::Alloc: OwnedAllocator { +impl Eq for Similarity + where R: Rotation> + Eq, + DefaultAllocator: Allocator { } -impl PartialEq for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation> + PartialEq, - S::Alloc: OwnedAllocator { +impl PartialEq for Similarity + where R: Rotation> + PartialEq, + DefaultAllocator: Allocator { #[inline] - fn eq(&self, right: &SimilarityBase) -> bool { + fn eq(&self, right: &Similarity) -> bool { self.isometry == right.isometry && self.scaling == right.scaling } } -impl ApproxEq for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation> + ApproxEq, - S::Alloc: OwnedAllocator, +impl ApproxEq for Similarity + where R: Rotation> + ApproxEq, + DefaultAllocator: Allocator, N::Epsilon: Copy { type Epsilon = N::Epsilon; @@ -231,46 +256,16 @@ impl ApproxEq for SimilarityBase * Display * */ -impl fmt::Display for SimilarityBase +impl fmt::Display for Similarity where N: Real + fmt::Display, - S: OwnedStorage, - R: Rotation> + fmt::Display, - S::Alloc: OwnedAllocator + Allocator { + R: Rotation> + fmt::Display, + DefaultAllocator: Allocator + Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "SimilarityBase {{")); + try!(writeln!(f, "Similarity {{")); try!(write!(f, "{:.*}", precision, self.isometry)); try!(write!(f, "Scaling: {:.*}", precision, self.scaling)); writeln!(f, "}}") } } - -/* -// /* -// * -// * ToHomogeneous -// * -// */ -// impl ToHomogeneous<$homogeneous> for $t { -// #[inline] -// fn to_homogeneous(&self) -> $homogeneous { -// self.vector.to_homogeneous() -// } -// } - - -// /* -// * -// * Absolute -// * -// */ -// impl Absolute for $t { -// type AbsoluteValue = $submatrix; -// -// #[inline] -// fn abs(m: &$t) -> $submatrix { -// Absolute::abs(&m.submatrix) -// } -// } -*/ diff --git a/src/geometry/similarity_alga.rs b/src/geometry/similarity_alga.rs index 5959d6f1..c60eb621 100644 --- a/src/geometry/similarity_alga.rs +++ b/src/geometry/similarity_alga.rs @@ -1,13 +1,13 @@ use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Real, Inverse, Multiplicative, Identity}; -use alga::linear::{Transformation, AffineTransformation, Rotation, Similarity, ProjectiveTransformation}; +use alga::linear::{Transformation, AffineTransformation, Rotation, ProjectiveTransformation}; +use alga::linear::Similarity as AlgaSimilarity; -use core::ColumnVector; -use core::dimension::{DimName, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::{DefaultAllocator, VectorN}; +use core::dimension::DimName; +use core::allocator::Allocator; -use geometry::{SimilarityBase, TranslationBase, PointBase}; +use geometry::{Similarity, Translation, Point}; /* @@ -15,22 +15,18 @@ use geometry::{SimilarityBase, TranslationBase, PointBase}; * Algebraic structures. * */ -impl Identity for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Identity for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] fn identity() -> Self { Self::identity() } } -impl Inverse for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Inverse for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] fn inverse(&self) -> Self { self.inverse() @@ -42,11 +38,9 @@ impl Inverse for SimilarityBase } } -impl AbstractMagma for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl AbstractMagma for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs @@ -55,11 +49,9 @@ impl AbstractMagma for SimilarityBase),* $(,)*) => {$( - impl $marker<$operator> for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { } + impl $marker<$operator> for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { } )*} ); @@ -76,49 +68,43 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl Transformation> for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] - fn transform_point(&self, pt: &PointBase) -> PointBase { + fn transform_point(&self, pt: &Point) -> Point { self * pt } #[inline] - fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn transform_vector(&self, v: &VectorN) -> VectorN { self * v } } -impl ProjectiveTransformation> for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl ProjectiveTransformation> for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { #[inline] - fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { + fn inverse_transform_point(&self, pt: &Point) -> Point { self.isometry.inverse_transform_point(pt) / self.scaling() } #[inline] - fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { self.isometry.inverse_transform_vector(v) / self.scaling() } } -impl AffineTransformation> for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl AffineTransformation> for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { type NonUniformScaling = N; type Rotation = R; - type Translation = TranslationBase; + type Translation = Translation; #[inline] - fn decompose(&self) -> (TranslationBase, R, N, R) { + fn decompose(&self) -> (Translation, R, N, R) { (self.isometry.translation.clone(), self.isometry.rotation.clone(), self.scaling(), R::identity()) } @@ -134,7 +120,7 @@ impl AffineTransformation> for Similarit #[inline] fn append_rotation(&self, r: &Self::Rotation) -> Self { - SimilarityBase::from_isometry(self.isometry.append_rotation(r), self.scaling()) + Similarity::from_isometry(self.isometry.append_rotation(r), self.scaling()) } #[inline] @@ -153,22 +139,20 @@ impl AffineTransformation> for Similarit } #[inline] - fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &PointBase) -> Option { + fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &Point) -> Option { let mut res = self.clone(); res.append_rotation_wrt_point_mut(r, p); Some(res) } } -impl Similarity> for SimilarityBase - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { +impl AlgaSimilarity> for Similarity + where R: Rotation>, + DefaultAllocator: Allocator { type Scaling = N; #[inline] - fn translation(&self) -> TranslationBase { + fn translation(&self) -> Translation { self.isometry.translation() } diff --git a/src/geometry/similarity_alias.rs b/src/geometry/similarity_alias.rs index 3bf96e75..557b5db1 100644 --- a/src/geometry/similarity_alias.rs +++ b/src/geometry/similarity_alias.rs @@ -1,19 +1,15 @@ -use core::MatrixArray; -use core::dimension::{U1, U2, U3}; +use core::dimension::{U2, U3}; -use geometry::{Rotation, SimilarityBase, UnitQuaternion, UnitComplex}; - -/// A D-dimensional similarity. -pub type Similarity = SimilarityBase, Rotation>; +use geometry::{Similarity, UnitQuaternion, UnitComplex, Rotation2, Rotation3}; /// A 2-dimensional similarity. -pub type Similarity2 = SimilarityBase, UnitComplex>; +pub type Similarity2 = Similarity>; /// A 3-dimensional similarity. -pub type Similarity3 = SimilarityBase, UnitQuaternion>; +pub type Similarity3 = Similarity>; /// A 2-dimensional similarity using a rotation matrix for its rotation part. -pub type SimilarityMatrix2 = Similarity; +pub type SimilarityMatrix2 = Similarity>; /// A 3-dimensional similarity using a rotation matrix for its rotation part. -pub type SimilarityMatrix3 = Similarity; +pub type SimilarityMatrix3 = Similarity>; diff --git a/src/geometry/similarity_construction.rs b/src/geometry/similarity_construction.rs index d8f039f1..180f0cf3 100644 --- a/src/geometry/similarity_construction.rs +++ b/src/geometry/similarity_construction.rs @@ -1,5 +1,7 @@ #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; use num::One; use rand::{Rng, Rand}; @@ -7,32 +9,27 @@ use rand::{Rng, Rand}; use alga::general::Real; use alga::linear::Rotation as AlgaRotation; -use core::ColumnVector; -use core::dimension::{DimName, U1, U2, U3, U4}; -use core::allocator::{OwnedAllocator, Allocator}; -use core::storage::OwnedStorage; +use core::{DefaultAllocator, Vector2, Vector3}; +use core::dimension::{DimName, U2, U3}; +use core::allocator::Allocator; -use geometry::{PointBase, TranslationBase, RotationBase, SimilarityBase, - UnitComplex, UnitQuaternionBase, IsometryBase}; +use geometry::{Point, Translation, Similarity, UnitComplex, UnitQuaternion, Isometry, + Point3, Rotation2, Rotation3}; -impl SimilarityBase - where N: Real, - S: OwnedStorage, - R: AlgaRotation>, - S::Alloc: OwnedAllocator { +impl Similarity + where R: AlgaRotation>, + DefaultAllocator: Allocator { /// Creates a new identity similarity. #[inline] pub fn identity() -> Self { - Self::from_isometry(IsometryBase::identity(), N::one()) + Self::from_isometry(Isometry::identity(), N::one()) } } -impl One for SimilarityBase - where N: Real, - S: OwnedStorage, - R: AlgaRotation>, - S::Alloc: OwnedAllocator { +impl One for Similarity + where R: AlgaRotation>, + DefaultAllocator: Allocator { /// Creates a new identity similarity. #[inline] fn one() -> Self { @@ -40,11 +37,9 @@ impl One for SimilarityBase } } -impl Rand for SimilarityBase - where N: Real + Rand, - S: OwnedStorage, - R: AlgaRotation> + Rand, - S::Alloc: OwnedAllocator { +impl Rand for Similarity + where R: AlgaRotation> + Rand, + DefaultAllocator: Allocator { #[inline] fn rand(rng: &mut G) -> Self { let mut s = rng.gen(); @@ -56,26 +51,24 @@ impl Rand for SimilarityBase } } -impl SimilarityBase - where N: Real, - S: OwnedStorage, - R: AlgaRotation>, - S::Alloc: OwnedAllocator { +impl Similarity + where R: AlgaRotation>, + DefaultAllocator: Allocator { /// The similarity that applies tha scaling factor `scaling`, followed by the rotation `r` with /// its axis passing through the point `p`. #[inline] - pub fn rotation_wrt_point(r: R, p: PointBase, scaling: N) -> Self { + pub fn rotation_wrt_point(r: R, p: Point, scaling: N) -> Self { let shift = r.transform_vector(&-&p.coords); - Self::from_parts(TranslationBase::from_vector(shift + p.coords), r, scaling) + Self::from_parts(Translation::from_vector(shift + p.coords), r, scaling) } } #[cfg(feature = "arbitrary")] -impl Arbitrary for SimilarityBase +impl Arbitrary for Similarity where N: Real + Arbitrary + Send, - S: OwnedStorage + Send, - R: AlgaRotation> + Arbitrary + Send, - S::Alloc: OwnedAllocator { + R: AlgaRotation> + Arbitrary + Send, + DefaultAllocator: Allocator, + Owned: Send { #[inline] fn arbitrary(rng: &mut G) -> Self { let mut s = Arbitrary::arbitrary(rng); @@ -94,45 +87,31 @@ impl Arbitrary for SimilarityBase */ // 2D rotation. -impl SimilarityBase> - where N: Real, - S: OwnedStorage, - SR: OwnedStorage, - S::Alloc: OwnedAllocator, - SR::Alloc: OwnedAllocator { +impl Similarity> { /// Creates a new similarity from a translation and a rotation angle. #[inline] - pub fn new(translation: ColumnVector, angle: N, scaling: N) -> Self { - Self::from_parts(TranslationBase::from_vector(translation), RotationBase::::new(angle), scaling) + pub fn new(translation: Vector2, angle: N, scaling: N) -> Self { + Self::from_parts(Translation::from_vector(translation), Rotation2::new(angle), scaling) } } -impl SimilarityBase> - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Similarity> { /// Creates a new similarity from a translation and a rotation angle. #[inline] - pub fn new(translation: ColumnVector, angle: N, scaling: N) -> Self { - Self::from_parts(TranslationBase::from_vector(translation), UnitComplex::new(angle), scaling) + pub fn new(translation: Vector2, angle: N, scaling: N) -> Self { + Self::from_parts(Translation::from_vector(translation), UnitComplex::new(angle), scaling) } } // 3D rotation. macro_rules! similarity_construction_impl( - ($Rot: ty, $RotId: ident, $RRDim: ty, $RCDim: ty) => { - impl SimilarityBase - where N: Real, - S: OwnedStorage, - SR: OwnedStorage, - S::Alloc: OwnedAllocator, - SR::Alloc: OwnedAllocator + - Allocator { + ($Rot: ty) => { + impl Similarity { /// Creates a new similarity from a translation, rotation axis-angle, and scaling /// factor. #[inline] - pub fn new(translation: ColumnVector, axisangle: ColumnVector, scaling: N) -> Self { - Self::from_isometry(IsometryBase::<_, _, _, $Rot>::new(translation, axisangle), scaling) + pub fn new(translation: Vector3, axisangle: Vector3, scaling: N) -> Self { + Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling) } /// Creates an similarity that corresponds to the a scaling factor and a local frame of @@ -147,12 +126,12 @@ macro_rules! similarity_construction_impl( /// * up - Vertical direction. The only requirement of this parameter is to not be collinear /// to `eye - at`. Non-collinearity is not checked. #[inline] - pub fn new_observer_frame(eye: &PointBase, - target: &PointBase, - up: &ColumnVector, + pub fn new_observer_frame(eye: &Point3, + target: &Point3, + up: &Vector3, scaling: N) -> Self { - Self::from_isometry(IsometryBase::<_, _, _, $Rot>::new_observer_frame(eye, target, up), scaling) + Self::from_isometry(Isometry::<_, U3, $Rot>::new_observer_frame(eye, target, up), scaling) } /// Builds a right-handed look-at view matrix including scaling factor. @@ -166,12 +145,12 @@ macro_rules! similarity_construction_impl( /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_rh(eye: &PointBase, - target: &PointBase, - up: &ColumnVector, + pub fn look_at_rh(eye: &Point3, + target: &Point3, + up: &Vector3, scaling: N) -> Self { - Self::from_isometry(IsometryBase::<_, _, _, $Rot>::look_at_rh(eye, target, up), scaling) + Self::from_isometry(Isometry::<_, U3, $Rot>::look_at_rh(eye, target, up), scaling) } /// Builds a left-handed look-at view matrix including a scaling factor. @@ -185,16 +164,16 @@ macro_rules! similarity_construction_impl( /// * up - A vector approximately aligned with required the vertical axis. The only /// requirement of this parameter is to not be collinear to `target - eye`. #[inline] - pub fn look_at_lh(eye: &PointBase, - target: &PointBase, - up: &ColumnVector, + pub fn look_at_lh(eye: &Point3, + target: &Point3, + up: &Vector3, scaling: N) -> Self { - Self::from_isometry(IsometryBase::<_, _, _, $Rot>::look_at_lh(eye, target, up), scaling) + Self::from_isometry(Isometry::<_, _, $Rot>::look_at_lh(eye, target, up), scaling) } } } ); -similarity_construction_impl!(RotationBase, RotationBase, U3, U3); -similarity_construction_impl!(UnitQuaternionBase, UnitQuaternionBase, U4, U1); +similarity_construction_impl!(Rotation3); +similarity_construction_impl!(UnitQuaternion); diff --git a/src/geometry/similarity_conversion.rs b/src/geometry/similarity_conversion.rs index e629db77..8f5a675d 100644 --- a/src/geometry/similarity_conversion.rs +++ b/src/geometry/similarity_conversion.rs @@ -1,49 +1,46 @@ use alga::general::{Real, SubsetOf, SupersetOf}; use alga::linear::Rotation; -use core::{SquareMatrix, OwnedSquareMatrix}; -use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; +use core::{DefaultAllocator, MatrixN}; +use core::dimension::{DimName, DimNameAdd, DimNameSum, DimMin, U1}; +use core::allocator::Allocator; -use geometry::{PointBase, TranslationBase, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; +use geometry::{Point, Translation, Isometry, Similarity, Transform, SuperTCategoryOf, TAffine}; /* * This file provides the following conversions: * ============================================= * - * SimilarityBase -> SimilarityBase - * SimilarityBase -> TransformBase - * SimilarityBase -> Matrix (homogeneous) + * Similarity -> Similarity + * Similarity -> Transform + * Similarity -> Matrix (homogeneous) */ -impl SubsetOf> for SimilarityBase +impl SubsetOf> for Similarity where N1: Real + SubsetOf, N2: Real + SupersetOf, - R1: Rotation> + SubsetOf, - R2: Rotation>, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R1: Rotation> + SubsetOf, + R2: Rotation>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> SimilarityBase { - SimilarityBase::from_isometry( + fn to_superset(&self) -> Similarity { + Similarity::from_isometry( self.isometry.to_superset(), self.scaling().to_superset() ) } #[inline] - fn is_in_subset(sim: &SimilarityBase) -> bool { - ::is_convertible::<_, IsometryBase>(&sim.isometry) && + fn is_in_subset(sim: &Similarity) -> bool { + ::is_convertible::<_, Isometry>(&sim.isometry) && ::is_convertible::<_, N1>(&sim.scaling()) } #[inline] - unsafe fn from_superset_unchecked(sim: &SimilarityBase) -> Self { - SimilarityBase::from_isometry( + unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + Similarity::from_isometry( sim.isometry.to_subset_unchecked(), sim.scaling().to_subset_unchecked() ) @@ -51,65 +48,63 @@ impl SubsetOf> } -impl SubsetOf> for SimilarityBase +impl SubsetOf> for Similarity where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, C: SuperTCategoryOf, - R: Rotation> + - SubsetOf, SA::Alloc>> + // needed by: .to_homogeneous() - SubsetOf, SB>>, // needed by: ::convert_unchecked(mm) - D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator + // needed by R - Allocator, DimNameSum> + // needed by: .to_homogeneous() - Allocator, DimNameSum>, // needed by R - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + // needed by: mm.fixed_slice_mut - Allocator + // needed by: m.fixed_slice - Allocator { // needed by: m.fixed_slice + R: Rotation> + + SubsetOf>> + + SubsetOf>>, + D: DimNameAdd + + DimMin, // needed by .determinant() + DefaultAllocator: Allocator + + Allocator + // needed by R + Allocator, DimNameSum> + // needed by: .to_homogeneous() + Allocator, DimNameSum> + // needed by R + Allocator<(usize, usize), D> + // needed by .determinant() + Allocator, DimNameSum> + + Allocator + + Allocator { #[inline] - fn to_superset(&self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] - fn is_in_subset(t: &TransformBase) -> bool { + fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] - unsafe fn from_superset_unchecked(t: &TransformBase) -> Self { + unsafe fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } -impl SubsetOf, SB>> for SimilarityBase +impl SubsetOf>> for Similarity where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, - R: Rotation> + - SubsetOf, SA::Alloc>> + // needed by: .to_homogeneous() - SubsetOf, SB>>, // needed by: ::convert_unchecked(mm) - D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator + // needed by R - Allocator, DimNameSum> + // needed by: .to_homogeneous() - Allocator, DimNameSum>, // needed by R - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + // needed by: mm.fixed_slice_mut - Allocator + // needed by: m.fixed_slice - Allocator { // needed by: m.fixed_slice + R: Rotation> + + SubsetOf>> + + SubsetOf>>, + D: DimNameAdd + + DimMin, // needed by .determinant() + DefaultAllocator: Allocator + + Allocator + // needed by R + Allocator, DimNameSum> + // needed by .to_homogeneous() + Allocator, DimNameSum> + // needed by R + Allocator<(usize, usize), D> + // needed by .determinant() + Allocator, DimNameSum> + + Allocator + + Allocator { #[inline] - fn to_superset(&self) -> SquareMatrix, SB> { + fn to_superset(&self) -> MatrixN> { self.to_homogeneous().to_superset() } #[inline] - fn is_in_subset(m: &SquareMatrix, SB>) -> bool { + fn is_in_subset(m: &MatrixN>) -> bool { let mut rot = m.fixed_slice::(0, 0).clone_owned(); if rot.fixed_columns_mut::(0).try_normalize_mut(N2::zero()).is_some() && rot.fixed_columns_mut::(1).try_normalize_mut(N2::zero()).is_some() && @@ -138,7 +133,7 @@ impl SubsetOf, SB>> for } #[inline] - unsafe fn from_superset_unchecked(m: &SquareMatrix, SB>) -> Self { + unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let mut mm = m.clone_owned(); let na = mm.fixed_slice_mut::(0, 0).normalize_mut(); let nb = mm.fixed_slice_mut::(0, 1).normalize_mut(); @@ -156,7 +151,7 @@ impl SubsetOf, SB>> for } let t = m.fixed_slice::(0, D::dim()).into_owned(); - let t = TranslationBase::from_vector(::convert_unchecked(t)); + let t = Translation::from_vector(::convert_unchecked(t)); Self::from_parts(t, ::convert_unchecked(mm), ::convert_unchecked(scale)) } diff --git a/src/geometry/similarity_ops.rs b/src/geometry/similarity_ops.rs index 59274db1..768acb9e 100644 --- a/src/geometry/similarity_ops.rs +++ b/src/geometry/similarity_ops.rs @@ -1,14 +1,13 @@ use std::ops::{Mul, MulAssign, Div, DivAssign}; use alga::general::Real; -use alga::linear::Rotation; +use alga::linear::Rotation as AlgaRotation; -use core::ColumnVector; +use core::{DefaultAllocator, VectorN}; use core::dimension::{DimName, U1, U3, U4}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::allocator::Allocator; -use geometry::{PointBase, RotationBase, SimilarityBase, TranslationBase, UnitQuaternionBase, IsometryBase}; +use geometry::{Point, Rotation, Similarity, Translation, UnitQuaternion, Isometry}; // FIXME: there are several cloning of rotations that we could probably get rid of (but we didn't // yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` @@ -22,43 +21,43 @@ use geometry::{PointBase, RotationBase, SimilarityBase, TranslationBase, UnitQua * * (Operators) * - * SimilarityBase × SimilarityBase - * SimilarityBase × R - * SimilarityBase × IsometryBase + * Similarity × Similarity + * Similarity × R + * Similarity × Isometry * - * IsometryBase × SimilarityBase - * IsometryBase ÷ SimilarityBase + * Isometry × Similarity + * Isometry ÷ Similarity * * - * SimilarityBase ÷ SimilarityBase - * SimilarityBase ÷ R - * SimilarityBase ÷ IsometryBase + * Similarity ÷ Similarity + * Similarity ÷ R + * Similarity ÷ Isometry * - * SimilarityBase × PointBase - * SimilarityBase × ColumnVector + * Similarity × Point + * Similarity × Vector * * - * SimilarityBase × TranslationBase - * TranslationBase × SimilarityBase + * Similarity × Translation + * Translation × Similarity * - * NOTE: The following are provided explicitly because we can't have R × SimilarityBase. - * RotationBase × SimilarityBase - * UnitQuaternion × SimilarityBase + * NOTE: The following are provided explicitly because we can't have R × Similarity. + * Rotation × Similarity + * UnitQuaternion × Similarity * - * RotationBase ÷ SimilarityBase - * UnitQuaternion ÷ SimilarityBase + * Rotation ÷ Similarity + * UnitQuaternion ÷ Similarity * * (Assignment Operators) * - * SimilarityBase ×= TranslationBase + * Similarity ×= Translation * - * SimilarityBase ×= SimilarityBase - * SimilarityBase ×= IsometryBase - * SimilarityBase ×= R + * Similarity ×= Similarity + * Similarity ×= Isometry + * Similarity ×= R * - * SimilarityBase ÷= SimilarityBase - * SimilarityBase ÷= IsometryBase - * SimilarityBase ÷= R + * Similarity ÷= Similarity + * Similarity ÷= Isometry + * Similarity ÷= R * */ @@ -68,11 +67,9 @@ macro_rules! similarity_binop_impl( ($Op: ident, $op: ident; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N, D: DimName, S, R> $Op<$Rhs> for $Lhs - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { + impl<$($lives ,)* N: Real, D: DimName, R> $Op<$Rhs> for $Lhs + where R: AlgaRotation>, + DefaultAllocator: Allocator { type Output = $Output; #[inline] @@ -117,22 +114,18 @@ macro_rules! similarity_binop_assign_impl_all( $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; [val] => $action_val: expr; [ref] => $action_ref: expr;) => { - impl $OpAssign<$Rhs> for $Lhs - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { + impl $OpAssign<$Rhs> for $Lhs + where R: AlgaRotation>, + DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: $Rhs) { $action_val } } - impl<'b, N, D: DimName, S, R> $OpAssign<&'b $Rhs> for $Lhs - where N: Real, - S: OwnedStorage, - R: Rotation>, - S::Alloc: OwnedAllocator { + impl<'b, N: Real, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs + where R: AlgaRotation>, + DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { $action_ref @@ -141,11 +134,11 @@ macro_rules! similarity_binop_assign_impl_all( } ); -// SimilarityBase × SimilarityBase -// SimilarityBase ÷ SimilarityBase +// Similarity × Similarity +// Similarity ÷ Similarity similarity_binop_impl_all!( Mul, mul; - self: SimilarityBase, rhs: SimilarityBase, Output = SimilarityBase; + self: Similarity, rhs: Similarity, Output = Similarity; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; @@ -159,7 +152,7 @@ similarity_binop_impl_all!( similarity_binop_impl_all!( Div, div; - self: SimilarityBase, rhs: SimilarityBase, Output = SimilarityBase; + self: Similarity, rhs: Similarity, Output = Similarity; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); @@ -167,10 +160,10 @@ similarity_binop_impl_all!( ); -// SimilarityBase ×= TranslationBase +// Similarity ×= Translation similarity_binop_assign_impl_all!( MulAssign, mul_assign; - self: SimilarityBase, rhs: TranslationBase; + self: Similarity, rhs: Translation; [val] => *self *= &rhs; [ref] => { let shift = self.isometry.rotation.transform_vector(&rhs.vector) * self.scaling(); @@ -179,11 +172,11 @@ similarity_binop_assign_impl_all!( ); -// SimilarityBase ×= SimilarityBase -// SimilarityBase ÷= SimilarityBase +// Similarity ×= Similarity +// Similarity ÷= Similarity similarity_binop_assign_impl_all!( MulAssign, mul_assign; - self: SimilarityBase, rhs: SimilarityBase; + self: Similarity, rhs: Similarity; [val] => *self *= &rhs; [ref] => { *self *= &rhs.isometry; @@ -194,18 +187,18 @@ similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!( DivAssign, div_assign; - self: SimilarityBase, rhs: SimilarityBase; + self: Similarity, rhs: Similarity; [val] => *self /= &rhs; // FIXME: don't invert explicitly. [ref] => *self *= rhs.inverse(); ); -// SimilarityBase ×= IsometryBase -// SimilarityBase ÷= IsometryBase +// Similarity ×= Isometry +// Similarity ÷= Isometry similarity_binop_assign_impl_all!( MulAssign, mul_assign; - self: SimilarityBase, rhs: IsometryBase; + self: Similarity, rhs: Isometry; [val] => *self *= &rhs; [ref] => { let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); @@ -217,18 +210,18 @@ similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!( DivAssign, div_assign; - self: SimilarityBase, rhs: IsometryBase; + self: Similarity, rhs: Isometry; [val] => *self /= &rhs; // FIXME: don't invert explicitly. [ref] => *self *= rhs.inverse(); ); -// SimilarityBase ×= R -// SimilarityBase ÷= R +// Similarity ×= R +// Similarity ÷= R similarity_binop_assign_impl_all!( MulAssign, mul_assign; - self: SimilarityBase, rhs: R; + self: Similarity, rhs: R; [val] => self.isometry.rotation *= rhs; [ref] => self.isometry.rotation *= rhs.clone(); ); @@ -236,59 +229,59 @@ similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!( DivAssign, div_assign; - self: SimilarityBase, rhs: R; + self: Similarity, rhs: R; // FIXME: don't invert explicitly? [val] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse(); ); -// SimilarityBase × R -// SimilarityBase ÷ R +// Similarity × R +// Similarity ÷ R similarity_binop_impl_all!( Mul, mul; - self: SimilarityBase, rhs: R, Output = SimilarityBase; + self: Similarity, rhs: R, Output = Similarity; [val val] => { let scaling = self.scaling(); - SimilarityBase::from_isometry(self.isometry * rhs, scaling) + Similarity::from_isometry(self.isometry * rhs, scaling) }; - [ref val] => SimilarityBase::from_isometry(&self.isometry * rhs, self.scaling()); + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); [val ref] => { let scaling = self.scaling(); - SimilarityBase::from_isometry(self.isometry * rhs, scaling) + Similarity::from_isometry(self.isometry * rhs, scaling) }; - [ref ref] => SimilarityBase::from_isometry(&self.isometry * rhs, self.scaling()); + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); ); similarity_binop_impl_all!( Div, div; - self: SimilarityBase, rhs: R, Output = SimilarityBase; + self: Similarity, rhs: R, Output = Similarity; [val val] => { let scaling = self.scaling(); - SimilarityBase::from_isometry(self.isometry / rhs, scaling) + Similarity::from_isometry(self.isometry / rhs, scaling) }; - [ref val] => SimilarityBase::from_isometry(&self.isometry / rhs, self.scaling()); + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); [val ref] => { let scaling = self.scaling(); - SimilarityBase::from_isometry(self.isometry / rhs, scaling) + Similarity::from_isometry(self.isometry / rhs, scaling) }; - [ref ref] => SimilarityBase::from_isometry(&self.isometry / rhs, self.scaling()); + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); ); -// SimilarityBase × IsometryBase -// SimilarityBase ÷ IsometryBase +// Similarity × Isometry +// Similarity ÷ Isometry similarity_binop_impl_all!( Mul, mul; - self: SimilarityBase, rhs: IsometryBase, Output = SimilarityBase; + self: Similarity, rhs: Isometry, Output = Similarity; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => { let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); - SimilarityBase::from_parts( - TranslationBase::from_vector(&self.isometry.translation.vector + shift), + Similarity::from_parts( + Translation::from_vector(&self.isometry.translation.vector + shift), self.isometry.rotation.clone() * rhs.rotation.clone(), self.scaling()) }; @@ -298,40 +291,40 @@ similarity_binop_impl_all!( similarity_binop_impl_all!( Div, div; - self: SimilarityBase, rhs: IsometryBase, Output = SimilarityBase; + self: Similarity, rhs: Isometry, Output = Similarity; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); [ref ref] => self * rhs.inverse(); ); -// IsometryBase × SimilarityBase -// IsometryBase ÷ SimilarityBase +// Isometry × Similarity +// Isometry ÷ Similarity similarity_binop_impl_all!( Mul, mul; - self: IsometryBase, rhs: SimilarityBase, Output = SimilarityBase; + self: Isometry, rhs: Similarity, Output = Similarity; [val val] => { let scaling = rhs.scaling(); - SimilarityBase::from_isometry(self * rhs.isometry, scaling) + Similarity::from_isometry(self * rhs.isometry, scaling) }; [ref val] => { let scaling = rhs.scaling(); - SimilarityBase::from_isometry(self * rhs.isometry, scaling) + Similarity::from_isometry(self * rhs.isometry, scaling) }; [val ref] => { let scaling = rhs.scaling(); - SimilarityBase::from_isometry(self * &rhs.isometry, scaling) + Similarity::from_isometry(self * &rhs.isometry, scaling) }; [ref ref] => { let scaling = rhs.scaling(); - SimilarityBase::from_isometry(self * &rhs.isometry, scaling) + Similarity::from_isometry(self * &rhs.isometry, scaling) }; ); similarity_binop_impl_all!( Div, div; - self: IsometryBase, rhs: SimilarityBase, Output = SimilarityBase; + self: Isometry, rhs: Similarity, Output = Similarity; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); @@ -339,10 +332,10 @@ similarity_binop_impl_all!( ); -// SimilarityBase × PointBase +// Similarity × Point similarity_binop_impl_all!( Mul, mul; - self: SimilarityBase, right: PointBase, Output = PointBase; + self: Similarity, right: Point, Output = Point; [val val] => { let scaling = self.scaling(); self.isometry.translation * (self.isometry.rotation.transform_point(&right) * scaling) @@ -356,10 +349,10 @@ similarity_binop_impl_all!( ); -// SimilarityBase × Vector +// Similarity × Vector similarity_binop_impl_all!( Mul, mul; - self: SimilarityBase, right: ColumnVector, Output = ColumnVector; + self: Similarity, right: VectorN, Output = VectorN; [val val] => self.isometry.rotation.transform_vector(&right) * self.scaling(); [ref val] => self.isometry.rotation.transform_vector(&right) * self.scaling(); [val ref] => self.isometry.rotation.transform_vector(right) * self.scaling(); @@ -367,37 +360,37 @@ similarity_binop_impl_all!( ); -// SimilarityBase × TranslationBase +// Similarity × Translation similarity_binop_impl_all!( Mul, mul; - self: SimilarityBase, right: TranslationBase, Output = SimilarityBase; + self: Similarity, right: Translation, Output = Similarity; [val val] => &self * &right; [ref val] => self * &right; [val ref] => &self * right; [ref ref] => { let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling(); - SimilarityBase::from_parts( - TranslationBase::from_vector(&self.isometry.translation.vector + shift), + Similarity::from_parts( + Translation::from_vector(&self.isometry.translation.vector + shift), self.isometry.rotation.clone(), self.scaling()) }; ); -// TranslationBase × SimilarityBase +// Translation × Similarity similarity_binop_impl_all!( Mul, mul; - self: TranslationBase, right: SimilarityBase, Output = SimilarityBase; + self: Translation, right: Similarity, Output = Similarity; [val val] => { let scaling = right.scaling(); - SimilarityBase::from_isometry(self * right.isometry, scaling) + Similarity::from_isometry(self * right.isometry, scaling) }; [ref val] => { let scaling = right.scaling(); - SimilarityBase::from_isometry(self * right.isometry, scaling) + Similarity::from_isometry(self * right.isometry, scaling) }; - [val ref] => SimilarityBase::from_isometry(self * &right.isometry, right.scaling()); - [ref ref] => SimilarityBase::from_isometry(self * &right.isometry, right.scaling()); + [val ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); + [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); ); @@ -406,12 +399,9 @@ macro_rules! similarity_from_composition_impl( ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(for $Dims: ident: $DimsBound: ident),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs - where N: Real, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + impl<$($lives ,)* N: Real $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + where DefaultAllocator: Allocator + + Allocator { type Output = $Output; #[inline] @@ -458,25 +448,25 @@ macro_rules! similarity_from_composition_impl_all( ); -// RotationBase × SimilarityBase +// Rotation × Similarity similarity_from_composition_impl_all!( Mul, mul; (D, D), (D, U1) for D: DimName; - self: RotationBase, right: SimilarityBase>, - Output = SimilarityBase>; + self: Rotation, right: Similarity>, + Output = Similarity>; [val val] => &self * &right; [ref val] => self * &right; [val ref] => &self * right; - [ref ref] => SimilarityBase::from_isometry(self * &right.isometry, right.scaling()); + [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); ); -// RotationBase ÷ SimilarityBase +// Rotation ÷ Similarity similarity_from_composition_impl_all!( Div, div; (D, D), (D, U1) for D: DimName; - self: RotationBase, right: SimilarityBase>, - Output = SimilarityBase>; + self: Rotation, right: Similarity>, + Output = Similarity>; // FIXME: don't call iverse explicitly? [val val] => self * right.inverse(); [ref val] => self * right.inverse(); @@ -485,25 +475,25 @@ similarity_from_composition_impl_all!( ); -// UnitQuaternion × SimilarityBase +// UnitQuaternion × Similarity similarity_from_composition_impl_all!( Mul, mul; (U4, U1), (U3, U1); - self: UnitQuaternionBase, right: SimilarityBase>, - Output = SimilarityBase>; + self: UnitQuaternion, right: Similarity>, + Output = Similarity>; [val val] => &self * &right; [ref val] => self * &right; [val ref] => &self * right; - [ref ref] => SimilarityBase::from_isometry(self * &right.isometry, right.scaling()); + [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); ); -// UnitQuaternion ÷ SimilarityBase +// UnitQuaternion ÷ Similarity similarity_from_composition_impl_all!( Div, div; (U4, U1), (U3, U1); - self: UnitQuaternionBase, right: SimilarityBase>, - Output = SimilarityBase>; + self: UnitQuaternion, right: Similarity>, + Output = Similarity>; // FIXME: don't call inverse explicitly? [val val] => self * right.inverse(); [ref val] => self * right.inverse(); diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index 5ff2d85e..f0f921ae 100644 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -1,16 +1,15 @@ use std::any::Any; use std::fmt::Debug; use std::marker::PhantomData; -use approx::ApproxEq; #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; -use alga::general::Field; +use alga::general::Real; -use core::{Scalar, SquareMatrix, OwnedSquareMatrix}; +use core::{DefaultAllocator, MatrixN}; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use core::storage::{Storage, StorageMut}; +use core::storage::Owned; use core::allocator::Allocator; /// Trait implemented by phantom types identifying the projective transformation type. @@ -26,11 +25,9 @@ pub trait TCategory: Any + Debug + Copy + PartialEq + Send { /// Checks that the given matrix is a valid homogeneous representation of an element of the /// category `Self`. - fn check_homogeneous_invariants(mat: &SquareMatrix) -> bool - where N: Scalar + Field + ApproxEq, - D: DimName, - S: Storage, - N::Epsilon: Copy; + fn check_homogeneous_invariants(mat: &MatrixN) -> bool + where N::Epsilon: Copy, + DefaultAllocator: Allocator; } /// Traits that gives the `Transform` category that is compatible with the result of the @@ -68,22 +65,18 @@ pub enum TAffine { } impl TCategory for TGeneral { #[inline] - fn check_homogeneous_invariants(_: &SquareMatrix) -> bool - where N: Scalar + Field + ApproxEq, - D: DimName, - S: Storage, - N::Epsilon: Copy { + fn check_homogeneous_invariants(_: &MatrixN) -> bool + where N::Epsilon: Copy, + DefaultAllocator: Allocator { true } } impl TCategory for TProjective { #[inline] - fn check_homogeneous_invariants(mat: &SquareMatrix) -> bool - where N: Scalar + Field + ApproxEq, - D: DimName, - S: Storage, - N::Epsilon: Copy { + fn check_homogeneous_invariants(mat: &MatrixN) -> bool + where N::Epsilon: Copy, + DefaultAllocator: Allocator { mat.is_invertible() } } @@ -95,11 +88,9 @@ impl TCategory for TAffine { } #[inline] - fn check_homogeneous_invariants(mat: &SquareMatrix) -> bool - where N: Scalar + Field + ApproxEq, - D: DimName, - S: Storage, - N::Epsilon: Copy { + fn check_homogeneous_invariants(mat: &MatrixN) -> bool + where N::Epsilon: Copy, + DefaultAllocator: Allocator { let last = D::dim() - 1; mat.is_invertible() && mat[(last, last)] == N::one() && @@ -121,17 +112,17 @@ impl TCategoryMul for T { } category_mul_impl!( - // TGeneral * TGeneral => TGeneral; - TGeneral * TProjective => TGeneral; - TGeneral * TAffine => TGeneral; +// TGeneral * TGeneral => TGeneral; + TGeneral * TProjective => TGeneral; + TGeneral * TAffine => TGeneral; - TProjective * TGeneral => TGeneral; - // TProjective * TProjective => TProjective; - TProjective * TAffine => TProjective; + TProjective * TGeneral => TGeneral; +// TProjective * TProjective => TProjective; + TProjective * TAffine => TProjective; - TAffine * TGeneral => TGeneral; - TAffine * TProjective => TProjective; - // TAffine * TAffine => TAffine; + TAffine * TGeneral => TGeneral; + TAffine * TProjective => TProjective; +// TAffine * TAffine => TAffine; ); macro_rules! super_tcategory_impl( @@ -143,109 +134,104 @@ macro_rules! super_tcategory_impl( impl SuperTCategoryOf for T { } super_tcategory_impl!( - TGeneral >= TProjective; - TGeneral >= TAffine; + TGeneral >= TProjective; + TGeneral >= TAffine; TProjective >= TAffine; ); -/// A transformation matrix that owns its data. -pub type OwnedTransform - = TransformBase, DimNameSum>>::Buffer, C>; - - /// A transformation matrix in homogeneous coordinates. /// /// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a /// 3D transformation. #[repr(C)] -#[derive(Debug, Clone, Copy)] // FIXME: Hash -pub struct TransformBase, S, C: TCategory> { - matrix: SquareMatrix, S>, +#[derive(Debug)] +pub struct Transform, C: TCategory> + where DefaultAllocator: Allocator, DimNameSum> { + matrix: MatrixN>, _phantom: PhantomData } -#[cfg(feature = "serde-serialize")] -impl Serialize for TransformBase - where N: Scalar, - D: DimNameAdd, - C: TCategory, - SquareMatrix, S>: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.matrix.serialize(serializer) +// FIXME +// impl + hash::Hash, C: TCategory> hash::Hash for Transform +// where DefaultAllocator: Allocator, DimNameSum>, +// Owned, DimNameSum>: hash::Hash { +// fn hash(&self, state: &mut H) { +// self.matrix.hash(state); +// } +// } + +impl + Copy, C: TCategory> Copy for Transform + where DefaultAllocator: Allocator, DimNameSum>, + Owned, DimNameSum>: Copy { +} + +impl, C: TCategory> Clone for Transform + where DefaultAllocator: Allocator, DimNameSum> { + #[inline] + fn clone(&self) -> Self { + Transform::from_matrix_unchecked(self.matrix.clone()) } } #[cfg(feature = "serde-serialize")] -impl<'de, N, D, S, C> Deserialize<'de> for TransformBase - where N: Scalar, - D: DimNameAdd, - C: TCategory, - SquareMatrix, S>: Deserialize<'de>, -{ - fn deserialize(deserializer: T) -> Result - where T: Deserializer<'de> - { - SquareMatrix::deserialize(deserializer).map(|x| TransformBase { matrix: x, _phantom: PhantomData }) - } +impl, C: TCategory> serde::Serialize for Transform +where DefaultAllocator: Allocator, DimNameSum>, + Owned, DimNameSum>: serde::Serialize { + + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.matrix.serialize(serializer) + } } -// XXX: for some reasons, implementing Clone and Copy manually causes an ICE… +#[cfg(feature = "serde-serialize")] +impl<'a, N: Real, D: DimNameAdd, C: TCategory> serde::Deserialize<'a> for Transform +where DefaultAllocator: Allocator, DimNameSum>, + Owned, DimNameSum>: serde::Deserialize<'a> { -impl Eq for TransformBase - where N: Scalar + Eq, - D: DimNameAdd, - S: Storage, DimNameSum> { } + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let matrix = MatrixN::>::deserialize(deserializer)?; -impl PartialEq for TransformBase - where N: Scalar, - D: DimNameAdd, - S: Storage, DimNameSum> { + Ok(Transform::from_matrix_unchecked(matrix)) + } +} + + +impl, C: TCategory> Eq for Transform + where DefaultAllocator: Allocator, DimNameSum> { } + +impl, C: TCategory> PartialEq for Transform + where DefaultAllocator: Allocator, DimNameSum> { #[inline] fn eq(&self, right: &Self) -> bool { self.matrix == right.matrix } } -impl TransformBase - where N: Scalar, - D: DimNameAdd, - S: Storage, DimNameSum> { +impl, C: TCategory> Transform + where DefaultAllocator: Allocator, DimNameSum> { /// Creates a new transformation from the given homogeneous matrix. The transformation category /// of `Self` is not checked to be verified by the given matrix. #[inline] - pub fn from_matrix_unchecked(matrix: SquareMatrix, S>) -> Self { - TransformBase { + pub fn from_matrix_unchecked(matrix: MatrixN>) -> Self { + Transform { matrix: matrix, _phantom: PhantomData } } - /// Moves this transform into one that owns its data. - #[inline] - pub fn into_owned(self) -> OwnedTransform { - TransformBase::from_matrix_unchecked(self.matrix.into_owned()) - } - - /// Clones this transform into one that owns its data. - #[inline] - pub fn clone_owned(&self) -> OwnedTransform { - TransformBase::from_matrix_unchecked(self.matrix.clone_owned()) - } - /// The underlying matrix. #[inline] - pub fn unwrap(self) -> SquareMatrix, S> { + pub fn unwrap(self) -> MatrixN> { self.matrix } /// A reference to the underlynig matrix. #[inline] - pub fn matrix(&self) -> &SquareMatrix, S> { + pub fn matrix(&self) -> &MatrixN> { &self.matrix } @@ -254,7 +240,7 @@ impl TransformBase /// It is `_unchecked` because direct modifications of this matrix may break invariants /// identified by this transformation category. #[inline] - pub fn matrix_mut_unchecked(&mut self) -> &mut SquareMatrix, S> { + pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN> { &mut self.matrix } @@ -265,28 +251,28 @@ impl TransformBase /// `TAffine` because not all projective transformations are affine (the other way-round is /// valid though). #[inline] - pub fn set_category>(self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.matrix) + pub fn set_category>(self) -> Transform { + Transform::from_matrix_unchecked(self.matrix) + } + + /// Clones this transform into one that owns its data. + #[inline] + pub fn clone_owned(&self) -> Transform { + Transform::from_matrix_unchecked(self.matrix.clone_owned()) } /// Converts this transform into its equivalent homogeneous transformation matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix, S::Alloc> { + pub fn to_homogeneous(&self) -> MatrixN> { self.matrix().clone_owned() } -} -impl TransformBase - where N: Scalar + Field + ApproxEq, - D: DimNameAdd, - C: TCategory, - S: Storage, DimNameSum> { /// Attempts to invert this transformation. You may use `.inverse` instead of this /// transformation has a subcategory of `TProjective`. #[inline] - pub fn try_inverse(self) -> Option> { + pub fn try_inverse(self) -> Option> { if let Some(m) = self.matrix.try_inverse() { - Some(TransformBase::from_matrix_unchecked(m)) + Some(Transform::from_matrix_unchecked(m)) } else { None @@ -296,18 +282,12 @@ impl TransformBase /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral` /// category (it may not be invertible). #[inline] - pub fn inverse(self) -> OwnedTransform + pub fn inverse(self) -> Transform where C: SubTCategoryOf { // FIXME: specialize for TAffine? - TransformBase::from_matrix_unchecked(self.matrix.try_inverse().unwrap()) + Transform::from_matrix_unchecked(self.matrix.try_inverse().unwrap()) } -} -impl TransformBase - where N: Scalar + Field + ApproxEq, - D: DimNameAdd, - C: TCategory, - S: StorageMut, DimNameSum> { /// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this /// transformation has a subcategory of `TProjective`. #[inline] @@ -324,14 +304,12 @@ impl TransformBase } } -impl TransformBase - where N: Scalar, - D: DimNameAdd, - S: Storage, DimNameSum> { +impl> Transform + where DefaultAllocator: Allocator, DimNameSum> { /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this /// transformation category is not `TGeneral`. #[inline] - pub fn matrix_mut(&mut self) -> &mut SquareMatrix, S> { + pub fn matrix_mut(&mut self) -> &mut MatrixN> { self.matrix_mut_unchecked() } } @@ -345,5 +323,4 @@ mod tests { fn checks_homogeneous_invariants_of_square_identity_matrix() { assert!(TAffine::check_homogeneous_invariants(&Matrix4::::identity())); } - } diff --git a/src/geometry/transform_alga.rs b/src/geometry/transform_alga.rs index 5c7e1abc..e91d49ed 100644 --- a/src/geometry/transform_alga.rs +++ b/src/geometry/transform_alga.rs @@ -1,15 +1,12 @@ -use approx::ApproxEq; - use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Field, Real, Inverse, Multiplicative, Identity}; + AbstractSemigroup, Real, Inverse, Multiplicative, Identity}; use alga::linear::{Transformation, ProjectiveTransformation}; -use core::{Scalar, ColumnVector}; +use core::{DefaultAllocator, VectorN}; use core::dimension::{DimNameSum, DimNameAdd, U1}; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; +use core::allocator::Allocator; -use geometry::{PointBase, TransformBase, TCategory, SubTCategoryOf, TProjective}; +use geometry::{Point, Transform, TCategory, SubTCategoryOf, TProjective}; /* @@ -17,22 +14,18 @@ use geometry::{PointBase, TransformBase, TCategory, SubTCategoryOf, TProjective} * Algebraic structures. * */ -impl, S, C> Identity for TransformBase - where N: Scalar + Field, - S: OwnedStorage, DimNameSum>, - C: TCategory, - S::Alloc: OwnedAllocator, DimNameSum, S> { +impl, C> Identity for Transform + where C: TCategory, + DefaultAllocator: Allocator, DimNameSum> { #[inline] fn identity() -> Self { Self::identity() } } -impl, S, C> Inverse for TransformBase - where N: Scalar + Field + ApproxEq, - S: OwnedStorage, DimNameSum>, - C: SubTCategoryOf, - S::Alloc: OwnedAllocator, DimNameSum, S> { +impl, C> Inverse for Transform + where C: SubTCategoryOf, + DefaultAllocator: Allocator, DimNameSum> { #[inline] fn inverse(&self) -> Self { self.clone().inverse() @@ -44,11 +37,9 @@ impl, S, C> Inverse for TransformBase, S, C> AbstractMagma for TransformBase - where N: Scalar + Field, - S: OwnedStorage, DimNameSum>, - C: TCategory, - S::Alloc: OwnedAllocator, DimNameSum, S> { +impl, C> AbstractMagma for Transform + where C: TCategory, + DefaultAllocator: Allocator, DimNameSum> { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs @@ -57,21 +48,17 @@ impl, S, C> AbstractMagma for TransformBase macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl, S, C> $marker<$operator> for TransformBase - where N: Scalar + Field, - S: OwnedStorage, DimNameSum>, - C: TCategory, - S::Alloc: OwnedAllocator, DimNameSum, S> { } + impl, C> $marker<$operator> for Transform + where C: TCategory, + DefaultAllocator: Allocator, DimNameSum> { } )*} ); macro_rules! impl_inversible_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl, S, C> $marker<$operator> for TransformBase - where N: Scalar + Field + ApproxEq, - S: OwnedStorage, DimNameSum>, - C: SubTCategoryOf, - S::Alloc: OwnedAllocator, DimNameSum, S> { } + impl, C> $marker<$operator> for Transform + where C: SubTCategoryOf, + DefaultAllocator: Allocator, DimNameSum> { } )*} ); @@ -91,64 +78,54 @@ impl_inversible_multiplicative_structures!( * Transformation groups. * */ -impl, SA, SB, C> Transformation> for TransformBase +impl, C> Transformation> for Transform where N: Real, - SA: OwnedStorage, DimNameSum>, - SB: OwnedStorage, C: TCategory, - SA::Alloc: OwnedAllocator, DimNameSum, SA> + - Allocator + - Allocator + - Allocator, - SB::Alloc: OwnedAllocator { + DefaultAllocator: Allocator, DimNameSum> + + Allocator> + + Allocator + + Allocator { #[inline] - fn transform_point(&self, pt: &PointBase) -> PointBase { + fn transform_point(&self, pt: &Point) -> Point { self * pt } #[inline] - fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn transform_vector(&self, v: &VectorN) -> VectorN { self * v } } -impl, SA, SB, C> ProjectiveTransformation> for TransformBase +impl, C> ProjectiveTransformation> for Transform where N: Real, - SA: OwnedStorage, DimNameSum>, - SB: OwnedStorage, C: SubTCategoryOf, - SA::Alloc: OwnedAllocator, DimNameSum, SA> + - Allocator + - Allocator + - Allocator, - SB::Alloc: OwnedAllocator { + DefaultAllocator: Allocator, DimNameSum> + + Allocator> + + Allocator + + Allocator { #[inline] - fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { + fn inverse_transform_point(&self, pt: &Point) -> Point { self.inverse() * pt } #[inline] - fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { self.inverse() * v } } // FIXME: we need to implement an SVD for this. // -// impl, SA, SB, C> AffineTransformation> for TransformBase +// impl, C> AffineTransformation> for Transform // where N: Real, -// SA: OwnedStorage, DimNameSum>, -// SB: OwnedStorage, // C: SubTCategoryOf, -// SA::Alloc: OwnedAllocator, DimNameSum, SA> + -// Allocator + -// Allocator + -// Allocator, -// SB::Alloc: OwnedAllocator { -// type PreRotation = OwnedRotation; -// type NonUniformScaling = OwnedColumnVector; -// type PostRotation = OwnedRotation; -// type Translation = OwnedTranslation; +// DefaultAllocator: Allocator, DimNameSum> + +// Allocator + +// Allocator { +// type PreRotation = Rotation; +// type NonUniformScaling = VectorN; +// type PostRotation = Rotation; +// type Translation = Translation; // // #[inline] // fn decompose(&self) -> (Self::Translation, Self::PostRotation, Self::NonUniformScaling, Self::PreRotation) { diff --git a/src/geometry/transform_alias.rs b/src/geometry/transform_alias.rs index c387fb4f..e0235b55 100644 --- a/src/geometry/transform_alias.rs +++ b/src/geometry/transform_alias.rs @@ -1,29 +1,17 @@ -use core::MatrixArray; -use core::dimension::{U1, U2, U3, DimNameSum}; +use core::dimension::{U2, U3}; -use geometry::{TransformBase, TGeneral, TProjective, TAffine}; - -/// A `D`-dimensional general transformation that may not be inversible. Stored as an homogeneous -/// `(D + 1) × (D + 1)` matrix. -pub type Transform = TransformBase, DimNameSum>, TGeneral>; - -/// An inversible `D`-dimensional general transformation. Stored as an homogeneous -/// `(D + 1) × (D + 1)` matrix. -pub type Projective = TransformBase, DimNameSum>, TProjective>; - -/// A `D`-dimensional affine transformation. Stored as an homogeneous `(D + 1) × (D + 1)` matrix. -pub type Affine = TransformBase, DimNameSum>, TAffine>; +use geometry::{Transform, TGeneral, TProjective, TAffine}; /// A 2D general transformation that may not be inversible. Stored as an homogeneous 3x3 matrix. -pub type Transform2 = Transform; +pub type Transform2 = Transform; /// An inversible 2D general transformation. Stored as an homogeneous 3x3 matrix. -pub type Projective2 = Projective; +pub type Projective2 = Transform; /// A 2D affine transformation. Stored as an homogeneous 3x3 matrix. -pub type Affine2 = Affine; +pub type Affine2 = Transform; /// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix. -pub type Transform3 = Transform; +pub type Transform3 = Transform; /// An inversible 3D general transformation. Stored as an homogeneous 4x4 matrix. -pub type Projective3 = Projective; +pub type Projective3 = Transform; /// A 3D affine transformation. Stored as an homogeneous 4x4 matrix. -pub type Affine3 = Affine; +pub type Affine3 = Transform; diff --git a/src/geometry/transform_construction.rs b/src/geometry/transform_construction.rs index 9a2dbe98..38daf246 100644 --- a/src/geometry/transform_construction.rs +++ b/src/geometry/transform_construction.rs @@ -1,32 +1,25 @@ -use num::{Zero, One}; +use num::One; -use alga::general::Field; +use alga::general::Real; -use core::{Scalar, OwnedSquareMatrix}; +use core::{DefaultAllocator, MatrixN}; use core::dimension::{DimNameAdd, DimNameSum, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::allocator::Allocator; -use geometry::{TransformBase, TCategory}; +use geometry::{Transform, TCategory}; -impl TransformBase - where N: Scalar + Zero + One, - D: DimNameAdd, - S: OwnedStorage, DimNameSum>, - S::Alloc: OwnedAllocator, DimNameSum, S> { +impl, C: TCategory> Transform + where DefaultAllocator: Allocator, DimNameSum> { /// Creates a new identity transform. #[inline] pub fn identity() -> Self { - Self::from_matrix_unchecked(OwnedSquareMatrix::::identity()) + Self::from_matrix_unchecked(MatrixN::<_, DimNameSum>::identity()) } } -impl One for TransformBase - where N: Scalar + Field, - D: DimNameAdd, - S: OwnedStorage, DimNameSum>, - S::Alloc: OwnedAllocator, DimNameSum, S> { +impl, C: TCategory> One for Transform + where DefaultAllocator: Allocator, DimNameSum> { /// Creates a new identity transform. #[inline] fn one() -> Self { diff --git a/src/geometry/transform_conversion.rs b/src/geometry/transform_conversion.rs index 44267a00..56506474 100644 --- a/src/geometry/transform_conversion.rs +++ b/src/geometry/transform_conversion.rs @@ -1,67 +1,60 @@ -use approx::ApproxEq; +use alga::general::{SubsetOf, Real}; -use alga::general::{SubsetOf, Field}; - -use core::{Scalar, SquareMatrix}; +use core::{DefaultAllocator, MatrixN}; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::allocator::Allocator; -use geometry::{TransformBase, TCategory, SuperTCategoryOf}; +use geometry::{Transform, TCategory, SuperTCategoryOf}; -impl SubsetOf> for TransformBase - where N1: Scalar + Field + ApproxEq + SubsetOf, - N2: Scalar + Field + ApproxEq, +impl SubsetOf> for Transform + where N1: Real + SubsetOf, + N2: Real, C1: TCategory, C2: SuperTCategoryOf, D: DimNameAdd, - SA: OwnedStorage, DimNameSum>, - SB: OwnedStorage, DimNameSum>, - SA::Alloc: OwnedAllocator, DimNameSum, SA>, - SB::Alloc: OwnedAllocator, DimNameSum, SB>, + DefaultAllocator: Allocator, DimNameSum> + + Allocator, DimNameSum>, N1::Epsilon: Copy, N2::Epsilon: Copy { #[inline] - fn to_superset(&self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] - fn is_in_subset(t: &TransformBase) -> bool { + fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] - unsafe fn from_superset_unchecked(t: &TransformBase) -> Self { + unsafe fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } -impl SubsetOf, SB>> for TransformBase - where N1: Scalar + Field + ApproxEq + SubsetOf, - N2: Scalar + Field + ApproxEq, +impl SubsetOf>> for Transform + where N1: Real + SubsetOf, + N2: Real, C: TCategory, D: DimNameAdd, - SA: OwnedStorage, DimNameSum>, - SB: OwnedStorage, DimNameSum>, - SA::Alloc: OwnedAllocator, DimNameSum, SA>, - SB::Alloc: OwnedAllocator, DimNameSum, SB>, + DefaultAllocator: Allocator, DimNameSum> + + Allocator, DimNameSum>, N1::Epsilon: Copy, N2::Epsilon: Copy { #[inline] - fn to_superset(&self) -> SquareMatrix, SB> { + fn to_superset(&self) -> MatrixN> { self.matrix().to_superset() } #[inline] - fn is_in_subset(m: &SquareMatrix, SB>) -> bool { + fn is_in_subset(m: &MatrixN>) -> bool { C::check_homogeneous_invariants(m) } #[inline] - unsafe fn from_superset_unchecked(m: &SquareMatrix, SB>) -> Self { - TransformBase::from_matrix_unchecked(::convert_ref_unchecked(m)) + unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { + Transform::from_matrix_unchecked(::convert_ref_unchecked(m)) } } diff --git a/src/geometry/transform_ops.rs b/src/geometry/transform_ops.rs index bacc883e..2a5a2d95 100644 --- a/src/geometry/transform_ops.rs +++ b/src/geometry/transform_ops.rs @@ -1,17 +1,15 @@ use num::{Zero, One}; use std::ops::{Index, IndexMut, Mul, MulAssign, Div, DivAssign}; -use approx::ApproxEq; -use alga::general::{Field, Real, ClosedAdd, ClosedMul, ClosedNeg, SubsetOf}; +use alga::general::{Real, ClosedAdd, ClosedMul, SubsetOf}; -use core::{Scalar, ColumnVector, OwnedColumnVector, OwnedSquareMatrix}; -use core::storage::{Storage, StorageMut, OwnedStorage}; -use core::allocator::{Allocator, OwnedAllocator}; +use core::{DefaultAllocator, Scalar, VectorN, MatrixN}; +use core::allocator::Allocator; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1, U3, U4}; -use geometry::{PointBase, OwnedPoint, TransformBase, OwnedTransform, TCategory, TCategoryMul, - SubTCategoryOf, SuperTCategoryOf, TGeneral, TProjective, TAffine, RotationBase, - UnitQuaternionBase, IsometryBase, SimilarityBase, TranslationBase}; +use geometry::{Point, Transform, TCategory, TCategoryMul, + SubTCategoryOf, SuperTCategoryOf, TGeneral, TProjective, TAffine, Rotation, + UnitQuaternion, Isometry, Similarity, Translation}; /* * @@ -23,55 +21,55 @@ use geometry::{PointBase, OwnedPoint, TransformBase, OwnedTransform, TCategory, * * (Operators) * - * TransformBase × IsometryBase - * TransformBase × RotationBase - * TransformBase × SimilarityBase - * TransformBase × TransformBase - * TransformBase × UnitQuaternion - * FIXME: TransformBase × UnitComplex - * TransformBase × TranslationBase - * TransformBase × ColumnVector - * TransformBase × PointBase + * Transform × Isometry + * Transform × Rotation + * Transform × Similarity + * Transform × Transform + * Transform × UnitQuaternion + * FIXME: Transform × UnitComplex + * Transform × Translation + * Transform × Vector + * Transform × Point * - * IsometryBase × TransformBase - * RotationBase × TransformBase - * SimilarityBase × TransformBase - * TranslationBase × TransformBase - * UnitQuaternionBase × TransformBase - * FIXME: UnitComplex × TransformBase + * Isometry × Transform + * Rotation × Transform + * Similarity × Transform + * Translation × Transform + * UnitQuaternion × Transform + * FIXME: UnitComplex × Transform * - * FIXME: TransformBase ÷ IsometryBase - * TransformBase ÷ RotationBase - * FIXME: TransformBase ÷ SimilarityBase - * TransformBase ÷ TransformBase - * TransformBase ÷ UnitQuaternion - * TransformBase ÷ TranslationBase + * FIXME: Transform ÷ Isometry + * Transform ÷ Rotation + * FIXME: Transform ÷ Similarity + * Transform ÷ Transform + * Transform ÷ UnitQuaternion + * Transform ÷ Translation * - * FIXME: IsometryBase ÷ TransformBase - * RotationBase ÷ TransformBase - * FIXME: SimilarityBase ÷ TransformBase - * TranslationBase ÷ TransformBase - * UnitQuaternionBase ÷ TransformBase - * FIXME: UnitComplex ÷ TransformBase + * FIXME: Isometry ÷ Transform + * Rotation ÷ Transform + * FIXME: Similarity ÷ Transform + * Translation ÷ Transform + * UnitQuaternion ÷ Transform + * FIXME: UnitComplex ÷ Transform * * * (Assignment Operators) * * - * TransformBase ×= TransformBase - * TransformBase ×= SimilarityBase - * TransformBase ×= IsometryBase - * TransformBase ×= RotationBase - * TransformBase ×= UnitQuaternionBase - * FIXME: TransformBase ×= UnitComplex - * TransformBase ×= TranslationBase + * Transform ×= Transform + * Transform ×= Similarity + * Transform ×= Isometry + * Transform ×= Rotation + * Transform ×= UnitQuaternion + * FIXME: Transform ×= UnitComplex + * Transform ×= Translation * - * TransformBase ÷= TransformBase - * FIXME: TransformBase ÷= SimilarityBase - * FIXME: TransformBase ÷= IsometryBase - * TransformBase ÷= RotationBase - * TransformBase ÷= UnitQuaternionBase - * FIXME: TransformBase ÷= UnitComplex + * Transform ÷= Transform + * FIXME: Transform ÷= Similarity + * FIXME: Transform ÷= Isometry + * Transform ÷= Rotation + * Transform ÷= UnitQuaternion + * FIXME: Transform ÷= UnitComplex * */ @@ -80,10 +78,9 @@ use geometry::{PointBase, OwnedPoint, TransformBase, OwnedTransform, TCategory, * Indexing. * */ -impl Index<(usize, usize)> for TransformBase - where N: Scalar, - D: DimName + DimNameAdd, - S: Storage, DimNameSum> { +impl Index<(usize, usize)> for Transform + where D: DimName + DimNameAdd, + DefaultAllocator: Allocator, DimNameSum> { type Output = N; #[inline] @@ -93,10 +90,9 @@ impl Index<(usize, usize)> for TransformBase } // Only general transformations are mutably indexable. -impl IndexMut<(usize, usize)> for TransformBase - where N: Scalar, - D: DimName + DimNameAdd, - S: StorageMut, DimNameSum> { +impl IndexMut<(usize, usize)> for Transform + where D: DimName + DimNameAdd, + DefaultAllocator: Allocator, DimNameSum> { #[inline] fn index_mut(&mut self, ij: (usize, usize)) -> &mut N { self.matrix_mut().index_mut(ij) @@ -104,14 +100,11 @@ impl IndexMut<(usize, usize)> for TransformBase } -// TransformBase × ColumnVector +// Transform × Vector md_impl_all!( - Mul, mul where N: Field; - (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory - where SA::Alloc: Allocator - where SA::Alloc: Allocator - where SA::Alloc: Allocator; - self: TransformBase, rhs: ColumnVector, Output = OwnedColumnVector; + Mul, mul where N: Real; + (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory; + self: Transform, rhs: VectorN, Output = VectorN; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; @@ -132,14 +125,12 @@ md_impl_all!( ); -// TransformBase × PointBase +// Transform × Point md_impl_all!( - Mul, mul where N: Field; + Mul, mul where N: Real; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory - where SA::Alloc: Allocator - where SA::Alloc: Allocator - where SA::Alloc: Allocator; - self: TransformBase, rhs: PointBase, Output = OwnedPoint; + where DefaultAllocator: Allocator; + self: Transform, rhs: Point, Output = Point; [val val] => &self * &rhs; [ref val] => self * &rhs; [val ref] => &self * rhs; @@ -161,11 +152,11 @@ md_impl_all!( ); -// TransformBase × TransformBase +// Transform × Transform md_impl_all!( - Mul, mul; + Mul, mul where N: Real; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: TCategoryMul, CB: TCategory; - self: TransformBase, rhs: TransformBase, Output = OwnedTransform; + self: Transform, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.unwrap()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.matrix()); @@ -173,12 +164,11 @@ md_impl_all!( ); -// TransformBase × RotationBase +// Transform × Rotation md_impl_all!( - Mul, mul where N: One; - (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategoryMul - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: RotationBase, Output = OwnedTransform; + Mul, mul where N: Real; + (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategoryMul; + self: Transform, rhs: Rotation, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); @@ -186,12 +176,11 @@ md_impl_all!( ); -// RotationBase × TransformBase +// Rotation × Transform md_impl_all!( - Mul, mul where N: One; - (D, D), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul - where SA::Alloc: Allocator, DimNameSum >; - self: RotationBase, rhs: TransformBase, Output = OwnedTransform; + Mul, mul where N: Real; + (D, D), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul; + self: Rotation, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -199,13 +188,11 @@ md_impl_all!( ); -// TransformBase × UnitQuaternionBase +// Transform × UnitQuaternion md_impl_all!( Mul, mul where N: Real; - (U4, U4), (U4, U1) for C: TCategoryMul - where SB::Alloc: Allocator - where SB::Alloc: Allocator; - self: TransformBase, rhs: UnitQuaternionBase, Output = OwnedTransform; + (U4, U4), (U4, U1) for C: TCategoryMul; + self: Transform, rhs: UnitQuaternion, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); @@ -213,13 +200,11 @@ md_impl_all!( ); -// UnitQuaternionBase × TransformBase +// UnitQuaternion × Transform md_impl_all!( Mul, mul where N: Real; - (U4, U1), (U4, U4) for C: TCategoryMul - where SA::Alloc: Allocator - where SA::Alloc: Allocator; - self: UnitQuaternionBase, rhs: TransformBase, Output = OwnedTransform; + (U4, U1), (U4, U4) for C: TCategoryMul; + self: UnitQuaternion, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -228,26 +213,24 @@ md_impl_all!( -// TransformBase × IsometryBase +// Transform × Isometry md_impl_all!( Mul, mul where N: Real; (DimNameSum, DimNameSum), (D, U1) - for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SB::Alloc> > - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: IsometryBase, Output = OwnedTransform; + for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; + self: Transform, rhs: Isometry, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); ); -// IsometryBase × TransformBase +// Isometry × Transform md_impl_all!( Mul, mul where N: Real; (D, U1), (DimNameSum, DimNameSum) - for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SA::Alloc> > - where SA::Alloc: Allocator, DimNameSum >; - self: IsometryBase, rhs: TransformBase, Output = OwnedTransform; + for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; + self: Isometry, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -255,28 +238,24 @@ md_impl_all!( ); -// TransformBase × SimilarityBase +// Transform × Similarity md_impl_all!( Mul, mul where N: Real; (DimNameSum, DimNameSum), (D, U1) - for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SB::Alloc> > - where SB::Alloc: Allocator - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: SimilarityBase, Output = OwnedTransform; + for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; + self: Transform, rhs: Similarity, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); ); -// SimilarityBase × TransformBase +// Similarity × Transform md_impl_all!( Mul, mul where N: Real; (D, U1), (DimNameSum, DimNameSum) - for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SA::Alloc> > - where SA::Alloc: Allocator - where SA::Alloc: Allocator, DimNameSum >; - self: SimilarityBase, rhs: TransformBase, Output = OwnedTransform; + for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; + self: Similarity, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -293,25 +272,23 @@ md_impl_all!( * `DimNameAdd` requirement). * */ -// TransformBase × TranslationBase +// Transform × Translation md_impl_all!( Mul, mul where N: Real; - (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: TranslationBase, Output = OwnedTransform; + (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul; + self: Transform, rhs: Translation, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); ); -// TranslationBase × TransformBase +// Translation × Transform md_impl_all!( Mul, mul where N: Real; (D, U1), (DimNameSum, DimNameSum) - for D: DimNameAdd, C: TCategoryMul - where SA::Alloc: Allocator, DimNameSum >; - self: TranslationBase, rhs: TransformBase, Output = OwnedTransform; + for D: DimNameAdd, C: TCategoryMul; + self: Translation, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -320,23 +297,22 @@ md_impl_all!( -// TransformBase ÷ TransformBase +// Transform ÷ Transform md_impl_all!( - Div, div where N: ApproxEq, Field; + Div, div where N: Real; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: TCategoryMul, CB: SubTCategoryOf; - self: TransformBase, rhs: TransformBase, Output = OwnedTransform; + self: Transform, rhs: Transform, Output = Transform; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.clone_owned().inverse(); [ref ref] => self * rhs.clone_owned().inverse(); ); -// TransformBase ÷ RotationBase +// Transform ÷ Rotation md_impl_all!( - Div, div where N: One; - (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategoryMul - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: RotationBase, Output = OwnedTransform; + Div, div where N: Real; + (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategoryMul; + self: Transform, rhs: Rotation, Output = Transform; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); @@ -344,12 +320,11 @@ md_impl_all!( ); -// RotationBase ÷ TransformBase +// Rotation ÷ Transform md_impl_all!( - Div, div where N: One; - (D, D), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul - where SA::Alloc: Allocator, DimNameSum >; - self: RotationBase, rhs: TransformBase, Output = OwnedTransform; + Div, div where N: Real; + (D, D), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul; + self: Rotation, rhs: Transform, Output = Transform; [val val] => self.inverse() * rhs; [ref val] => self.inverse() * rhs; [val ref] => self.inverse() * rhs; @@ -357,13 +332,11 @@ md_impl_all!( ); -// TransformBase ÷ UnitQuaternionBase +// Transform ÷ UnitQuaternion md_impl_all!( Div, div where N: Real; - (U4, U4), (U4, U1) for C: TCategoryMul - where SB::Alloc: Allocator - where SB::Alloc: Allocator; - self: TransformBase, rhs: UnitQuaternionBase, Output = OwnedTransform; + (U4, U4), (U4, U1) for C: TCategoryMul; + self: Transform, rhs: UnitQuaternion, Output = Transform; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); @@ -371,13 +344,11 @@ md_impl_all!( ); -// UnitQuaternionBase ÷ TransformBase +// UnitQuaternion ÷ Transform md_impl_all!( Div, div where N: Real; - (U4, U1), (U4, U4) for C: TCategoryMul - where SA::Alloc: Allocator - where SA::Alloc: Allocator; - self: UnitQuaternionBase, rhs: TransformBase, Output = OwnedTransform; + (U4, U1), (U4, U4) for C: TCategoryMul; + self: UnitQuaternion, rhs: Transform, Output = Transform; [val val] => self.inverse() * rhs; [ref val] => self.inverse() * rhs; [val ref] => self.inverse() * rhs; @@ -386,26 +357,26 @@ md_impl_all!( -// // TransformBase ÷ IsometryBase +// // Transform ÷ Isometry // md_impl_all!( // Div, div where N: Real; // (DimNameSum, DimNameSum), (D, U1) -// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SB::Alloc> > +// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SB::Alloc: Allocator, DimNameSum >; -// self: TransformBase, rhs: IsometryBase, Output = OwnedTransform; +// self: Transform, rhs: Isometry, Output = Transform; // [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.inverse().to_homogeneous()); // [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous()); // [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.inverse().to_homogeneous()); // [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous()); // ); -// // IsometryBase ÷ TransformBase +// // Isometry ÷ Transform // md_impl_all!( // Div, div where N: Real; // (D, U1), (DimNameSum, DimNameSum) -// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SA::Alloc> > +// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SA::Alloc: Allocator, DimNameSum >; -// self: IsometryBase, rhs: TransformBase, Output = OwnedTransform; +// self: Isometry, rhs: Transform, Output = Transform; // [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -413,28 +384,28 @@ md_impl_all!( // ); -// // TransformBase ÷ SimilarityBase +// // Transform ÷ Similarity // md_impl_all!( // Div, div where N: Real; // (DimNameSum, DimNameSum), (D, U1) -// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SB::Alloc> > +// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SB::Alloc: Allocator // where SB::Alloc: Allocator, DimNameSum >; -// self: TransformBase, rhs: SimilarityBase, Output = OwnedTransform; +// self: Transform, rhs: Similarity, Output = Transform; // [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); // [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); // [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); // [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); // ); -// // SimilarityBase ÷ TransformBase +// // Similarity ÷ Transform // md_impl_all!( // Div, div where N: Real; // (D, U1), (DimNameSum, DimNameSum) -// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf, SA::Alloc> > +// for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SA::Alloc: Allocator // where SA::Alloc: Allocator, DimNameSum >; -// self: SimilarityBase, rhs: TransformBase, Output = OwnedTransform; +// self: Similarity, rhs: Transform, Output = Transform; // [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); @@ -443,25 +414,23 @@ md_impl_all!( -// TransformBase ÷ TranslationBase +// Transform ÷ Translation md_impl_all!( Div, div where N: Real; - (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: TranslationBase, Output = OwnedTransform; + (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul; + self: Transform, rhs: Translation, Output = Transform; [val val] => self * rhs.inverse(); [ref val] => self * rhs.inverse(); [val ref] => self * rhs.inverse(); [ref ref] => self * rhs.inverse(); ); -// TranslationBase ÷ TransformBase +// Translation ÷ Transform md_impl_all!( Div, div where N: Real; (D, U1), (DimNameSum, DimNameSum) - for D: DimNameAdd, C: TCategoryMul - where SA::Alloc: Allocator, DimNameSum >; - self: TranslationBase, rhs: TransformBase, Output = OwnedTransform; + for D: DimNameAdd, C: TCategoryMul; + self: Translation, rhs: Transform, Output = Transform; [val val] => self.inverse() * rhs; [ref val] => self.inverse() * rhs; [val ref] => self.inverse() * rhs; @@ -469,36 +438,33 @@ md_impl_all!( ); -// TransformBase ×= TransformBase +// Transform ×= Transform md_assign_impl_all!( - MulAssign, mul_assign; + MulAssign, mul_assign where N: Real; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: TCategory, CB: SubTCategoryOf; - self: TransformBase, rhs: TransformBase; + self: Transform, rhs: Transform; [val] => *self.matrix_mut_unchecked() *= rhs.unwrap(); [ref] => *self.matrix_mut_unchecked() *= rhs.matrix(); ); -// TransformBase ×= SimilarityBase +// Transform ×= Similarity md_assign_impl_all!( - MulAssign, mul_assign; + MulAssign, mul_assign where N: Real; (DimNameSum, DimNameSum), (D, U1) - for D: DimNameAdd, C: TCategory, R: SubsetOf, SB::Alloc> > - where SB::Alloc: Allocator, DimNameSum > - where SB::Alloc: Allocator; - self: TransformBase, rhs: SimilarityBase; + for D: DimNameAdd, C: TCategory, R: SubsetOf> >; + self: Transform, rhs: Similarity; [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); ); -// TransformBase ×= IsometryBase +// Transform ×= Isometry md_assign_impl_all!( - MulAssign, mul_assign; + MulAssign, mul_assign where N: Real; (DimNameSum, DimNameSum), (D, U1) - for D: DimNameAdd, C: TCategory, R: SubsetOf, SB::Alloc> > - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: IsometryBase; + for D: DimNameAdd, C: TCategory, R: SubsetOf> >; + self: Transform, rhs: Isometry; [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); ); @@ -511,105 +477,94 @@ md_assign_impl_all!( * `DimNameAdd` requirement). * */ -// TransformBase ×= TranslationBase -md_assign_impl_all!( - MulAssign, mul_assign where N: One; - (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: TranslationBase; - [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); - [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); -); - - -// TransformBase ×= RotationBase -md_assign_impl_all!( - MulAssign, mul_assign where N: One; - (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategory - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: RotationBase; - [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); - [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); -); - - -// TransformBase ×= UnitQuaternionBase +// Transform ×= Translation md_assign_impl_all!( MulAssign, mul_assign where N: Real; - (U4, U4), (U4, U1) for C: TCategory - where SB::Alloc: Allocator - where SB::Alloc: Allocator; - self: TransformBase, rhs: UnitQuaternionBase; + (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory; + self: Transform, rhs: Translation; [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); ); -// TransformBase ÷= TransformBase +// Transform ×= Rotation md_assign_impl_all!( - DivAssign, div_assign where N: Field, ApproxEq; + MulAssign, mul_assign where N: Real; + (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategory; + self: Transform, rhs: Rotation; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); +); + + +// Transform ×= UnitQuaternion +md_assign_impl_all!( + MulAssign, mul_assign where N: Real; + (U4, U4), (U4, U1) for C: TCategory; + self: Transform, rhs: UnitQuaternion; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); +); + + +// Transform ÷= Transform +md_assign_impl_all!( + DivAssign, div_assign where N: Real; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: SuperTCategoryOf, CB: SubTCategoryOf; - self: TransformBase, rhs: TransformBase; + self: Transform, rhs: Transform; [val] => *self *= rhs.clone_owned().inverse(); [ref] => *self *= rhs.clone_owned().inverse(); ); -// // TransformBase ÷= SimilarityBase +// // Transform ÷= Similarity // md_assign_impl_all!( // DivAssign, div_assign; // (DimNameSum, DimNameSum), (D, U1) -// for D: DimNameAdd, C: TCategory, R: SubsetOf, SB::Alloc> > -// where SB::Alloc: Allocator, DimNameSum > -// where SB::Alloc: Allocator; -// self: TransformBase, rhs: SimilarityBase; +// for D: DimNameAdd, C: TCategory, R: SubsetOf> >; +// self: Transform, rhs: Similarity; // [val] => *self *= rhs.inverse(); // [ref] => *self *= rhs.inverse(); // ); // // -// // TransformBase ÷= IsometryBase +// // Transform ÷= Isometry // md_assign_impl_all!( // DivAssign, div_assign; // (DimNameSum, DimNameSum), (D, U1) -// for D: DimNameAdd, C: TCategory, R: SubsetOf, SB::Alloc> > -// where SB::Alloc: Allocator, DimNameSum >; -// self: TransformBase, rhs: IsometryBase; +// for D: DimNameAdd, C: TCategory, R: SubsetOf> >; +// self: Transform, rhs: Isometry; // [val] => *self *= rhs.inverse(); // [ref] => *self *= rhs.inverse(); // ); -// TransformBase ÷= TranslationBase -md_assign_impl_all!( - DivAssign, div_assign where N: One, ClosedNeg; - (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: TranslationBase; - [val] => *self *= rhs.inverse(); - [ref] => *self *= rhs.inverse(); -); - - -// TransformBase ÷= RotationBase -md_assign_impl_all!( - DivAssign, div_assign where N: One; - (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategory - where SB::Alloc: Allocator, DimNameSum >; - self: TransformBase, rhs: RotationBase; - [val] => *self *= rhs.inverse(); - [ref] => *self *= rhs.inverse(); -); - - -// TransformBase ÷= UnitQuaternionBase +// Transform ÷= Translation md_assign_impl_all!( DivAssign, div_assign where N: Real; - (U4, U4), (U4, U1) for C: TCategory - where SB::Alloc: Allocator - where SB::Alloc: Allocator; - self: TransformBase, rhs: UnitQuaternionBase; + (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory; + self: Transform, rhs: Translation; + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); +); + + +// Transform ÷= Rotation +md_assign_impl_all!( + DivAssign, div_assign where N: Real; + (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategory; + self: Transform, rhs: Rotation; + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); +); + + +// Transform ÷= UnitQuaternion +md_assign_impl_all!( + DivAssign, div_assign where N: Real; + (U4, U4), (U4, U1) for C: TCategory; + self: Transform, rhs: UnitQuaternion; [val] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse(); ); diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 1580bcb7..3b8261aa 100644 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -1,114 +1,124 @@ use num::{Zero, One}; +use std::hash; use std::fmt; use approx::ApproxEq; #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Serializer, Deserialize, Deserializer}; +use serde; use alga::general::{Real, ClosedNeg}; -use core::{Scalar, ColumnVector, OwnedSquareMatrix}; +use core::{DefaultAllocator, Scalar, MatrixN, VectorN}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; -use core::storage::{Storage, StorageMut, Owned}; +use core::storage::Owned; use core::allocator::Allocator; -/// A translation with an owned vector storage. -pub type OwnedTranslation = TranslationBase>::Alloc>>; - /// A translation. #[repr(C)] -#[derive(Hash, Debug, Clone, Copy)] -pub struct TranslationBase*/> { +#[derive(Debug)] +pub struct Translation + where DefaultAllocator: Allocator { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. - pub vector: ColumnVector + pub vector: VectorN } -#[cfg(feature = "serde-serialize")] -impl Serialize for TranslationBase - where N: Scalar, - D: DimName, - ColumnVector: Serialize, -{ - fn serialize(&self, serializer: T) -> Result - where T: Serializer - { - self.vector.serialize(serializer) +impl hash::Hash for Translation + where DefaultAllocator: Allocator, + Owned: hash::Hash { + fn hash(&self, state: &mut H) { + self.vector.hash(state) + } +} + +impl Copy for Translation + where DefaultAllocator: Allocator, + Owned: Copy { } + +impl Clone for Translation + where DefaultAllocator: Allocator, + Owned: Clone { + #[inline] + fn clone(&self) -> Self { + Translation::from_vector(self.vector.clone()) } } #[cfg(feature = "serde-serialize")] -impl<'de, N, D, S> Deserialize<'de> for TranslationBase - where N: Scalar, - D: DimName, - ColumnVector: Deserialize<'de>, -{ - fn deserialize(deserializer: T) -> Result - where T: Deserializer<'de> - { - ColumnVector::deserialize(deserializer).map(|x| TranslationBase { vector: x }) - } +impl serde::Serialize for Translation +where DefaultAllocator: Allocator, + Owned: serde::Serialize { + + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + self.vector.serialize(serializer) + } } -impl TranslationBase - where N: Scalar, - S: Storage { +#[cfg(feature = "serde-serialize")] +impl<'a, N: Scalar, D: DimName> serde::Deserialize<'a> for Translation +where DefaultAllocator: Allocator, + Owned: serde::Deserialize<'a> { + + fn deserialize(deserializer: Des) -> Result + where Des: serde::Deserializer<'a> { + let matrix = VectorN::::deserialize(deserializer)?; + + Ok(Translation::from_vector(matrix)) + } +} + +impl Translation + where DefaultAllocator: Allocator { /// Creates a new translation from the given vector. #[inline] - pub fn from_vector(vector: ColumnVector) -> TranslationBase { - TranslationBase { + pub fn from_vector(vector: VectorN) -> Translation { + Translation { vector: vector } } /// Inverts `self`. #[inline] - pub fn inverse(&self) -> OwnedTranslation + pub fn inverse(&self) -> Translation where N: ClosedNeg { - TranslationBase::from_vector(-&self.vector) + Translation::from_vector(-&self.vector) } /// Converts this translation into its equivalent homogeneous transformation matrix. #[inline] - pub fn to_homogeneous(&self) -> OwnedSquareMatrix, S::Alloc> + pub fn to_homogeneous(&self) -> MatrixN> where N: Zero + One, D: DimNameAdd, - S::Alloc: Allocator, DimNameSum> { - let mut res = OwnedSquareMatrix::::identity(); + DefaultAllocator: Allocator, DimNameSum> { + let mut res = MatrixN::>::identity(); res.fixed_slice_mut::(0, D::dim()).copy_from(&self.vector); res } -} - -impl TranslationBase - where N: Scalar + ClosedNeg, - S: StorageMut { /// Inverts `self` in-place. #[inline] - pub fn inverse_mut(&mut self) { + pub fn inverse_mut(&mut self) + where N: ClosedNeg { self.vector.neg_mut() } } -impl Eq for TranslationBase - where N: Scalar + Eq, - S: Storage { +impl Eq for Translation + where DefaultAllocator: Allocator { } -impl PartialEq for TranslationBase - where N: Scalar + PartialEq, - S: Storage { +impl PartialEq for Translation + where DefaultAllocator: Allocator { #[inline] - fn eq(&self, right: &TranslationBase) -> bool { + fn eq(&self, right: &Translation) -> bool { self.vector == right.vector } } -impl ApproxEq for TranslationBase - where N: Scalar + ApproxEq, - S: Storage, +impl ApproxEq for Translation + where DefaultAllocator: Allocator, N::Epsilon: Copy { type Epsilon = N::Epsilon; @@ -143,31 +153,14 @@ impl ApproxEq for TranslationBase * Display * */ -impl fmt::Display for TranslationBase - where N: Real + fmt::Display, - S: Storage, - S::Alloc: Allocator { +impl fmt::Display for Translation + where DefaultAllocator: Allocator + + Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "TranslationBase {{")); + try!(writeln!(f, "Translation {{")); try!(write!(f, "{:.*}", precision, self.vector)); writeln!(f, "}}") } } - - -// // /* -// // * -// // * Absolute -// // * -// // */ -// // impl Absolute for $t { -// // type AbsoluteValue = $submatrix; -// // -// // #[inline] -// // fn abs(m: &$t) -> $submatrix { -// // Absolute::abs(&m.submatrix) -// // } -// // } -// */ diff --git a/src/geometry/translation_alga.rs b/src/geometry/translation_alga.rs index fcac3860..b0fbdbcc 100644 --- a/src/geometry/translation_alga.rs +++ b/src/geometry/translation_alga.rs @@ -1,14 +1,14 @@ use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id}; use alga::linear::{Transformation, ProjectiveTransformation, Similarity, AffineTransformation, - Isometry, DirectIsometry, Translation}; + Isometry, DirectIsometry}; +use alga::linear::Translation as AlgaTranslation; -use core::ColumnVector; -use core::dimension::{DimName, U1}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::{DefaultAllocator, VectorN}; +use core::dimension::DimName; +use core::allocator::Allocator; -use geometry::{TranslationBase, PointBase}; +use geometry::{Translation, Point}; /* @@ -16,20 +16,16 @@ use geometry::{TranslationBase, PointBase}; * Algebraic structures. * */ -impl Identity for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Identity for Translation + where DefaultAllocator: Allocator { #[inline] fn identity() -> Self { Self::identity() } } -impl Inverse for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Inverse for Translation + where DefaultAllocator: Allocator { #[inline] fn inverse(&self) -> Self { self.inverse() @@ -41,10 +37,8 @@ impl Inverse for TranslationBase } } -impl AbstractMagma for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AbstractMagma for Translation + where DefaultAllocator: Allocator { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs @@ -53,10 +47,8 @@ impl AbstractMagma for TranslationBase),* $(,)*) => {$( - impl $marker<$operator> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { } + impl $marker<$operator> for Translation + where DefaultAllocator: Allocator { } )*} ); @@ -73,40 +65,34 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Transformation> for Translation + where DefaultAllocator: Allocator { #[inline] - fn transform_point(&self, pt: &PointBase) -> PointBase { + fn transform_point(&self, pt: &Point) -> Point { pt + &self.vector } #[inline] - fn transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn transform_vector(&self, v: &VectorN) -> VectorN { v.clone() } } -impl ProjectiveTransformation> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl ProjectiveTransformation> for Translation + where DefaultAllocator: Allocator { #[inline] - fn inverse_transform_point(&self, pt: &PointBase) -> PointBase { + fn inverse_transform_point(&self, pt: &Point) -> Point { pt - &self.vector } #[inline] - fn inverse_transform_vector(&self, v: &ColumnVector) -> ColumnVector { + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { v.clone() } } -impl AffineTransformation> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AffineTransformation> for Translation + where DefaultAllocator: Allocator { type Rotation = Id; type NonUniformScaling = Id; type Translation = Self; @@ -148,10 +134,9 @@ impl AffineTransformation> for TranslationB } -impl Similarity> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Similarity> for Translation + where DefaultAllocator: Allocator { + type Scaling = Id; #[inline] @@ -172,10 +157,8 @@ impl Similarity> for TranslationBase {$( - impl $Trait> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { } + impl $Trait> for Translation + where DefaultAllocator: Allocator { } )*} ); @@ -183,17 +166,15 @@ marker_impl!(Isometry, DirectIsometry); /// Subgroups of the n-dimensional translation group `T(n)`. -impl Translation> for TranslationBase - where N: Real, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl AlgaTranslation> for Translation + where DefaultAllocator: Allocator { #[inline] - fn to_vector(&self) -> ColumnVector { + fn to_vector(&self) -> VectorN { self.vector.clone() } #[inline] - fn from_vector(v: ColumnVector) -> Option { + fn from_vector(v: VectorN) -> Option { Some(Self::from_vector(v)) } @@ -203,7 +184,7 @@ impl Translation> for TranslationBase, b: &PointBase) -> Option { + fn translation_between(a: &Point, b: &Point) -> Option { Some(Self::from_vector(b - a)) } } diff --git a/src/geometry/translation_alias.rs b/src/geometry/translation_alias.rs index b607d6af..c6dfcf4b 100644 --- a/src/geometry/translation_alias.rs +++ b/src/geometry/translation_alias.rs @@ -1,10 +1,6 @@ -use core::MatrixArray; -use core::dimension::{U1, U2, U3}; +use core::dimension::{U2, U3}; -use geometry::TranslationBase; - -/// A D-dimensional translation. -pub type Translation = TranslationBase>; +use geometry::Translation; /// A 2-dimensional translation. pub type Translation2 = Translation; diff --git a/src/geometry/translation_construction.rs b/src/geometry/translation_construction.rs index 92bbe342..1030f34a 100644 --- a/src/geometry/translation_construction.rs +++ b/src/geometry/translation_construction.rs @@ -1,43 +1,39 @@ #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "arbitrary")] +use core::storage::Owned; use num::{Zero, One}; use rand::{Rng, Rand}; use alga::general::ClosedAdd; -use core::{ColumnVector, Scalar}; +use core::{DefaultAllocator, Scalar, VectorN}; use core::dimension::{DimName, U1, U2, U3, U4, U5, U6}; -use core::storage::OwnedStorage; -use core::allocator::OwnedAllocator; +use core::allocator::Allocator; -use geometry::TranslationBase; +use geometry::Translation; + +impl Translation + where DefaultAllocator: Allocator { -impl TranslationBase - where N: Scalar + Zero, - S: OwnedStorage, - S::Alloc: OwnedAllocator { /// Creates a new square identity rotation of the given `dimension`. #[inline] - pub fn identity() -> TranslationBase { - Self::from_vector(ColumnVector::::from_element(N::zero())) + pub fn identity() -> Translation { + Self::from_vector(VectorN::::from_element(N::zero())) } } -impl One for TranslationBase - where N: Scalar + Zero + ClosedAdd, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl One for Translation + where DefaultAllocator: Allocator { #[inline] fn one() -> Self { Self::identity() } } -impl Rand for TranslationBase - where N: Scalar + Rand, - S: OwnedStorage, - S::Alloc: OwnedAllocator { +impl Rand for Translation + where DefaultAllocator: Allocator { #[inline] fn rand(rng: &mut G) -> Self { Self::from_vector(rng.gen()) @@ -46,10 +42,9 @@ impl Rand for TranslationBase #[cfg(feature = "arbitrary")] -impl Arbitrary for TranslationBase - where N: Scalar + Arbitrary + Send, - S: OwnedStorage + Send, - S::Alloc: OwnedAllocator { +impl Arbitrary for Translation + where DefaultAllocator: Allocator, + Owned: Send { #[inline] fn arbitrary(rng: &mut G) -> Self { Self::from_vector(Arbitrary::arbitrary(rng)) @@ -63,14 +58,12 @@ impl Arbitrary for TranslationBase */ macro_rules! componentwise_constructors_impl( ($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$( - impl TranslationBase - where N: Scalar, - S: OwnedStorage, - S::Alloc: OwnedAllocator { + impl Translation + where DefaultAllocator: Allocator { /// Initializes this matrix from its components. #[inline] pub fn new($($args: N),*) -> Self { - Self::from_vector(ColumnVector::::new($($args),*)) + Self::from_vector(VectorN::::new($($args),*)) } } )*} diff --git a/src/geometry/translation_conversion.rs b/src/geometry/translation_conversion.rs index c449a54f..e6c8a4b5 100644 --- a/src/geometry/translation_conversion.rs +++ b/src/geometry/translation_conversion.rs @@ -1,146 +1,133 @@ use alga::general::{SubsetOf, SupersetOf, Real}; use alga::linear::Rotation; -use core::{Scalar, ColumnVector, SquareMatrix}; +use core::{DefaultAllocator, Scalar, VectorN, MatrixN}; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use core::storage::OwnedStorage; -use core::allocator::{Allocator, OwnedAllocator}; +use core::allocator::Allocator; -use geometry::{PointBase, TranslationBase, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; +use geometry::{Point, Translation, Isometry, Similarity, Transform, SuperTCategoryOf, TAffine}; /* * This file provides the following conversions: * ============================================= * - * TranslationBase -> TranslationBase - * TranslationBase -> IsometryBase - * TranslationBase -> SimilarityBase - * TranslationBase -> TransformBase - * TranslationBase -> Matrix (homogeneous) + * Translation -> Translation + * Translation -> Isometry + * Translation -> Similarity + * Translation -> Transform + * Translation -> Matrix (homogeneous) */ -impl SubsetOf> for TranslationBase +impl SubsetOf> for Translation where N1: Scalar, N2: Scalar + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> TranslationBase { - TranslationBase::from_vector(self.vector.to_superset()) + fn to_superset(&self) -> Translation { + Translation::from_vector(self.vector.to_superset()) } #[inline] - fn is_in_subset(rot: &TranslationBase) -> bool { - ::is_convertible::<_, ColumnVector>(&rot.vector) + fn is_in_subset(rot: &Translation) -> bool { + ::is_convertible::<_, VectorN>(&rot.vector) } #[inline] - unsafe fn from_superset_unchecked(rot: &TranslationBase) -> Self { - TranslationBase::from_vector(rot.vector.to_subset_unchecked()) + unsafe fn from_superset_unchecked(rot: &Translation) -> Self { + Translation::from_vector(rot.vector.to_subset_unchecked()) } } -impl SubsetOf> for TranslationBase +impl SubsetOf> for Translation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - R: Rotation>, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R: Rotation>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> IsometryBase { - IsometryBase::from_parts(self.to_superset(), R::identity()) + fn to_superset(&self) -> Isometry { + Isometry::from_parts(self.to_superset(), R::identity()) } #[inline] - fn is_in_subset(iso: &IsometryBase) -> bool { + fn is_in_subset(iso: &Isometry) -> bool { iso.rotation == R::identity() } #[inline] - unsafe fn from_superset_unchecked(iso: &IsometryBase) -> Self { + unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { Self::from_superset_unchecked(&iso.translation) } } -impl SubsetOf> for TranslationBase +impl SubsetOf> for Translation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, - R: Rotation>, - SA::Alloc: OwnedAllocator, - SB::Alloc: OwnedAllocator { + R: Rotation>, + DefaultAllocator: Allocator + + Allocator { #[inline] - fn to_superset(&self) -> SimilarityBase { - SimilarityBase::from_parts(self.to_superset(), R::identity(), N2::one()) + fn to_superset(&self) -> Similarity { + Similarity::from_parts(self.to_superset(), R::identity(), N2::one()) } #[inline] - fn is_in_subset(sim: &SimilarityBase) -> bool { + fn is_in_subset(sim: &Similarity) -> bool { sim.isometry.rotation == R::identity() && sim.scaling() == N2::one() } #[inline] - unsafe fn from_superset_unchecked(sim: &SimilarityBase) -> Self { + unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { Self::from_superset_unchecked(&sim.isometry.translation) } } -impl SubsetOf> for TranslationBase +impl SubsetOf> for Translation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, C: SuperTCategoryOf, D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator, DimNameSum>, - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + - Allocator, D> { + DefaultAllocator: Allocator + + Allocator + + Allocator, DimNameSum> + + Allocator, DimNameSum> { #[inline] - fn to_superset(&self) -> TransformBase { - TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) } #[inline] - fn is_in_subset(t: &TransformBase) -> bool { + fn is_in_subset(t: &Transform) -> bool { >::is_in_subset(t.matrix()) } #[inline] - unsafe fn from_superset_unchecked(t: &TransformBase) -> Self { + unsafe fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } -impl SubsetOf, SB>> for TranslationBase +impl SubsetOf>> for Translation where N1: Real, N2: Real + SupersetOf, - SA: OwnedStorage, - SB: OwnedStorage, DimNameSum>, D: DimNameAdd, - SA::Alloc: OwnedAllocator + - Allocator, DimNameSum>, - SB::Alloc: OwnedAllocator, DimNameSum, SB> + - Allocator + - Allocator, D> { + DefaultAllocator: Allocator + + Allocator + + Allocator, DimNameSum> + + Allocator, DimNameSum> { #[inline] - fn to_superset(&self) -> SquareMatrix, SB> { + fn to_superset(&self) -> MatrixN> { self.to_homogeneous().to_superset() } #[inline] - fn is_in_subset(m: &SquareMatrix, SB>) -> bool { + fn is_in_subset(m: &MatrixN>) -> bool { let id = m.fixed_slice::, D>(0, 0); // Scalar types agree. @@ -152,7 +139,7 @@ impl SubsetOf, SB>> for Tr } #[inline] - unsafe fn from_superset_unchecked(m: &SquareMatrix, SB>) -> Self { + unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let t = m.fixed_slice::(0, D::dim()); Self::from_vector(::convert_unchecked(t.into_owned())) } diff --git a/src/geometry/translation_ops.rs b/src/geometry/translation_ops.rs index 08db5ac6..08284524 100644 --- a/src/geometry/translation_ops.rs +++ b/src/geometry/translation_ops.rs @@ -2,167 +2,166 @@ use std::ops::{Mul, MulAssign, Div, DivAssign}; use alga::general::{ClosedAdd, ClosedSub}; -use core::Scalar; +use core::{DefaultAllocator, Scalar}; use core::dimension::{DimName, U1}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; -use core::storage::{OwnedStorage, Storage}; -use core::allocator::{OwnedAllocator, SameShapeAllocator}; +use core::allocator::{Allocator, SameShapeAllocator}; -use geometry::{PointBase, OwnedPoint, TranslationBase, OwnedTranslation}; +use geometry::{Point, Translation}; -// TranslationBase × TranslationBase +// Translation × Translation add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: &'a TranslationBase, right: &'b TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(&self.vector + &right.vector); 'a, 'b); + self: &'a Translation, right: &'b Translation, Output = Translation; + Translation::from_vector(&self.vector + &right.vector); 'a, 'b); add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: &'a TranslationBase, right: TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(&self.vector + right.vector); 'a); + self: &'a Translation, right: Translation, Output = Translation; + Translation::from_vector(&self.vector + right.vector); 'a); add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: TranslationBase, right: &'b TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(self.vector + &right.vector); 'b); + self: Translation, right: &'b Translation, Output = Translation; + Translation::from_vector(self.vector + &right.vector); 'b); add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: TranslationBase, right: TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(self.vector + right.vector); ); + self: Translation, right: Translation, Output = Translation; + Translation::from_vector(self.vector + right.vector); ); -// TranslationBase ÷ TranslationBase +// Translation ÷ Translation // FIXME: instead of calling inverse explicitely, could we just add a `mul_tr` or `mul_inv` method? add_sub_impl!(Div, div, ClosedSub; (D, U1), (D, U1) -> (D) for D: DimName; - self: &'a TranslationBase, right: &'b TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(&self.vector - &right.vector); 'a, 'b); + self: &'a Translation, right: &'b Translation, Output = Translation; + Translation::from_vector(&self.vector - &right.vector); 'a, 'b); add_sub_impl!(Div, div, ClosedSub; (D, U1), (D, U1) -> (D) for D: DimName; - self: &'a TranslationBase, right: TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(&self.vector - right.vector); 'a); + self: &'a Translation, right: Translation, Output = Translation; + Translation::from_vector(&self.vector - right.vector); 'a); add_sub_impl!(Div, div, ClosedSub; (D, U1), (D, U1) -> (D) for D: DimName; - self: TranslationBase, right: &'b TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(self.vector - &right.vector); 'b); + self: Translation, right: &'b Translation, Output = Translation; + Translation::from_vector(self.vector - &right.vector); 'b); add_sub_impl!(Div, div, ClosedSub; (D, U1), (D, U1) -> (D) for D: DimName; - self: TranslationBase, right: TranslationBase, Output = OwnedTranslation; - TranslationBase::from_vector(self.vector - right.vector); ); + self: Translation, right: Translation, Output = Translation; + Translation::from_vector(self.vector - right.vector); ); -// TranslationBase × PointBase +// Translation × Point // FIXME: we don't handle properly non-zero origins here. Do we want this to be the intended // behavior? add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: &'a TranslationBase, right: &'b PointBase, Output = OwnedPoint; + self: &'a Translation, right: &'b Point, Output = Point; right + &self.vector; 'a, 'b); add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: &'a TranslationBase, right: PointBase, Output = OwnedPoint; + self: &'a Translation, right: Point, Output = Point; right + &self.vector; 'a); add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: TranslationBase, right: &'b PointBase, Output = OwnedPoint; + self: Translation, right: &'b Point, Output = Point; right + self.vector; 'b); add_sub_impl!(Mul, mul, ClosedAdd; (D, U1), (D, U1) -> (D) for D: DimName; - self: TranslationBase, right: PointBase, Output = OwnedPoint; + self: Translation, right: Point, Output = Point; right + self.vector; ); -// TranslationBase *= TranslationBase +// Translation *= Translation add_sub_assign_impl!(MulAssign, mul_assign, ClosedAdd; (D, U1), (D, U1) for D: DimName; - self: TranslationBase, right: &'b TranslationBase; + self: Translation, right: &'b Translation; self.vector += &right.vector; 'b); add_sub_assign_impl!(MulAssign, mul_assign, ClosedAdd; (D, U1), (D, U1) for D: DimName; - self: TranslationBase, right: TranslationBase; + self: Translation, right: Translation; self.vector += right.vector; ); add_sub_assign_impl!(DivAssign, div_assign, ClosedSub; (D, U1), (D, U1) for D: DimName; - self: TranslationBase, right: &'b TranslationBase; + self: Translation, right: &'b Translation; self.vector -= &right.vector; 'b); add_sub_assign_impl!(DivAssign, div_assign, ClosedSub; (D, U1), (D, U1) for D: DimName; - self: TranslationBase, right: TranslationBase; + self: Translation, right: Translation; self.vector -= right.vector; ); /* -// TranslationBase × Matrix +// Translation × Matrix add_sub_impl!(Mul, mul; (D1, D1), (R2, C2) for D1, R2, C2; - self: &'a TranslationBase, right: &'b Matrix, Output = MatrixMul; + self: &'a Translation, right: &'b Matrix, Output = MatrixMN; self.vector() * right; 'a, 'b); add_sub_impl!(Mul, mul; (D1, D1), (R2, C2) for D1, R2, C2; - self: &'a TranslationBase, right: Matrix, Output = MatrixMul; + self: &'a Translation, right: Matrix, Output = MatrixMN; self.vector() * right; 'a); add_sub_impl!(Mul, mul; (D1, D1), (R2, C2) for D1, R2, C2; - self: TranslationBase, right: &'b Matrix, Output = MatrixMul; + self: Translation, right: &'b Matrix, Output = MatrixMN; self.unwrap() * right; 'b); add_sub_impl!(Mul, mul; (D1, D1), (R2, C2) for D1, R2, C2; - self: TranslationBase, right: Matrix, Output = MatrixMul; + self: Translation, right: Matrix, Output = MatrixMN; self.unwrap() * right; ); -// Matrix × TranslationBase +// Matrix × Translation add_sub_impl!(Mul, mul; (R1, C1), (D2, D2) for R1, C1, D2; - self: &'a Matrix, right: &'b TranslationBase, Output = MatrixMul; + self: &'a Matrix, right: &'b Translation, Output = MatrixMN; self * right.vector(); 'a, 'b); add_sub_impl!(Mul, mul; (R1, C1), (D2, D2) for R1, C1, D2; - self: &'a Matrix, right: TranslationBase, Output = MatrixMul; + self: &'a Matrix, right: Translation, Output = MatrixMN; self * right.unwrap(); 'a); add_sub_impl!(Mul, mul; (R1, C1), (D2, D2) for R1, C1, D2; - self: Matrix, right: &'b TranslationBase, Output = MatrixMul; + self: Matrix, right: &'b Translation, Output = MatrixMN; self * right.vector(); 'b); add_sub_impl!(Mul, mul; (R1, C1), (D2, D2) for R1, C1, D2; - self: Matrix, right: TranslationBase, Output = MatrixMul; + self: Matrix, right: Translation, Output = MatrixMN; self * right.unwrap(); ); -// Matrix *= TranslationBase +// Matrix *= Translation md_assign_impl!(MulAssign, mul_assign; (R1, C1), (C1, C1) for R1, C1; - self: Matrix, right: &'b TranslationBase; + self: Matrix, right: &'b Translation; self.mul_assign(right.vector()); 'b); md_assign_impl!(MulAssign, mul_assign; (R1, C1), (C1, C1) for R1, C1; - self: Matrix, right: TranslationBase; + self: Matrix, right: Translation; self.mul_assign(right.unwrap()); ); md_assign_impl!(DivAssign, div_assign; (R1, C1), (C1, C1) for R1, C1; - self: Matrix, right: &'b TranslationBase; + self: Matrix, right: &'b Translation; self.mul_assign(right.inverse().vector()); 'b); md_assign_impl!(DivAssign, div_assign; (R1, C1), (C1, C1) for R1, C1; - self: Matrix, right: TranslationBase; + self: Matrix, right: Translation; self.mul_assign(right.inverse().unwrap()); ); */ diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index 8d371234..9d44ab2f 100644 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -3,8 +3,7 @@ use approx::ApproxEq; use num_complex::Complex; use alga::general::Real; -use core::{Unit, SquareMatrix, Vector1, Matrix3}; -use core::dimension::U2; +use core::{Unit, Vector1, Matrix2, Matrix3}; use geometry::Rotation2; /// A complex number with a norm equal to 1. @@ -52,11 +51,11 @@ use geometry::Rotation2; /// /// ///

/// ///

/// ///

/// ///

/// ///

/// ///

/// ///