Add the most common matrix decompositions.

This commit is contained in:
Sébastien Crozet 2017-08-02 19:37:44 +02:00 committed by Sébastien Crozet
parent e0cc7ff21b
commit 3f70af97dd
161 changed files with 12998 additions and 6131 deletions

View File

@ -4,20 +4,89 @@ documented here.
This project adheres to [Semantic Versioning](http://semver.org/). 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 ### 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 * `.kronecker(a, b)` computes the kronecker product (i.e. matrix tensor
product) of two matrices. 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<D>(...)` removes `D` columns.
* `.remove_columns(...)` removes a number of columns known at run-time.
Row removal:
* `.remove_row(...)` removes one row.
* `.remove_fixed_rows<D>(...)` 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<D>(...)` 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<D>(...)` 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] ## [0.12.0]
The main change of this release is the update of the dependency serde to 1.0. The main change of this release is the update of the dependency serde to 1.0.
### Added ### Added
* `.trace()` that computes the trace of a matrix (i.e., the sum of its * `.trace()` that computes the trace of a matrix (the sum of its diagonal
diagonal elements.) elements.)
## [0.11.0] ## [0.11.0]
The [website](http://nalgebra.org) has been fully rewritten and gives a good The [website](http://nalgebra.org) has been fully rewritten and gives a good

View File

@ -16,20 +16,21 @@ name = "nalgebra"
path = "src/lib.rs" path = "src/lib.rs"
[features] [features]
arbitrary = [ "quickcheck" ] arbitrary = [ "quickcheck" ]
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
debug = [ ]
[dependencies] [dependencies]
typenum = "1.4" typenum = "1.7"
generic-array = "0.8" generic-array = "0.8"
rand = "0.3" rand = "0.3"
num-traits = "0.1" num-traits = "0.1"
num-complex = "0.1" num-complex = "0.1"
approx = "0.1" approx = "0.1"
alga = "0.5" alga = "0.5"
serde = { version = "1.0", optional = true } matrixmultiply = "0.1"
serde_derive = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
# clippy = "*" serde_derive = { version = "1.0", optional = true }
[dependencies.quickcheck] [dependencies.quickcheck]
optional = true optional = true
@ -37,3 +38,6 @@ version = "0.4"
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" serde_json = "1.0"
[workspace]
members = [ "nalgebra-lapack" ]

View File

@ -1,11 +1,11 @@
all: all:
CARGO_INCREMENTAL=1 cargo build --features "arbitrary serde-serialize" cargo check --features "debug arbitrary serde-serialize"
doc: doc:
CARGO_INCREMENTAL=1 cargo doc --no-deps --features "arbitrary serde-serialize" cargo doc --no-deps --features "debug arbitrary serde-serialize"
bench: bench:
cargo bench cargo bench
test: test:
cargo test --features "arbitrary serde-serialize" cargo test --features "debug arbitrary serde-serialize"

View File

@ -4,20 +4,12 @@ macro_rules! bench_binop(
($name: ident, $t1: ty, $t2: ty, $binop: ident) => { ($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
#[bench] #[bench]
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
const LEN: usize = 1 << 13;
let mut rng = IsaacRng::new_unseeded(); let mut rng = IsaacRng::new_unseeded();
let a = rng.gen::<$t1>();
let elems1: Vec<$t1> = (0usize .. LEN).map(|_| rng.gen::<$t1>()).collect(); let b = rng.gen::<$t2>();
let elems2: Vec<$t2> = (0usize .. LEN).map(|_| rng.gen::<$t2>()).collect();
let mut i = 0;
bh.iter(|| { bh.iter(|| {
i = (i + 1) & (LEN - 1); a.$binop(b)
unsafe {
test::black_box(elems1.get_unchecked(i).$binop(*elems2.get_unchecked(i)))
}
}) })
} }
} }
@ -27,43 +19,27 @@ macro_rules! bench_binop_ref(
($name: ident, $t1: ty, $t2: ty, $binop: ident) => { ($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
#[bench] #[bench]
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
const LEN: usize = 1 << 13;
let mut rng = IsaacRng::new_unseeded(); let mut rng = IsaacRng::new_unseeded();
let a = rng.gen::<$t1>();
let elems1: Vec<$t1> = (0usize .. LEN).map(|_| rng.gen::<$t1>()).collect(); let b = rng.gen::<$t2>();
let elems2: Vec<$t2> = (0usize .. LEN).map(|_| rng.gen::<$t2>()).collect();
let mut i = 0;
bh.iter(|| { bh.iter(|| {
i = (i + 1) & (LEN - 1); a.$binop(&b)
unsafe {
test::black_box(elems1.get_unchecked(i).$binop(elems2.get_unchecked(i)))
}
}) })
} }
} }
); );
macro_rules! bench_binop_na( macro_rules! bench_binop_fn(
($name: ident, $t1: ty, $t2: ty, $binop: ident) => { ($name: ident, $t1: ty, $t2: ty, $binop: path) => {
#[bench] #[bench]
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
const LEN: usize = 1 << 13;
let mut rng = IsaacRng::new_unseeded(); let mut rng = IsaacRng::new_unseeded();
let a = rng.gen::<$t1>();
let elems1: Vec<$t1> = (0usize .. LEN).map(|_| rng.gen::<$t1>()).collect(); let b = rng.gen::<$t2>();
let elems2: Vec<$t2> = (0usize .. LEN).map(|_| rng.gen::<$t2>()).collect();
let mut i = 0;
bh.iter(|| { bh.iter(|| {
i = (i + 1) & (LEN - 1); $binop(&a, &b)
unsafe {
test::black_box(na::$binop(elems1.get_unchecked(i), elems2.get_unchecked(i)))
}
}) })
} }
} }

192
benches/core/matrix.rs Normal file
View File

@ -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<f32>, Matrix2<f32>, mul);
bench_binop!(mat3_mul_m, Matrix3<f32>, Matrix3<f32>, mul);
bench_binop!(mat4_mul_m, Matrix4<f32>, Matrix4<f32>, mul);
bench_binop_ref!(mat2_tr_mul_m, Matrix2<f32>, Matrix2<f32>, tr_mul);
bench_binop_ref!(mat3_tr_mul_m, Matrix3<f32>, Matrix3<f32>, tr_mul);
bench_binop_ref!(mat4_tr_mul_m, Matrix4<f32>, Matrix4<f32>, tr_mul);
bench_binop!(mat2_add_m, Matrix2<f32>, Matrix2<f32>, add);
bench_binop!(mat3_add_m, Matrix3<f32>, Matrix3<f32>, add);
bench_binop!(mat4_add_m, Matrix4<f32>, Matrix4<f32>, add);
bench_binop!(mat2_sub_m, Matrix2<f32>, Matrix2<f32>, sub);
bench_binop!(mat3_sub_m, Matrix3<f32>, Matrix3<f32>, sub);
bench_binop!(mat4_sub_m, Matrix4<f32>, Matrix4<f32>, sub);
bench_binop!(mat2_mul_v, Matrix2<f32>, Vector2<f32>, mul);
bench_binop!(mat3_mul_v, Matrix3<f32>, Vector3<f32>, mul);
bench_binop!(mat4_mul_v, Matrix4<f32>, Vector4<f32>, mul);
bench_binop_ref!(mat2_tr_mul_v, Matrix2<f32>, Vector2<f32>, tr_mul);
bench_binop_ref!(mat3_tr_mul_v, Matrix3<f32>, Vector3<f32>, tr_mul);
bench_binop_ref!(mat4_tr_mul_v, Matrix4<f32>, Vector4<f32>, tr_mul);
bench_binop!(mat2_mul_s, Matrix2<f32>, f32, mul);
bench_binop!(mat3_mul_s, Matrix3<f32>, f32, mul);
bench_binop!(mat4_mul_s, Matrix4<f32>, f32, mul);
bench_binop!(mat2_div_s, Matrix2<f32>, f32, div);
bench_binop!(mat3_div_s, Matrix3<f32>, f32, div);
bench_binop!(mat4_div_s, Matrix4<f32>, f32, div);
bench_unop!(mat2_inv, Matrix2<f32>, try_inverse);
bench_unop!(mat3_inv, Matrix3<f32>, try_inverse);
bench_unop!(mat4_inv, Matrix4<f32>, try_inverse);
bench_unop!(mat2_transpose, Matrix2<f32>, transpose);
bench_unop!(mat3_transpose, Matrix3<f32>, transpose);
bench_unop!(mat4_transpose, Matrix4<f32>, 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::<f64>::new_random(100, 100);
let b = DMatrix::<f64>::new_random(100, 100);
bench.iter(|| { &a + &b })
}
#[bench]
fn mat4_mul_mat4(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(4, 4);
let b = DMatrix::<f64>::new_random(4, 4);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat5_mul_mat5(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(5, 5);
let b = DMatrix::<f64>::new_random(5, 5);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat6_mul_mat6(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(6, 6);
let b = DMatrix::<f64>::new_random(6, 6);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat7_mul_mat7(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(7, 7);
let b = DMatrix::<f64>::new_random(7, 7);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat8_mul_mat8(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(8, 8);
let b = DMatrix::<f64>::new_random(8, 8);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat9_mul_mat9(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(9, 9);
let b = DMatrix::<f64>::new_random(9, 9);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat10_mul_mat10(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(10, 10);
let b = DMatrix::<f64>::new_random(10, 10);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat10_mul_mat10_static(bench: &mut Bencher) {
let a = MatrixN::<f64, U10>::new_random();
let b = MatrixN::<f64, U10>::new_random();
bench.iter(|| { &a * &b })
}
#[bench]
fn mat100_mul_mat100(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(100, 100);
let b = DMatrix::<f64>::new_random(100, 100);
bench.iter(|| { &a * &b })
}
#[bench]
fn mat500_mul_mat500(bench: &mut Bencher) {
let a = DMatrix::<f64>::from_element(500, 500, 5f64);
let b = DMatrix::<f64>::from_element(500, 500, 6f64);
bench.iter(|| { &a * &b })
}
#[bench]
fn copy_from(bench: &mut Bencher) {
let a = DMatrix::<f64>::new_random(1000, 1000);
let mut b = DMatrix::<f64>::new_random(1000, 1000);
bench.iter(|| {
b.copy_from(&a);
})
}
#[bench]
fn axpy(bench: &mut Bencher) {
let x = DVector::<f64>::from_element(100000, 2.0);
let mut y = DVector::<f64>::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::<f64>::new_random(1000, 1000);
let b = DVector::<f64>::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::<f64>::new_random(100, 100);
let b = DMatrix::<f64>::new_random(100, 100);
let mut ab = DMatrix::<f64>::from_element(100, 100, 0.0);
bench.iter(|| {
test::black_box(a.mul_to(&b, &mut ab));
})
}

2
benches/core/mod.rs Normal file
View File

@ -0,0 +1,2 @@
mod matrix;
mod vector;

128
benches/core/vector.rs Normal file
View File

@ -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<f32>, Vector2<f32>, add);
bench_binop!(vec3_add_v_f32, Vector3<f32>, Vector3<f32>, add);
bench_binop!(vec4_add_v_f32, Vector4<f32>, Vector4<f32>, add);
bench_binop!(vec2_add_v_f64, Vector2<f64>, Vector2<f64>, add);
bench_binop!(vec3_add_v_f64, Vector3<f64>, Vector3<f64>, add);
bench_binop!(vec4_add_v_f64, Vector4<f64>, Vector4<f64>, add);
bench_binop!(vec2_sub_v, Vector2<f32>, Vector2<f32>, sub);
bench_binop!(vec3_sub_v, Vector3<f32>, Vector3<f32>, sub);
bench_binop!(vec4_sub_v, Vector4<f32>, Vector4<f32>, sub);
bench_binop!(vec2_mul_s, Vector2<f32>, f32, mul);
bench_binop!(vec3_mul_s, Vector3<f32>, f32, mul);
bench_binop!(vec4_mul_s, Vector4<f32>, f32, mul);
bench_binop!(vec2_div_s, Vector2<f32>, f32, div);
bench_binop!(vec3_div_s, Vector3<f32>, f32, div);
bench_binop!(vec4_div_s, Vector4<f32>, f32, div);
bench_binop_ref!(vec2_dot_f32, Vector2<f32>, Vector2<f32>, dot);
bench_binop_ref!(vec3_dot_f32, Vector3<f32>, Vector3<f32>, dot);
bench_binop_ref!(vec4_dot_f32, Vector4<f32>, Vector4<f32>, dot);
bench_binop_ref!(vec2_dot_f64, Vector2<f64>, Vector2<f64>, dot);
bench_binop_ref!(vec3_dot_f64, Vector3<f64>, Vector3<f64>, dot);
bench_binop_ref!(vec4_dot_f64, Vector4<f64>, Vector4<f64>, dot);
bench_binop_ref!(vec3_cross, Vector3<f32>, Vector3<f32>, cross);
bench_unop!(vec2_norm, Vector2<f32>, norm);
bench_unop!(vec3_norm, Vector3<f32>, norm);
bench_unop!(vec4_norm, Vector4<f32>, norm);
bench_unop!(vec2_normalize, Vector2<f32>, normalize);
bench_unop!(vec3_normalize, Vector3<f32>, normalize);
bench_unop!(vec4_normalize, Vector4<f32>, normalize);
bench_binop_ref!(vec10000_dot_f64, VectorN<f64, U10000>, VectorN<f64, U10000>, dot);
bench_binop_ref!(vec10000_dot_f32, VectorN<f32, U10000>, VectorN<f32, U10000>, 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::<f64>();
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::<f64>();
let beta = rng.gen::<f64>();
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::<f64>();
bh.iter(|| {
let mut a = a.fixed_rows_mut::<U10000>(0);
let b = b.fixed_rows::<U10000>(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::<f64, U10000>::new_random();
let b = VectorN::<f64, U10000>::new_random();
let n = rng.gen::<f64>();
// 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::<f32>();
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::<f32>();
let beta = rng.gen::<f32>();
bh.iter(|| {
a.axpy(n, &b, beta)
})
}

1
benches/geometry/mod.rs Normal file
View File

@ -0,0 +1 @@
mod quaternion;

View File

@ -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<f32>, Quaternion<f32>, add);
bench_binop!(quaternion_sub_q, Quaternion<f32>, Quaternion<f32>, sub);
bench_binop!(quaternion_mul_q, Quaternion<f32>, Quaternion<f32>, mul);
bench_binop!(unit_quaternion_mul_v, UnitQuaternion<f32>, Vector3<f32>, mul);
bench_binop!(quaternion_mul_s, Quaternion<f32>, f32, mul);
bench_binop!(quaternion_div_s, Quaternion<f32>, f32, div);
bench_unop!(quaternion_inv, Quaternion<f32>, try_inverse);
bench_unop!(unit_quaternion_inv, UnitQuaternion<f32>, inverse);
// bench_unop_self!(quaternion_conjugate, Quaternion<f32>, conjugate);
// bench_unop!(quaternion_normalize, Quaternion<f32>, normalize);

20
benches/lib.rs Normal file
View File

@ -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<f64> {
let mut rng = IsaacRng::new_unseeded();
DMatrix::<f64>::from_fn(nrows, ncols, |_, _| rng.gen())
}

View File

@ -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::<f64>::new_random(100, 100);
bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))
}
#[bench]
fn bidiagonalize_100x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 500);
bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))
}
#[bench]
fn bidiagonalize_4x4(bh: &mut Bencher) {
let m = Matrix4::<f64>::new_random();
bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))
}
#[bench]
fn bidiagonalize_500x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 100);
bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))
}
#[bench]
fn bidiagonalize_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(500, 500);
bh.iter(|| {
let bidiag = Bidiagonal::new(m.clone());
let _ = bidiag.unpack();
})
}

109
benches/linalg/cholesky.rs Normal file
View File

@ -0,0 +1,109 @@
use test::{self, Bencher};
use na::{DMatrix, DVector, Cholesky};
#[bench]
fn cholesky_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(10, 10);
let m = &m * m.transpose();
let v = DVector::<f64>::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::<f64>::new_random(100, 100);
let m = &m * m.transpose();
let v = DVector::<f64>::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::<f64>::new_random(500, 500);
let m = &m * m.transpose();
let v = DVector::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(500, 500);
let m = &m * m.transpose();
let chol = Cholesky::new(m.clone()).unwrap();
bh.iter(|| {
let _ = chol.inverse();
})
}

30
benches/linalg/eigen.rs Normal file
View File

@ -0,0 +1,30 @@
use test::Bencher;
use na::{DMatrix, Eigen};
#[bench]
fn eigen_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))
}
#[bench]
fn eigen_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 500);
bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))
}
#[bench]
fn eigenvalues_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))
}
#[bench]
fn eigenvalues_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 500);
bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))
}

View File

@ -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::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(10, 10);
let lu = FullPivLU::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(10, 1.0);
lu.solve(&mut b);
})
}
#[bench]
fn full_piv_lu_solve_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let lu = FullPivLU::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(100, 1.0);
lu.solve(&mut b);
})
}
#[bench]
fn full_piv_lu_solve_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 500);
let lu = FullPivLU::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(500, 1.0);
lu.solve(&mut b);
})
}
#[bench]
fn full_piv_lu_inverse_10x10(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(500, 500);
let lu = FullPivLU::new(m.clone());
bh.iter(|| {
test::black_box(lu.determinant())
})
}

View File

@ -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::<f64>::new_random();
bh.iter(|| test::black_box(Hessenberg::new(m.clone())))
}
#[bench]
fn hessenberg_decompose_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
bh.iter(|| test::black_box(Hessenberg::new(m.clone())))
}
#[bench]
fn hessenberg_decompose_200x200(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(200, 200);
bh.iter(|| test::black_box(Hessenberg::new(m.clone())))
}
#[bench]
fn hessenberg_decompose_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(500, 500);
bh.iter(|| {
let hess = Hessenberg::new(m.clone());
let _ = hess.unpack();
})
}

114
benches/linalg/lu.rs Normal file
View File

@ -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::<f64>::new_random(10, 10);
bh.iter(|| test::black_box(LU::new(m.clone())))
}
#[bench]
fn lu_decompose_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
bh.iter(|| test::black_box(LU::new(m.clone())))
}
#[bench]
fn lu_decompose_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 500);
bh.iter(|| test::black_box(LU::new(m.clone())))
}
#[bench]
fn lu_solve_10x10(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(10, 10);
let lu = LU::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(10, 1.0);
lu.solve(&mut b);
})
}
#[bench]
fn lu_solve_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let lu = LU::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(100, 1.0);
lu.solve(&mut b);
})
}
#[bench]
fn lu_solve_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 500);
let lu = LU::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(500, 1.0);
lu.solve(&mut b);
})
}
#[bench]
fn lu_inverse_10x10(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(500, 500);
let lu = LU::new(m.clone());
bh.iter(|| {
test::black_box(lu.determinant())
})
}

11
benches/linalg/mod.rs Normal file
View File

@ -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;

137
benches/linalg/qr.rs Normal file
View File

@ -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::<f64>::new_random(100, 100);
bh.iter(|| test::black_box(QR::new(m.clone())))
}
#[bench]
fn qr_decompose_100x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 500);
bh.iter(|| test::black_box(QR::new(m.clone())))
}
#[bench]
fn qr_decompose_4x4(bh: &mut Bencher) {
let m = Matrix4::<f64>::new_random();
bh.iter(|| test::black_box(QR::new(m.clone())))
}
#[bench]
fn qr_decompose_500x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 100);
bh.iter(|| test::black_box(QR::new(m.clone())))
}
#[bench]
fn qr_decompose_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::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::<f64>::new_random(10, 10);
let qr = QR::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(10, 1.0);
qr.solve(&mut b);
})
}
#[bench]
fn qr_solve_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let qr = QR::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(100, 1.0);
qr.solve(&mut b);
})
}
#[bench]
fn qr_solve_500x500(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(500, 500);
let qr = QR::new(m.clone());
bh.iter(|| {
let mut b = DVector::<f64>::from_element(500, 1.0);
qr.solve(&mut b);
})
}
#[bench]
fn qr_inverse_10x10(bh: &mut Bencher) {
let m = DMatrix::<f64>::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::<f64>::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::<f64>::new_random(500, 500);
let qr = QR::new(m.clone());
bh.iter(|| {
test::black_box(qr.try_inverse())
})
}

51
benches/linalg/schur.rs Normal file
View File

@ -0,0 +1,51 @@
use test::{self, Bencher};
use na::{Matrix4, RealSchur};
#[bench]
fn schur_decompose_4x4(bh: &mut Bencher) {
let m = Matrix4::<f64>::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::<f64>::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()))
}

82
benches/linalg/solve.rs Normal file
View File

@ -0,0 +1,82 @@
use test::Bencher;
use na::{DMatrix, DVector};
#[bench]
fn solve_l_triangular_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let v = DVector::<f64>::new_random(100);
bh.iter(|| {
let _ = m.solve_lower_triangular(&v);
})
}
#[bench]
fn solve_l_triangular_1000x1000(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(1000, 1000);
let v = DVector::<f64>::new_random(1000);
bh.iter(|| {
let _ = m.solve_lower_triangular(&v);
})
}
#[bench]
fn tr_solve_l_triangular_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let v = DVector::<f64>::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::<f64>::new_random(1000, 1000);
let v = DVector::<f64>::new_random(1000);
bh.iter(|| {
let _ = m.tr_solve_lower_triangular(&v);
})
}
#[bench]
fn solve_u_triangular_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let v = DVector::<f64>::new_random(100);
bh.iter(|| {
let _ = m.solve_upper_triangular(&v);
})
}
#[bench]
fn solve_u_triangular_1000x1000(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(1000, 1000);
let v = DVector::<f64>::new_random(1000);
bh.iter(|| {
let _ = m.solve_upper_triangular(&v);
})
}
#[bench]
fn tr_solve_u_triangular_100x100(bh: &mut Bencher) {
let m = DMatrix::<f64>::new_random(100, 100);
let v = DVector::<f64>::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::<f64>::new_random(1000, 1000);
let v = DVector::<f64>::new_random(1000);
bh.iter(|| {
let _ = m.tr_solve_upper_triangular(&v);
})
}

99
benches/linalg/svd.rs Normal file
View File

@ -0,0 +1,99 @@
use test::{self, Bencher};
use na::{Matrix4, SVD};
#[bench]
fn svd_decompose_4x4(bh: &mut Bencher) {
let m = Matrix4::<f64>::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::<f64>::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::<f64>::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::<f64>::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)))
}

View File

@ -0,0 +1,27 @@
use test::{self, Bencher};
use na::{Matrix4, SymmetricEigen};
#[bench]
fn symmetric_eigen_decompose_4x4(bh: &mut Bencher) {
let m = Matrix4::<f64>::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())))
}

View File

@ -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<f32>, Matrix2<f32>, mul);
bench_binop!(_bench_mat3_mul_m, Matrix3<f32>, Matrix3<f32>, mul);
bench_binop!(_bench_mat4_mul_m, Matrix4<f32>, Matrix4<f32>, mul);
bench_binop_ref!(_bench_mat2_tr_mul_m, Matrix2<f32>, Matrix2<f32>, tr_mul);
bench_binop_ref!(_bench_mat3_tr_mul_m, Matrix3<f32>, Matrix3<f32>, tr_mul);
bench_binop_ref!(_bench_mat4_tr_mul_m, Matrix4<f32>, Matrix4<f32>, tr_mul);
bench_binop!(_bench_mat2_add_m, Matrix2<f32>, Matrix2<f32>, add);
bench_binop!(_bench_mat3_add_m, Matrix3<f32>, Matrix3<f32>, add);
bench_binop!(_bench_mat4_add_m, Matrix4<f32>, Matrix4<f32>, add);
bench_binop!(_bench_mat2_sub_m, Matrix2<f32>, Matrix2<f32>, sub);
bench_binop!(_bench_mat3_sub_m, Matrix3<f32>, Matrix3<f32>, sub);
bench_binop!(_bench_mat4_sub_m, Matrix4<f32>, Matrix4<f32>, sub);
bench_binop!(_bench_mat2_mul_v, Matrix2<f32>, Vector2<f32>, mul);
bench_binop!(_bench_mat3_mul_v, Matrix3<f32>, Vector3<f32>, mul);
bench_binop!(_bench_mat4_mul_v, Matrix4<f32>, Vector4<f32>, mul);
bench_binop_ref!(_bench_mat2_tr_mul_v, Matrix2<f32>, Vector2<f32>, tr_mul);
bench_binop_ref!(_bench_mat3_tr_mul_v, Matrix3<f32>, Vector3<f32>, tr_mul);
bench_binop_ref!(_bench_mat4_tr_mul_v, Matrix4<f32>, Vector4<f32>, tr_mul);
bench_binop!(_bench_mat2_mul_s, Matrix2<f32>, f32, mul);
bench_binop!(_bench_mat3_mul_s, Matrix3<f32>, f32, mul);
bench_binop!(_bench_mat4_mul_s, Matrix4<f32>, f32, mul);
bench_binop!(_bench_mat2_div_s, Matrix2<f32>, f32, div);
bench_binop!(_bench_mat3_div_s, Matrix3<f32>, f32, div);
bench_binop!(_bench_mat4_div_s, Matrix4<f32>, f32, div);
bench_unop!(_bench_mat2_inv, Matrix2<f32>, try_inverse);
bench_unop!(_bench_mat3_inv, Matrix3<f32>, try_inverse);
bench_unop!(_bench_mat4_inv, Matrix4<f32>, try_inverse);
bench_unop!(_bench_mat2_transpose, Matrix2<f32>, transpose);
bench_unop!(_bench_mat3_transpose, Matrix3<f32>, transpose);
bench_unop!(_bench_mat4_transpose, Matrix4<f32>, transpose);

View File

@ -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<f32>, Quaternion<f32>, add);
bench_binop!(_bench_quaternion_sub_q, Quaternion<f32>, Quaternion<f32>, sub);
bench_binop!(_bench_quaternion_mul_q, Quaternion<f32>, Quaternion<f32>, mul);
bench_binop!(_bench_unit_quaternion_mul_v, UnitQuaternion<f32>, Vector3<f32>, mul);
bench_binop!(_bench_quaternion_mul_s, Quaternion<f32>, f32, mul);
bench_binop!(_bench_quaternion_div_s, Quaternion<f32>, f32, div);
bench_unop!(_bench_quaternion_inv, Quaternion<f32>, try_inverse);
bench_unop!(_bench_unit_quaternion_inv, UnitQuaternion<f32>, inverse);
// bench_unop_self!(_bench_quaternion_conjugate, Quaternion<f32>, conjugate);
// bench_unop!(_bench_quaternion_normalize, Quaternion<f32>, normalize);

View File

@ -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<f32>, Vector2<f32>, add);
bench_binop!(_bench_vec3_add_v, Vector3<f32>, Vector3<f32>, add);
bench_binop!(_bench_vec4_add_v, Vector4<f32>, Vector4<f32>, add);
bench_binop!(_bench_vec2_sub_v, Vector2<f32>, Vector2<f32>, sub);
bench_binop!(_bench_vec3_sub_v, Vector3<f32>, Vector3<f32>, sub);
bench_binop!(_bench_vec4_sub_v, Vector4<f32>, Vector4<f32>, sub);
bench_binop!(_bench_vec2_mul_s, Vector2<f32>, f32, mul);
bench_binop!(_bench_vec3_mul_s, Vector3<f32>, f32, mul);
bench_binop!(_bench_vec4_mul_s, Vector4<f32>, f32, mul);
bench_binop!(_bench_vec2_div_s, Vector2<f32>, f32, div);
bench_binop!(_bench_vec3_div_s, Vector3<f32>, f32, div);
bench_binop!(_bench_vec4_div_s, Vector4<f32>, f32, div);
bench_binop_ref!(_bench_vec2_dot, Vector2<f32>, Vector2<f32>, dot);
bench_binop_ref!(_bench_vec3_dot, Vector3<f32>, Vector3<f32>, dot);
bench_binop_ref!(_bench_vec4_dot, Vector4<f32>, Vector4<f32>, dot);
bench_binop_ref!(_bench_vec3_cross, Vector3<f32>, Vector3<f32>, cross);
bench_unop!(_bench_vec2_norm, Vector2<f32>, norm);
bench_unop!(_bench_vec3_norm, Vector3<f32>, norm);
bench_unop!(_bench_vec4_norm, Vector4<f32>, norm);
bench_unop!(_bench_vec2_normalize, Vector2<f32>, normalize);
bench_unop!(_bench_vec3_normalize, Vector3<f32>, normalize);
bench_unop!(_bench_vec4_normalize, Vector4<f32>, normalize);

View File

@ -1,11 +1,10 @@
extern crate alga; extern crate alga;
extern crate nalgebra as na; extern crate nalgebra as na;
use alga::general::Real;
use alga::linear::FiniteDimInnerSpace; use alga::linear::FiniteDimInnerSpace;
use na::{Unit, ColumnVector, OwnedColumnVector, Vector2, Vector3}; use na::{Real, DefaultAllocator, Unit, VectorN, Vector2, Vector3};
use na::storage::Storage; use na::allocator::Allocator;
use na::dimension::{DimName, U1}; use na::dimension::Dim;
/// Reflects a vector wrt. the hyperplane with normal `plane_normal`. /// Reflects a vector wrt. the hyperplane with normal `plane_normal`.
fn reflect_wrt_hyperplane_with_algebraic_genericity<V>(plane_normal: &Unit<V>, vector: &V) -> V fn reflect_wrt_hyperplane_with_algebraic_genericity<V>(plane_normal: &Unit<V>, vector: &V) -> V
@ -16,12 +15,12 @@ fn reflect_wrt_hyperplane_with_algebraic_genericity<V>(plane_normal: &Unit<V>, v
/// Reflects a vector wrt. the hyperplane with normal `plane_normal`. /// Reflects a vector wrt. the hyperplane with normal `plane_normal`.
fn reflect_wrt_hyperplane_with_structural_genericity<N, D, S>(plane_normal: &Unit<ColumnVector<N, D, S>>, fn reflect_wrt_hyperplane_with_dimensional_genericity<N: Real, D: Dim>(plane_normal: &Unit<VectorN<N, D>>,
vector: &ColumnVector<N, D, S>) vector: &VectorN<N, D>)
-> OwnedColumnVector<N, D, S::Alloc> -> VectorN<N, D>
where N: Real, where N: Real,
D: DimName, D: Dim,
S: Storage<N, D, U1> { DefaultAllocator: Allocator<N, D> {
let n = plane_normal.as_ref(); // Get the underlying V. let n = plane_normal.as_ref(); // Get the underlying V.
vector - n * (n.dot(vector) * na::convert(2.0)) 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(&plane2, &v2).y, -2.0);
assert_eq!(reflect_wrt_hyperplane_with_algebraic_genericity(&plane3, &v3).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_dimensional_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(&plane3, &v3).y, -2.0);
// Call each specific implementation depending on the dimension. // Call each specific implementation depending on the dimension.
assert_eq!(reflect_wrt_hyperplane2(&plane2, &v2).y, -2.0); assert_eq!(reflect_wrt_hyperplane2(&plane2, &v2).y, -2.0);

View File

@ -1,7 +1,7 @@
use core::Matrix; use core::Matrix;
use core::dimension::{Dynamic, U1, U2, U3, U4, U5, U6}; use core::dimension::{Dynamic, U1, U2, U3, U4, U5, U6};
use core::matrix_array::MatrixArray;
use core::matrix_vec::MatrixVec; use core::matrix_vec::MatrixVec;
use core::storage::Owned;
/* /*
* *
@ -10,14 +10,18 @@ use core::matrix_vec::MatrixVec;
* *
* *
*/ */
/// A dynamically sized column-major matrix. /// A staticaly sized column-major matrix with `R` rows and `C` columns.
pub type DMatrix<N> = Matrix<N, Dynamic, Dynamic, MatrixVec<N, Dynamic, Dynamic>>; #[deprecated(note = "This matrix name contains a typo. Use MatrixMN instead.")]
pub type MatrixNM<N, R, C> = Matrix<N, R, C, Owned<N, R, C>>;
/// A staticaly sized column-major matrix with `R` rows and `C` columns. /// A staticaly sized column-major matrix with `R` rows and `C` columns.
pub type MatrixNM<N, R, C> = Matrix<N, R, C, MatrixArray<N, R, C>>; pub type MatrixMN<N, R, C> = Matrix<N, R, C, Owned<N, R, C>>;
/// A staticaly sized column-major square matrix with `D` rows and columns. /// A staticaly sized column-major square matrix with `D` rows and columns.
pub type MatrixN<N, D> = MatrixNM<N, D, D>; pub type MatrixN<N, D> = MatrixMN<N, D, D>;
/// A dynamically sized column-major matrix.
pub type DMatrix<N> = MatrixN<N, Dynamic>;
/// A stack-allocated, column-major, 1x1 square matrix. /// A stack-allocated, column-major, 1x1 square matrix.
pub type Matrix1<N> = MatrixN<N, U1>; pub type Matrix1<N> = MatrixN<N, U1>;
@ -33,75 +37,75 @@ pub type Matrix5<N> = MatrixN<N, U5>;
pub type Matrix6<N> = MatrixN<N, U6>; pub type Matrix6<N> = MatrixN<N, U6>;
/// A stack-allocated, column-major, 1x2 square matrix. /// A stack-allocated, column-major, 1x2 square matrix.
pub type Matrix1x2<N> = MatrixNM<N, U1, U2>; pub type Matrix1x2<N> = MatrixMN<N, U1, U2>;
/// A stack-allocated, column-major, 1x3 square matrix. /// A stack-allocated, column-major, 1x3 square matrix.
pub type Matrix1x3<N> = MatrixNM<N, U1, U3>; pub type Matrix1x3<N> = MatrixMN<N, U1, U3>;
/// A stack-allocated, column-major, 1x4 square matrix. /// A stack-allocated, column-major, 1x4 square matrix.
pub type Matrix1x4<N> = MatrixNM<N, U1, U4>; pub type Matrix1x4<N> = MatrixMN<N, U1, U4>;
/// A stack-allocated, column-major, 1x5 square matrix. /// A stack-allocated, column-major, 1x5 square matrix.
pub type Matrix1x5<N> = MatrixNM<N, U1, U5>; pub type Matrix1x5<N> = MatrixMN<N, U1, U5>;
/// A stack-allocated, column-major, 1x6 square matrix. /// A stack-allocated, column-major, 1x6 square matrix.
pub type Matrix1x6<N> = MatrixNM<N, U1, U6>; pub type Matrix1x6<N> = MatrixMN<N, U1, U6>;
/// A stack-allocated, column-major, 2x3 square matrix. /// A stack-allocated, column-major, 2x3 square matrix.
pub type Matrix2x3<N> = MatrixNM<N, U2, U3>; pub type Matrix2x3<N> = MatrixMN<N, U2, U3>;
/// A stack-allocated, column-major, 2x4 square matrix. /// A stack-allocated, column-major, 2x4 square matrix.
pub type Matrix2x4<N> = MatrixNM<N, U2, U4>; pub type Matrix2x4<N> = MatrixMN<N, U2, U4>;
/// A stack-allocated, column-major, 2x5 square matrix. /// A stack-allocated, column-major, 2x5 square matrix.
pub type Matrix2x5<N> = MatrixNM<N, U2, U5>; pub type Matrix2x5<N> = MatrixMN<N, U2, U5>;
/// A stack-allocated, column-major, 2x6 square matrix. /// A stack-allocated, column-major, 2x6 square matrix.
pub type Matrix2x6<N> = MatrixNM<N, U2, U6>; pub type Matrix2x6<N> = MatrixMN<N, U2, U6>;
/// A stack-allocated, column-major, 3x4 square matrix. /// A stack-allocated, column-major, 3x4 square matrix.
pub type Matrix3x4<N> = MatrixNM<N, U3, U4>; pub type Matrix3x4<N> = MatrixMN<N, U3, U4>;
/// A stack-allocated, column-major, 3x5 square matrix. /// A stack-allocated, column-major, 3x5 square matrix.
pub type Matrix3x5<N> = MatrixNM<N, U3, U5>; pub type Matrix3x5<N> = MatrixMN<N, U3, U5>;
/// A stack-allocated, column-major, 3x6 square matrix. /// A stack-allocated, column-major, 3x6 square matrix.
pub type Matrix3x6<N> = MatrixNM<N, U3, U6>; pub type Matrix3x6<N> = MatrixMN<N, U3, U6>;
/// A stack-allocated, column-major, 4x5 square matrix. /// A stack-allocated, column-major, 4x5 square matrix.
pub type Matrix4x5<N> = MatrixNM<N, U4, U5>; pub type Matrix4x5<N> = MatrixMN<N, U4, U5>;
/// A stack-allocated, column-major, 4x6 square matrix. /// A stack-allocated, column-major, 4x6 square matrix.
pub type Matrix4x6<N> = MatrixNM<N, U4, U6>; pub type Matrix4x6<N> = MatrixMN<N, U4, U6>;
/// A stack-allocated, column-major, 5x6 square matrix. /// A stack-allocated, column-major, 5x6 square matrix.
pub type Matrix5x6<N> = MatrixNM<N, U5, U6>; pub type Matrix5x6<N> = MatrixMN<N, U5, U6>;
/// A stack-allocated, column-major, 2x1 square matrix. /// A stack-allocated, column-major, 2x1 square matrix.
pub type Matrix2x1<N> = MatrixNM<N, U2, U1>; pub type Matrix2x1<N> = MatrixMN<N, U2, U1>;
/// A stack-allocated, column-major, 3x1 square matrix. /// A stack-allocated, column-major, 3x1 square matrix.
pub type Matrix3x1<N> = MatrixNM<N, U3, U1>; pub type Matrix3x1<N> = MatrixMN<N, U3, U1>;
/// A stack-allocated, column-major, 4x1 square matrix. /// A stack-allocated, column-major, 4x1 square matrix.
pub type Matrix4x1<N> = MatrixNM<N, U4, U1>; pub type Matrix4x1<N> = MatrixMN<N, U4, U1>;
/// A stack-allocated, column-major, 5x1 square matrix. /// A stack-allocated, column-major, 5x1 square matrix.
pub type Matrix5x1<N> = MatrixNM<N, U5, U1>; pub type Matrix5x1<N> = MatrixMN<N, U5, U1>;
/// A stack-allocated, column-major, 6x1 square matrix. /// A stack-allocated, column-major, 6x1 square matrix.
pub type Matrix6x1<N> = MatrixNM<N, U6, U1>; pub type Matrix6x1<N> = MatrixMN<N, U6, U1>;
/// A stack-allocated, column-major, 3x2 square matrix. /// A stack-allocated, column-major, 3x2 square matrix.
pub type Matrix3x2<N> = MatrixNM<N, U3, U2>; pub type Matrix3x2<N> = MatrixMN<N, U3, U2>;
/// A stack-allocated, column-major, 4x2 square matrix. /// A stack-allocated, column-major, 4x2 square matrix.
pub type Matrix4x2<N> = MatrixNM<N, U4, U2>; pub type Matrix4x2<N> = MatrixMN<N, U4, U2>;
/// A stack-allocated, column-major, 5x2 square matrix. /// A stack-allocated, column-major, 5x2 square matrix.
pub type Matrix5x2<N> = MatrixNM<N, U5, U2>; pub type Matrix5x2<N> = MatrixMN<N, U5, U2>;
/// A stack-allocated, column-major, 6x2 square matrix. /// A stack-allocated, column-major, 6x2 square matrix.
pub type Matrix6x2<N> = MatrixNM<N, U6, U2>; pub type Matrix6x2<N> = MatrixMN<N, U6, U2>;
/// A stack-allocated, column-major, 4x3 square matrix. /// A stack-allocated, column-major, 4x3 square matrix.
pub type Matrix4x3<N> = MatrixNM<N, U4, U3>; pub type Matrix4x3<N> = MatrixMN<N, U4, U3>;
/// A stack-allocated, column-major, 5x3 square matrix. /// A stack-allocated, column-major, 5x3 square matrix.
pub type Matrix5x3<N> = MatrixNM<N, U5, U3>; pub type Matrix5x3<N> = MatrixMN<N, U5, U3>;
/// A stack-allocated, column-major, 6x3 square matrix. /// A stack-allocated, column-major, 6x3 square matrix.
pub type Matrix6x3<N> = MatrixNM<N, U6, U3>; pub type Matrix6x3<N> = MatrixMN<N, U6, U3>;
/// A stack-allocated, column-major, 5x4 square matrix. /// A stack-allocated, column-major, 5x4 square matrix.
pub type Matrix5x4<N> = MatrixNM<N, U5, U4>; pub type Matrix5x4<N> = MatrixMN<N, U5, U4>;
/// A stack-allocated, column-major, 6x4 square matrix. /// A stack-allocated, column-major, 6x4 square matrix.
pub type Matrix6x4<N> = MatrixNM<N, U6, U4>; pub type Matrix6x4<N> = MatrixMN<N, U6, U4>;
/// A stack-allocated, column-major, 6x5 square matrix. /// A stack-allocated, column-major, 6x5 square matrix.
pub type Matrix6x5<N> = MatrixNM<N, U6, U5>; pub type Matrix6x5<N> = MatrixMN<N, U6, U5>;
/* /*
@ -115,7 +119,7 @@ pub type Matrix6x5<N> = MatrixNM<N, U6, U5>;
pub type DVector<N> = Matrix<N, Dynamic, U1, MatrixVec<N, Dynamic, U1>>; pub type DVector<N> = Matrix<N, Dynamic, U1, MatrixVec<N, Dynamic, U1>>;
/// A statically sized D-dimensional column vector. /// A statically sized D-dimensional column vector.
pub type VectorN<N, D> = MatrixNM<N, D, U1>; pub type VectorN<N, D> = MatrixMN<N, D, U1>;
/// A stack-allocated, 1-dimensional column vector. /// A stack-allocated, 1-dimensional column vector.
pub type Vector1<N> = VectorN<N, U1>; pub type Vector1<N> = VectorN<N, U1>;
@ -142,7 +146,7 @@ pub type Vector6<N> = VectorN<N, U6>;
pub type RowDVector<N> = Matrix<N, U1, Dynamic, MatrixVec<N, U1, Dynamic>>; pub type RowDVector<N> = Matrix<N, U1, Dynamic, MatrixVec<N, U1, Dynamic>>;
/// A statically sized D-dimensional row vector. /// A statically sized D-dimensional row vector.
pub type RowVectorN<N, D> = MatrixNM<N, U1, D>; pub type RowVectorN<N, D> = MatrixMN<N, U1, D>;
/// A stack-allocated, 1-dimensional row vector. /// A stack-allocated, 1-dimensional row vector.
pub type RowVector1<N> = RowVectorN<N, U1>; pub type RowVector1<N> = RowVectorN<N, U1>;

View File

@ -2,10 +2,10 @@
use std::any::Any; use std::any::Any;
use core::Scalar; use core::{DefaultAllocator, Scalar};
use core::constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint}; use core::constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint};
use core::dimension::{Dim, U1}; 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()` /// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()`
/// elements of type `N`. /// 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 /// Every allocator must be both static and dynamic. Though not all implementations may share the
/// same `Buffer` type. /// same `Buffer` type.
pub trait Allocator<N: Scalar, R: Dim, C: Dim>: Any + Sized { pub trait Allocator<N: Scalar, R: Dim, C: Dim = U1>: Any + Sized {
/// The type of buffer this allocator can instanciate. /// The type of buffer this allocator can instanciate.
type Buffer: OwnedStorage<N, R, C, Alloc = Self>; type Buffer: ContiguousStorageMut<N, R, C> + Clone;
/// Allocates a buffer with the given number of rows and columns without initializing its content. /// 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; unsafe fn allocate_uninitialized(nrows: R, ncols: C) -> Self::Buffer;
@ -27,15 +27,20 @@ pub trait Allocator<N: Scalar, R: Dim, C: Dim>: Any + Sized {
fn allocate_from_iterator<I: IntoIterator<Item = N>>(nrows: R, ncols: C, iter: I) -> Self::Buffer; fn allocate_from_iterator<I: IntoIterator<Item = N>>(nrows: R, ncols: C, iter: I) -> Self::Buffer;
} }
/// A matrix data allocator dedicated to the given owned matrix storage. /// A matrix reallocator. Changes the size of the memory buffer that initially contains (RFrom ×
pub trait OwnedAllocator<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C, Alloc = Self>>: /// CFrom) elements to a smaller or larger size (RTo, CTo).
Allocator<N, R, C, Buffer = S> { pub trait Reallocator<N: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
} Allocator<N, RFrom, CFrom> + Allocator<N, RTo, CTo> {
/// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer
impl<N, R, C, T, S> OwnedAllocator<N, R, C, S> for T /// `buf`. Data stored by `buf` are linearly copied to the output:
where N: Scalar, R: Dim, C: Dim, ///
T: Allocator<N, R, C, Buffer = S>, /// * The copy is performed as if both were just arrays (without a matrix structure).
S: OwnedStorage<N, R, C, Alloc = T> { /// * 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: <Self as Allocator<N, RFrom, CFrom>>::Buffer)
-> <Self as Allocator<N, RTo, CTo>>::Buffer;
} }
/// The number of rows of the result of a componentwise operation on two matrices. /// The number of rows of the result of a componentwise operation on two matrices.
@ -45,45 +50,36 @@ pub type SameShapeR<R1, R2> = <ShapeConstraint as SameNumberOfRows<R1, R2>>::Rep
pub type SameShapeC<C1, C2> = <ShapeConstraint as SameNumberOfColumns<C1, C2>>::Representative; pub type SameShapeC<C1, C2> = <ShapeConstraint as SameNumberOfColumns<C1, C2>>::Representative;
// FIXME: Bad name. // FIXME: Bad name.
/// Restricts the given number of rows and columns to be respectively the same. Can only be used /// Restricts the given number of rows and columns to be respectively the same.
/// when `Self = SA::Alloc`. pub trait SameShapeAllocator<N, R1, C1, R2, C2>:
pub trait SameShapeAllocator<N, R1, C1, R2, C2, SA>:
Allocator<N, R1, C1> + Allocator<N, R1, C1> +
Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>> Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>
where R1: Dim, R2: Dim, C1: Dim, C2: Dim, where R1: Dim, R2: Dim, C1: Dim, C2: Dim,
N: Scalar, N: Scalar,
SA: Storage<N, R1, C1, Alloc = Self>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
} }
impl<N, R1, R2, C1, C2, SA> SameShapeAllocator<N, R1, C1, R2, C2, SA> for SA::Alloc impl<N, R1, R2, C1, C2> SameShapeAllocator<N, R1, C1, R2, C2> for DefaultAllocator
where R1: Dim, R2: Dim, C1: Dim, C2: Dim, where R1: Dim, R2: Dim, C1: Dim, C2: Dim,
N: Scalar, N: Scalar,
SA: Storage<N, R1, C1>, DefaultAllocator: Allocator<N, R1, C1> + Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
SA::Alloc: ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
Allocator<N, R1, C1> +
Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
} }
// XXX: Bad name. // XXX: Bad name.
/// Restricts the given number of rows to be equal. Can only be used when `Self = SA::Alloc`. /// Restricts the given number of rows to be equal.
pub trait SameShapeColumnVectorAllocator<N, R1, R2, SA>: pub trait SameShapeVectorAllocator<N, R1, R2>:
Allocator<N, R1, U1> + Allocator<N, R1> +
Allocator<N, SameShapeR<R1, R2>, U1> + Allocator<N, SameShapeR<R1, R2>> +
SameShapeAllocator<N, R1, U1, R2, U1, SA> SameShapeAllocator<N, R1, U1, R2, U1>
where R1: Dim, R2: Dim, where R1: Dim, R2: Dim,
N: Scalar, N: Scalar,
SA: Storage<N, R1, U1, Alloc = Self>,
ShapeConstraint: SameNumberOfRows<R1, R2> { ShapeConstraint: SameNumberOfRows<R1, R2> {
} }
impl<N, R1, R2, SA> SameShapeColumnVectorAllocator<N, R1, R2, SA> for SA::Alloc impl<N, R1, R2> SameShapeVectorAllocator<N, R1, R2> for DefaultAllocator
where R1: Dim, R2: Dim, where R1: Dim, R2: Dim,
N: Scalar, N: Scalar,
SA: Storage<N, R1, U1>, DefaultAllocator: Allocator<N, R1, U1> + Allocator<N, SameShapeR<R1, R2>>,
SA::Alloc: ShapeConstraint: SameNumberOfRows<R1, R2> {
Allocator<N, R1, U1> +
Allocator<N, SameShapeR<R1, R2>, U1>,
ShapeConstraint: SameNumberOfRows<R1, R2> {
} }

458
src/core/blas.rs Normal file
View File

@ -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<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// 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<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// 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<N, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
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<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N
where SB: Storage<N, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2> {
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::<U2>() || R2::is::<U2>()) &&
(C::is::<U1>() || C2::is::<U1>()) {
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::<U3>() || R2::is::<U3>()) &&
(C::is::<U1>() || C2::is::<U1>()) {
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::<U4>() || R2::is::<U4>()) &&
(C::is::<U1>() || C2::is::<U1>()) {
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<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N
where SB: Storage<N, R2, C2>,
ShapeConstraint: DimEq<C, R2> + DimEq<R, C2> {
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<N>(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<N>(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<N, D: Dim, S> Vector<N, D, S>
where N: Scalar + Zero + ClosedAdd + ClosedMul,
S: StorageMut<N, D> {
/// Computes `self = a * x + b * self`.
///
/// If be is zero, `self` is never read from.
#[inline]
pub fn axpy<D2: Dim, SB>(&mut self, a: N, x: &Vector<N, D2, SB>, b: N)
where SB: Storage<N, D2>,
ShapeConstraint: DimEq<D, D2> {
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<R2: Dim, C2: Dim, D3: Dim, SB, SC>(&mut self,
alpha: N,
a: &Matrix<N, R2, C2, SB>,
x: &Vector<N, D3, SC>,
beta: N)
where N: One,
SB: Storage<N, R2, C2>,
SC: Storage<N, D3>,
ShapeConstraint: DimEq<D, R2> +
AreMultipliable<R2, C2, D3, U1> {
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<D2: Dim, D3: Dim, SB, SC>(&mut self,
alpha: N,
a: &Matrix<N, D2, D2, SB>,
x: &Vector<N, D3, SC>,
beta: N)
where N: One,
SB: Storage<N, D2, D2>,
SC: Storage<N, D3>,
ShapeConstraint: DimEq<D, D2> +
AreMultipliable<D2, D2, D3, U1> {
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<N, R1: Dim, C1: Dim, S: StorageMut<N, R1, C1>> Matrix<N, R1, C1, S>
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<D2: Dim, D3: Dim, SB, SC>(&mut self, alpha: N, x: &Vector<N, D2, SB>, y: &Vector<N, D3, SC>, beta: N)
where N: One,
SB: Storage<N, D2>,
SC: Storage<N, D3>,
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3> {
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<R2: Dim, C2: Dim, R3: Dim, C3: Dim, SB, SC>(&mut self,
alpha: N,
a: &Matrix<N, R2, C2, SB>,
b: &Matrix<N, R3, C3, SC>,
beta: N)
where N: One,
SB: Storage<N, R2, C2>,
SC: Storage<N, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> +
SameNumberOfColumns<C1, C3> +
AreMultipliable<R2, C2, R3, C3> {
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::<Dynamic>() || C1::is::<Dynamic>() ||
R2::is::<Dynamic>() || C2::is::<Dynamic>() ||
R3::is::<Dynamic>() || C3::is::<Dynamic>();
// 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::<f32>() {
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::<f64>() {
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<N, R1: Dim, C1: Dim, S: StorageMut<N, R1, C1>> Matrix<N, R1, C1, S>
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<D2: Dim, D3: Dim, SB, SC>(&mut self,
alpha: N,
x: &Vector<N, D2, SB>,
y: &Vector<N, D3, SC>,
beta: N)
where N: One,
SB: Storage<N, D2>,
SC: Storage<N, D3>,
ShapeConstraint: DimEq<R1, D2> + DimEq<C1, D3> {
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);
}
}
}

View File

@ -7,20 +7,20 @@
use num::One; use num::One;
use core::{Scalar, SquareMatrix, OwnedSquareMatrix, ColumnVector, Unit}; use core::{DefaultAllocator, Scalar, SquareMatrix, Vector, Unit,
use core::dimension::{DimName, DimNameSub, DimNameDiff, U1, U2, U3, U4}; VectorN, MatrixN, Vector3, Matrix3, Matrix4};
use core::storage::{Storage, StorageMut, OwnedStorage}; use core::dimension::{DimName, DimNameSub, DimNameDiff, U1};
use core::allocator::{Allocator, OwnedAllocator}; use core::storage::{Storage, StorageMut};
use geometry::{PointBase, OrthographicBase, PerspectiveBase, IsometryBase, OwnedRotation, OwnedPoint}; use core::allocator::Allocator;
use geometry::{Point, Isometry, Point3, Rotation2, Rotation3, Orthographic3, Perspective3, IsometryMatrix3};
use alga::general::{Real, Field}; use alga::general::{Real, Field};
use alga::linear::Transformation; use alga::linear::Transformation;
impl<N, D: DimName, S> SquareMatrix<N, D, S> impl<N, D: DimName> MatrixN<N, D>
where N: Scalar + Field, where N: Scalar + Field,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
/// Creates a new homogeneous matrix that applies the same scaling factor on each dimension. /// Creates a new homogeneous matrix that applies the same scaling factor on each dimension.
#[inline] #[inline]
pub fn new_scaling(scaling: N) -> Self { pub fn new_scaling(scaling: N) -> Self {
@ -32,9 +32,9 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Creates a new homogeneous matrix that applies a distinct scaling factor for each dimension. /// Creates a new homogeneous matrix that applies a distinct scaling factor for each dimension.
#[inline] #[inline]
pub fn new_nonuniform_scaling<SB>(scaling: &ColumnVector<N, DimNameDiff<D, U1>, SB>) -> Self pub fn new_nonuniform_scaling<SB>(scaling: &Vector<N, DimNameDiff<D, U1>, SB>) -> Self
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1> { SB: Storage<N, DimNameDiff<D, U1>> {
let mut res = Self::one(); let mut res = Self::one();
for i in 0 .. scaling.len() { for i in 0 .. scaling.len() {
res[(i, i)] = scaling[i]; res[(i, i)] = scaling[i];
@ -45,10 +45,9 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Creates a new homogeneous matrix that applies a pure translation. /// Creates a new homogeneous matrix that applies a pure translation.
#[inline] #[inline]
pub fn new_translation<SB>(translation: &ColumnVector<N, DimNameDiff<D, U1>, SB>) -> Self pub fn new_translation<SB>(translation: &Vector<N, DimNameDiff<D, U1>, SB>) -> Self
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>> {
S::Alloc: Allocator<N, DimNameDiff<D, U1>, U1> {
let mut res = Self::one(); let mut res = Self::one();
res.fixed_slice_mut::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1).copy_from(translation); res.fixed_slice_mut::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1).copy_from(translation);
@ -56,44 +55,30 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
} }
} }
impl<N, S> SquareMatrix<N, U3, S> impl<N: Real> Matrix3<N> {
where N: Real,
S: OwnedStorage<N, U3, U3>,
S::Alloc: OwnedAllocator<N, U3, U3, S> {
/// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian. /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian.
#[inline] #[inline]
pub fn new_rotation(angle: N) -> Self pub fn new_rotation(angle: N) -> Self {
where S::Alloc: Allocator<N, U2, U2> { Rotation2::new(angle).to_homogeneous()
OwnedRotation::<N, U2, S::Alloc>::new(angle).to_homogeneous()
} }
} }
impl<N, S> SquareMatrix<N, U4, S> impl<N: Real> Matrix4<N> {
where N: Real,
S: OwnedStorage<N, U4, U4>,
S::Alloc: OwnedAllocator<N, U4, U4, S> {
/// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
/// ///
/// Returns the identity matrix if the given argument is zero. /// Returns the identity matrix if the given argument is zero.
#[inline] #[inline]
pub fn new_rotation<SB>(axisangle: ColumnVector<N, U3, SB>) -> Self pub fn new_rotation(axisangle: Vector3<N>) -> Self {
where SB: Storage<N, U3, U1>, Rotation3::new(axisangle).to_homogeneous()
S::Alloc: Allocator<N, U3, U3> {
OwnedRotation::<N, U3, S::Alloc>::new(axisangle).to_homogeneous()
} }
/// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
/// ///
/// Returns the identity matrix if the given argument is zero. /// Returns the identity matrix if the given argument is zero.
#[inline] #[inline]
pub fn new_rotation_wrt_point<SB>(axisangle: ColumnVector<N, U3, SB>, pt: OwnedPoint<N, U3, S::Alloc>) -> Self pub fn new_rotation_wrt_point(axisangle: Vector3<N>, pt: Point3<N>) -> Self {
where SB: Storage<N, U3, U1>, let rot = Rotation3::from_scaled_axis(axisangle);
S::Alloc: Allocator<N, U3, U3> + Isometry::rotation_wrt_point(rot, pt).to_homogeneous()
Allocator<N, U3, U1> +
Allocator<N, U1, U3> {
let rot = OwnedRotation::<N, U3, S::Alloc>::from_scaled_axis(axisangle);
IsometryBase::rotation_wrt_point(rot, pt).to_homogeneous()
} }
/// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
@ -101,37 +86,32 @@ impl<N, S> SquareMatrix<N, U4, S>
/// Returns the identity matrix if the given argument is zero. /// Returns the identity matrix if the given argument is zero.
/// This is identical to `Self::new_rotation`. /// This is identical to `Self::new_rotation`.
#[inline] #[inline]
pub fn from_scaled_axis<SB>(axisangle: ColumnVector<N, U3, SB>) -> Self pub fn from_scaled_axis(axisangle: Vector3<N>) -> Self {
where SB: Storage<N, U3, U1>, Rotation3::from_scaled_axis(axisangle).to_homogeneous()
S::Alloc: Allocator<N, U3, U3> {
OwnedRotation::<N, U3, S::Alloc>::from_scaled_axis(axisangle).to_homogeneous()
} }
/// Creates a new rotation from Euler angles. /// Creates a new rotation from Euler angles.
/// ///
/// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw. /// 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 pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
where S::Alloc: Allocator<N, U3, U3> { Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous()
OwnedRotation::<N, U3, S::Alloc>::from_euler_angles(roll, pitch, yaw).to_homogeneous()
} }
/// Builds a 3D homogeneous rotation matrix from an axis and a rotation angle. /// Builds a 3D homogeneous rotation matrix from an axis and a rotation angle.
pub fn from_axis_angle<SB>(axis: &Unit<ColumnVector<N, U3, SB>>, angle: N) -> Self pub fn from_axis_angle(axis: &Unit<Vector3<N>>, angle: N) -> Self {
where SB: Storage<N, U3, U1>, Rotation3::from_axis_angle(axis, angle).to_homogeneous()
S::Alloc: Allocator<N, U3, U3> {
OwnedRotation::<N, U3, S::Alloc>::from_axis_angle(axis, angle).to_homogeneous()
} }
/// Creates a new homogeneous matrix for an orthographic projection. /// Creates a new homogeneous matrix for an orthographic projection.
#[inline] #[inline]
pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self { 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. /// Creates a new homogeneous matrix for a perspective projection.
#[inline] #[inline]
pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self { 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 /// Creates an isometry that corresponds to the local frame of an observer standing at the
@ -140,57 +120,30 @@ impl<N, S> SquareMatrix<N, U4, S>
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
/// `eye`. /// `eye`.
#[inline] #[inline]
pub fn new_observer_frame<SB>(eye: &PointBase<N, U3, SB>, pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
target: &PointBase<N, U3, SB>, IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous()
up: &ColumnVector<N, U3, SB>)
-> Self
where SB: OwnedStorage<N, U3, U1, Alloc = S::Alloc>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> +
Allocator<N, U1, U3> +
Allocator<N, U3, U3> {
IsometryBase::<N, U3, SB, OwnedRotation<N, U3, SB::Alloc>>
::new_observer_frame(eye, target, up).to_homogeneous()
} }
/// Builds a right-handed look-at view matrix. /// Builds a right-handed look-at view matrix.
#[inline] #[inline]
pub fn look_at_rh<SB>(eye: &PointBase<N, U3, SB>, pub fn look_at_rh(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
target: &PointBase<N, U3, SB>, IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous()
up: &ColumnVector<N, U3, SB>)
-> Self
where SB: OwnedStorage<N, U3, U1, Alloc = S::Alloc>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> +
Allocator<N, U1, U3> +
Allocator<N, U3, U3> {
IsometryBase::<N, U3, SB, OwnedRotation<N, U3, SB::Alloc>>
::look_at_rh(eye, target, up).to_homogeneous()
} }
/// Builds a left-handed look-at view matrix. /// Builds a left-handed look-at view matrix.
#[inline] #[inline]
pub fn look_at_lh<SB>(eye: &PointBase<N, U3, SB>, pub fn look_at_lh(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
target: &PointBase<N, U3, SB>, IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous()
up: &ColumnVector<N, U3, SB>)
-> Self
where SB: OwnedStorage<N, U3, U1, Alloc = S::Alloc>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> +
Allocator<N, U1, U3> +
Allocator<N, U3, U3> {
IsometryBase::<N, U3, SB, OwnedRotation<N, U3, SB::Alloc>>
::look_at_lh(eye, target, up).to_homogeneous()
} }
} }
impl<N, D: DimName, S> SquareMatrix<N, D, S> impl<N: Scalar + Field, D: DimName, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
where N: Scalar + Field,
S: Storage<N, D, D> {
/// Computes the transformation equal to `self` followed by an uniform scaling factor. /// Computes the transformation equal to `self` followed by an uniform scaling factor.
#[inline] #[inline]
pub fn append_scaling(&self, scaling: N) -> OwnedSquareMatrix<N, D, S::Alloc> pub fn append_scaling(&self, scaling: N) -> MatrixN<N, D>
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
S::Alloc: Allocator<N, DimNameDiff<D, U1>, D> { DefaultAllocator: Allocator<N, D, D> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
res.append_scaling_mut(scaling); res.append_scaling_mut(scaling);
res res
@ -198,9 +151,9 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to an uniform scaling factor followed by `self`. /// Computes the transformation equal to an uniform scaling factor followed by `self`.
#[inline] #[inline]
pub fn prepend_scaling(&self, scaling: N) -> OwnedSquareMatrix<N, D, S::Alloc> pub fn prepend_scaling(&self, scaling: N) -> MatrixN<N, D>
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
S::Alloc: Allocator<N, D, DimNameDiff<D, U1>> { DefaultAllocator: Allocator<N, D, D> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
res.prepend_scaling_mut(scaling); res.prepend_scaling_mut(scaling);
res res
@ -208,11 +161,10 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to `self` followed by a non-uniform scaling factor. /// Computes the transformation equal to `self` followed by a non-uniform scaling factor.
#[inline] #[inline]
pub fn append_nonuniform_scaling<SB>(&self, scaling: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn append_nonuniform_scaling<SB>(&self, scaling: &Vector<N, DimNameDiff<D, U1>, SB>) -> MatrixN<N, D>
-> OwnedSquareMatrix<N, D, S::Alloc> where D: DimNameSub<U1>,
where D: DimNameSub<U1>, SB: Storage<N, DimNameDiff<D, U1>>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: Allocator<N, U1, D> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
res.append_nonuniform_scaling_mut(scaling); res.append_nonuniform_scaling_mut(scaling);
res res
@ -220,11 +172,10 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to a non-uniform scaling factor followed by `self`. /// Computes the transformation equal to a non-uniform scaling factor followed by `self`.
#[inline] #[inline]
pub fn prepend_nonuniform_scaling<SB>(&self, scaling: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn prepend_nonuniform_scaling<SB>(&self, scaling: &Vector<N, DimNameDiff<D, U1>, SB>) -> MatrixN<N, D>
-> OwnedSquareMatrix<N, D, S::Alloc> where D: DimNameSub<U1>,
where D: DimNameSub<U1>, SB: Storage<N, DimNameDiff<D, U1>>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: Allocator<N, D, U1> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
res.prepend_nonuniform_scaling_mut(scaling); res.prepend_nonuniform_scaling_mut(scaling);
res res
@ -232,11 +183,10 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to `self` followed by a translation. /// Computes the transformation equal to `self` followed by a translation.
#[inline] #[inline]
pub fn append_translation<SB>(&self, shift: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn append_translation<SB>(&self, shift: &Vector<N, DimNameDiff<D, U1>, SB>) -> MatrixN<N, D>
-> OwnedSquareMatrix<N, D, S::Alloc>
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>>,
S::Alloc: Allocator<N, DimNameDiff<D, U1>, U1> { DefaultAllocator: Allocator<N, D, D> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
res.append_translation_mut(shift); res.append_translation_mut(shift);
res res
@ -244,28 +194,23 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to a translation followed by `self`. /// Computes the transformation equal to a translation followed by `self`.
#[inline] #[inline]
pub fn prepend_translation<SB>(&self, shift: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn prepend_translation<SB>(&self, shift: &Vector<N, DimNameDiff<D, U1>, SB>) -> MatrixN<N, D>
-> OwnedSquareMatrix<N, D, S::Alloc>
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>>,
S::Alloc: Allocator<N, DimNameDiff<D, U1>, U1> + DefaultAllocator: Allocator<N, D, D> +
Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>> + Allocator<N, DimNameDiff<D, U1>> {
Allocator<N, U1, DimNameDiff<D, U1>> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
res.prepend_translation_mut(shift); res.prepend_translation_mut(shift);
res res
} }
} }
impl<N, D: DimName, S> SquareMatrix<N, D, S> impl<N: Scalar + Field, D: DimName, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
where N: Scalar + Field,
S: StorageMut<N, D, D> {
/// Computes in-place the transformation equal to `self` followed by an uniform scaling factor. /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor.
#[inline] #[inline]
pub fn append_scaling_mut(&mut self, scaling: N) pub fn append_scaling_mut(&mut self, scaling: N)
where D: DimNameSub<U1>, where D: DimNameSub<U1> {
S::Alloc: Allocator<N, DimNameDiff<D, U1>, D> {
let mut to_scale = self.fixed_rows_mut::<DimNameDiff<D, U1>>(0); let mut to_scale = self.fixed_rows_mut::<DimNameDiff<D, U1>>(0);
to_scale *= scaling; to_scale *= scaling;
} }
@ -273,18 +218,16 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes in-place the transformation equal to an uniform scaling factor followed by `self`. /// Computes in-place the transformation equal to an uniform scaling factor followed by `self`.
#[inline] #[inline]
pub fn prepend_scaling_mut(&mut self, scaling: N) pub fn prepend_scaling_mut(&mut self, scaling: N)
where D: DimNameSub<U1>, where D: DimNameSub<U1> {
S::Alloc: Allocator<N, D, DimNameDiff<D, U1>> {
let mut to_scale = self.fixed_columns_mut::<DimNameDiff<D, U1>>(0); let mut to_scale = self.fixed_columns_mut::<DimNameDiff<D, U1>>(0);
to_scale *= scaling; to_scale *= scaling;
} }
/// Computes in-place the transformation equal to `self` followed by a non-uniform scaling factor. /// Computes in-place the transformation equal to `self` followed by a non-uniform scaling factor.
#[inline] #[inline]
pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<N, DimNameDiff<D, U1>, SB>)
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>> {
S::Alloc: Allocator<N, U1, D> {
for i in 0 .. scaling.len() { for i in 0 .. scaling.len() {
let mut to_scale = self.fixed_rows_mut::<U1>(i); let mut to_scale = self.fixed_rows_mut::<U1>(i);
to_scale *= scaling[i]; to_scale *= scaling[i];
@ -293,10 +236,9 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes in-place the transformation equal to a non-uniform scaling factor followed by `self`. /// Computes in-place the transformation equal to a non-uniform scaling factor followed by `self`.
#[inline] #[inline]
pub fn prepend_nonuniform_scaling_mut<SB>(&mut self, scaling: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn prepend_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<N, DimNameDiff<D, U1>, SB>)
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>> {
S::Alloc: Allocator<N, D, U1> {
for i in 0 .. scaling.len() { for i in 0 .. scaling.len() {
let mut to_scale = self.fixed_columns_mut::<U1>(i); let mut to_scale = self.fixed_columns_mut::<U1>(i);
to_scale *= scaling[i]; to_scale *= scaling[i];
@ -305,10 +247,9 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to `self` followed by a translation. /// Computes the transformation equal to `self` followed by a translation.
#[inline] #[inline]
pub fn append_translation_mut<SB>(&mut self, shift: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn append_translation_mut<SB>(&mut self, shift: &Vector<N, DimNameDiff<D, U1>, SB>)
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>> {
S::Alloc: Allocator<N, DimNameDiff<D, U1>, U1> {
for i in 0 .. D::dim() { for i in 0 .. D::dim() {
for j in 0 .. D::dim() - 1 { for j in 0 .. D::dim() - 1 {
self[(j, i)] += shift[j] * self[(D::dim() - 1, i)]; self[(j, i)] += shift[j] * self[(D::dim() - 1, i)];
@ -318,12 +259,10 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
/// Computes the transformation equal to a translation followed by `self`. /// Computes the transformation equal to a translation followed by `self`.
#[inline] #[inline]
pub fn prepend_translation_mut<SB>(&mut self, shift: &ColumnVector<N, DimNameDiff<D, U1>, SB>) pub fn prepend_translation_mut<SB>(&mut self, shift: &Vector<N, DimNameDiff<D, U1>, SB>)
where D: DimNameSub<U1>, where D: DimNameSub<U1>,
SB: Storage<N, DimNameDiff<D, U1>, U1>, SB: Storage<N, DimNameDiff<D, U1>>,
S::Alloc: Allocator<N, DimNameDiff<D, U1>, U1> + DefaultAllocator: Allocator<N, DimNameDiff<D, U1>> {
Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>> +
Allocator<N, U1, DimNameDiff<D, U1>> {
let scale = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0).tr_dot(&shift); let scale = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0).tr_dot(&shift);
let post_translation = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0) * shift; let post_translation = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0) * shift;
@ -335,19 +274,12 @@ impl<N, D: DimName, S> SquareMatrix<N, D, S>
} }
impl<N, D, SA, SB> Transformation<PointBase<N, DimNameDiff<D, U1>, SB>> for SquareMatrix<N, D, SA> impl<N: Real, D: DimNameSub<U1>> Transformation<Point<N, DimNameDiff<D, U1>>> for MatrixN<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
D: DimNameSub<U1>, Allocator<N, DimNameDiff<D, U1>> +
SA: OwnedStorage<N, D, D>, Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>> {
SB: OwnedStorage<N, DimNameDiff<D, U1>, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA> +
Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>> +
Allocator<N, DimNameDiff<D, U1>, U1> +
Allocator<N, U1, DimNameDiff<D, U1>>,
SB::Alloc: OwnedAllocator<N, DimNameDiff<D, U1>, U1, SB> {
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, DimNameDiff<D, U1>, SB>) fn transform_vector(&self, v: &VectorN<N, DimNameDiff<D, U1>>) -> VectorN<N, DimNameDiff<D, U1>> {
-> ColumnVector<N, DimNameDiff<D, U1>, SB> {
let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0); let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0); let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
let n = normalizer.tr_dot(&v); let n = normalizer.tr_dot(&v);
@ -360,8 +292,7 @@ impl<N, D, SA, SB> Transformation<PointBase<N, DimNameDiff<D, U1>, SB>> for Squa
} }
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, DimNameDiff<D, U1>, SB>) fn transform_point(&self, pt: &Point<N, DimNameDiff<D, U1>>) -> Point<N, DimNameDiff<D, U1>> {
-> PointBase<N, DimNameDiff<D, U1>, SB> {
let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0); let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1); let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0); let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);

View File

@ -4,21 +4,22 @@ use num::Signed;
use alga::general::{ClosedMul, ClosedDiv}; use alga::general::{ClosedMul, ClosedDiv};
use core::{Scalar, Matrix, OwnedMatrix, MatrixSum}; use core::{DefaultAllocator, Scalar, Matrix, MatrixMN, MatrixSum};
use core::dimension::Dim; use core::dimension::Dim;
use core::storage::{Storage, StorageMut}; use core::storage::{Storage, StorageMut};
use core::allocator::SameShapeAllocator; use core::allocator::{Allocator, SameShapeAllocator};
use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns};
/// The type of the result of a matrix componentwise operation. /// The type of the result of a matrix componentwise operation.
pub type MatrixComponentOp<N, R1, C1, R2, C2, SA> = MatrixSum<N, R1, C1, R2, C2, SA>; pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>;
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Computes the componentwise absolute value. /// Computes the componentwise absolute value.
#[inline] #[inline]
pub fn abs(&self) -> OwnedMatrix<N, R, C, S::Alloc> pub fn abs(&self) -> MatrixMN<N, R, C>
where N: Signed { where N: Signed,
DefaultAllocator: Allocator<N, R, C> {
let mut res = self.clone_owned(); let mut res = self.clone_owned();
for e in res.iter_mut() { for e in res.iter_mut() {
@ -33,27 +34,32 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
macro_rules! component_binop_impl( macro_rules! component_binop_impl(
($($binop: ident, $binop_mut: ident, $Trait: ident . $binop_assign: ident, $desc:expr, $desc_mut:expr);* $(;)*) => {$( ($($binop: ident, $binop_mut: ident, $Trait: ident . $binop_assign: ident, $desc:expr, $desc_mut:expr);* $(;)*) => {$(
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA> {
#[doc = $desc] #[doc = $desc]
#[inline] #[inline]
pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R, C, R2, C2, S> pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R1, C1, R2, C2>
where N: $Trait, where N: $Trait,
R2: Dim, C2: Dim, R2: Dim, C2: Dim,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
S::Alloc: SameShapeAllocator<N, R, C, R2, C2, S>, DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
let mut res = self.clone_owned_sum(); let mut res = self.clone_owned_sum();
for (res, rhs) in res.iter_mut().zip(rhs.iter()) { for j in 0 .. res.ncols() {
res.$binop_assign(*rhs); for i in 0 .. res.nrows() {
unsafe {
res.get_unchecked_mut(i, j).$binop_assign(*rhs.get_unchecked(i, j));
}
}
} }
res res
} }
} }
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R1: Dim, C1: Dim, SA: StorageMut<N, R1, C1>> Matrix<N, R1, C1, SA> {
#[doc = $desc_mut] #[doc = $desc_mut]
#[inline] #[inline]
pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>) pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
@ -61,9 +67,16 @@ macro_rules! component_binop_impl(
R2: Dim, R2: Dim,
C2: Dim, C2: Dim,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
for (me, rhs) in self.iter_mut().zip(rhs.iter()) {
me.$binop_assign(*rhs); 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));
}
}
} }
} }
} }

View File

@ -6,8 +6,7 @@ use core::dimension::{Dim, DimName, Dynamic};
pub struct ShapeConstraint; pub struct ShapeConstraint;
/// Constraints `C1` and `R2` to be equivalent. /// Constraints `C1` and `R2` to be equivalent.
pub trait AreMultipliable<R1: Dim, C1: Dim, pub trait AreMultipliable<R1: Dim, C1: Dim, R2: Dim, C2: Dim>: DimEq<C1, R2> {
R2: Dim, C2: Dim> {
} }
@ -15,11 +14,30 @@ impl<R1: Dim, C1: Dim, R2: Dim, C2: Dim> AreMultipliable<R1, C1, R2, C2> for Sha
where ShapeConstraint: DimEq<C1, R2> { where ShapeConstraint: DimEq<C1, R2> {
} }
/// Constraints `D1` and `D2` to be equivalent.
pub trait DimEq<D1: Dim, D2: Dim> {
/// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
/// constant.
type Representative: Dim;
}
impl<D: Dim> DimEq<D, D> for ShapeConstraint {
type Representative = D;
}
impl<D: DimName> DimEq<D, Dynamic> for ShapeConstraint {
type Representative = D;
}
impl<D: DimName> DimEq<Dynamic, D> for ShapeConstraint {
type Representative = D;
}
macro_rules! equality_trait_decl( macro_rules! equality_trait_decl(
($($doc: expr, $Trait: ident),* $(,)*) => {$( ($($doc: expr, $Trait: ident),* $(,)*) => {$(
// XXX: we can't do something like `DimEq<D1> for D2` because we would require a blancket impl… // XXX: we can't do something like `DimEq<D1> for D2` because we would require a blancket impl…
#[doc = $doc] #[doc = $doc]
pub trait $Trait<D1: Dim, D2: Dim> { pub trait $Trait<D1: Dim, D2: Dim>: DimEq<D1, D2> + DimEq<D2, D1> {
/// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
/// constant. /// constant.
type Representative: Dim; type Representative: Dim;
@ -40,9 +58,6 @@ macro_rules! equality_trait_decl(
); );
equality_trait_decl!( equality_trait_decl!(
"Constraints `D1` and `D2` to be equivalent.",
DimEq,
"Constraints `D1` and `D2` to be equivalent. \ "Constraints `D1` and `D2` to be equivalent. \
They are both assumed to be the number of \ They are both assumed to be the number of \
rows of a matrix.", rows of a matrix.",

View File

@ -1,5 +1,7 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
#[cfg(feature = "arbitrary")]
use core::storage::Owned;
use std::iter; use std::iter;
use num::{Zero, One, Bounded}; use num::{Zero, One, Bounded};
@ -8,38 +10,44 @@ use typenum::{self, Cmp, Greater};
use alga::general::{ClosedAdd, ClosedMul}; 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::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6};
use core::allocator::{Allocator, OwnedAllocator}; use core::allocator::Allocator;
use core::storage::{Storage, OwnedStorage}; use core::storage::Storage;
/* /*
* *
* Generic constructors. * Generic constructors.
* *
*/ */
impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S> impl<N: Scalar, R: Dim, C: Dim> MatrixMN<N, R, C>
// XXX: needed because of a compiler bug. See the rust compiler issue #26026. where DefaultAllocator: Allocator<N, R, C> {
where S::Alloc: OwnedAllocator<N, R, C, S> {
/// Creates a new uninitialized matrix. If the matrix has a compile-time dimension, this panics /// 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()`. /// if `nrows != R::to_usize()` or `ncols != C::to_usize()`.
#[inline] #[inline]
pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> Matrix<N, R, C, S> { pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> Self {
Matrix::from_data(S::Alloc::allocate_uninitialized(nrows, ncols)) Self::from_data(DefaultAllocator::allocate_uninitialized(nrows, ncols))
} }
/// Creates a matrix with all its elements set to `elem`. /// Creates a matrix with all its elements set to `elem`.
#[inline] #[inline]
pub fn from_element_generic(nrows: R, ncols: C, elem: N) -> Matrix<N, R, C, S> { pub fn from_element_generic(nrows: R, ncols: C, elem: N) -> Self {
let len = nrows.value() * ncols.value(); 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. /// Creates a matrix with all its elements filled by an iterator.
#[inline] #[inline]
pub fn from_iterator_generic<I>(nrows: R, ncols: C, iter: I) -> Matrix<N, R, C, S> pub fn from_iterator_generic<I>(nrows: R, ncols: C, iter: I) -> Self
where I: IntoIterator<Item = N> { where I: IntoIterator<Item = N> {
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 /// Creates a matrix with its elements filled with the components provided by a slice in
@ -48,7 +56,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
/// The order of elements in the slice must follow the usual mathematic writing, i.e., /// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row. /// row-by-row.
#[inline] #[inline]
pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Matrix<N, R, C, S> { pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Self {
assert!(slice.len() == nrows.value() * ncols.value(), assert!(slice.len() == nrows.value() * ncols.value(),
"Matrix init. error: the slice did not contain the right number of elements."); "Matrix init. error: the slice did not contain the right number of elements.");
@ -69,14 +77,14 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
/// Creates a matrix with its elements filled with the components provided by a slice. The /// 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). /// components must have the same layout as the matrix data storage (i.e. row-major or column-major).
#[inline] #[inline]
pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Matrix<N, R, C, S> { pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[N]) -> Self {
Matrix::from_iterator_generic(nrows, ncols, slice.iter().cloned()) 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 /// Creates a matrix filled with the results of a function applied to each of its component
/// coordinates. /// coordinates.
#[inline] #[inline]
pub fn from_fn_generic<F>(nrows: R, ncols: C, mut f: F) -> Matrix<N, R, C, S> pub fn from_fn_generic<F>(nrows: R, ncols: C, mut f: F) -> Self
where F: FnMut(usize, usize) -> N { where F: FnMut(usize, usize) -> N {
let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) }; let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) };
@ -94,7 +102,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
/// If the matrix is not square, the largest square submatrix starting at index `(0, 0)` is set /// 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. /// to the identity matrix. All other entries are set to zero.
#[inline] #[inline]
pub fn identity_generic(nrows: R, ncols: C) -> Matrix<N, R, C, S> pub fn identity_generic(nrows: R, ncols: C) -> Self
where N: Zero + One { where N: Zero + One {
Self::from_diagonal_element_generic(nrows, ncols, N::one()) Self::from_diagonal_element_generic(nrows, ncols, N::one())
} }
@ -104,10 +112,9 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
/// If the matrix is not square, the largest square submatrix starting at index `(0, 0)` is set /// 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. /// to the identity matrix. All other entries are set to zero.
#[inline] #[inline]
pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: N) -> Matrix<N, R, C, S> pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: N) -> Self
where N: Zero + One { where N: Zero + One {
let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) }; let mut res = Self::zeros_generic(nrows, ncols);
res.fill(N::zero());
for i in 0 .. ::min(nrows.value(), ncols.value()) { for i in 0 .. ::min(nrows.value(), ncols.value()) {
unsafe { *res.get_unchecked_mut(i, i) = elt } unsafe { *res.get_unchecked_mut(i, i) = elt }
@ -116,12 +123,29 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
res 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. /// Builds a new matrix from its rows.
/// ///
/// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do /// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do
/// not have the same dimensions. /// not have the same dimensions.
#[inline] #[inline]
pub fn from_rows<SB>(rows: &[Matrix<N, U1, C, SB>]) -> Matrix<N, R, C, S> pub fn from_rows<SB>(rows: &[Matrix<N, U1, C, SB>]) -> Self
where SB: Storage<N, U1, C> { where SB: Storage<N, U1, C> {
assert!(rows.len() > 0, "At least one row must be given."); assert!(rows.len() > 0, "At least one row must be given.");
@ -144,8 +168,8 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
/// Panics if not enough columns are provided (for statically-sized matrices), or if all /// Panics if not enough columns are provided (for statically-sized matrices), or if all
/// columns do not have the same dimensions. /// columns do not have the same dimensions.
#[inline] #[inline]
pub fn from_columns<SB>(columns: &[ColumnVector<N, R, SB>]) -> Matrix<N, R, C, S> pub fn from_columns<SB>(columns: &[Vector<N, R, SB>]) -> Self
where SB: Storage<N, R, U1> { where SB: Storage<N, R> {
assert!(columns.len() > 0, "At least one column must be given."); assert!(columns.len() > 0, "At least one column must be given.");
let ncols = C::try_to_usize().unwrap_or(columns.len()); let ncols = C::try_to_usize().unwrap_or(columns.len());
@ -160,31 +184,27 @@ impl<N: Scalar, R: Dim, C: Dim, S: OwnedStorage<N, R, C>> Matrix<N, R, C, S>
// FIXME: optimize that. // FIXME: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| columns[j][i]) Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| columns[j][i])
} }
}
impl<N, R: Dim, C: Dim, S> Matrix<N, R, C, S>
where N: Scalar + Rand,
S: OwnedStorage<N, R, C>,
S::Alloc: OwnedAllocator<N, R, C, S> {
/// Creates a matrix filled with random values. /// Creates a matrix filled with random values.
#[inline] #[inline]
pub fn new_random_generic(nrows: R, ncols: C) -> Matrix<N, R, C, S> { pub fn new_random_generic(nrows: R, ncols: C) -> Self
Matrix::from_fn_generic(nrows, ncols, |_, _| rand::random()) where N: Rand {
Self::from_fn_generic(nrows, ncols, |_, _| rand::random())
} }
} }
impl<N, D: Dim, S> SquareMatrix<N, D, S> impl<N, D: Dim> MatrixN<N, D>
where N: Scalar + Zero, where N: Scalar,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
/// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0.
#[inline] #[inline]
pub fn from_diagonal<SB: Storage<N, D, U1>>(diag: &ColumnVector<N, D, SB>) -> Self { pub fn from_diagonal<SB: Storage<N, D>>(diag: &Vector<N, D, SB>) -> Self
where N: Zero {
let (dim, _) = diag.data.shape(); 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() { 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 res
@ -199,25 +219,31 @@ impl<N, D: Dim, S> SquareMatrix<N, D, S>
*/ */
macro_rules! impl_constructors( macro_rules! impl_constructors(
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<N: Scalar, $($DimIdent: $DimBound, )* S> Matrix<N $(, $Dims)*, S> impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where S: OwnedStorage<N $(, $Dims)*>, where DefaultAllocator: Allocator<N $(, $Dims)*> {
S::Alloc: OwnedAllocator<N $(, $Dims)*, S> {
/// Creates a new uninitialized matrix. /// Creates a new uninitialized matrix.
#[inline] #[inline]
pub unsafe fn new_uninitialized($($args: usize),*) -> Matrix<N $(, $Dims)*, S> { pub unsafe fn new_uninitialized($($args: usize),*) -> Self {
Self::new_uninitialized_generic($($gargs),*) Self::new_uninitialized_generic($($gargs),*)
} }
/// Creates a matrix with all its elements set to `elem`. /// Creates a matrix with all its elements set to `elem`.
#[inline] #[inline]
pub fn from_element($($args: usize,)* elem: N) -> Matrix<N $(, $Dims)*, S> { pub fn from_element($($args: usize,)* elem: N) -> Self {
Self::from_element_generic($($gargs, )* elem) 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. /// Creates a matrix with all its elements filled by an iterator.
#[inline] #[inline]
pub fn from_iterator<I>($($args: usize,)* iter: I) -> Matrix<N $(, $Dims)*, S> pub fn from_iterator<I>($($args: usize,)* iter: I) -> Self
where I: IntoIterator<Item = N> { where I: IntoIterator<Item = N> {
Self::from_iterator_generic($($gargs, )* iter) 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., /// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row. /// row-by-row.
#[inline] #[inline]
pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Matrix<N $(, $Dims)*, S> { pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* slice) Self::from_row_slice_generic($($gargs, )* slice)
} }
/// Creates a matrix with its elements filled with the components provided by a slice /// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order. /// in column-major order.
#[inline] #[inline]
pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Matrix<N $(, $Dims)*, S> { pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* slice) Self::from_column_slice_generic($($gargs, )* slice)
} }
@ -243,7 +269,7 @@ macro_rules! impl_constructors(
/// component coordinates. /// component coordinates.
// FIXME: don't take a dimension of the matrix is statically sized. // FIXME: don't take a dimension of the matrix is statically sized.
#[inline] #[inline]
pub fn from_fn<F>($($args: usize,)* f: F) -> Matrix<N $(, $Dims)*, S> pub fn from_fn<F>($($args: usize,)* f: F) -> Self
where F: FnMut(usize, usize) -> N { where F: FnMut(usize, usize) -> N {
Self::from_fn_generic($($gargs, )* f) 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 /// submatrix (starting at the first row and column) is set to the identity while all
/// other entries are set to zero. /// other entries are set to zero.
#[inline] #[inline]
pub fn identity($($args: usize,)*) -> Matrix<N $(, $Dims)*, S> pub fn identity($($args: usize,)*) -> Self
where N: Zero + One { where N: Zero + One {
Self::identity_generic($($gargs),* ) 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 /// Creates a matrix filled with its diagonal filled with `elt` and all other
/// components set to zero. /// components set to zero.
#[inline] #[inline]
pub fn from_diagonal_element($($args: usize,)* elt: N) -> Matrix<N $(, $Dims)*, S> pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self
where N: Zero + One { where N: Zero + One {
Self::from_diagonal_element_generic($($gargs, )* elt) 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<N: Scalar + Rand, $($DimIdent: $DimBound, )* S> Matrix<N $(, $Dims)*, S> impl<N: Scalar + Rand, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where S: OwnedStorage<N $(, $Dims)*>, where DefaultAllocator: Allocator<N $(, $Dims)*> {
S::Alloc: OwnedAllocator<N $(, $Dims)*, S> {
/// Creates a matrix filled with random values. /// Creates a matrix filled with random values.
#[inline] #[inline]
pub fn new_random($($args: usize),*) -> Matrix<N $(, $Dims)*, S> { pub fn new_random($($args: usize),*) -> Self {
Self::new_random_generic($($gargs),*) Self::new_random_generic($($gargs),*)
} }
} }
@ -305,10 +340,9 @@ impl_constructors!(Dynamic, Dynamic;
* Zero, One, Rand traits. * Zero, One, Rand traits.
* *
*/ */
impl<N, R: DimName, C: DimName, S> Zero for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> Zero for MatrixMN<N, R, C>
where N: Scalar + Zero + ClosedAdd, where N: Scalar + Zero + ClosedAdd,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn zero() -> Self { fn zero() -> Self {
Self::from_element(N::zero()) Self::from_element(N::zero())
@ -320,20 +354,18 @@ impl<N, R: DimName, C: DimName, S> Zero for Matrix<N, R, C, S>
} }
} }
impl<N, D: DimName, S> One for Matrix<N, D, D, S> impl<N, D: DimName> One for MatrixN<N, D>
where N: Scalar + Zero + One + ClosedMul + ClosedAdd, where N: Scalar + Zero + One + ClosedMul + ClosedAdd,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, R: DimName, C: DimName, S> Bounded for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> Bounded for MatrixMN<N, R, C>
where N: Scalar + Bounded, where N: Scalar + Bounded,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn max_value() -> Self { fn max_value() -> Self {
Self::from_element(N::max_value()) Self::from_element(N::max_value())
@ -345,9 +377,8 @@ impl<N, R: DimName, C: DimName, S> Bounded for Matrix<N, R, C, S>
} }
} }
impl<N: Scalar + Rand, R: Dim, C: Dim, S> Rand for Matrix<N, R, C, S> impl<N: Scalar + Rand, R: Dim, C: Dim> Rand for MatrixMN<N, R, C>
where S: OwnedStorage<N, R, C>, where DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn rand<G: Rng>(rng: &mut G) -> Self { fn rand<G: Rng>(rng: &mut G) -> Self {
let nrows = R::try_to_usize().unwrap_or(rng.gen_range(0, 10)); let nrows = R::try_to_usize().unwrap_or(rng.gen_range(0, 10));
@ -359,11 +390,11 @@ impl<N: Scalar + Rand, R: Dim, C: Dim, S> Rand for Matrix<N, R, C, S>
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<N, R, C, S> Arbitrary for Matrix<N, R, C, S> impl<N, R, C> Arbitrary for MatrixMN<N, R, C>
where R: Dim, C: Dim, where R: Dim, C: Dim,
N: Scalar + Arbitrary + Send, N: Scalar + Arbitrary + Send,
S: OwnedStorage<N, R, C> + Send, DefaultAllocator: Allocator<N, R, C>,
S::Alloc: OwnedAllocator<N, R, C, S> { Owned<N, R, C>: Clone + Send {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nrows = R::try_to_usize().unwrap_or(g.gen_range(0, 10)); let nrows = R::try_to_usize().unwrap_or(g.gen_range(0, 10));
@ -381,13 +412,12 @@ impl<N, R, C, S> Arbitrary for Matrix<N, R, C, S>
*/ */
macro_rules! componentwise_constructors_impl( macro_rules! componentwise_constructors_impl(
($($R: ty, $C: ty, $($args: ident:($irow: expr,$icol: expr)),*);* $(;)*) => {$( ($($R: ty, $C: ty, $($args: ident:($irow: expr,$icol: expr)),*);* $(;)*) => {$(
impl<N, S> Matrix<N, $R, $C, S> impl<N> MatrixMN<N, $R, $C>
where N: Scalar, where N: Scalar,
S: OwnedStorage<N, $R, $C>, DefaultAllocator: Allocator<N, $R, $C> {
S::Alloc: OwnedAllocator<N, $R, $C, S> {
/// Initializes this matrix from its components. /// Initializes this matrix from its components.
#[inline] #[inline]
pub fn new($($args: N),*) -> Matrix<N, $R, $C, S> { pub fn new($($args: N),*) -> Self {
unsafe { unsafe {
let mut res = Self::new_uninitialized(); let mut res = Self::new_uninitialized();
$( *res.get_unchecked_mut($irow, $icol) = $args; )* $( *res.get_unchecked_mut($irow, $icol) = $args; )*
@ -549,16 +579,15 @@ componentwise_constructors_impl!(
* Axis constructors. * Axis constructors.
* *
*/ */
impl<N, R: DimName, S> ColumnVector<N, R, S> impl<N, R: DimName> VectorN<N, R>
where N: Scalar + Zero + One, where N: Scalar + Zero + One,
S: OwnedStorage<N, R, U1>, DefaultAllocator: Allocator<N, R> {
S::Alloc: OwnedAllocator<N, R, U1, S> {
/// The column vector with a 1 as its first component, and zero elsewhere. /// The column vector with a 1 as its first component, and zero elsewhere.
#[inline] #[inline]
pub fn x() -> Self pub fn x() -> Self
where R::Value: Cmp<typenum::U0, Output = Greater> { where R::Value: Cmp<typenum::U0, Output = Greater> {
let mut res = Self::from_element(N::zero()); 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 res
} }
@ -568,7 +597,7 @@ where N: Scalar + Zero + One,
pub fn y() -> Self pub fn y() -> Self
where R::Value: Cmp<typenum::U1, Output = Greater> { where R::Value: Cmp<typenum::U1, Output = Greater> {
let mut res = Self::from_element(N::zero()); 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 res
} }
@ -578,7 +607,7 @@ where N: Scalar + Zero + One,
pub fn z() -> Self pub fn z() -> Self
where R::Value: Cmp<typenum::U2, Output = Greater> { where R::Value: Cmp<typenum::U2, Output = Greater> {
let mut res = Self::from_element(N::zero()); 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 res
} }
@ -588,7 +617,7 @@ where N: Scalar + Zero + One,
pub fn w() -> Self pub fn w() -> Self
where R::Value: Cmp<typenum::U3, Output = Greater> { where R::Value: Cmp<typenum::U3, Output = Greater> {
let mut res = Self::from_element(N::zero()); 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 res
} }
@ -598,7 +627,7 @@ where N: Scalar + Zero + One,
pub fn a() -> Self pub fn a() -> Self
where R::Value: Cmp<typenum::U4, Output = Greater> { where R::Value: Cmp<typenum::U4, Output = Greater> {
let mut res = Self::from_element(N::zero()); 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 res
} }
@ -608,7 +637,7 @@ where N: Scalar + Zero + One,
pub fn b() -> Self pub fn b() -> Self
where R::Value: Cmp<typenum::U5, Output = Greater> { where R::Value: Cmp<typenum::U5, Output = Greater> {
let mut res = Self::from_element(N::zero()); 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 res
} }

View File

@ -3,37 +3,35 @@ use std::mem;
use std::convert::{From, Into, AsRef, AsMut}; use std::convert::{From, Into, AsRef, AsMut};
use alga::general::{SubsetOf, SupersetOf}; use alga::general::{SubsetOf, SupersetOf};
use core::{Scalar, Matrix}; use core::{DefaultAllocator, Scalar, Matrix, MatrixMN};
use core::dimension::{Dim, use core::dimension::{Dim,
U1, U2, U3, U4, U1, U2, U3, U4,
U5, U6, U7, U8, U5, U6, U7, U8,
U9, U10, U11, U12, U9, U10, U11, U12,
U13, U14, U15, U16 U13, U14, U15, U16
}; };
use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns};
use core::storage::{Storage, StorageMut, OwnedStorage};
use core::iter::{MatrixIter, MatrixIterMut}; 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. // FIXME: too bad this won't work allo slice conversions.
impl<N1, N2, R1, C1, R2, C2, SA, SB> SubsetOf<Matrix<N2, R2, C2, SB>> for Matrix<N1, R1, C1, SA> impl<N1, N2, R1, C1, R2, C2> SubsetOf<MatrixMN<N2, R2, C2>> for MatrixMN<N1, R1, C1>
where R1: Dim, C1: Dim, R2: Dim, C2: Dim, where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
N1: Scalar, N1: Scalar,
N2: Scalar + SupersetOf<N1>, N2: Scalar + SupersetOf<N1>,
SA: OwnedStorage<N1, R1, C1>, DefaultAllocator: Allocator<N2, R2, C2> +
SB: OwnedStorage<N2, R2, C2>, Allocator<N1, R1, C1> +
SB::Alloc: OwnedAllocator<N2, R2, C2, SB>, SameShapeAllocator<N1, R1, C1, R2, C2>,
SA::Alloc: OwnedAllocator<N1, R1, C1, SA> +
SameShapeAllocator<N1, R1, C1, R2, C2, SA>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
#[inline] #[inline]
fn to_superset(&self) -> Matrix<N2, R2, C2, SB> { fn to_superset(&self) -> MatrixMN<N2, R2, C2> {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
let nrows2 = R2::from_usize(nrows); let nrows2 = R2::from_usize(nrows);
let ncols2 = C2::from_usize(ncols); let ncols2 = C2::from_usize(ncols);
let mut res = unsafe { Matrix::<N2, R2, C2, SB>::new_uninitialized_generic(nrows2, ncols2) }; let mut res = unsafe { MatrixMN::<N2, R2, C2>::new_uninitialized_generic(nrows2, ncols2) };
for i in 0 .. nrows { for i in 0 .. nrows {
for j in 0 .. ncols { for j in 0 .. ncols {
unsafe { unsafe {
@ -46,12 +44,12 @@ impl<N1, N2, R1, C1, R2, C2, SA, SB> SubsetOf<Matrix<N2, R2, C2, SB>> for Matrix
} }
#[inline] #[inline]
fn is_in_subset(m: &Matrix<N2, R2, C2, SB>) -> bool { fn is_in_subset(m: &MatrixMN<N2, R2, C2>) -> bool {
m.iter().all(|e| e.is_in_subset()) m.iter().all(|e| e.is_in_subset())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &Matrix<N2, R2, C2, SB>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixMN<N2, R2, C2>) -> Self {
let (nrows2, ncols2) = m.shape(); let (nrows2, ncols2) = m.shape();
let nrows = R1::from_usize(nrows2); let nrows = R1::from_usize(nrows2);
let ncols = C1::from_usize(ncols2); let ncols = C1::from_usize(ncols2);
@ -90,10 +88,9 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> IntoIterator for &'a
macro_rules! impl_from_into_asref_1D( macro_rules! impl_from_into_asref_1D(
($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$( ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
impl<N, S> From<[N; $SZ]> for Matrix<N, $NRows, $NCols, S> impl<N> From<[N; $SZ]> for MatrixMN<N, $NRows, $NCols>
where N: Scalar, where N: Scalar,
S: OwnedStorage<N, $NRows, $NCols>, DefaultAllocator: Allocator<N, $NRows, $NCols> {
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn from(arr: [N; $SZ]) -> Self { fn from(arr: [N; $SZ]) -> Self {
unsafe { unsafe {
@ -107,8 +104,7 @@ macro_rules! impl_from_into_asref_1D(
impl<N, S> Into<[N; $SZ]> for Matrix<N, $NRows, $NCols, S> impl<N, S> Into<[N; $SZ]> for Matrix<N, $NRows, $NCols, S>
where N: Scalar, where N: Scalar,
S: OwnedStorage<N, $NRows, $NCols>, S: ContiguousStorage<N, $NRows, $NCols> {
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn into(self) -> [N; $SZ] { fn into(self) -> [N; $SZ] {
unsafe { unsafe {
@ -122,8 +118,7 @@ macro_rules! impl_from_into_asref_1D(
impl<N, S> AsRef<[N; $SZ]> for Matrix<N, $NRows, $NCols, S> impl<N, S> AsRef<[N; $SZ]> for Matrix<N, $NRows, $NCols, S>
where N: Scalar, where N: Scalar,
S: OwnedStorage<N, $NRows, $NCols>, S: ContiguousStorage<N, $NRows, $NCols> {
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn as_ref(&self) -> &[N; $SZ] { fn as_ref(&self) -> &[N; $SZ] {
unsafe { unsafe {
@ -134,8 +129,7 @@ macro_rules! impl_from_into_asref_1D(
impl<N, S> AsMut<[N; $SZ]> for Matrix<N, $NRows, $NCols, S> impl<N, S> AsMut<[N; $SZ]> for Matrix<N, $NRows, $NCols, S>
where N: Scalar, where N: Scalar,
S: OwnedStorage<N, $NRows, $NCols>, S: ContiguousStorageMut<N, $NRows, $NCols> {
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [N; $SZ] { fn as_mut(&mut self) -> &mut [N; $SZ] {
unsafe { unsafe {
@ -165,10 +159,8 @@ impl_from_into_asref_1D!(
macro_rules! impl_from_into_asref_2D( macro_rules! impl_from_into_asref_2D(
($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$(
impl<N, S> From<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S> impl<N: Scalar> From<[[N; $SZRows]; $SZCols]> for MatrixMN<N, $NRows, $NCols>
where N: Scalar, where DefaultAllocator: Allocator<N, $NRows, $NCols> {
S: OwnedStorage<N, $NRows, $NCols>,
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn from(arr: [[N; $SZRows]; $SZCols]) -> Self { fn from(arr: [[N; $SZRows]; $SZCols]) -> Self {
unsafe { unsafe {
@ -180,10 +172,8 @@ macro_rules! impl_from_into_asref_2D(
} }
} }
impl<N, S> Into<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S> impl<N: Scalar, S> Into<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S>
where N: Scalar, where S: ContiguousStorage<N, $NRows, $NCols> {
S: OwnedStorage<N, $NRows, $NCols>,
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn into(self) -> [[N; $SZRows]; $SZCols] { fn into(self) -> [[N; $SZRows]; $SZCols] {
unsafe { unsafe {
@ -195,10 +185,8 @@ macro_rules! impl_from_into_asref_2D(
} }
} }
impl<N, S> AsRef<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S> impl<N: Scalar, S> AsRef<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S>
where N: Scalar, where S: ContiguousStorage<N, $NRows, $NCols> {
S: OwnedStorage<N, $NRows, $NCols>,
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn as_ref(&self) -> &[[N; $SZRows]; $SZCols] { fn as_ref(&self) -> &[[N; $SZRows]; $SZCols] {
unsafe { unsafe {
@ -207,10 +195,8 @@ macro_rules! impl_from_into_asref_2D(
} }
} }
impl<N, S> AsMut<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S> impl<N: Scalar, S> AsMut<[[N; $SZRows]; $SZCols]> for Matrix<N, $NRows, $NCols, S>
where N: Scalar, where S: ContiguousStorageMut<N, $NRows, $NCols> {
S: OwnedStorage<N, $NRows, $NCols>,
S::Alloc: OwnedAllocator<N, $NRows, $NCols, S> {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [[N; $SZRows]; $SZCols] { fn as_mut(&mut self) -> &mut [[N; $SZRows]; $SZCols] {
unsafe { 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!( 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); (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); (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6);

View File

@ -9,8 +9,7 @@ use std::ops::{Deref, DerefMut};
use core::{Scalar, Matrix}; use core::{Scalar, Matrix};
use core::dimension::{U1, U2, U3, U4, U5, U6}; use core::dimension::{U1, U2, U3, U4, U5, U6};
use core::storage::OwnedStorage; use core::storage::{ContiguousStorage, ContiguousStorageMut};
use core::allocator::OwnedAllocator;
/* /*
* *
@ -35,22 +34,20 @@ macro_rules! coords_impl(
macro_rules! deref_impl( macro_rules! deref_impl(
($R: ty, $C: ty; $Target: ident) => { ($R: ty, $C: ty; $Target: ident) => {
impl<N: Scalar, S> Deref for Matrix<N, $R, $C, S> impl<N: Scalar, S> Deref for Matrix<N, $R, $C, S>
where S: OwnedStorage<N, $R, $C>, where S: ContiguousStorage<N, $R, $C> {
S::Alloc: OwnedAllocator<N, $R, $C, S> {
type Target = $Target<N>; type Target = $Target<N>;
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self.data.ptr()) }
} }
} }
impl<N: Scalar, S> DerefMut for Matrix<N, $R, $C, S> impl<N: Scalar, S> DerefMut for Matrix<N, $R, $C, S>
where S: OwnedStorage<N, $R, $C>, where S: ContiguousStorageMut<N, $R, $C> {
S::Alloc: OwnedAllocator<N, $R, $C, S> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self.data.ptr_mut()) }
} }
} }
} }

View File

@ -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<N, D: Dim, S> SquareMatrix<N, D, S>
where N: Real,
S: OwnedStorage<N, D, D>,
S::Alloc: OwnedAllocator<N, D, D, S> {
/// 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<SB, D2>(dimension: D, start: usize, vector: &ColumnVector<N, D2, SB>)
-> OwnedSquareMatrix<N, D, S::Alloc>
where D2: Dim,
SB: Storage<N, D2, U1> {
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<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
/// QR decomposition using Householder reflections.
pub fn qr(self) -> (OwnedSquareMatrix<N, D, S::Alloc>, OwnedSquareMatrix<N, D, S::Alloc>)
where S::Alloc: Allocator<N, Dynamic, U1> +
Allocator<N, D, U1> {
let (nrows, ncols) = self.data.shape();
// XXX: too restrictive.
assert!(nrows.value() >= ncols.value(), "");
let mut q = OwnedSquareMatrix::<N, D, S::Alloc>::identity_generic(nrows, ncols);
let mut r = self.into_owned();
// Temporary buffer that contains a column.
let mut col = unsafe {
OwnedColumnVector::<N, D, S::Alloc>::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::<N, D, S::Alloc>::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<N, D, S::Alloc>, OwnedColumnVector<N, D, S::Alloc>)
where S::Alloc: Allocator<N, D, U1> +
Allocator<N, Dynamic, U1> {
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::<N, D, S::Alloc>::new_uninitialized_generic(dim, U1) };
let mut s = unsafe { OwnedColumnVector::<N, D, S::Alloc>::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<OwnedSquareMatrix<N, D, S::Alloc>, &'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<OwnedSquareMatrix<N, D, S::Alloc>, &'static str> {
let out = self.transpose();
self.do_cholesky(out)
}
#[inline(always)]
fn do_cholesky(&self, mut out: OwnedSquareMatrix<N, D, S::Alloc>)
-> Result<OwnedSquareMatrix<N, D, S::Alloc>, &'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<N, D, S::Alloc>, OwnedSquareMatrix<N, D, S::Alloc>)
where S::Alloc: Allocator<N, D, U1> + Allocator<N, Dynamic, U1> {
let (nrows, ncols) = self.data.shape();
let mut h = self.clone_owned();
let mut q = OwnedSquareMatrix::<N, D, S::Alloc>::identity_generic(nrows, ncols);
if ncols.value() <= 2 {
return (q, h);
}
// Temporary buffer that contains a column.
let mut col = unsafe {
OwnedColumnVector::<N, D, S::Alloc>::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::<N, D, S::Alloc>::new_householder_generic(nrows, ite + 1, &v);
q = q * &p;
h = &p * h * p;
}
}
(q, h)
}
}

View File

@ -4,6 +4,8 @@
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time. //! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
use std::mem; use std::mem;
use std::ptr;
use std::cmp;
use std::ops::Mul; use std::ops::Mul;
use typenum::Prod; use typenum::Prod;
@ -11,7 +13,8 @@ use generic_array::ArrayLength;
use core::Scalar; use core::Scalar;
use core::dimension::{Dim, DimName, Dynamic}; 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_array::MatrixArray;
use core::matrix_vec::MatrixVec; use core::matrix_vec::MatrixVec;
@ -107,3 +110,110 @@ impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
MatrixVec::new(nrows, ncols, res) MatrixVec::new(nrows, ncols, res)
} }
} }
/*
*
* Reallocator.
*
*/
// Anything -> Static × Static
impl<N: Scalar, RFrom, CFrom, RTo, CTo> Reallocator<N, RFrom, CFrom, RTo, CTo> for DefaultAllocator
where RFrom: Dim,
CFrom: Dim,
RTo: DimName,
CTo: DimName,
Self: Allocator<N, RFrom, CFrom>,
RTo::Value: Mul<CTo::Value>,
Prod<RTo::Value, CTo::Value>: ArrayLength<N> {
#[inline]
unsafe fn reallocate_copy(rto: RTo, cto: CTo, buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer) -> MatrixArray<N, RTo, CTo> {
let mut res = <Self as Allocator<N, RTo, CTo>>::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<N: Scalar, RFrom, CFrom, CTo> Reallocator<N, RFrom, CFrom, Dynamic, CTo> for DefaultAllocator
where RFrom: DimName,
CFrom: DimName,
CTo: Dim,
RFrom::Value: Mul<CFrom::Value>,
Prod<RFrom::Value, CFrom::Value>: ArrayLength<N> {
#[inline]
unsafe fn reallocate_copy(rto: Dynamic, cto: CTo, buf: MatrixArray<N, RFrom, CFrom>) -> MatrixVec<N, Dynamic, CTo> {
let mut res = <Self as Allocator<N, Dynamic, CTo>>::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<N: Scalar, RFrom, CFrom, RTo> Reallocator<N, RFrom, CFrom, RTo, Dynamic> for DefaultAllocator
where RFrom: DimName,
CFrom: DimName,
RTo: DimName,
RFrom::Value: Mul<CFrom::Value>,
Prod<RFrom::Value, CFrom::Value>: ArrayLength<N> {
#[inline]
unsafe fn reallocate_copy(rto: RTo, cto: Dynamic, buf: MatrixArray<N, RFrom, CFrom>) -> MatrixVec<N, RTo, Dynamic> {
let mut res = <Self as Allocator<N, RTo, Dynamic>>::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<N: Scalar, CFrom: Dim, CTo: Dim> Reallocator<N, Dynamic, CFrom, Dynamic, CTo> for DefaultAllocator {
#[inline]
unsafe fn reallocate_copy(rto: Dynamic, cto: CTo, buf: MatrixVec<N, Dynamic, CFrom>) -> MatrixVec<N, Dynamic, CTo> {
let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf)
}
}
impl<N: Scalar, CFrom: Dim, RTo: DimName> Reallocator<N, Dynamic, CFrom, RTo, Dynamic> for DefaultAllocator {
#[inline]
unsafe fn reallocate_copy(rto: RTo, cto: Dynamic, buf: MatrixVec<N, Dynamic, CFrom>) -> MatrixVec<N, RTo, Dynamic> {
let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf)
}
}
impl<N: Scalar, RFrom: DimName, CTo: Dim> Reallocator<N, RFrom, Dynamic, Dynamic, CTo> for DefaultAllocator {
#[inline]
unsafe fn reallocate_copy(rto: Dynamic, cto: CTo, buf: MatrixVec<N, RFrom, Dynamic>) -> MatrixVec<N, Dynamic, CTo> {
let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf)
}
}
impl<N: Scalar, RFrom: DimName, RTo: DimName> Reallocator<N, RFrom, Dynamic, RTo, Dynamic> for DefaultAllocator {
#[inline]
unsafe fn reallocate_copy(rto: RTo, cto: Dynamic, buf: MatrixVec<N, RFrom, Dynamic>) -> MatrixVec<N, RTo, Dynamic> {
let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf)
}
}

View File

@ -3,9 +3,11 @@
//! Traits and tags for identifying the dimension of all algebraic entities. //! Traits and tags for identifying the dimension of all algebraic entities.
use std::fmt::Debug; use std::fmt::Debug;
use std::any::Any; use std::any::{TypeId, Any};
use std::cmp;
use std::ops::{Add, Sub, Mul, Div}; 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")] #[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer}; 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 /// 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). /// integers and `Dynamic` (for dimensions not known at compile-time).
pub trait Dim: Any + Debug + Copy + PartialEq + Send { pub trait Dim: Any + Debug + Copy + PartialEq + Send {
#[inline(always)]
fn is<D: Dim>() -> bool {
TypeId::of::<Self>() == TypeId::of::<D>()
}
/// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self = /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self =
/// Dynamic`. /// Dynamic`.
fn try_to_usize() -> Option<usize>; fn try_to_usize() -> Option<usize>;
@ -85,6 +92,24 @@ impl Dim for Dynamic {
} }
} }
impl Add<usize> for Dynamic {
type Output = Dynamic;
#[inline]
fn add(self, rhs: usize) -> Dynamic {
Dynamic::new(self.value + rhs)
}
}
impl Sub<usize> for Dynamic {
type Output = Dynamic;
#[inline]
fn sub(self, rhs: usize) -> Dynamic {
Dynamic::new(self.value - rhs)
}
}
/* /*
* *
* Operations. * Operations.
@ -93,7 +118,7 @@ impl Dim for Dynamic {
macro_rules! dim_ops( macro_rules! dim_ops(
($($DimOp: ident, $DimNameOp: ident, ($($DimOp: ident, $DimNameOp: ident,
$Op: ident, $op: ident, $Op: ident, $op: ident, $op_path: path,
$DimResOp: ident, $DimNameResOp: ident, $DimResOp: ident, $DimNameResOp: ident,
$ResOp: ident);* $(;)*) => {$( $ResOp: ident);* $(;)*) => {$(
pub type $DimResOp<D1, D2> = <D1 as $DimOp<D2>>::Output; pub type $DimResOp<D1, D2> = <D1 as $DimOp<D2>>::Output;
@ -120,7 +145,7 @@ macro_rules! dim_ops(
#[inline] #[inline]
fn $op(self, other: D) -> Dynamic { 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] #[inline]
fn $op(self, other: Dynamic) -> Dynamic { 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!( dim_ops!(
DimAdd, DimNameAdd, Add, add, DimSum, DimNameSum, Sum; DimAdd, DimNameAdd, Add, add, Add::add, DimSum, DimNameSum, Sum;
DimMul, DimNameMul, Mul, mul, DimProd, DimNameProd, Prod; DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod;
DimSub, DimNameSub, Sub, sub, DimDiff, DimNameDiff, Diff; DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff;
DimDiv, DimNameDiv, Div, div, DimQuot, DimNameQuot, Quot; 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;
); );

539
src/core/edition.rs Normal file
View File

@ -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<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Extracts the upper triangular part of this matrix (including the diagonal).
#[inline]
pub fn upper_triangle(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
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<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
let mut res = self.clone_owned();
res.fill_upper_triangle(N::zero(), 1);
res
}
}
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// 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<R2: Dim, S2>(&mut self, diag: &Vector<N, R2, S2>)
where R: DimMin<C>,
S2: Storage<N, R2>,
ShapeConstraint: DimEq<DimMinimum<R, C>, 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<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
/// 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<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/*
*
* Column removal.
*
*/
/// Removes the `i`-th column from this matrix.
#[inline]
pub fn remove_column(self, i: usize) -> MatrixMN<N, R, DimDiff<C, U1>>
where C: DimSub<U1>,
DefaultAllocator: Reallocator<N, R, C, R, DimDiff<C, U1>> {
self.remove_fixed_columns::<U1>(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<D>(self, i: usize) -> MatrixMN<N, R, DimDiff<C, D>>
where D: DimName,
C: DimSub<D>,
DefaultAllocator: Reallocator<N, R, C, R, DimDiff<C, D>> {
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<N, R, Dynamic>
where C: DimSub<Dynamic, Output = Dynamic>,
DefaultAllocator: Reallocator<N, R, C, R, Dynamic> {
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<D>(self, i: usize, nremove: D) -> MatrixMN<N, R, DimDiff<C, D>>
where D: Dim,
C: DimSub<D>,
DefaultAllocator: Reallocator<N, R, C, R, DimDiff<C, D>> {
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<N, DimDiff<R, U1>, C>
where R: DimSub<U1>,
DefaultAllocator: Reallocator<N, R, C, DimDiff<R, U1>, C> {
self.remove_fixed_rows::<U1>(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<D>(self, i: usize) -> MatrixMN<N, DimDiff<R, D>, C>
where D: DimName,
R: DimSub<D>,
DefaultAllocator: Reallocator<N, R, C, DimDiff<R, D>, 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<N, Dynamic, C>
where R: DimSub<Dynamic, Output = Dynamic>,
DefaultAllocator: Reallocator<N, R, C, Dynamic, C> {
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<D>(self, i: usize, nremove: D) -> MatrixMN<N, DimDiff<R, D>, C>
where D: Dim,
R: DimSub<D>,
DefaultAllocator: Reallocator<N, R, C, DimDiff<R, D>, 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<N, R, DimSum<C, U1>>
where C: DimAdd<U1>,
DefaultAllocator: Reallocator<N, R, C, R, DimSum<C, U1>> {
self.insert_fixed_columns::<U1>(i, val)
}
/// Inserts `D` column filled with `val` at the `i-th` position.
#[inline]
pub fn insert_fixed_columns<D>(self, i: usize, val: N) -> MatrixMN<N, R, DimSum<C, D>>
where D: DimName,
C: DimAdd<D>,
DefaultAllocator: Reallocator<N, R, C, R, DimSum<C, D>> {
let mut res = unsafe { self.insert_columns_generic_uninitialized(i, D::name()) };
res.fixed_columns_mut::<D>(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<N, R, Dynamic>
where C: DimAdd<Dynamic, Output = Dynamic>,
DefaultAllocator: Reallocator<N, R, C, R, Dynamic> {
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<D>(self, i: usize, ninsert: D)
-> MatrixMN<N, R, DimSum<C, D>>
where D: Dim,
C: DimAdd<D>,
DefaultAllocator: Reallocator<N, R, C, R, DimSum<C, D>> {
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<N, DimSum<R, U1>, C>
where R: DimAdd<U1>,
DefaultAllocator: Reallocator<N, R, C, DimSum<R, U1>, C> {
self.insert_fixed_rows::<U1>(i, val)
}
/// Inserts `D` row filled with `val` at the `i-th` position.
#[inline]
pub fn insert_fixed_rows<D>(self, i: usize, val: N) -> MatrixMN<N, DimSum<R, D>, C>
where D: DimName,
R: DimAdd<D>,
DefaultAllocator: Reallocator<N, R, C, DimSum<R, D>, C> {
let mut res = unsafe { self.insert_rows_generic_uninitialized(i, D::name()) };
res.fixed_rows_mut::<D>(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<N, Dynamic, C>
where R: DimAdd<Dynamic, Output = Dynamic>,
DefaultAllocator: Reallocator<N, R, C, Dynamic, C> {
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<D>(self, i: usize, ninsert: D)
-> MatrixMN<N, DimSum<R, D>, C>
where D: Dim,
R: DimAdd<D>,
DefaultAllocator: Reallocator<N, R, C, DimSum<R, D>, 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<N>
where DefaultAllocator: Reallocator<N, R, C, Dynamic, Dynamic> {
self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val)
}
pub fn fixed_resize<R2: DimName, C2: DimName>(self, val: N) -> MatrixMN<N, R2, C2>
where DefaultAllocator: Reallocator<N, R, C, R2, C2> {
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<R2: Dim, C2: Dim>(self, new_nrows: R2, new_ncols: C2, val: N) -> MatrixMN<N, R2, C2>
where DefaultAllocator: Reallocator<N, R, C, R2, C2> {
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<N: Scalar>(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<N: Scalar>(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);
}
}

View File

@ -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<N, D: Dim, S> SquareMatrix<N, D, S>
where N: Scalar + Field + ApproxEq,
S: Storage<N, D, D> {
/// Attempts to invert this matrix.
#[inline]
pub fn try_inverse(self) -> Option<OwnedSquareMatrix<N, D, S::Alloc>> {
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<N, D: Dim, S> SquareMatrix<N, D, S>
where N: Scalar + Field + ApproxEq,
S: StorageMut<N, D, D> {
/// 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<N, D, S>(mut matrix: SquareMatrix<N, D, S>) -> Option<OwnedSquareMatrix<N, D, S::Alloc>>
where D: Dim,
N: Scalar + Field + ApproxEq,
S: StorageMut<N, D, D> {
assert!(matrix.is_square(), "Unable to invert a non-square matrix.");
let dim = matrix.data.shape().0;
let mut res: OwnedSquareMatrix<N, D, S::Alloc> = 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)
}
}

View File

@ -81,6 +81,13 @@ macro_rules! iterator {
self.size_hint().0 self.size_hint().0
} }
} }
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + $Storage<N, R, C>> ExactSizeIterator for $Name<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.size
}
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,42 +7,39 @@ use alga::general::{AbstractMagma, AbstractGroupAbelian, AbstractGroup, Abstract
ClosedAdd, ClosedNeg, ClosedMul}; ClosedAdd, ClosedNeg, ClosedMul};
use alga::linear::{VectorSpace, NormedSpace, InnerSpace, FiniteDimVectorSpace, FiniteDimInnerSpace}; 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::dimension::{Dim, DimName};
use core::storage::OwnedStorage; use core::storage::{Storage, StorageMut};
use core::allocator::OwnedAllocator; use core::allocator::Allocator;
/* /*
* *
* Additive structures. * Additive structures.
* *
*/ */
impl<N, R: DimName, C: DimName, S> Identity<Additive> for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> Identity<Additive> for MatrixMN<N, R, C>
where N: Scalar + Zero, where N: Scalar + Zero,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::from_element(N::zero()) Self::from_element(N::zero())
} }
} }
impl<N, R: DimName, C: DimName, S> AbstractMagma<Additive> for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> AbstractMagma<Additive> for MatrixMN<N, R, C>
where N: Scalar + ClosedAdd, where N: Scalar + ClosedAdd,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn operate(&self, other: &Self) -> Self { fn operate(&self, other: &Self) -> Self {
self + other self + other
} }
} }
impl<N, R: DimName, C: DimName, S> Inverse<Additive> for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> Inverse<Additive> for MatrixMN<N, R, C>
where N: Scalar + ClosedNeg, where N: Scalar + ClosedNeg,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn inverse(&self) -> Matrix<N, R, C, S> { fn inverse(&self) -> MatrixMN<N, R, C> {
-self -self
} }
@ -54,10 +51,9 @@ impl<N, R: DimName, C: DimName, S> Inverse<Additive> for Matrix<N, R, C, S>
macro_rules! inherit_additive_structure( macro_rules! inherit_additive_structure(
($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$( ($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$(
impl<N, R: DimName, C: DimName, S> $marker<$operator> for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> $marker<$operator> for MatrixMN<N, R, C>
where N: Scalar + $marker<$operator> $(+ $bounds)*, where N: Scalar + $marker<$operator> $(+ $bounds)*,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> { }
S::Alloc: OwnedAllocator<N, R, C, S> { }
)*} )*}
); );
@ -70,10 +66,9 @@ inherit_additive_structure!(
AbstractGroupAbelian<Additive> + Zero + ClosedAdd + ClosedNeg AbstractGroupAbelian<Additive> + Zero + ClosedAdd + ClosedNeg
); );
impl<N, R: DimName, C: DimName, S> AbstractModule for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> AbstractModule for MatrixMN<N, R, C>
where N: Scalar + RingCommutative, where N: Scalar + RingCommutative,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
type AbstractRing = N; type AbstractRing = N;
#[inline] #[inline]
@ -82,24 +77,21 @@ impl<N, R: DimName, C: DimName, S> AbstractModule for Matrix<N, R, C, S>
} }
} }
impl<N, R: DimName, C: DimName, S> Module for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> Module for MatrixMN<N, R, C>
where N: Scalar + RingCommutative, where N: Scalar + RingCommutative,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
type Ring = N; type Ring = N;
} }
impl<N, R: DimName, C: DimName, S> VectorSpace for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> VectorSpace for MatrixMN<N, R, C>
where N: Scalar + Field, where N: Scalar + Field,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
type Field = N; type Field = N;
} }
impl<N, R: DimName, C: DimName, S> FiniteDimVectorSpace for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> FiniteDimVectorSpace for MatrixMN<N, R, C>
where N: Scalar + Field, where N: Scalar + Field,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn dimension() -> usize { fn dimension() -> usize {
R::dim() * C::dim() R::dim() * C::dim()
@ -131,10 +123,8 @@ impl<N, R: DimName, C: DimName, S> FiniteDimVectorSpace for Matrix<N, R, C, S>
} }
} }
impl<N, R: DimName, C: DimName, S> NormedSpace for Matrix<N, R, C, S> impl<N: Real, R: DimName, C: DimName> NormedSpace for MatrixMN<N, R, C>
where N: Real, where DefaultAllocator: Allocator<N, R, C> {
S: OwnedStorage<N, R, C>,
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn norm_squared(&self) -> N { fn norm_squared(&self) -> N {
self.norm_squared() self.norm_squared()
@ -166,10 +156,8 @@ impl<N, R: DimName, C: DimName, S> NormedSpace for Matrix<N, R, C, S>
} }
} }
impl<N, R: DimName, C: DimName, S> InnerSpace for Matrix<N, R, C, S> impl<N: Real, R: DimName, C: DimName> InnerSpace for MatrixMN<N, R, C>
where N: Real, where DefaultAllocator: Allocator<N, R, C> {
S: OwnedStorage<N, R, C>,
S::Alloc: OwnedAllocator<N, R, C, S> {
type Real = N; type Real = N;
#[inline] #[inline]
@ -187,12 +175,10 @@ impl<N, R: DimName, C: DimName, S> InnerSpace for Matrix<N, R, C, S>
// In particular: // In particular:
// use `x()` instead of `::canonical_basis_element` // use `x()` instead of `::canonical_basis_element`
// use `::new(x, y, z)` instead of `::from_slice` // use `::new(x, y, z)` instead of `::from_slice`
impl<N, R: DimName, C: DimName, S> FiniteDimInnerSpace for Matrix<N, R, C, S> impl<N: Real, R: DimName, C: DimName> FiniteDimInnerSpace for MatrixMN<N, R, C>
where N: Real, where DefaultAllocator: Allocator<N, R, C> {
S: OwnedStorage<N, R, C>,
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn orthonormalize(vs: &mut [Matrix<N, R, C, S>]) -> usize { fn orthonormalize(vs: &mut [MatrixMN<N, R, C>]) -> usize {
let mut nbasis_elements = 0; let mut nbasis_elements = 0;
for i in 0 .. vs.len() { for i in 0 .. vs.len() {
@ -307,20 +293,18 @@ impl<N, R: DimName, C: DimName, S> FiniteDimInnerSpace for Matrix<N, R, C, S>
* *
* *
*/ */
impl<N, D: DimName, S> Identity<Multiplicative> for SquareMatrix<N, D, S> impl<N, D: DimName> Identity<Multiplicative> for MatrixN<N, D>
where N: Scalar + Zero + One, where N: Scalar + Zero + One,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, D: DimName, S> AbstractMagma<Multiplicative> for SquareMatrix<N, D, S> impl<N, D: DimName> AbstractMagma<Multiplicative> for MatrixN<N, D>
where N: Scalar + Zero + ClosedAdd + ClosedMul, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn operate(&self, other: &Self) -> Self { fn operate(&self, other: &Self) -> Self {
self * other self * other
@ -329,10 +313,9 @@ impl<N, D: DimName, S> AbstractMagma<Multiplicative> for SquareMatrix<N, D, S>
macro_rules! impl_multiplicative_structure( macro_rules! impl_multiplicative_structure(
($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$( ($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$(
impl<N, D: DimName, S> $marker<$operator> for SquareMatrix<N, D, S> impl<N, D: DimName> $marker<$operator> for MatrixN<N, D>
where N: Scalar + Zero + ClosedAdd + ClosedMul + $marker<$operator> $(+ $bounds)*, where N: Scalar + Zero + One + ClosedAdd + ClosedMul + $marker<$operator> $(+ $bounds)*,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> { }
S::Alloc: OwnedAllocator<N, D, D, S> { }
)*} )*}
); );
@ -341,421 +324,24 @@ impl_multiplicative_structure!(
AbstractMonoid<Multiplicative> + One AbstractMonoid<Multiplicative> + One
); );
// // FIXME: Field too strong?
// impl<N, S> Matrix for Matrix<N, S>
// where N: Scalar + Field,
// S: Storage<N> {
// type Field = N;
// type Row = OwnedMatrix<N, Static<U1>, S::C, S::Alloc>;
// type Column = OwnedMatrix<N, S::R, Static<U1>, S::Alloc>;
// type Transpose = OwnedMatrix<N, S::C, S::R, S::Alloc>;
// #[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<N, S> MatrixMut for Matrix<N, S>
// where N: Scalar + Field,
// S: StorageMut<N> {
// #[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<N: Real> SquareMatrixMut for $t<N> {
// #[inline]
// fn from_diagonal(diag: &Self::Coordinates) -> Self {
// let mut res: $t<N> = ::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<N: Real> SquareMatrix for $t<N> {
// type Vector = $vector<N>;
// #[inline]
// fn diagonal(&self) -> Self::Coordinates {
// $vector::new(self.m11)
// }
// #[inline]
// fn determinant(&self) -> Self::Field {
// self.m11
// }
// #[inline]
// fn try_inverse(&self) -> Option<Self> {
// 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::<N>() / ::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<N: Real> SquareMatrix for $t<N> {
// type Vector = $vector<N>;
// #[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<Self> {
// 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<N: Real> SquareMatrix for $t<N> {
// type Vector = $vector<N>;
// #[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<Self> {
// 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<N: Real> SquareMatrix for $t<N> {
// type Vector = $vector<N>;
// #[inline]
// fn diagonal(&self) -> Self::Coordinates {
// let mut diagonal: $vector<N> = ::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<Self> {
// 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<N> = ::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 * Ordering
* *
*/ */
impl<N, R: Dim, C: Dim, S> MeetSemilattice for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim> MeetSemilattice for MatrixMN<N, R, C>
where N: Scalar + MeetSemilattice, where N: Scalar + MeetSemilattice,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn meet(&self, other: &Self) -> Self { fn meet(&self, other: &Self) -> Self {
self.zip_map(other, |a, b| a.meet(&b)) self.zip_map(other, |a, b| a.meet(&b))
} }
} }
impl<N, R: Dim, C: Dim, S> JoinSemilattice for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim> JoinSemilattice for MatrixMN<N, R, C>
where N: Scalar + JoinSemilattice, where N: Scalar + JoinSemilattice,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn join(&self, other: &Self) -> Self { fn join(&self, other: &Self) -> Self {
self.zip_map(other, |a, b| a.join(&b)) self.zip_map(other, |a, b| a.join(&b))
@ -763,10 +349,9 @@ impl<N, R: Dim, C: Dim, S> JoinSemilattice for Matrix<N, R, C, S>
} }
impl<N, R: Dim, C: Dim, S> Lattice for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim> Lattice for MatrixMN<N, R, C>
where N: Scalar + Lattice, where N: Scalar + Lattice,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C> {
S::Alloc: OwnedAllocator<N, R, C, S> {
#[inline] #[inline]
fn meet_join(&self, other: &Self) -> (Self, Self) { fn meet_join(&self, other: &Self) -> (Self, Self) {
let shape = self.data.shape(); let shape = self.data.shape();

View File

@ -18,7 +18,7 @@ use generic_array::{ArrayLength, GenericArray};
use core::Scalar; use core::Scalar;
use core::dimension::{DimName, U1}; 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::allocator::Allocator;
use core::default_allocator::DefaultAllocator; use core::default_allocator::DefaultAllocator;
@ -136,22 +136,10 @@ unsafe impl<N, R, C> Storage<N, R, C> for MatrixArray<N, R, C>
R: DimName, R: DimName,
C: DimName, C: DimName,
R::Value: Mul<C::Value>, R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N> { Prod<R::Value, C::Value>: ArrayLength<N>,
DefaultAllocator: Allocator<N, R, C, Buffer = Self> {
type RStride = U1; type RStride = U1;
type CStride = R; type CStride = R;
type Alloc = DefaultAllocator;
#[inline]
fn into_owned(self) -> Owned<N, R, C, Self::Alloc> {
self
}
#[inline]
fn clone_owned(&self) -> Owned<N, R, C, Self::Alloc> {
let it = self.iter().cloned();
Self::Alloc::allocate_from_iterator(self.shape().0, self.shape().1, it)
}
#[inline] #[inline]
fn ptr(&self) -> *const N { fn ptr(&self) -> *const N {
@ -167,30 +155,44 @@ unsafe impl<N, R, C> Storage<N, R, C> for MatrixArray<N, R, C>
fn strides(&self) -> (Self::RStride, Self::CStride) { fn strides(&self) -> (Self::RStride, Self::CStride) {
(Self::RStride::name(), Self::CStride::name()) (Self::RStride::name(), Self::CStride::name())
} }
#[inline]
fn is_contiguous(&self) -> bool {
true
}
#[inline]
fn into_owned(self) -> Owned<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self
}
#[inline]
fn clone_owned(&self) -> Owned<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
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<N, R, C> StorageMut<N, R, C> for MatrixArray<N, R, C> unsafe impl<N, R, C> StorageMut<N, R, C> for MatrixArray<N, R, C>
where N: Scalar, where N: Scalar,
R: DimName, R: DimName,
C: DimName, C: DimName,
R::Value: Mul<C::Value>, R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N> { Prod<R::Value, C::Value>: ArrayLength<N>,
DefaultAllocator: Allocator<N, R, C, Buffer = Self> {
#[inline] #[inline]
fn ptr_mut(&mut self) -> *mut N { fn ptr_mut(&mut self) -> *mut N {
self[..].as_mut_ptr() self[..].as_mut_ptr()
} }
}
unsafe impl<N, R, C> OwnedStorage<N, R, C> for MatrixArray<N, R, C>
where N: Scalar,
R: DimName,
C: DimName,
R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N> {
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
}
#[inline] #[inline]
fn as_mut_slice(&mut self) -> &mut [N] { fn as_mut_slice(&mut self) -> &mut [N] {
@ -198,6 +200,24 @@ unsafe impl<N, R, C> OwnedStorage<N, R, C> for MatrixArray<N, R, C>
} }
} }
unsafe impl<N, R, C> ContiguousStorage<N, R, C> for MatrixArray<N, R, C>
where N: Scalar,
R: DimName,
C: DimName,
R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>,
DefaultAllocator: Allocator<N, R, C, Buffer = Self> {
}
unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for MatrixArray<N, R, C>
where N: Scalar,
R: DimName,
C: DimName,
R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>,
DefaultAllocator: Allocator<N, R, C, Buffer = Self> {
}
/* /*
* *

View File

@ -1,28 +1,31 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use std::slice;
use core::{Scalar, Matrix}; use core::{Scalar, Matrix};
use core::dimension::{Dim, DimName, Dynamic, DimMul, DimProd, U1}; use core::dimension::{Dim, DimName, Dynamic, DimMul, DimProd, U1};
use core::iter::MatrixIter; use core::iter::MatrixIter;
use core::storage::{Storage, StorageMut, Owned}; use core::storage::{Storage, StorageMut, Owned};
use core::allocator::Allocator; use core::allocator::Allocator;
use core::default_allocator::DefaultAllocator;
macro_rules! slice_storage_impl( macro_rules! slice_storage_impl(
($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { ($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => {
#[doc = $doc] #[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, ptr: $Ptr,
shape: (R, C), shape: (R, C),
strides: (RStride, CStride), 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 // Dynamic is arbitrary. It's just to be able to call the constructors with `Slice::`
// `Slice::` impl<'a, N: Scalar, R: Dim, C: Dim> $T<'a, N, R, C, Dynamic, Dynamic> {
impl<'a, N: Scalar, R: Dim, C: Dim> $T<'a, N, R, C, Dynamic, Dynamic, ()> {
/// Create a new matrix slice without bound checking. /// Create a new matrix slice without bound checking.
#[inline] #[inline]
pub unsafe fn new_unchecked<RStor, CStor, S>(storage: $SRef, start: (usize, usize), shape: (R, C)) pub unsafe fn new_unchecked<RStor, CStor, S>(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, where RStor: Dim,
CStor: Dim, CStor: Dim,
S: $Storage<N, RStor, CStor> { S: $Storage<N, RStor, CStor> {
@ -37,17 +40,29 @@ macro_rules! slice_storage_impl(
start: (usize, usize), start: (usize, usize),
shape: (R, C), shape: (R, C),
strides: (RStride, CStride)) strides: (RStride, CStride))
-> $T<'a, N, R, C, RStride, CStride, S::Alloc> -> $T<'a, N, R, C, RStride, CStride>
where RStor: Dim, where RStor: Dim,
CStor: Dim, CStor: Dim,
S: $Storage<N, RStor, CStor>, S: $Storage<N, RStor, CStor>,
RStride: Dim, RStride: Dim,
CStride: 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<RStride, CStride>(ptr: $Ptr,
shape: (R, C),
strides: (RStride, CStride))
-> $T<'a, N, R, C, RStride, CStride>
where RStride: Dim,
CStride: Dim {
$T { $T {
ptr: storage.$get_addr(start.0, start.1), ptr: ptr,
shape: shape, shape: shape,
strides: (strides.0, strides.1), strides: strides,
_phantoms: PhantomData _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 impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
for SliceStorage<'a, N, R, C, RStride, CStride, Alloc> { } for SliceStorage<'a, N, R, C, RStride, CStride> { }
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> Clone impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
for SliceStorage<'a, N, R, C, RStride, CStride, Alloc> { for SliceStorage<'a, N, R, C, RStride, CStride> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
SliceStorage { SliceStorage {
@ -83,26 +98,11 @@ for SliceStorage<'a, N, R, C, RStride, CStride, Alloc> {
macro_rules! storage_impl( macro_rules! storage_impl(
($($T: ident),* $(,)*) => {$( ($($T: ident),* $(,)*) => {$(
unsafe impl<'a, N, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> Storage<N, R, C> unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<N, R, C>
for $T<'a, N, R, C, RStride, CStride, Alloc> for $T<'a, N, R, C, RStride, CStride> {
where N: Scalar,
Alloc: Allocator<N, R, C> {
type RStride = RStride; type RStride = RStride;
type CStride = CStride; type CStride = CStride;
type Alloc = Alloc;
#[inline]
fn into_owned(self) -> Owned<N, R, C, Self::Alloc> {
self.clone_owned()
}
#[inline]
fn clone_owned(&self) -> Owned<N, R, C, Self::Alloc> {
let (nrows, ncols) = self.shape();
let it = MatrixIter::new(self).cloned();
Alloc::allocate_from_iterator(nrows, ncols, it)
}
#[inline] #[inline]
fn ptr(&self) -> *const N { fn ptr(&self) -> *const N {
@ -118,20 +118,74 @@ macro_rules! storage_impl(
fn strides(&self) -> (Self::RStride, Self::CStride) { fn strides(&self) -> (Self::RStride, Self::CStride) {
self.strides 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::<U1>() && C::is::<U1>()) || // Column vector.
(CStride::is::<U1>() && R::is::<U1>()) { // 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<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self.clone_owned()
}
#[inline]
fn clone_owned(&self) -> Owned<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
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); storage_impl!(SliceStorage, SliceStorageMut);
unsafe impl<'a, N, R: Dim, C: Dim, RStride: Dim, CStride: Dim, Alloc> StorageMut<N, R, C> unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut<N, R, C>
for SliceStorageMut<'a, N, R, C, RStride, CStride, Alloc> for SliceStorageMut<'a, N, R, C, RStride, CStride> {
where N: Scalar,
Alloc: Allocator<N, R, C> {
#[inline] #[inline]
fn ptr_mut(&mut self) -> *mut N { fn ptr_mut(&mut self) -> *mut N {
self.ptr 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<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
#[inline] #[inline]
fn assert_slice_index(&self, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) { fn assert_slice_index(&self, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) {
let my_shape = self.shape(); let my_shape = self.shape();
assert!(start.0 + (shape.0 - 1) * steps.0 <= my_shape.0, "Matrix slicing out of bounds."); // NOTE: we previously did: (shape.0 - 1) * steps.0
assert!(start.1 + (shape.1 - 1) * steps.1 <= my_shape.1, "Matrix slicing out of bounds."); // 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( 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: ident,
$row_part: ident,
$rows: ident, $rows: ident,
$rows_with_step: ident, $rows_with_step: ident,
$fixed_rows: ident, $fixed_rows: ident,
$fixed_rows_with_step: ident, $fixed_rows_with_step: ident,
$rows_generic: ident, $rows_generic: ident,
$rows_generic_with_step: ident,
$column: ident, $column: ident,
$column_part: ident,
$columns: ident, $columns: ident,
$columns_with_step: ident, $columns_with_step: ident,
$fixed_columns: ident, $fixed_columns: ident,
$fixed_columns_with_step: ident, $fixed_columns_with_step: ident,
$columns_generic: ident, $columns_generic: ident,
$columns_generic_with_step: ident,
$slice: ident, $slice: ident,
$slice_with_steps: ident, $slice_with_steps: ident,
$fixed_slice: ident, $fixed_slice: ident,
$fixed_slice_with_steps: ident, $fixed_slice_with_steps: ident,
$generic_slice: 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. /// A matrix slice.
pub type $MatrixSlice<'a, N, R, C, RStride, CStride, Alloc> pub type $MatrixSlice<'a, N, R, C, RStride, CStride>
= Matrix<N, R, C, $SliceStorage<'a, N, R, C, RStride, CStride, Alloc>>; = Matrix<N, R, C, $SliceStorage<'a, N, R, C, RStride, CStride>>;
impl<N: Scalar, R: Dim, C: Dim, S: $Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: $Storage<N, R, C>> Matrix<N, R, C, S> {
/* /*
@ -175,65 +238,75 @@ macro_rules! matrix_slice_impl(
* Row slicing. * 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] #[inline]
pub fn $row($me: $Me, i: usize) -> $MatrixSlice<N, U1, C, S::RStride, S::CStride, S::Alloc> { pub fn $row($me: $Me, i: usize) -> $MatrixSlice<N, U1, C, S::RStride, S::CStride> {
$me.$fixed_rows::<U1>(i) $me.$fixed_rows::<U1>(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<N, U1, Dynamic, S::RStride, S::CStride> {
$me.$generic_slice((i, 0), (U1, Dynamic::new(n)))
}
/// Extracts from this matrix a set of consecutive rows. /// Extracts from this matrix a set of consecutive rows.
#[inline] #[inline]
pub fn $rows($me: $Me, first_row: usize, nrows: usize) pub fn $rows($me: $Me, first_row: usize, nrows: usize)
-> $MatrixSlice<N, Dynamic, C, S::RStride, S::CStride, S::Alloc> { -> $MatrixSlice<N, Dynamic, C, S::RStride, S::CStride> {
let my_shape = $me.data.shape(); $me.$rows_generic(first_row, Dynamic::new(nrows))
$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)
}
} }
/// Extracts from this matrix a set of consecutive rows regularly spaced by `step` rows. /// Extracts from this matrix a set of consecutive rows regularly spaced by `step` rows.
#[inline] #[inline]
pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize)
-> $MatrixSlice<N, Dynamic, C, Dynamic, S::CStride, S::Alloc> { -> $MatrixSlice<N, Dynamic, C, Dynamic, S::CStride> {
$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. /// Extracts a compile-time number of consecutive rows from this matrix.
#[inline] #[inline]
pub fn $fixed_rows<RSlice>($me: $Me, first_row: usize) pub fn $fixed_rows<RSlice>($me: $Me, first_row: usize)
-> $MatrixSlice<N, RSlice, C, S::RStride, S::CStride, S::Alloc> -> $MatrixSlice<N, RSlice, C, S::RStride, S::CStride>
where RSlice: DimName { where RSlice: DimName {
let my_shape = $me.data.shape(); $me.$rows_generic(first_row, RSlice::name())
$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)
}
} }
/// Extracts from this matrix a compile-time number of rows regularly spaced by `step` rows. /// Extracts from this matrix a compile-time number of rows regularly spaced by `step` rows.
#[inline] #[inline]
pub fn $fixed_rows_with_step<RSlice>($me: $Me, first_row: usize, step: usize) pub fn $fixed_rows_with_step<RSlice>($me: $Me, first_row: usize, step: usize)
-> $MatrixSlice<N, RSlice, C, Dynamic, S::CStride, S::Alloc> -> $MatrixSlice<N, RSlice, C, Dynamic, S::CStride>
where RSlice: DimName { 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 /// Extracts from this matrix `nrows` rows regularly spaced by `step` rows. Both argument may
/// or may not be values known at compile-time. /// or may not be values known at compile-time.
#[inline] #[inline]
pub fn $rows_generic<RSlice, RStep>($me: $Me, row_start: usize, nrows: RSlice, step: RStep) pub fn $rows_generic<RSlice>($me: $Me, row_start: usize, nrows: RSlice)
-> $MatrixSlice<N, RSlice, C, DimProd<RStep, S::RStride>, S::CStride, S::Alloc> -> $MatrixSlice<N, RSlice, C, S::RStride, S::CStride>
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<RSlice, RStep>($me: $Me, row_start: usize, nrows: RSlice, step: RStep)
-> $MatrixSlice<N, RSlice, C, DimProd<RStep, S::RStride>, S::CStride>
where RSlice: Dim, where RSlice: Dim,
RStep: DimMul<S::RStride> { RStep: DimMul<S::RStride> {
@ -257,66 +330,76 @@ macro_rules! matrix_slice_impl(
*/ */
/// Returns a slice containing the i-th column of this matrix. /// Returns a slice containing the i-th column of this matrix.
#[inline] #[inline]
pub fn $column($me: $Me, i: usize) -> $MatrixSlice<N, R, U1, S::RStride, S::CStride, S::Alloc> { pub fn $column($me: $Me, i: usize) -> $MatrixSlice<N, R, U1, S::RStride, S::CStride> {
$me.$fixed_columns::<U1>(i) $me.$fixed_columns::<U1>(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<N, Dynamic, U1, S::RStride, S::CStride> {
$me.$generic_slice((0, i), (Dynamic::new(n), U1))
}
/// Extracts from this matrix a set of consecutive columns. /// Extracts from this matrix a set of consecutive columns.
#[inline] #[inline]
pub fn $columns($me: $Me, first_col: usize, ncols: usize) pub fn $columns($me: $Me, first_col: usize, ncols: usize)
-> $MatrixSlice<N, R, Dynamic, S::RStride, S::CStride, S::Alloc> { -> $MatrixSlice<N, R, Dynamic, S::RStride, S::CStride> {
let my_shape = $me.data.shape(); $me.$columns_generic(first_col, Dynamic::new(ncols))
$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)
}
} }
/// Extracts from this matrix a set of consecutive columns regularly spaced by `step` columns. /// Extracts from this matrix a set of consecutive columns regularly spaced by `step` columns.
#[inline] #[inline]
pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize)
-> $MatrixSlice<N, R, Dynamic, S::RStride, Dynamic, S::Alloc> { -> $MatrixSlice<N, R, Dynamic, S::RStride, Dynamic> {
$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. /// Extracts a compile-time number of consecutive columns from this matrix.
#[inline] #[inline]
pub fn $fixed_columns<CSlice>($me: $Me, first_col: usize) pub fn $fixed_columns<CSlice>($me: $Me, first_col: usize)
-> $MatrixSlice<N, R, CSlice, S::RStride, S::CStride, S::Alloc> -> $MatrixSlice<N, R, CSlice, S::RStride, S::CStride>
where CSlice: DimName { where CSlice: DimName {
let my_shape = $me.data.shape(); $me.$columns_generic(first_col, CSlice::name())
$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)
}
} }
/// Extracts from this matrix a compile-time number of columns regularly spaced by `step` /// Extracts from this matrix a compile-time number of columns regularly spaced by `step`
/// columns. /// columns.
#[inline] #[inline]
pub fn $fixed_columns_with_step<CSlice>($me: $Me, first_col: usize, step: usize) pub fn $fixed_columns_with_step<CSlice>($me: $Me, first_col: usize, step: usize)
-> $MatrixSlice<N, R, CSlice, S::RStride, Dynamic, S::Alloc> -> $MatrixSlice<N, R, CSlice, S::RStride, Dynamic>
where CSlice: DimName { 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<CSlice>($me: $Me, first_col: usize, ncols: CSlice)
-> $MatrixSlice<N, R, CSlice, S::RStride, S::CStride>
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 /// Extracts from this matrix `ncols` columns regularly spaced by `step` columns. Both argument may
/// or may not be values known at compile-time. /// or may not be values known at compile-time.
#[inline] #[inline]
pub fn $columns_generic<CSlice, CStep>($me: $Me, first_col: usize, ncols: CSlice, step: CStep) pub fn $columns_generic_with_step<CSlice, CStep>($me: $Me, first_col: usize, ncols: CSlice, step: CStep)
-> $MatrixSlice<N, R, CSlice, S::RStride, DimProd<CStep, S::CStride>, S::Alloc> -> $MatrixSlice<N, R, CSlice, S::RStride, DimProd<CStep, S::CStride>>
where CSlice: Dim, where CSlice: Dim,
CStep: DimMul<S::CStride> { CStep: DimMul<S::CStride> {
let my_shape = $me.data.shape(); let my_shape = $me.data.shape();
let my_strides = $me.data.strides(); let my_strides = $me.data.strides();
@ -341,7 +424,7 @@ macro_rules! matrix_slice_impl(
/// consecutive elements. /// consecutive elements.
#[inline] #[inline]
pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize))
-> $MatrixSlice<N, Dynamic, Dynamic, S::RStride, S::CStride, S::Alloc> { -> $MatrixSlice<N, Dynamic, Dynamic, S::RStride, S::CStride> {
$me.assert_slice_index(start, shape, (1, 1)); $me.assert_slice_index(start, shape, (1, 1));
let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1));
@ -359,7 +442,7 @@ macro_rules! matrix_slice_impl(
/// original matrix. /// original matrix.
#[inline] #[inline]
pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize))
-> $MatrixSlice<N, Dynamic, Dynamic, Dynamic, Dynamic, S::Alloc> { -> $MatrixSlice<N, Dynamic, Dynamic, Dynamic, Dynamic> {
let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1));
let steps = (Dynamic::new(steps.0), Dynamic::new(steps.1)); let steps = (Dynamic::new(steps.0), Dynamic::new(steps.1));
@ -370,7 +453,7 @@ macro_rules! matrix_slice_impl(
/// CSlice::dim())` consecutive components. /// CSlice::dim())` consecutive components.
#[inline] #[inline]
pub fn $fixed_slice<RSlice, CSlice>($me: $Me, irow: usize, icol: usize) pub fn $fixed_slice<RSlice, CSlice>($me: $Me, irow: usize, icol: usize)
-> $MatrixSlice<N, RSlice, CSlice, S::RStride, S::CStride, S::Alloc> -> $MatrixSlice<N, RSlice, CSlice, S::RStride, S::CStride>
where RSlice: DimName, where RSlice: DimName,
CSlice: DimName { CSlice: DimName {
@ -389,7 +472,7 @@ macro_rules! matrix_slice_impl(
/// the original matrix. /// the original matrix.
#[inline] #[inline]
pub fn $fixed_slice_with_steps<RSlice, CSlice>($me: $Me, start: (usize, usize), steps: (usize, usize)) pub fn $fixed_slice_with_steps<RSlice, CSlice>($me: $Me, start: (usize, usize), steps: (usize, usize))
-> $MatrixSlice<N, RSlice, CSlice, Dynamic, Dynamic, S::Alloc> -> $MatrixSlice<N, RSlice, CSlice, Dynamic, Dynamic>
where RSlice: DimName, where RSlice: DimName,
CSlice: DimName { CSlice: DimName {
let shape = (RSlice::name(), CSlice::name()); 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. /// Creates a slice that may or may not have a fixed size and stride.
#[inline] #[inline]
pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice)) pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
-> $MatrixSlice<N, RSlice, CSlice, S::RStride, S::CStride, S::Alloc> -> $MatrixSlice<N, RSlice, CSlice, S::RStride, S::CStride>
where RSlice: Dim, where RSlice: Dim,
CSlice: Dim { CSlice: Dim {
@ -418,12 +501,13 @@ macro_rules! matrix_slice_impl(
start: (usize, usize), start: (usize, usize),
shape: (RSlice, CSlice), shape: (RSlice, CSlice),
steps: (RStep, CStep)) steps: (RStep, CStep))
-> $MatrixSlice<N, RSlice, CSlice, DimProd<RStep, S::RStride>, DimProd<CStep, S::CStride>, S::Alloc> -> $MatrixSlice<N, RSlice, CSlice, DimProd<RStep, S::RStride>, DimProd<CStep, S::CStride>>
where RSlice: Dim, where RSlice: Dim,
CSlice: Dim, CSlice: Dim,
RStep: DimMul<S::RStride>, RStep: DimMul<S::RStride>,
CStep: DimMul<S::CStride> { CStep: DimMul<S::CStride> {
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())); $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (steps.0.value(), steps.1.value()));
let my_strides = $me.data.strides(); let my_strides = $me.data.strides();
@ -434,49 +518,297 @@ macro_rules! matrix_slice_impl(
Matrix::from_data_statically_unchecked(data) 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<Range1: SliceRange<R>, Range2: SliceRange<R>>($me: $Me, r1: Range1, r2: Range2)
-> ($MatrixSlice<N, Range1::Size, C, S::RStride, S::CStride>,
$MatrixSlice<N, Range2::Size, C, S::RStride, S::CStride>) {
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<Range1: SliceRange<C>, Range2: SliceRange<C>>($me: $Me, r1: Range1, r2: Range2)
-> ($MatrixSlice<N, R, Range1::Size, S::RStride, S::CStride>,
$MatrixSlice<N, R, Range2::Size, S::RStride, S::CStride>) {
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!( matrix_slice_impl!(
self: &Self, MatrixSlice, SliceStorage, Storage, &self.data; self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data;
row, row,
row_part,
rows, rows,
rows_with_step, rows_with_step,
fixed_rows, fixed_rows,
fixed_rows_with_step, fixed_rows_with_step,
rows_generic, rows_generic,
rows_generic_with_step,
column, column,
column_part,
columns, columns,
columns_with_step, columns_with_step,
fixed_columns, fixed_columns,
fixed_columns_with_step, fixed_columns_with_step,
columns_generic, columns_generic,
columns_generic_with_step,
slice, slice,
slice_with_steps, slice_with_steps,
fixed_slice, fixed_slice,
fixed_slice_with_steps, fixed_slice_with_steps,
generic_slice, generic_slice,
generic_slice_with_steps); generic_slice_with_steps,
rows_range_pair,
columns_range_pair);
matrix_slice_impl!( 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_mut,
row_part_mut,
rows_mut, rows_mut,
rows_with_step_mut, rows_with_step_mut,
fixed_rows_mut, fixed_rows_mut,
fixed_rows_with_step_mut, fixed_rows_with_step_mut,
rows_generic_mut, rows_generic_mut,
rows_generic_with_step_mut,
column_mut, column_mut,
column_part_mut,
columns_mut, columns_mut,
columns_with_step_mut, columns_with_step_mut,
fixed_columns_mut, fixed_columns_mut,
fixed_columns_with_step_mut, fixed_columns_with_step_mut,
columns_generic_mut, columns_generic_mut,
columns_generic_with_step_mut,
slice_mut, slice_mut,
slice_with_steps_mut, slice_with_steps_mut,
fixed_slice_mut, fixed_slice_mut,
fixed_slice_with_steps_mut, fixed_slice_with_steps_mut,
generic_slice_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<D: Dim> {
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<D: Dim> SliceRange<D> 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<D: Dim> SliceRange<D> for Range<usize> {
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<D: Dim> SliceRange<D> for RangeFrom<usize> {
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<D: Dim> SliceRange<D> for RangeTo<usize> {
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<D: Dim> SliceRange<D> 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<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
#[inline]
pub fn slice_range<RowRange, ColRange>(&self, rows: RowRange, cols: ColRange)
-> MatrixSlice<N, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
where RowRange: SliceRange<R>,
ColRange: SliceRange<C> {
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<RowRange: SliceRange<R>>(&self, rows: RowRange)
-> MatrixSlice<N, RowRange::Size, C, S::RStride, S::CStride> {
self.slice_range(rows, ..)
}
#[inline]
pub fn columns_range<ColRange: SliceRange<C>>(&self, cols: ColRange)
-> MatrixSlice<N, R, ColRange::Size, S::RStride, S::CStride> {
self.slice_range(.., cols)
}
}
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
pub fn slice_range_mut<RowRange, ColRange>(&mut self, rows: RowRange, cols: ColRange)
-> MatrixSliceMut<N, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
where RowRange: SliceRange<R>,
ColRange: SliceRange<C> {
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<RowRange: SliceRange<R>>(&mut self, rows: RowRange)
-> MatrixSliceMut<N, RowRange::Size, C, S::RStride, S::CStride> {
self.slice_range_mut(rows, ..)
}
#[inline]
pub fn columns_range_mut<ColRange: SliceRange<C>>(&mut self, cols: ColRange)
-> MatrixSliceMut<N, R, ColRange::Size, S::RStride, S::CStride> {
self.slice_range_mut(.., cols)
}
}

View File

@ -2,7 +2,8 @@ use std::ops::Deref;
use core::Scalar; use core::Scalar;
use core::dimension::{Dim, DimName, Dynamic, U1}; 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; use core::default_allocator::DefaultAllocator;
/* /*
@ -45,6 +46,26 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
pub unsafe fn data_mut(&mut self) -> &mut Vec<N> { pub unsafe fn data_mut(&mut self) -> &mut Vec<N> {
&mut self.data &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<N>{
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<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> { impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
@ -62,24 +83,14 @@ impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
* Dynamic Dynamic * Dynamic Dynamic
* *
*/ */
unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for MatrixVec<N, Dynamic, C> { unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> {
type RStride = U1; type RStride = U1;
type CStride = Dynamic; type CStride = Dynamic;
type Alloc = DefaultAllocator;
#[inline]
fn into_owned(self) -> Owned<N, Dynamic, C, Self::Alloc> {
self
}
#[inline]
fn clone_owned(&self) -> Owned<N, Dynamic, C, Self::Alloc> {
self.clone()
}
#[inline] #[inline]
fn ptr(&self) -> *const N { fn ptr(&self) -> *const N {
self[..].as_ptr() self.data.as_ptr()
} }
#[inline] #[inline]
@ -91,27 +102,39 @@ unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for MatrixVec<N, Dynamic,
fn strides(&self) -> (Self::RStride, Self::CStride) { fn strides(&self) -> (Self::RStride, Self::CStride) {
(Self::RStride::name(), self.nrows) (Self::RStride::name(), self.nrows)
} }
}
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dynamic> {
type RStride = U1;
type CStride = R;
type Alloc = DefaultAllocator;
#[inline] #[inline]
fn into_owned(self) -> Owned<N, R, Dynamic, Self::Alloc> { fn is_contiguous(&self) -> bool {
true
}
#[inline]
fn into_owned(self) -> Owned<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C> {
self self
} }
#[inline] #[inline]
fn clone_owned(&self) -> Owned<N, R, Dynamic, Self::Alloc> { fn clone_owned(&self) -> Owned<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C> {
self.clone() self.clone()
} }
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
}
}
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> {
type RStride = U1;
type CStride = R;
#[inline] #[inline]
fn ptr(&self) -> *const N { fn ptr(&self) -> *const N {
self[..].as_ptr() self.data.as_ptr()
} }
#[inline] #[inline]
@ -123,6 +146,28 @@ unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dy
fn strides(&self) -> (Self::RStride, Self::CStride) { fn strides(&self) -> (Self::RStride, Self::CStride) {
(Self::RStride::name(), self.nrows) (Self::RStride::name(), self.nrows)
} }
#[inline]
fn is_contiguous(&self) -> bool {
true
}
#[inline]
fn into_owned(self) -> Owned<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic> {
self
}
#[inline]
fn clone_owned(&self) -> Owned<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic> {
self.clone()
}
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
}
} }
@ -130,20 +175,14 @@ unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dy
/* /*
* *
* StorageMut, OwnedStorage. * StorageMut, ContiguousStorage.
* *
*/ */
unsafe impl<N: Scalar, C: Dim> StorageMut<N, Dynamic, C> for MatrixVec<N, Dynamic, C> { unsafe impl<N: Scalar, C: Dim> StorageMut<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> {
#[inline] #[inline]
fn ptr_mut(&mut self) -> *mut N { fn ptr_mut(&mut self) -> *mut N {
self.as_mut_slice().as_mut_ptr() self.data.as_mut_ptr()
}
}
unsafe impl<N: Scalar, C: Dim> OwnedStorage<N, Dynamic, C> for MatrixVec<N, Dynamic, C> {
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
} }
#[inline] #[inline]
@ -152,18 +191,20 @@ unsafe impl<N: Scalar, C: Dim> OwnedStorage<N, Dynamic, C> for MatrixVec<N, Dyna
} }
} }
unsafe impl<N: Scalar, C: Dim> ContiguousStorage<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for MatrixVec<N, R, Dynamic> { where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> {
#[inline]
fn ptr_mut(&mut self) -> *mut N {
self.as_mut_slice().as_mut_ptr()
}
} }
unsafe impl<N: Scalar, R: DimName> OwnedStorage<N, R, Dynamic> for MatrixVec<N, R, Dynamic> { unsafe impl<N: Scalar, C: Dim> ContiguousStorageMut<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> {
}
unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> {
#[inline] #[inline]
fn as_slice(&self) -> &[N] { fn ptr_mut(&mut self) -> *mut N {
&self[..] self.data.as_mut_ptr()
} }
#[inline] #[inline]
@ -171,3 +212,11 @@ unsafe impl<N: Scalar, R: DimName> OwnedStorage<N, R, Dynamic> for MatrixVec<N,
&mut self.data[..] &mut self.data[..]
} }
} }
unsafe impl<N: Scalar, R: DimName> ContiguousStorage<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> {
}
unsafe impl<N: Scalar, R: DimName> ContiguousStorageMut<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> {
}

View File

@ -6,6 +6,7 @@ pub mod allocator;
pub mod storage; pub mod storage;
pub mod coordinates; pub mod coordinates;
mod ops; mod ops;
mod blas;
pub mod iter; pub mod iter;
pub mod default_allocator; pub mod default_allocator;
@ -15,8 +16,6 @@ mod construction;
mod properties; mod properties;
mod alias; mod alias;
mod matrix_alga; mod matrix_alga;
mod determinant;
mod inverse;
mod conversion; mod conversion;
mod matrix_slice; mod matrix_slice;
mod matrix_array; mod matrix_array;
@ -24,8 +23,7 @@ mod matrix_vec;
mod cg; mod cg;
mod unit; mod unit;
mod componentwise; mod componentwise;
mod edition;
mod decompositions;
#[doc(hidden)] #[doc(hidden)]
pub mod helper; pub mod helper;

View File

@ -1,15 +1,16 @@
use std::iter; use std::iter;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg, use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg,
Index, IndexMut}; Index, IndexMut};
use num::{Zero, One}; use std::cmp::PartialOrd;
use num::{Zero, One, Signed};
use alga::general::{ClosedMul, ClosedDiv, ClosedAdd, ClosedSub, ClosedNeg}; use alga::general::{ClosedMul, ClosedDiv, ClosedAdd, ClosedSub, ClosedNeg};
use core::{Scalar, Matrix, OwnedMatrix, SquareMatrix, MatrixSum, MatrixMul, MatrixTrMul}; use core::{DefaultAllocator, Scalar, Matrix, MatrixN, MatrixMN, MatrixSum};
use core::dimension::{Dim, DimMul, DimName, DimProd}; use core::dimension::{Dim, DimName, DimProd, DimMul};
use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable, DimEq};
use core::storage::{Storage, StorageMut, OwnedStorage}; use core::storage::{Storage, StorageMut, ContiguousStorageMut};
use core::allocator::{SameShapeAllocator, Allocator, OwnedAllocator}; use core::allocator::{SameShapeAllocator, Allocator, SameShapeR, SameShapeC};
/* /*
* *
@ -70,8 +71,9 @@ impl<N, R: Dim, C: Dim, S> IndexMut<(usize, usize)> for Matrix<N, R, C, S>
*/ */
impl<N, R: Dim, C: Dim, S> Neg for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim, S> Neg for Matrix<N, R, C, S>
where N: Scalar + ClosedNeg, where N: Scalar + ClosedNeg,
S: Storage<N, R, C> { S: Storage<N, R, C>,
type Output = OwnedMatrix<N, R, C, S::Alloc>; DefaultAllocator: Allocator<N, R, C> {
type Output = MatrixMN<N, R, C>;
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
@ -83,8 +85,9 @@ impl<N, R: Dim, C: Dim, S> Neg for Matrix<N, R, C, S>
impl<'a, N, R: Dim, C: Dim, S> Neg for &'a Matrix<N, R, C, S> impl<'a, N, R: Dim, C: Dim, S> Neg for &'a Matrix<N, R, C, S>
where N: Scalar + ClosedNeg, where N: Scalar + ClosedNeg,
S: Storage<N, R, C> { S: Storage<N, R, C>,
type Output = OwnedMatrix<N, R, C, S::Alloc>; DefaultAllocator: Allocator<N, R, C> {
type Output = MatrixMN<N, R, C>;
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
@ -109,33 +112,156 @@ impl<N, R: Dim, C: Dim, S> Matrix<N, R, C, S>
* Addition & Substraction * Addition & Substraction
* *
*/ */
macro_rules! componentwise_binop_impl( macro_rules! componentwise_binop_impl(
($Trait: ident, $method: ident, $bound: ident; ($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<N, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA>
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<R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
rhs: &Matrix<N, R2, C2, SB>,
out: &mut Matrix<N, R3, C3, SC>)
where SB: Storage<N, R2, C2>,
SC: StorageMut<N, R3, C3> {
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<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
where R2: Dim,
C2: Dim,
SA: StorageMut<N, R1, C1>,
SB: Storage<N, R2, C2> {
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<R2, C2, SB>(&self, rhs: &mut Matrix<N, R2, C2, SB>)
where R2: Dim,
C2: Dim,
SB: StorageMut<N, R2, C2> {
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<R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
rhs: &Matrix<N, R2, C2, SB>,
out: &mut Matrix<N, R3, C3, SC>)
where SB: Storage<N, R2, C2>,
SC: StorageMut<N, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
self.$method_to_statically_unchecked(rhs, out)
}
}
impl<'b, N, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix<N, R2, C2, SB>> for Matrix<N, R1, C1, SA> impl<'b, N, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix<N, R2, C2, SB>> for Matrix<N, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, C2: Dim, where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
N: Scalar + $bound, N: Scalar + $bound,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA::Alloc: SameShapeAllocator<N, R1, C1, R2, C2, SA>, DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
type Output = MatrixSum<N, R1, C1, R2, C2, SA>; type Output = MatrixSum<N, R1, C1, R2, C2>;
#[inline] #[inline]
fn $method(self, right: &'b Matrix<N, R2, C2, SB>) -> Self::Output { fn $method(self, rhs: &'b Matrix<N, R2, C2, SB>) -> Self::Output {
assert!(self.shape() == right.shape(), "Matrix addition/subtraction dimensions mismatch."); assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
let mut res = self.into_owned_sum::<R2, C2>(); let mut res = self.into_owned_sum::<R2, C2>();
res.$method_assign_statically_unchecked(rhs);
// 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 res
} }
} }
@ -145,26 +271,16 @@ macro_rules! componentwise_binop_impl(
N: Scalar + $bound, N: Scalar + $bound,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SB::Alloc: SameShapeAllocator<N, R2, C2, R1, C1, SB>, DefaultAllocator: SameShapeAllocator<N, R2, C2, R1, C1>,
ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> { ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> {
type Output = MatrixSum<N, R2, C2, R1, C1, SB>; type Output = MatrixSum<N, R2, C2, R1, C1>;
#[inline] #[inline]
fn $method(self, right: Matrix<N, R2, C2, SB>) -> Self::Output { fn $method(self, rhs: Matrix<N, R2, C2, SB>) -> Self::Output {
assert!(self.shape() == right.shape(), "Matrix addition/subtraction dimensions mismatch."); let mut rhs = rhs.into_owned_sum::<R1, C1>();
let mut res = right.into_owned_sum::<R1, C1>(); assert!(self.shape() == rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
self.$method_assign_statically_unchecked_rhs(&mut rhs);
// XXX: optimize our iterator! rhs
//
// 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
} }
} }
@ -173,13 +289,13 @@ macro_rules! componentwise_binop_impl(
N: Scalar + $bound, N: Scalar + $bound,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA::Alloc: SameShapeAllocator<N, R1, C1, R2, C2, SA>, DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
type Output = MatrixSum<N, R1, C1, R2, C2, SA>; type Output = MatrixSum<N, R1, C1, R2, C2>;
#[inline] #[inline]
fn $method(self, right: Matrix<N, R2, C2, SB>) -> Self::Output { fn $method(self, rhs: Matrix<N, R2, C2, SB>) -> Self::Output {
self.$method(&right) self.$method(&rhs)
} }
} }
@ -188,13 +304,21 @@ macro_rules! componentwise_binop_impl(
N: Scalar + $bound, N: Scalar + $bound,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA::Alloc: SameShapeAllocator<N, R1, C1, R2, C2, SA>, DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
type Output = MatrixSum<N, R1, C1, R2, C2, SA>; type Output = MatrixSum<N, R1, C1, R2, C2>;
#[inline] #[inline]
fn $method(self, right: &'b Matrix<N, R2, C2, SB>) -> Self::Output { fn $method(self, rhs: &'b Matrix<N, R2, C2, SB>) -> Self::Output {
self.clone_owned().$method(right) let mut res = unsafe {
let (nrows, ncols) = self.shape();
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
let ncols: SameShapeC<C1, C2> = 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<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
#[inline] #[inline]
fn $method_assign(&mut self, right: &'b Matrix<N, R2, C2, SB>) { fn $method_assign(&mut self, rhs: &'b Matrix<N, R2, C2, SB>) {
assert!(self.shape() == right.shape(), "Matrix addition/subtraction dimensions mismatch."); self.$method_assign_statically_unchecked(rhs)
for (left, right) in self.iter_mut().zip(right.iter()) {
left.$method_assign(*right)
}
} }
} }
@ -222,32 +343,34 @@ macro_rules! componentwise_binop_impl(
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> { ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
#[inline] #[inline]
fn $method_assign(&mut self, right: Matrix<N, R2, C2, SB>) { fn $method_assign(&mut self, rhs: Matrix<N, R2, C2, SB>) {
self.$method_assign(&right) self.$method_assign(&rhs)
} }
} }
} }
); );
componentwise_binop_impl!(Add, add, ClosedAdd; AddAssign, add_assign); componentwise_binop_impl!(Add, add, ClosedAdd;
componentwise_binop_impl!(Sub, sub, ClosedSub; SubAssign, sub_assign); 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<N, R: DimName, C: DimName, S> iter::Sum for Matrix<N, R, C, S> impl<N, R: DimName, C: DimName> iter::Sum for MatrixMN<N, R, C>
where N: Scalar + ClosedAdd + Zero, where N: Scalar + ClosedAdd + Zero,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C>
S::Alloc: OwnedAllocator<N, R, C, S>
{ {
fn sum<I: Iterator<Item = Matrix<N, R, C, S>>>(iter: I) -> Matrix<N, R, C, S> { fn sum<I: Iterator<Item = MatrixMN<N, R, C>>>(iter: I) -> MatrixMN<N, R, C> {
iter.fold(Matrix::zero(), |acc, x| acc + x) iter.fold(Matrix::zero(), |acc, x| acc + x)
} }
} }
impl<'a, N, R: DimName, C: DimName, S> iter::Sum<&'a Matrix<N, R, C, S>> for Matrix<N, R, C, S> impl<'a, N, R: DimName, C: DimName> iter::Sum<&'a MatrixMN<N, R, C>> for MatrixMN<N, R, C>
where N: Scalar + ClosedAdd + Zero, where N: Scalar + ClosedAdd + Zero,
S: OwnedStorage<N, R, C>, DefaultAllocator: Allocator<N, R, C>
S::Alloc: OwnedAllocator<N, R, C, S>
{ {
fn sum<I: Iterator<Item = &'a Matrix<N, R, C, S>>>(iter: I) -> Matrix<N, R, C, S> { fn sum<I: Iterator<Item = &'a MatrixMN<N, R, C>>>(iter: I) -> MatrixMN<N, R, C> {
iter.fold(Matrix::zero(), |acc, x| acc + x) iter.fold(Matrix::zero(), |acc, x| acc + x)
} }
} }
@ -266,8 +389,9 @@ macro_rules! componentwise_scalarop_impl(
$TraitAssign: ident, $method_assign: ident) => { $TraitAssign: ident, $method_assign: ident) => {
impl<N, R: Dim, C: Dim, S> $Trait<N> for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim, S> $Trait<N> for Matrix<N, R, C, S>
where N: Scalar + $bound, where N: Scalar + $bound,
S: Storage<N, R, C> { S: Storage<N, R, C>,
type Output = OwnedMatrix<N, R, C, S::Alloc>; DefaultAllocator: Allocator<N, R, C> {
type Output = MatrixMN<N, R, C>;
#[inline] #[inline]
fn $method(self, rhs: N) -> Self::Output { 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<N> for &'a Matrix<N, R, C, S> impl<'a, N, R: Dim, C: Dim, S> $Trait<N> for &'a Matrix<N, R, C, S>
where N: Scalar + $bound, where N: Scalar + $bound,
S: Storage<N, R, C> { S: Storage<N, R, C>,
type Output = OwnedMatrix<N, R, C, S::Alloc>; DefaultAllocator: Allocator<N, R, C> {
type Output = MatrixMN<N, R, C>;
#[inline] #[inline]
fn $method(self, rhs: N) -> Self::Output { fn $method(self, rhs: N) -> Self::Output {
@ -302,9 +427,11 @@ macro_rules! componentwise_scalarop_impl(
where N: Scalar + $bound, where N: Scalar + $bound,
S: StorageMut<N, R, C> { S: StorageMut<N, R, C> {
#[inline] #[inline]
fn $method_assign(&mut self, right: N) { fn $method_assign(&mut self, rhs: N) {
for left in self.iter_mut() { for j in 0 .. self.ncols() {
left.$method_assign(right) 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( macro_rules! left_scalar_mul_impl(
($($T: ty),* $(,)*) => {$( ($($T: ty),* $(,)*) => {$(
impl<R: Dim, C: Dim, S> Mul<Matrix<$T, R, C, S>> for $T impl<R: Dim, C: Dim, S: Storage<$T, R, C>> Mul<Matrix<$T, R, C, S>> for $T
where S: Storage<$T, R, C> { where DefaultAllocator: Allocator<$T, R, C> {
type Output = OwnedMatrix<$T, R, C, S::Alloc>; type Output = MatrixMN<$T, R, C>;
#[inline] #[inline]
fn mul(self, right: Matrix<$T, R, C, S>) -> Self::Output { fn mul(self, rhs: Matrix<$T, R, C, S>) -> Self::Output {
let mut res = right.into_owned(); let mut res = rhs.into_owned();
// XXX: optimize our iterator! // XXX: optimize our iterator!
// //
// Using our own iterator prevents loop unrolling, wich breaks some optimization // Using our own iterator prevents loop unrolling, wich breaks some optimization
// (like SIMD). On the other hand, using the slice iterator is 4x faster. // (like SIMD). On the other hand, using the slice iterator is 4x faster.
// for right in res.iter_mut() { // for rhs in res.iter_mut() {
for right in res.as_mut_slice().iter_mut() { for rhs in res.as_mut_slice().iter_mut() {
*right = self * *right *rhs = self * *rhs
} }
res res
} }
} }
impl<'b, R: Dim, C: Dim, S> Mul<&'b Matrix<$T, R, C, S>> for $T impl<'b, R: Dim, C: Dim, S: Storage<$T, R, C>> Mul<&'b Matrix<$T, R, C, S>> for $T
where S: Storage<$T, R, C> { where DefaultAllocator: Allocator<$T, R, C> {
type Output = OwnedMatrix<$T, R, C, S::Alloc>; type Output = MatrixMN<$T, R, C>;
#[inline] #[inline]
fn mul(self, right: &'b Matrix<$T, R, C, S>) -> Self::Output { fn mul(self, rhs: &'b Matrix<$T, R, C, S>) -> Self::Output {
self * right.clone_owned() self * rhs.clone_owned()
} }
} }
)*} )*}
@ -361,84 +488,66 @@ left_scalar_mul_impl!(
// Matrix × Matrix // Matrix × Matrix
impl<'a, 'b, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix<N, R2, C2, SB>> impl<'a, 'b, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix<N, R2, C2, SB>>
for &'a Matrix<N, R1, C1, SA> for &'a Matrix<N, R1, C1, SA>
where N: Scalar + Zero + ClosedAdd + ClosedMul, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<N, R2, C2>,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SA::Alloc: Allocator<N, R1, C2>, SB: Storage<N, R2, C2>,
ShapeConstraint: AreMultipliable<R1, C1, R2, C2> { DefaultAllocator: Allocator<N, R1, C2>,
type Output = MatrixMul<N, R1, C1, C2, SA>; ShapeConstraint: AreMultipliable<R1, C1, R2, C2> {
type Output = MatrixMN<N, R1, C2>;
#[inline] #[inline]
fn mul(self, right: &'b Matrix<N, R2, C2, SB>) -> Self::Output { fn mul(self, rhs: &'b Matrix<N, R2, C2, SB>) -> Self::Output {
let (nrows1, ncols1) = self.shape(); let mut res = unsafe {
let (nrows2, ncols2) = right.shape(); Matrix::new_uninitialized_generic(self.data.shape().0, rhs.data.shape().1)
assert!(ncols1 == nrows2, "Matrix multiplication dimensions mismatch.");
let mut res: MatrixMul<N, R1, C1, C2, SA> = unsafe {
Matrix::new_uninitialized_generic(self.data.shape().0, right.data.shape().1)
}; };
for i in 0 .. nrows1 { self.mul_to(rhs, &mut res);
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;
}
}
}
res res
} }
} }
impl<'a, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<Matrix<N, R2, C2, SB>> impl<'a, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<Matrix<N, R2, C2, SB>>
for &'a Matrix<N, R1, C1, SA> for &'a Matrix<N, R1, C1, SA>
where N: Scalar + Zero + ClosedAdd + ClosedMul, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SA::Alloc: Allocator<N, R1, C2>, DefaultAllocator: Allocator<N, R1, C2>,
ShapeConstraint: AreMultipliable<R1, C1, R2, C2> { ShapeConstraint: AreMultipliable<R1, C1, R2, C2> {
type Output = MatrixMul<N, R1, C1, C2, SA>; type Output = MatrixMN<N, R1, C2>;
#[inline] #[inline]
fn mul(self, right: Matrix<N, R2, C2, SB>) -> Self::Output { fn mul(self, rhs: Matrix<N, R2, C2, SB>) -> Self::Output {
self * &right self * &rhs
} }
} }
impl<'b, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix<N, R2, C2, SB>> impl<'b, N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix<N, R2, C2, SB>>
for Matrix<N, R1, C1, SA> for Matrix<N, R1, C1, SA>
where N: Scalar + Zero + ClosedAdd + ClosedMul, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SA::Alloc: Allocator<N, R1, C2>, DefaultAllocator: Allocator<N, R1, C2>,
ShapeConstraint: AreMultipliable<R1, C1, R2, C2> { ShapeConstraint: AreMultipliable<R1, C1, R2, C2> {
type Output = MatrixMul<N, R1, C1, C2, SA>; type Output = MatrixMN<N, R1, C2>;
#[inline] #[inline]
fn mul(self, right: &'b Matrix<N, R2, C2, SB>) -> Self::Output { fn mul(self, rhs: &'b Matrix<N, R2, C2, SB>) -> Self::Output {
&self * right &self * rhs
} }
} }
impl<N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<Matrix<N, R2, C2, SB>> impl<N, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<Matrix<N, R2, C2, SB>>
for Matrix<N, R1, C1, SA> for Matrix<N, R1, C1, SA>
where N: Scalar + Zero + ClosedAdd + ClosedMul, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA: Storage<N, R1, C1>, SA: Storage<N, R1, C1>,
SA::Alloc: Allocator<N, R1, C2>, DefaultAllocator: Allocator<N, R1, C2>,
ShapeConstraint: AreMultipliable<R1, C1, R2, C2> { ShapeConstraint: AreMultipliable<R1, C1, R2, C2> {
type Output = MatrixMul<N, R1, C1, C2, SA>; type Output = MatrixMN<N, R1, C2>;
#[inline] #[inline]
fn mul(self, right: Matrix<N, R2, C2, SB>) -> Self::Output { fn mul(self, rhs: Matrix<N, R2, C2, SB>) -> Self::Output {
&self * &right &self * &rhs
} }
} }
@ -447,84 +556,106 @@ for Matrix<N, R1, C1, SA>
// we can't use `a *= b` when C2 is not equal to C1. // we can't use `a *= b` when C2 is not equal to C1.
impl<N, R1, C1, R2, SA, SB> MulAssign<Matrix<N, R2, C1, SB>> for Matrix<N, R1, C1, SA> impl<N, R1, C1, R2, SA, SB> MulAssign<Matrix<N, R2, C1, SB>> for Matrix<N, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, where R1: Dim, C1: Dim, R2: Dim,
N: Scalar + Zero + ClosedAdd + ClosedMul, N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<N, R2, C1>, SB: Storage<N, R2, C1>,
SA: OwnedStorage<N, R1, C1>, SA: ContiguousStorageMut<N, R1, C1> + Clone,
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>, ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
SA::Alloc: OwnedAllocator<N, R1, C1, SA> { DefaultAllocator: Allocator<N, R1, C1, Buffer = SA> {
#[inline] #[inline]
fn mul_assign(&mut self, right: Matrix<N, R2, C1, SB>) { fn mul_assign(&mut self, rhs: Matrix<N, R2, C1, SB>) {
*self = &*self * right *self = &*self * rhs
} }
} }
impl<'b, N, R1, C1, R2, SA, SB> MulAssign<&'b Matrix<N, R2, C1, SB>> for Matrix<N, R1, C1, SA> impl<'b, N, R1, C1, R2, SA, SB> MulAssign<&'b Matrix<N, R2, C1, SB>> for Matrix<N, R1, C1, SA>
where R1: Dim, C1: Dim, R2: Dim, where R1: Dim, C1: Dim, R2: Dim,
N: Scalar + Zero + ClosedAdd + ClosedMul, N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<N, R2, C1>, SB: Storage<N, R2, C1>,
SA: OwnedStorage<N, R1, C1>, SA: ContiguousStorageMut<N, R1, C1> + Clone,
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>, ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
// FIXME: this is too restrictive. See comments for the non-ref version. // FIXME: this is too restrictive. See comments for the non-ref version.
SA::Alloc: OwnedAllocator<N, R1, C1, SA> { DefaultAllocator: Allocator<N, R1, C1, Buffer = SA> {
#[inline] #[inline]
fn mul_assign(&mut self, right: &'b Matrix<N, R2, C1, SB>) { fn mul_assign(&mut self, rhs: &'b Matrix<N, R2, C1, SB>) {
*self = &*self * right *self = &*self * rhs
} }
} }
// Transpose-multiplication. // Transpose-multiplication.
impl<N, R1: Dim, C1: Dim, SA> Matrix<N, R1, C1, SA> impl<N, R1: Dim, C1: Dim, SA> Matrix<N, R1, C1, SA>
where N: Scalar, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
SA: Storage<N, R1, C1> { SA: Storage<N, R1, C1> {
/// Equivalent to `self.transpose() * right`. /// Equivalent to `self.transpose() * rhs`.
#[inline] #[inline]
pub fn tr_mul<R2: Dim, C2: Dim, SB>(&self, right: &Matrix<N, R2, C2, SB>) -> MatrixTrMul<N, R1, C1, C2, SA> pub fn tr_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixMN<N, C1, C2>
where N: Zero + ClosedAdd + ClosedMul, where SB: Storage<N, R2, C2>,
SB: Storage<N, R2, C2>, DefaultAllocator: Allocator<N, C1, C2>,
SA::Alloc: Allocator<N, C1, C2>, ShapeConstraint: SameNumberOfRows<R1, R2> {
ShapeConstraint: AreMultipliable<C1, R1, R2, C2> {
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<R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
rhs: &Matrix<N, R2, C2, SB>,
out: &mut Matrix<N, R3, C3, SC>)
where SB: Storage<N, R2, C2>,
SC: StorageMut<N, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> +
DimEq<C1, R3> +
DimEq<C2, C3> {
let (nrows1, ncols1) = self.shape(); 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."); assert!(nrows1 == nrows2, "Matrix multiplication dimensions mismatch.");
assert!(nrows3 == ncols1 && ncols3 == ncols2, "Matrix multiplication output dimensions mismatch.");
let mut res: MatrixTrMul<N, R1, C1, C2, SA> = unsafe {
Matrix::new_uninitialized_generic(self.data.shape().1, right.data.shape().1)
};
for i in 0 .. ncols1 { for i in 0 .. ncols1 {
for j in 0 .. ncols2 { for j in 0 .. ncols2 {
let mut acc = N::zero(); let dot = self.column(i).dot(&rhs.column(j));
unsafe { *out.get_unchecked_mut(i, j) = dot };
unsafe {
for k in 0 .. nrows1 {
acc += *self.get_unchecked(k, i) * *right.get_unchecked(k, j);
}
*res.get_unchecked_mut(i, j) = acc;
}
} }
} }
}
res /// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations.
#[inline]
pub fn mul_to<R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
rhs: &Matrix<N, R2, C2, SB>,
out: &mut Matrix<N, R3, C3, SC>)
where SB: Storage<N, R2, C2>,
SC: StorageMut<N, R3, C3>,
ShapeConstraint: SameNumberOfRows<R3, R1> +
SameNumberOfColumns<C3, C2> +
AreMultipliable<R1, C1, R2, C2> {
out.gemm(N::one(), self, rhs, N::zero());
} }
/// The kronecker product of two matrices (aka. tensor product of the corresponding linear /// The kronecker product of two matrices (aka. tensor product of the corresponding linear
/// maps). /// maps).
pub fn kronecker<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) pub fn kronecker<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>)
-> OwnedMatrix<N, DimProd<R1, R2>, DimProd<C1, C2>, SA::Alloc> -> MatrixMN<N, DimProd<R1, R2>, DimProd<C1, C2>>
where N: ClosedMul, where N: ClosedMul,
R1: DimMul<R2>, R1: DimMul<R2>,
C1: DimMul<C2>, C1: DimMul<C2>,
SB: Storage<N, R2, C2>, SB: Storage<N, R2, C2>,
SA::Alloc: Allocator<N, DimProd<R1, R2>, DimProd<C1, C2>> { DefaultAllocator: Allocator<N, DimProd<R1, R2>, DimProd<C1, C2>> {
let (nrows1, ncols1) = self.data.shape(); let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape(); let (nrows2, ncols2) = rhs.data.shape();
let mut res: OwnedMatrix<_, _, _, SA::Alloc> = let mut res = unsafe { Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2)) };
unsafe { Matrix::new_uninitialized_generic(nrows1.mul(nrows2), ncols1.mul(ncols2)) };
{ {
let mut data_res = res.data.ptr_mut(); let mut data_res = res.data.ptr_mut();
@ -549,22 +680,76 @@ impl<N, R1: Dim, C1: Dim, SA> Matrix<N, R1, C1, SA>
} }
} }
impl<N, D: DimName, S> iter::Product for SquareMatrix<N, D, S> impl<N: Scalar + ClosedAdd, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Adds a scalar to `self`.
#[inline]
pub fn add_scalar(&self, rhs: N) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
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<N, R, C> {
for e in self.iter_mut() {
*e += rhs
}
}
}
impl<N, D: DimName> iter::Product for MatrixN<N, D>
where N: Scalar + Zero + One + ClosedMul + ClosedAdd, where N: Scalar + Zero + One + ClosedMul + ClosedAdd,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D>
S::Alloc: OwnedAllocator<N, D, D, S>
{ {
fn product<I: Iterator<Item = SquareMatrix<N, D, S>>>(iter: I) -> SquareMatrix<N, D, S> { fn product<I: Iterator<Item = MatrixN<N, D>>>(iter: I) -> MatrixN<N, D> {
iter.fold(Matrix::one(), |acc, x| acc * x) iter.fold(Matrix::one(), |acc, x| acc * x)
} }
} }
impl<'a, N, D: DimName, S> iter::Product<&'a SquareMatrix<N, D, S>> for SquareMatrix<N, D, S> impl<'a, N, D: DimName> iter::Product<&'a MatrixN<N, D>> for MatrixN<N, D>
where N: Scalar + Zero + One + ClosedMul + ClosedAdd, where N: Scalar + Zero + One + ClosedMul + ClosedAdd,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D>
S::Alloc: OwnedAllocator<N, D, D, S>
{ {
fn product<I: Iterator<Item = &'a SquareMatrix<N, D, S>>>(iter: I) -> SquareMatrix<N, D, S> { fn product<I: Iterator<Item = &'a MatrixN<N, D>>>(iter: I) -> MatrixN<N, D> {
iter.fold(Matrix::one(), |acc, x| acc * x) iter.fold(Matrix::one(), |acc, x| acc * x)
} }
} }
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// 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
}
}

View File

@ -2,33 +2,38 @@
use num::{Zero, One}; use num::{Zero, One};
use approx::ApproxEq; use approx::ApproxEq;
use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Field}; use alga::general::{ClosedAdd, ClosedMul, Real};
use core::{Scalar, Matrix, SquareMatrix}; use core::{DefaultAllocator, Scalar, Matrix, SquareMatrix};
use core::dimension::Dim; use core::dimension::{Dim, DimMin};
use core::storage::Storage; use core::storage::Storage;
use core::allocator::Allocator;
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Indicates if this is a square matrix. /// Indicates if this is a square matrix.
#[inline] #[inline]
pub fn is_square(&self) -> bool { pub fn is_empty(&self) -> bool {
let shape = self.shape(); let (nrows, ncols) = self.shape();
shape.0 == shape.1 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<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
// FIXME: ApproxEq prevents us from using those methods on integer matrices… // 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`. /// 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)` /// 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. /// for i from `0` to `min(R, C)`) are equal one; and that all other elements are zero.
#[inline] #[inline]
pub fn is_identity(&self, eps: N::Epsilon) -> bool 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 (nrows, ncols) = self.shape();
let d; let d;
@ -75,32 +80,35 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
true true
} }
}
/// Checks that `Mᵀ × M = Id`.
impl<N: Scalar + ApproxEq, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S>
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`.
/// ///
/// In this definition `Id` is approximately equal to the identity matrix with a relative error /// In this definition `Id` is approximately equal to the identity matrix with a relative error
/// equal to `eps`. /// equal to `eps`.
#[inline] #[inline]
pub fn is_orthogonal(&self, eps: N::Epsilon) -> bool { pub fn is_orthogonal(&self, eps: N::Epsilon) -> bool
self.is_square() && (self.tr_mul(self)).is_identity(eps) where N: Zero + One + ClosedAdd + ClosedMul + ApproxEq,
S: Storage<N, R, C>,
N::Epsilon: Copy,
DefaultAllocator: Allocator<N, C, C> {
(self.tr_mul(self)).is_identity(eps)
} }
}
impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S>
where DefaultAllocator: Allocator<N, D, D> {
/// Checks that this matrix is orthogonal and has a determinant equal to 1. /// Checks that this matrix is orthogonal and has a determinant equal to 1.
#[inline] #[inline]
pub fn is_special_orthogonal(&self, eps: N::Epsilon) -> bool pub fn is_special_orthogonal(&self, eps: N) -> bool
where N: ClosedSub + PartialOrd { where D: DimMin<D, Output = D>,
self.is_orthogonal(eps) && self.determinant() > N::zero() DefaultAllocator: Allocator<(usize, usize), D> {
self.is_square() && self.is_orthogonal(eps) && self.determinant() > N::zero()
} }
/// Returns `true` if this matrix is invertible. /// Returns `true` if this matrix is invertible.
#[inline] #[inline]
pub fn is_invertible(&self) -> bool pub fn is_invertible(&self) -> bool {
where N: Field {
// FIXME: improve this? // FIXME: improve this?
self.clone_owned().try_inverse().is_some() self.clone_owned().try_inverse().is_some()
} }

View File

@ -1,3 +1,4 @@
use std::any::TypeId;
use std::fmt::Debug; use std::fmt::Debug;
use std::any::Any; use std::any::Any;
@ -5,5 +6,9 @@ use std::any::Any;
/// ///
/// This does not make any assumption on the algebraic properties of `Self`. /// This does not make any assumption on the algebraic properties of `Self`.
pub trait Scalar: Copy + PartialEq + Debug + Any { pub trait Scalar: Copy + PartialEq + Debug + Any {
#[inline]
fn is<T: Scalar>() -> bool {
TypeId::of::<Self>() == TypeId::of::<T>()
}
} }
impl<T: Copy + PartialEq + Debug + Any> Scalar for T { } impl<T: Copy + PartialEq + Debug + Any> Scalar for T { }

View File

@ -1,39 +1,28 @@
//! Abstract definition of a matrix data storage. //! Abstract definition of a matrix data storage.
use std::fmt::Debug;
use std::mem; use std::mem;
use std::any::Any;
use core::Scalar; use core::Scalar;
use dimension::Dim; use core::default_allocator::DefaultAllocator;
use allocator::{Allocator, SameShapeR, SameShapeC}; 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)`. /// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`.
pub type SumStorage<N, R1, C1, R2, C2, SA> = pub type SameShapeStorage<N, R1, C1, R2, C2> = <DefaultAllocator as Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>>::Buffer;
<<SA as Storage<N, R1, C1>>::Alloc as Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>>::Buffer;
/* // FIXME: better name than Owned ?
* 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<N, R1, C1, C2, SA> =
<<SA as Storage<N, R1, C1>>::Alloc as Allocator<N, R1, C2>>::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<N, R1, C1, C2, SA> =
<<SA as Storage<N, R1, C1>>::Alloc as Allocator<N, C1, C2>>::Buffer;
/*
* Alias for allocation result.
*/
/// The owned data storage that can be allocated from `S`. /// The owned data storage that can be allocated from `S`.
pub type Owned<N, R, C, A> = pub type Owned<N, R, C = U1> = <DefaultAllocator as Allocator<N, R, C>>::Buffer;
<A as Allocator<N, R, C>>::Buffer;
/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`.
pub type RStride<N, R, C = U1> = <<DefaultAllocator as Allocator<N, R, C>>::Buffer as Storage<N, R, C>>::RStride;
/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`.
pub type CStride<N, R, C = U1> = <<DefaultAllocator as Allocator<N, R, C>>::Buffer as Storage<N, R, C>>::CStride;
/// The trait shared by all matrix data storage. /// The trait shared by all matrix data storage.
@ -45,22 +34,13 @@ pub type Owned<N, R, C, A> =
/// should **not** allow the user to modify the size of the underlying buffer with safe methods /// 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 /// (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. /// vector's size so that it no longer contains enough elements: this will lead to UB.
pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim>: Sized { pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
/// The static stride of this storage's rows. /// The static stride of this storage's rows.
type RStride: Dim; type RStride: Dim;
/// The static stride of this storage's columns. /// The static stride of this storage's columns.
type CStride: Dim; type CStride: Dim;
/// The allocator for this family of storage.
type Alloc: Allocator<N, R, C>;
/// Builds a matrix data storage that does not contain any reference.
fn into_owned(self) -> Owned<N, R, C, Self::Alloc>;
/// Clones this data storage into one that does not contain any reference.
fn clone_owned(&self) -> Owned<N, R, C, Self::Alloc>;
/// The matrix data pointer. /// The matrix data pointer.
fn ptr(&self) -> *const N; fn ptr(&self) -> *const N;
@ -110,6 +90,24 @@ pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim>: Sized {
unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N { unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N {
self.get_unchecked_linear(self.linear_index(irow, icol)) 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<N, R, C>
where DefaultAllocator: Allocator<N, R, C>;
/// Clones this data storage into one that does not contain any reference.
fn clone_owned(&self) -> Owned<N, R, C>
where DefaultAllocator: Allocator<N, R, C>;
} }
@ -118,7 +116,7 @@ pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim>: Sized {
/// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable /// 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 /// 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). /// contains only an internal reference to them).
pub unsafe trait StorageMut<N: Scalar, R: Dim, C: Dim>: Storage<N, R, C> { pub unsafe trait StorageMut<N: Scalar, R: Dim, C: Dim = U1>: Storage<N, R, C> {
/// The matrix mutable data pointer. /// The matrix mutable data pointer.
fn ptr_mut(&mut self) -> *mut N; fn ptr_mut(&mut self) -> *mut N;
@ -163,22 +161,24 @@ pub unsafe trait StorageMut<N: Scalar, R: Dim, C: Dim>: Storage<N, R, C> {
self.swap_unchecked_linear(lid1, lid2) self.swap_unchecked_linear(lid1, lid2)
} }
}
/// A matrix storage that does not contain any reference and that is stored contiguously in memory. /// Retrieves the mutable data buffer as a contiguous slice.
/// ///
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols[`, the value /// Matrix components may not be contiguous, depending on its strides.
/// `.get_unchecked_linear` succeeds. This trait is unsafe because failing to comply to this may
/// cause Undefined Behaviors.
pub unsafe trait OwnedStorage<N: Scalar, R: Dim, C: Dim>: StorageMut<N, R, C> + Clone + Any
where Self::Alloc: Allocator<N, R, C, Buffer = Self> {
// 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.
#[inline] #[inline]
fn as_mut_slice(&mut self) -> &mut [N]; 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<N: Scalar, R: Dim, C: Dim = U1>: Storage<N, R, C> { }
/// 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<N: Scalar, R: Dim, C: Dim = U1>: ContiguousStorage<N, R, C> + StorageMut<N, R, C> { }

8
src/debug/mod.rs Normal file
View File

@ -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::*;

View File

@ -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<N: Real, D: Dim = Dynamic>
where DefaultAllocator: Allocator<N, D, D> {
m: MatrixN<N, D>
}
impl<N: Real, D: Dim> RandomOrthogonal<N, D>
where DefaultAllocator: Allocator<N, D, D> {
/// Retrieve the generated matrix.
pub fn unwrap(self) -> MatrixN<N, D> {
self.m
}
/// Creates a new random orthogonal matrix from its dimension and a random reals generators.
pub fn new<Rand: FnMut() -> 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<N> = UnitComplex::from_complex(c);
rot.rotate(&mut res.fixed_rows_mut::<U2>(i));
}
RandomOrthogonal { m: res }
}
}
#[cfg(feature = "arbitrary")]
impl<N: Real + Arbitrary + Send, D: Dim> Arbitrary for RandomOrthogonal<N, D>
where DefaultAllocator: Allocator<N, D, D>,
Owned<N, D, D>: Clone + Send {
fn arbitrary<G: Gen>(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))
}
}

54
src/debug/random_sdp.rs Normal file
View File

@ -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<N: Real, D: Dim = Dynamic>
where DefaultAllocator: Allocator<N, D, D> {
m: MatrixN<N, D>
}
impl<N: Real, D: Dim> RandomSDP<N, D>
where DefaultAllocator: Allocator<N, D, D> {
/// Retrieve the generated matrix.
pub fn unwrap(self) -> MatrixN<N, D> {
self.m
}
/// Creates a new well conditioned symmetric definite-positive matrix from its dimension and a
/// random reals generators.
pub fn new<Rand: FnMut() -> 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<N: Real + Arbitrary + Send, D: Dim> Arbitrary for RandomSDP<N, D>
where DefaultAllocator: Allocator<N, D, D>,
Owned<N, D, D>: Clone + Send {
fn arbitrary<G: Gen>(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))
}
}

View File

@ -1,30 +1,40 @@
use std::fmt; use std::fmt;
use std::hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use approx::ApproxEq; use approx::ApproxEq;
#[cfg(feature = "serde-serialize")]
use serde;
use alga::general::{Real, SubsetOf}; use alga::general::{Real, SubsetOf};
use alga::linear::Rotation; use alga::linear::Rotation;
use core::{Scalar, OwnedSquareMatrix}; use core::{DefaultAllocator, MatrixN};
use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1};
use core::storage::{Storage, OwnedStorage}; use core::storage::Owned;
use core::allocator::{Allocator, OwnedAllocator}; use core::allocator::Allocator;
use geometry::{TranslationBase, PointBase}; use geometry::{Translation, Point};
/// An isometry that uses a data storage deduced from the allocator `A`.
pub type OwnedIsometryBase<N, D, A, R> =
IsometryBase<N, D, <A as Allocator<N, D, U1>>::Buffer, R>;
/// A direct isometry, i.e., a rotation followed by a translation. /// A direct isometry, i.e., a rotation followed by a translation.
#[repr(C)] #[repr(C)]
#[derive(Hash, Debug, Clone, Copy)] #[derive(Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct IsometryBase<N: Scalar, D: DimName, S, R> { #[cfg_attr(feature = "serde-serialize",
serde(bound(
serialize = "R: serde::Serialize,
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: serde::Serialize")))]
#[cfg_attr(feature = "serde-serialize",
serde(bound(
deserialize = "R: serde::Deserialize<'de>,
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: serde::Deserialize<'de>")))]
pub struct Isometry<N: Real, D: DimName, R>
where DefaultAllocator: Allocator<N, D> {
/// The pure rotational part of this isometry. /// The pure rotational part of this isometry.
pub rotation: R, pub rotation: R,
/// The pure translational part of this isometry. /// The pure translational part of this isometry.
pub translation: TranslationBase<N, D, S>, pub translation: Translation<N, D>,
// One dummy private field just to prevent explicit construction. // One dummy private field just to prevent explicit construction.
@ -32,15 +42,34 @@ pub struct IsometryBase<N: Scalar, D: DimName, S, R> {
_noconstruct: PhantomData<N> _noconstruct: PhantomData<N>
} }
impl<N, D: DimName, S, R> IsometryBase<N, D, S, R> impl<N: Real + hash::Hash, D: DimName + hash::Hash, R: hash::Hash> hash::Hash for Isometry<N, D, R>
where N: Real, where DefaultAllocator: Allocator<N, D>,
S: OwnedStorage<N, D, U1>, Owned<N, D>: hash::Hash {
R: Rotation<PointBase<N, D, S>>, fn hash<H: hash::Hasher>(&self, state: &mut H) {
S::Alloc: OwnedAllocator<N, D, U1, S> { self.translation.hash(state);
self.rotation.hash(state);
}
}
impl<N: Real, D: DimName + Copy, R: Rotation<Point<N, D>> + Copy> Copy for Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy {
}
impl<N: Real, D: DimName, R: Rotation<Point<N, D>> + Clone> Clone for Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D> {
#[inline]
fn clone(&self) -> Self {
Isometry::from_parts(self.translation.clone(), self.rotation.clone())
}
}
impl<N: Real, D: DimName, R: Rotation<Point<N, D>>> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D> {
/// Creates a new isometry from its rotational and translational parts. /// Creates a new isometry from its rotational and translational parts.
#[inline] #[inline]
pub fn from_parts(translation: TranslationBase<N, D, S>, rotation: R) -> IsometryBase<N, D, S, R> { pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> {
IsometryBase { Isometry {
rotation: rotation, rotation: rotation,
translation: translation, translation: translation,
_noconstruct: PhantomData _noconstruct: PhantomData
@ -49,7 +78,7 @@ impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
/// Inverts `self`. /// Inverts `self`.
#[inline] #[inline]
pub fn inverse(&self) -> IsometryBase<N, D, S, R> { pub fn inverse(&self) -> Isometry<N, D, R> {
let mut res = self.clone(); let mut res = self.clone();
res.inverse_mut(); res.inverse_mut();
res res
@ -65,7 +94,7 @@ impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
/// Appends to `self` the given translation in-place. /// Appends to `self` the given translation in-place.
#[inline] #[inline]
pub fn append_translation_mut(&mut self, t: &TranslationBase<N, D, S>) { pub fn append_translation_mut(&mut self, t: &Translation<N, D>) {
self.translation.vector += &t.vector self.translation.vector += &t.vector
} }
@ -79,7 +108,7 @@ impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
/// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that
/// lets `p` invariant. /// lets `p` invariant.
#[inline] #[inline]
pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &PointBase<N, D, S>) { pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point<N, D>) {
self.translation.vector -= &p.coords; self.translation.vector -= &p.coords;
self.append_rotation_mut(r); self.append_rotation_mut(r);
self.translation.vector += &p.coords; self.translation.vector += &p.coords;
@ -89,7 +118,7 @@ impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
/// `self.translation`. /// `self.translation`.
#[inline] #[inline]
pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { 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, &center) self.append_rotation_wrt_point_mut(r, &center)
} }
} }
@ -98,16 +127,15 @@ impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
// and makes it hard to use it, e.g., for Transform × Isometry implementation. // 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 // 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). // explicit struct construction is prevented by the dummy ZST field).
impl<N, D: DimName, S, R> IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> Isometry<N, D, R>
where N: Scalar, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
/// Converts this isometry into its equivalent homogeneous transformation matrix. /// Converts this isometry into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where D: DimNameAdd<U1>, where D: DimNameAdd<U1>,
R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc>>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>>>,
S::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
let mut res: OwnedSquareMatrix<N, _, S::Alloc> = ::convert_ref(&self.rotation); let mut res: MatrixN<N, _> = ::convert_ref(&self.rotation);
res.fixed_slice_mut::<D, U1>(0, D::dim()).copy_from(&self.translation.vector); res.fixed_slice_mut::<D, U1>(0, D::dim()).copy_from(&self.translation.vector);
res res
@ -115,30 +143,24 @@ impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
} }
impl<N, D: DimName, S, R> Eq for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> Eq for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>> + Eq,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>> + Eq,
S::Alloc: OwnedAllocator<N, D, U1, S> {
} }
impl<N, D: DimName, S, R> PartialEq for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> PartialEq for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>> + PartialEq,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>> + PartialEq,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn eq(&self, right: &IsometryBase<N, D, S, R>) -> bool { fn eq(&self, right: &Isometry<N, D, R>) -> bool {
self.translation == right.translation && self.translation == right.translation &&
self.rotation == right.rotation self.rotation == right.rotation
} }
} }
impl<N, D: DimName, S, R> ApproxEq for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> ApproxEq for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>> + ApproxEq<Epsilon = N::Epsilon>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D>,
R: Rotation<PointBase<N, D, S>> + ApproxEq<Epsilon = N::Epsilon>,
S::Alloc: OwnedAllocator<N, D, U1, S>,
N::Epsilon: Copy { N::Epsilon: Copy {
type Epsilon = N::Epsilon; type Epsilon = N::Epsilon;
@ -175,32 +197,16 @@ impl<N, D: DimName, S, R> ApproxEq for IsometryBase<N, D, S, R>
* Display * Display
* *
*/ */
impl<N, D: DimName, S, R> fmt::Display for IsometryBase<N, D, S, R> impl<N: Real + fmt::Display, D: DimName, R> fmt::Display for Isometry<N, D, R>
where N: Real + fmt::Display, where R: fmt::Display,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> +
R: fmt::Display, Allocator<usize, D> {
S::Alloc: OwnedAllocator<N, D, U1, S> + Allocator<usize, D, U1> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let precision = f.precision().unwrap_or(3); 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.translation));
try!(write!(f, "{:.*}", precision, self.rotation)); try!(write!(f, "{:.*}", precision, self.rotation));
writeln!(f, "}}") writeln!(f, "}}")
} }
} }
// /*
// *
// * Absolute
// *
// */
// impl<N: Absolute> Absolute for $t<N> {
// type AbsoluteValue = $submatrix<N::AbsoluteValue>;
//
// #[inline]
// fn abs(m: &$t<N>) -> $submatrix<N::AbsoluteValue> {
// Absolute::abs(&m.submatrix)
// }
// }

View File

@ -1,14 +1,14 @@
use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id}; AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id};
use alga::linear::{Transformation, Similarity, AffineTransformation, DirectIsometry, Isometry, use alga::linear::{Transformation, Similarity, AffineTransformation, DirectIsometry,
Rotation, ProjectiveTransformation}; Rotation, ProjectiveTransformation};
use alga::linear::Isometry as AlgaIsometry;
use core::ColumnVector; use core::{DefaultAllocator, VectorN};
use core::dimension::{DimName, U1}; use core::dimension::DimName;
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::{IsometryBase, TranslationBase, PointBase}; use geometry::{Isometry, Translation, Point};
/* /*
@ -16,22 +16,18 @@ use geometry::{IsometryBase, TranslationBase, PointBase};
* Algebraic structures. * Algebraic structures.
* *
*/ */
impl<N, D: DimName, S, R> Identity<Multiplicative> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> Identity<Multiplicative> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, D: DimName, S, R> Inverse<Multiplicative> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
self.inverse() self.inverse()
@ -43,11 +39,9 @@ impl<N, D: DimName, S, R> Inverse<Multiplicative> for IsometryBase<N, D, S, R>
} }
} }
impl<N, D: DimName, S, R> AbstractMagma<Multiplicative> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> AbstractMagma<Multiplicative> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
@ -56,11 +50,9 @@ impl<N, D: DimName, S, R> AbstractMagma<Multiplicative> for IsometryBase<N, D, S
macro_rules! impl_multiplicative_structures( macro_rules! impl_multiplicative_structures(
($($marker: ident<$operator: ident>),* $(,)*) => {$( ($($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, D: DimName, S, R> $marker<$operator> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> $marker<$operator> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> { }
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> { }
)*} )*}
); );
@ -77,49 +69,43 @@ impl_multiplicative_structures!(
* Transformation groups. * Transformation groups.
* *
*/ */
impl<N, D: DimName, S, R> Transformation<PointBase<N, D, S>> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> Transformation<Point<N, D>> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, D, S>) -> PointBase<N, D, S> { fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self * pt self * pt
} }
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, D, S>) -> ColumnVector<N, D, S> { fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self * v self * v
} }
} }
impl<N, D: DimName, S, R> ProjectiveTransformation<PointBase<N, D, S>> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> ProjectiveTransformation<Point<N, D>> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &PointBase<N, D, S>) -> PointBase<N, D, S> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self.rotation.inverse_transform_point(&(pt - &self.translation.vector)) self.rotation.inverse_transform_point(&(pt - &self.translation.vector))
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &ColumnVector<N, D, S>) -> ColumnVector<N, D, S> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self.rotation.inverse_transform_vector(v) self.rotation.inverse_transform_vector(v)
} }
} }
impl<N, D: DimName, S, R> AffineTransformation<PointBase<N, D, S>> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> AffineTransformation<Point<N, D>> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Rotation = R; type Rotation = R;
type NonUniformScaling = Id; type NonUniformScaling = Id;
type Translation = TranslationBase<N, D, S>; type Translation = Translation<N, D>;
#[inline] #[inline]
fn decompose(&self) -> (TranslationBase<N, D, S>, R, Id, R) { fn decompose(&self) -> (Translation<N, D>, R, Id, R) {
(self.translation.clone(), self.rotation.clone(), Id::new(), R::identity()) (self.translation.clone(), self.rotation.clone(), Id::new(), R::identity())
} }
@ -136,7 +122,7 @@ impl<N, D: DimName, S, R> AffineTransformation<PointBase<N, D, S>> for IsometryB
#[inline] #[inline]
fn append_rotation(&self, r: &Self::Rotation) -> Self { fn append_rotation(&self, r: &Self::Rotation) -> Self {
let shift = r.transform_vector(&self.translation.vector); 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] #[inline]
@ -155,22 +141,20 @@ impl<N, D: DimName, S, R> AffineTransformation<PointBase<N, D, S>> for IsometryB
} }
#[inline] #[inline]
fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &PointBase<N, D, S>) -> Option<Self> { fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &Point<N, D>) -> Option<Self> {
let mut res = self.clone(); let mut res = self.clone();
res.append_rotation_wrt_point_mut(r, p); res.append_rotation_wrt_point_mut(r, p);
Some(res) Some(res)
} }
} }
impl<N, D: DimName, S, R> Similarity<PointBase<N, D, S>> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> Similarity<Point<N, D>> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Scaling = Id; type Scaling = Id;
#[inline] #[inline]
fn translation(&self) -> TranslationBase<N, D, S> { fn translation(&self) -> Translation<N, D> {
self.translation.clone() self.translation.clone()
} }
@ -187,12 +171,10 @@ impl<N, D: DimName, S, R> Similarity<PointBase<N, D, S>> for IsometryBase<N, D,
macro_rules! marker_impl( macro_rules! marker_impl(
($($Trait: ident),*) => {$( ($($Trait: ident),*) => {$(
impl<N, D: DimName, S, R> $Trait<PointBase<N, D, S>> for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R> $Trait<Point<N, D>> for Isometry<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> { }
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> { }
)*} )*}
); );
marker_impl!(Isometry, DirectIsometry); marker_impl!(AlgaIsometry, DirectIsometry);

View File

@ -1,19 +1,16 @@
use core::MatrixArray; use core::dimension::{U2, U3};
use core::dimension::{U1, U2, U3};
use geometry::{Rotation, IsometryBase, UnitQuaternion, UnitComplex}; use geometry::{Isometry, Rotation2, Rotation3, UnitQuaternion, UnitComplex};
/// A D-dimensional isometry.
pub type Isometry<N, D> = IsometryBase<N, D, MatrixArray<N, D, U1>, Rotation<N, D>>;
/// A 2-dimensional isometry using a unit complex number for its rotational part. /// A 2-dimensional isometry using a unit complex number for its rotational part.
pub type Isometry2<N> = IsometryBase<N, U2, MatrixArray<N, U2, U1>, UnitComplex<N>>; pub type Isometry2<N> = Isometry<N, U2, UnitComplex<N>>;
/// A 3-dimensional isometry using a unit quaternion for its rotational part. /// A 3-dimensional isometry using a unit quaternion for its rotational part.
pub type Isometry3<N> = IsometryBase<N, U3, MatrixArray<N, U3, U1>, UnitQuaternion<N>>; pub type Isometry3<N> = Isometry<N, U3, UnitQuaternion<N>>;
/// A 2-dimensional isometry using a rotation matrix for its rotation part. /// A 2-dimensional isometry using a rotation matrix for its rotational part.
pub type IsometryMatrix2<N> = Isometry<N, U2>; pub type IsometryMatrix2<N> = Isometry<N, U2, Rotation2<N>>;
/// A 3-dimensional isometry using a rotation matrix for its rotation part. /// A 3-dimensional isometry using a rotation matrix for its rotational part.
pub type IsometryMatrix3<N> = Isometry<N, U3>; pub type IsometryMatrix3<N> = Isometry<N, U3, Rotation3<N>>;

View File

@ -1,5 +1,7 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
#[cfg(feature = "arbitrary")]
use core::storage::Owned;
use num::One; use num::One;
use rand::{Rng, Rand}; use rand::{Rng, Rand};
@ -7,31 +9,33 @@ use rand::{Rng, Rand};
use alga::general::Real; use alga::general::Real;
use alga::linear::Rotation as AlgaRotation; use alga::linear::Rotation as AlgaRotation;
use core::ColumnVector; use core::{DefaultAllocator, Vector2, Vector3};
use core::dimension::{DimName, U1, U2, U3, U4}; use core::dimension::{DimName, U2, U3};
use core::allocator::{OwnedAllocator, Allocator}; use core::allocator::Allocator;
use core::storage::OwnedStorage;
use geometry::{PointBase, TranslationBase, RotationBase, IsometryBase, UnitQuaternionBase, UnitComplex}; use geometry::{Point, Translation, Rotation, Isometry, UnitQuaternion, UnitComplex,
Point3, Rotation2, Rotation3};
impl<N, D: DimName, S, R> IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
R: AlgaRotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// Creates a new identity isometry. /// Creates a new identity isometry.
#[inline] #[inline]
pub fn identity() -> Self { 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<N, D>) -> Self {
let shift = r.transform_vector(&-&p.coords);
Self::from_parts(Translation::from_vector(shift + p.coords), r)
} }
} }
impl<N, D: DimName, S, R> One for IsometryBase<N, D, S, R> impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> One for Isometry<N, D, R>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
R: AlgaRotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// Creates a new identity isometry. /// Creates a new identity isometry.
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
@ -39,37 +43,21 @@ impl<N, D: DimName, S, R> One for IsometryBase<N, D, S, R>
} }
} }
impl<N, D: DimName, S, R> Rand for IsometryBase<N, D, S, R> impl<N: Real + Rand, D: DimName, R> Rand for Isometry<N, D, R>
where N: Real + Rand, where R: AlgaRotation<Point<N, D>> + Rand,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: AlgaRotation<PointBase<N, D, S>> + Rand,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn rand<G: Rng>(rng: &mut G) -> Self { fn rand<G: Rng>(rng: &mut G) -> Self {
Self::from_parts(rng.gen(), rng.gen()) Self::from_parts(rng.gen(), rng.gen())
} }
} }
impl<N, D: DimName, S, R> IsometryBase<N, D, S, R>
where N: Real,
S: OwnedStorage<N, D, U1>,
R: AlgaRotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// 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<N, D, S>) -> Self {
let shift = r.transform_vector(&-&p.coords);
Self::from_parts(TranslationBase::from_vector(shift + p.coords), r)
}
}
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<N, D: DimName, S, R> Arbitrary for IsometryBase<N, D, S, R> impl<N, D: DimName, R> Arbitrary for Isometry<N, D, R>
where N: Real + Arbitrary + Send, where N: Real + Arbitrary + Send,
S: OwnedStorage<N, D, U1> + Send, R: AlgaRotation<Point<N, D>> + Arbitrary + Send,
R: AlgaRotation<PointBase<N, D, S>> + Arbitrary + Send, Owned<N, D>: Send,
S::Alloc: OwnedAllocator<N, D, U1, S> { DefaultAllocator: Allocator<N, D> {
#[inline] #[inline]
fn arbitrary<G: Gen>(rng: &mut G) -> Self { fn arbitrary<G: Gen>(rng: &mut G) -> Self {
Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng)) Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
@ -83,45 +71,31 @@ impl<N, D: DimName, S, R> Arbitrary for IsometryBase<N, D, S, R>
*/ */
// 2D rotation. // 2D rotation.
impl<N, S, SR> IsometryBase<N, U2, S, RotationBase<N, U2, SR>> impl<N: Real> Isometry<N, U2, Rotation2<N>> {
where N: Real,
S: OwnedStorage<N, U2, U1, Alloc = SR::Alloc>,
SR: OwnedStorage<N, U2, U2>,
S::Alloc: OwnedAllocator<N, U2, U1, S>,
SR::Alloc: OwnedAllocator<N, U2, U2, SR> {
/// Creates a new isometry from a translation and a rotation angle. /// Creates a new isometry from a translation and a rotation angle.
#[inline] #[inline]
pub fn new(translation: ColumnVector<N, U2, S>, angle: N) -> Self { pub fn new(translation: Vector2<N>, angle: N) -> Self {
Self::from_parts(TranslationBase::from_vector(translation), RotationBase::<N, U2, SR>::new(angle)) Self::from_parts(Translation::from_vector(translation), Rotation::<N, U2>::new(angle))
} }
} }
impl<N, S> IsometryBase<N, U2, S, UnitComplex<N>> impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
where N: Real,
S: OwnedStorage<N, U2, U1>,
S::Alloc: OwnedAllocator<N, U2, U1, S> {
/// Creates a new isometry from a translation and a rotation angle. /// Creates a new isometry from a translation and a rotation angle.
#[inline] #[inline]
pub fn new(translation: ColumnVector<N, U2, S>, angle: N) -> Self { pub fn new(translation: Vector2<N>, angle: N) -> Self {
Self::from_parts(TranslationBase::from_vector(translation), UnitComplex::from_angle(angle)) Self::from_parts(Translation::from_vector(translation), UnitComplex::from_angle(angle))
} }
} }
// 3D rotation. // 3D rotation.
macro_rules! isometry_construction_impl( macro_rules! isometry_construction_impl(
($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => { ($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => {
impl<N, S, SR> IsometryBase<N, U3, S, $RotId<$($RotParams),*>> impl<N: Real> Isometry<N, U3, $RotId<$($RotParams),*>> {
where N: Real,
S: OwnedStorage<N, U3, U1, Alloc = SR::Alloc>,
SR: OwnedStorage<N, $RRDim, $RCDim>,
S::Alloc: OwnedAllocator<N, U3, U1, S>,
SR::Alloc: OwnedAllocator<N, $RRDim, $RCDim, SR> +
Allocator<N, U3, U3> {
/// Creates a new isometry from a translation and a rotation axis-angle. /// Creates a new isometry from a translation and a rotation axis-angle.
#[inline] #[inline]
pub fn new(translation: ColumnVector<N, U3, S>, axisangle: ColumnVector<N, U3, S>) -> Self { pub fn new(translation: Vector3<N>, axisangle: Vector3<N>) -> Self {
Self::from_parts( Self::from_parts(
TranslationBase::from_vector(translation), Translation::from_vector(translation),
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle)) $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 /// * up - Vertical direction. The only requirement of this parameter is to not be collinear
/// to `eye - at`. Non-collinearity is not checked. /// to `eye - at`. Non-collinearity is not checked.
#[inline] #[inline]
pub fn new_observer_frame(eye: &PointBase<N, U3, S>, pub fn new_observer_frame(eye: &Point3<N>,
target: &PointBase<N, U3, S>, target: &Point3<N>,
up: &ColumnVector<N, U3, S>) up: &Vector3<N>)
-> Self { -> Self {
Self::from_parts( Self::from_parts(
TranslationBase::from_vector(eye.coords.clone()), Translation::from_vector(eye.coords.clone()),
$RotId::new_observer_frame(&(target - eye), up)) $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 /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_rh(eye: &PointBase<N, U3, S>, pub fn look_at_rh(eye: &Point3<N>,
target: &PointBase<N, U3, S>, target: &Point3<N>,
up: &ColumnVector<N, U3, S>) up: &Vector3<N>)
-> Self { -> Self {
let rotation = $RotId::look_at_rh(&(target - eye), up); let rotation = $RotId::look_at_rh(&(target - eye), up);
let trans = &rotation * (-eye); 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. /// 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 /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_lh(eye: &PointBase<N, U3, S>, pub fn look_at_lh(eye: &Point3<N>,
target: &PointBase<N, U3, S>, target: &Point3<N>,
up: &ColumnVector<N, U3, S>) up: &Vector3<N>)
-> Self { -> Self {
let rotation = $RotId::look_at_lh(&(target - eye), up); let rotation = $RotId::look_at_lh(&(target - eye), up);
let trans = &rotation * (-eye); 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<N, U3, SR>, U3, U3); isometry_construction_impl!(Rotation3<N>, U3, U3);
isometry_construction_impl!(UnitQuaternionBase<N, SR>, U4, U1); isometry_construction_impl!(UnitQuaternion<N>, U4, U1);

View File

@ -1,50 +1,47 @@
use alga::general::{Real, SubsetOf, SupersetOf}; use alga::general::{Real, SubsetOf, SupersetOf};
use alga::linear::Rotation; use alga::linear::Rotation;
use core::{SquareMatrix, OwnedSquareMatrix}; use core::{DefaultAllocator, MatrixN};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use core::dimension::{DimName, DimNameAdd, DimNameSum, DimMin, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::{Allocator, OwnedAllocator};
use geometry::{PointBase, TranslationBase, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; use geometry::{Point, Translation, Isometry, Similarity, Transform, SuperTCategoryOf, TAffine};
/* /*
* This file provides the following conversions: * This file provides the following conversions:
* ============================================= * =============================================
* *
* IsometryBase -> IsometryBase * Isometry -> Isometry
* IsometryBase -> SimilarityBase * Isometry -> Similarity
* IsometryBase -> TransformBase * Isometry -> Transform
* IsometryBase -> Matrix (homogeneous) * Isometry -> Matrix (homogeneous)
*/ */
impl<N1, N2, D: DimName, SA, SB, R1, R2> SubsetOf<IsometryBase<N2, D, SB, R2>> for IsometryBase<N1, D, SA, R1> impl<N1, N2, D: DimName, R1, R2> SubsetOf<Isometry<N2, D, R2>> for Isometry<N1, D, R1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R1: Rotation<PointBase<N1, D, SA>> + SubsetOf<R2>, R1: Rotation<Point<N1, D>> + SubsetOf<R2>,
R2: Rotation<PointBase<N2, D, SB>>, R2: Rotation<Point<N2, D>>,
SA: OwnedStorage<N1, D, U1>, DefaultAllocator: Allocator<N1, D> +
SB: OwnedStorage<N2, D, U1>, Allocator<N2, D> {
SA::Alloc: OwnedAllocator<N1, D, U1, SA>,
SB::Alloc: OwnedAllocator<N2, D, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> IsometryBase<N2, D, SB, R2> { fn to_superset(&self) -> Isometry<N2, D, R2> {
IsometryBase::from_parts( Isometry::from_parts(
self.translation.to_superset(), self.translation.to_superset(),
self.rotation.to_superset() self.rotation.to_superset()
) )
} }
#[inline] #[inline]
fn is_in_subset(iso: &IsometryBase<N2, D, SB, R2>) -> bool { fn is_in_subset(iso: &Isometry<N2, D, R2>) -> bool {
::is_convertible::<_, TranslationBase<N1, D, SA>>(&iso.translation) && ::is_convertible::<_, Translation<N1, D>>(&iso.translation) &&
::is_convertible::<_, R1>(&iso.rotation) ::is_convertible::<_, R1>(&iso.rotation)
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(iso: &IsometryBase<N2, D, SB, R2>) -> Self { unsafe fn from_superset_unchecked(iso: &Isometry<N2, D, R2>) -> Self {
IsometryBase::from_parts( Isometry::from_parts(
iso.translation.to_subset_unchecked(), iso.translation.to_subset_unchecked(),
iso.rotation.to_subset_unchecked() iso.rotation.to_subset_unchecked()
) )
@ -52,95 +49,91 @@ impl<N1, N2, D: DimName, SA, SB, R1, R2> SubsetOf<IsometryBase<N2, D, SB, R2>> f
} }
impl<N1, N2, D: DimName, SA, SB, R1, R2> SubsetOf<SimilarityBase<N2, D, SB, R2>> for IsometryBase<N1, D, SA, R1> impl<N1, N2, D: DimName, R1, R2> SubsetOf<Similarity<N2, D, R2>> for Isometry<N1, D, R1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R1: Rotation<PointBase<N1, D, SA>> + SubsetOf<R2>, R1: Rotation<Point<N1, D>> + SubsetOf<R2>,
R2: Rotation<PointBase<N2, D, SB>>, R2: Rotation<Point<N2, D>>,
SA: OwnedStorage<N1, D, U1>, DefaultAllocator: Allocator<N1, D> +
SB: OwnedStorage<N2, D, U1>, Allocator<N2, D> {
SA::Alloc: OwnedAllocator<N1, D, U1, SA>,
SB::Alloc: OwnedAllocator<N2, D, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> SimilarityBase<N2, D, SB, R2> { fn to_superset(&self) -> Similarity<N2, D, R2> {
SimilarityBase::from_isometry( Similarity::from_isometry(
self.to_superset(), self.to_superset(),
N2::one() N2::one()
) )
} }
#[inline] #[inline]
fn is_in_subset(sim: &SimilarityBase<N2, D, SB, R2>) -> bool { fn is_in_subset(sim: &Similarity<N2, D, R2>) -> bool {
::is_convertible::<_, IsometryBase<N1, D, SA, R1>>(&sim.isometry) && ::is_convertible::<_, Isometry<N1, D, R1>>(&sim.isometry) &&
sim.scaling() == N2::one() sim.scaling() == N2::one()
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(sim: &SimilarityBase<N2, D, SB, R2>) -> Self { unsafe fn from_superset_unchecked(sim: &Similarity<N2, D, R2>) -> Self {
::convert_ref_unchecked(&sim.isometry) ::convert_ref_unchecked(&sim.isometry)
} }
} }
impl<N1, N2, D, SA, SB, R, C> SubsetOf<TransformBase<N2, D, SB, C>> for IsometryBase<N1, D, SA, R> impl<N1, N2, D, R, C> SubsetOf<Transform<N2, D, C>> for Isometry<N1, D, R>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, U1>,
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>,
C: SuperTCategoryOf<TAffine>, C: SuperTCategoryOf<TAffine>,
R: Rotation<PointBase<N1, D, SA>> + R: Rotation<Point<N1, D>> +
SubsetOf<OwnedSquareMatrix<N1, DimNameSum<D, U1>, SA::Alloc>> + // needed by: .to_homogeneous() SubsetOf<MatrixN<N1, DimNameSum<D, U1>>> +
SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>>, // needed by: ::convert_unchecked(mm) SubsetOf<MatrixN<N2, DimNameSum<D, U1>>>,
D: DimNameAdd<U1>, D: DimNameAdd<U1> +
SA::Alloc: OwnedAllocator<N1, D, U1, SA> + DimMin<D, Output = D>, // needed by .is_special_orthogonal()
Allocator<N1, D, D> + // needed by R DefaultAllocator: Allocator<N1, D> +
Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous() Allocator<N1, D, D> + // needed by R
Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, // needed by R Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous()
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB> + Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by R
Allocator<N2, D, D> + // needed by: mm.fixed_slice_mut Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N2, D, U1> + // needed by: m.fixed_slice Allocator<(usize, usize), D> + // needed by .is_special_orthogonal()
Allocator<N2, U1, D> { // needed by: m.fixed_slice Allocator<N2, D, D> +
Allocator<N2, D> {
#[inline] #[inline]
fn to_superset(&self) -> TransformBase<N2, D, SB, C> { fn to_superset(&self) -> Transform<N2, D, C> {
TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(t: &TransformBase<N2, D, SB, C>) -> bool { fn is_in_subset(t: &Transform<N2, D, C>) -> bool {
<Self as SubsetOf<_>>::is_in_subset(t.matrix()) <Self as SubsetOf<_>>::is_in_subset(t.matrix())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(t: &TransformBase<N2, D, SB, C>) -> Self { unsafe fn from_superset_unchecked(t: &Transform<N2, D, C>) -> Self {
Self::from_superset_unchecked(t.matrix()) Self::from_superset_unchecked(t.matrix())
} }
} }
impl<N1, N2, D, SA, SB, R> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for IsometryBase<N1, D, SA, R> impl<N1, N2, D, R> SubsetOf<MatrixN<N2, DimNameSum<D, U1>>> for Isometry<N1, D, R>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, U1>, R: Rotation<Point<N1, D>> +
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, SubsetOf<MatrixN<N1, DimNameSum<D, U1>>> +
R: Rotation<PointBase<N1, D, SA>> + SubsetOf<MatrixN<N2, DimNameSum<D, U1>>>,
SubsetOf<OwnedSquareMatrix<N1, DimNameSum<D, U1>, SA::Alloc>> + // needed by: .to_homogeneous() D: DimNameAdd<U1> +
SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>>, // needed by: ::convert_unchecked(mm) DimMin<D, Output = D>, // needed by .is_special_orthogonal()
D: DimNameAdd<U1>, DefaultAllocator: Allocator<N1, D> +
SA::Alloc: OwnedAllocator<N1, D, U1, SA> + Allocator<N1, D, D> + // needed by R
Allocator<N1, D, D> + // needed by R Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous()
Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous() Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by R
Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, // needed by R Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> +
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB> + Allocator<(usize, usize), D> + // needed by .is_special_orthogonal()
Allocator<N2, D, D> + // needed by: mm.fixed_slice_mut Allocator<N2, D, D> +
Allocator<N2, D, U1> + // needed by: m.fixed_slice Allocator<N2, D> {
Allocator<N2, U1, D> { // needed by: m.fixed_slice
#[inline] #[inline]
fn to_superset(&self) -> SquareMatrix<N2, DimNameSum<D, U1>, SB> { fn to_superset(&self) -> MatrixN<N2, DimNameSum<D, U1>> {
self.to_homogeneous().to_superset() self.to_homogeneous().to_superset()
} }
#[inline] #[inline]
fn is_in_subset(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> bool { fn is_in_subset(m: &MatrixN<N2, DimNameSum<D, U1>>) -> bool {
let rot = m.fixed_slice::<D, D>(0, 0); let rot = m.fixed_slice::<D, D>(0, 0);
let bottom = m.fixed_slice::<U1, D>(D::dim(), 0); let bottom = m.fixed_slice::<U1, D>(D::dim(), 0);
@ -154,9 +147,9 @@ impl<N1, N2, D, SA, SB, R> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self {
let t = m.fixed_slice::<D, U1>(0, D::dim()).into_owned(); let t = m.fixed_slice::<D, U1>(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())) Self::from_parts(t, ::convert_unchecked(m.clone_owned()))
} }

View File

@ -1,14 +1,13 @@
use std::ops::{Mul, MulAssign, Div, DivAssign}; use std::ops::{Mul, MulAssign, Div, DivAssign};
use alga::general::Real; 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::dimension::{DimName, U1, U3, U4};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
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 // 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>` // 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) * (Operators)
* *
* IsometryBase × IsometryBase * Isometry × Isometry
* IsometryBase × R * Isometry × R
* *
* *
* IsometryBase ÷ IsometryBase * Isometry ÷ Isometry
* IsometryBase ÷ R * Isometry ÷ R
* *
* IsometryBase × PointBase * Isometry × Point
* IsometryBase × ColumnVector * Isometry × Vector
* *
* *
* IsometryBase × TranslationBase * Isometry × Translation
* TranslationBase × IsometryBase * Translation × Isometry
* TranslationBase × R -> IsometryBase<R> * Translation × R -> Isometry<R>
* *
* NOTE: The following are provided explicitly because we can't have R × IsometryBase. * NOTE: The following are provided explicitly because we can't have R × Isometry.
* RotationBase × IsometryBase<RotationBase> * Rotation × Isometry<Rotation>
* UnitQuaternion × IsometryBase<UnitQuaternion> * UnitQuaternion × Isometry<UnitQuaternion>
* *
* RotationBase ÷ IsometryBase<RotationBase> * Rotation ÷ Isometry<Rotation>
* UnitQuaternion ÷ IsometryBase<UnitQuaternion> * UnitQuaternion ÷ Isometry<UnitQuaternion>
* *
* RotationBase × TranslationBase -> IsometryBase<RotationBase> * Rotation × Translation -> Isometry<Rotation>
* UnitQuaternion × TranslationBase -> IsometryBase<UnitQuaternion> * UnitQuaternion × Translation -> Isometry<UnitQuaternion>
* *
* *
* (Assignment Operators) * (Assignment Operators)
* *
* IsometryBase ×= TranslationBase * Isometry ×= Translation
* *
* IsometryBase ×= IsometryBase * Isometry ×= Isometry
* IsometryBase ×= R * Isometry ×= R
* *
* IsometryBase ÷= IsometryBase * Isometry ÷= Isometry
* IsometryBase ÷= R * Isometry ÷= R
* *
*/ */
@ -65,11 +64,9 @@ macro_rules! isometry_binop_impl(
($Op: ident, $op: ident; ($Op: ident, $op: ident;
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N, D: DimName, S, R> $Op<$Rhs> for $Lhs impl<$($lives ,)* N: Real, D: DimName, R> $Op<$Rhs> for $Lhs
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
@ -114,22 +111,18 @@ macro_rules! isometry_binop_assign_impl_all(
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty;
[val] => $action_val: expr; [val] => $action_val: expr;
[ref] => $action_ref: expr;) => { [ref] => $action_ref: expr;) => {
impl<N, D: DimName, S, R> $OpAssign<$Rhs> for $Lhs impl<N: Real, D: DimName, R> $OpAssign<$Rhs> for $Lhs
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn $op_assign(&mut $lhs, $rhs: $Rhs) { fn $op_assign(&mut $lhs, $rhs: $Rhs) {
$action_val $action_val
} }
} }
impl<'b, N, D: DimName, S, R> $OpAssign<&'b $Rhs> for $Lhs impl<'b, N: Real, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) {
$action_ref $action_ref
@ -138,18 +131,18 @@ macro_rules! isometry_binop_assign_impl_all(
} }
); );
// IsometryBase × IsometryBase // Isometry × Isometry
// IsometryBase ÷ IsometryBase // Isometry ÷ Isometry
isometry_binop_impl_all!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: IsometryBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>, Output = IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: Isometry<N, D, R>, Output = Isometry<N, D, R>;
[val val] => &self * &rhs; [val val] => &self * &rhs;
[ref val] => self * &rhs; [ref val] => self * &rhs;
[val ref] => &self * rhs; [val ref] => &self * rhs;
[ref ref] => { [ref ref] => {
let shift = self.rotation.transform_vector(&rhs.translation.vector); 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. 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!( isometry_binop_impl_all!(
Div, div; Div, div;
self: IsometryBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>, Output = IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: Isometry<N, D, R>, Output = Isometry<N, D, R>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => 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!( isometry_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: IsometryBase<N, D, S, R>, rhs: TranslationBase<N, D, S>; self: Isometry<N, D, R>, rhs: Translation<N, D>;
[val] => *self *= &rhs; [val] => *self *= &rhs;
[ref] => { [ref] => {
let shift = self.rotation.transform_vector(&rhs.vector); let shift = self.rotation.transform_vector(&rhs.vector);
@ -176,11 +169,11 @@ isometry_binop_assign_impl_all!(
}; };
); );
// IsometryBase ×= IsometryBase // Isometry ×= Isometry
// IsometryBase ÷= IsometryBase // Isometry ÷= Isometry
isometry_binop_assign_impl_all!( isometry_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: IsometryBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: Isometry<N, D, R>;
[val] => *self *= &rhs; [val] => *self *= &rhs;
[ref] => { [ref] => {
let shift = self.rotation.transform_vector(&rhs.translation.vector); let shift = self.rotation.transform_vector(&rhs.translation.vector);
@ -191,66 +184,68 @@ isometry_binop_assign_impl_all!(
isometry_binop_assign_impl_all!( isometry_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: IsometryBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: Isometry<N, D, R>;
[val] => *self /= &rhs; [val] => *self /= &rhs;
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse();
); );
// IsometryBase ×= R // Isometry ×= R
// IsometryBase ÷= R // Isometry ÷= R
isometry_binop_assign_impl_all!( isometry_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: IsometryBase<N, D, S, R>, rhs: R; self: Isometry<N, D, R>, rhs: R;
[val] => self.rotation *= rhs; [val] => self.rotation *= rhs;
[ref] => self.rotation *= rhs.clone(); [ref] => self.rotation *= rhs.clone();
); );
isometry_binop_assign_impl_all!( isometry_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: IsometryBase<N, D, S, R>, rhs: R; self: Isometry<N, D, R>, rhs: R;
// FIXME: don't invert explicitly? // FIXME: don't invert explicitly?
[val] => *self *= rhs.inverse(); [val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse();
); );
// IsometryBase × R // Isometry × R
// IsometryBase ÷ R // Isometry ÷ R
isometry_binop_impl_all!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: IsometryBase<N, D, S, R>, rhs: R, Output = IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: R, Output = Isometry<N, D, R>;
[val val] => IsometryBase::from_parts(self.translation, self.rotation * rhs); [val val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[ref val] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone.
[val ref] => IsometryBase::from_parts(self.translation, self.rotation * rhs.clone()); [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone());
[ref ref] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone());
); );
isometry_binop_impl_all!( isometry_binop_impl_all!(
Div, div; Div, div;
self: IsometryBase<N, D, S, R>, rhs: R, Output = IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: R, Output = Isometry<N, D, R>;
[val val] => IsometryBase::from_parts(self.translation, self.rotation / rhs); [val val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[ref val] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() / rhs); [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs);
[val ref] => IsometryBase::from_parts(self.translation, self.rotation / rhs.clone()); [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone());
[ref ref] => IsometryBase::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone());
); );
// IsometryBase × PointBase // Isometry × Point
isometry_binop_impl_all!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: IsometryBase<N, D, S, R>, right: PointBase<N, D, S>, Output = PointBase<N, D, S>; self: Isometry<N, D, R>, right: Point<N, D>, Output = Point<N, D>;
[val val] => self.translation * self.rotation.transform_point(&right); [val val] => self.translation * self.rotation.transform_point(&right);
[ref 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); [ref ref] => &self.translation * self.rotation.transform_point(right);
); );
// IsometryBase × Vector // Isometry × Vector
isometry_binop_impl_all!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: IsometryBase<N, D, S, R>, right: ColumnVector<N, D, S>, Output = ColumnVector<N, D, S>; // FIXME: because of `transform_vector`, we cant use a generic storage type for the rhs vector,
// i.e., right: Vector<N, D, S> where S: Storage<N, D>.
self: Isometry<N, D, R>, right: VectorN<N, D>, Output = VectorN<N, D>;
[val val] => self.rotation.transform_vector(&right); [val val] => self.rotation.transform_vector(&right);
[ref val] => self.rotation.transform_vector(&right); [ref val] => self.rotation.transform_vector(&right);
[val ref] => 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!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: IsometryBase<N, D, S, R>, right: TranslationBase<N, D, S>, Output = IsometryBase<N, D, S, R>; self: Isometry<N, D, R>, right: Translation<N, D>, Output = Isometry<N, D, R>;
[val val] => &self * &right; [val val] => &self * &right;
[ref val] => self * &right; [ref val] => self * &right;
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let new_tr = &self.translation.vector + self.rotation.transform_vector(&right.vector); 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!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: TranslationBase<N, D, S>, right: IsometryBase<N, D, S, R>, Output = IsometryBase<N, D, S, R>; self: Translation<N, D>, right: Isometry<N, D, R>, Output = Isometry<N, D, R>;
[val val] => IsometryBase::from_parts(self * right.translation, right.rotation); [val val] => Isometry::from_parts(self * right.translation, right.rotation);
[ref val] => IsometryBase::from_parts(self * &right.translation, right.rotation); [ref val] => Isometry::from_parts(self * &right.translation, right.rotation);
[val ref] => IsometryBase::from_parts(self * &right.translation, right.rotation.clone()); [val ref] => Isometry::from_parts(self * &right.translation, right.rotation.clone());
[ref ref] => IsometryBase::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!( isometry_binop_impl_all!(
Mul, mul; Mul, mul;
self: TranslationBase<N, D, S>, right: R, Output = IsometryBase<N, D, S, R>; self: Translation<N, D>, right: R, Output = Isometry<N, D, R>;
[val val] => IsometryBase::from_parts(self, right); [val val] => Isometry::from_parts(self, right);
[ref val] => IsometryBase::from_parts(self.clone(), right); [ref val] => Isometry::from_parts(self.clone(), right);
[val ref] => IsometryBase::from_parts(self, right.clone()); [val ref] => Isometry::from_parts(self, right.clone());
[ref ref] => IsometryBase::from_parts(self.clone(), 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),*; ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(for $Dims: ident: $DimsBound: ident),*;
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N: Real $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs
where N: Real, where DefaultAllocator: Allocator<N, $R1, $C1> +
SA: OwnedStorage<N, $R1, $C1>, Allocator<N, $R2, $C2> {
SB: OwnedStorage<N, $R2, $C2, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, $R1, $C1, SA>,
SB::Alloc: OwnedAllocator<N, $R2, $C2, SB> {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
@ -352,51 +344,51 @@ macro_rules! isometry_from_composition_impl_all(
); );
// RotationBase × TranslationBase // Rotation × Translation
isometry_from_composition_impl_all!( isometry_from_composition_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, U1) for D: DimName; (D, D), (D, U1) for D: DimName;
self: RotationBase<N, D, SA>, right: TranslationBase<N, D, SB>, Output = IsometryBase<N, D, SB, RotationBase<N, D, SA>>; self: Rotation<N, D>, right: Translation<N, D>, Output = Isometry<N, D, Rotation<N, D>>;
[val val] => IsometryBase::from_parts(TranslationBase::from_vector(&self * right.vector), self); [val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self);
[ref val] => IsometryBase::from_parts(TranslationBase::from_vector(self * right.vector), self.clone()); [ref val] => Isometry::from_parts(Translation::from_vector(self * right.vector), self.clone());
[val ref] => IsometryBase::from_parts(TranslationBase::from_vector(&self * &right.vector), self); [val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self);
[ref ref] => IsometryBase::from_parts(TranslationBase::from_vector(self * &right.vector), self.clone()); [ref ref] => Isometry::from_parts(Translation::from_vector(self * &right.vector), self.clone());
); );
// UnitQuaternionBase × TranslationBase // UnitQuaternion × Translation
isometry_from_composition_impl_all!( isometry_from_composition_impl_all!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, right: TranslationBase<N, U3, SB>, self: UnitQuaternion<N>, right: Translation<N, U3>,
Output = IsometryBase<N, U3, SB, UnitQuaternionBase<N, SA>>; Output = Isometry<N, U3, UnitQuaternion<N>>;
[val val] => IsometryBase::from_parts(TranslationBase::from_vector(&self * right.vector), self); [val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self);
[ref val] => IsometryBase::from_parts(TranslationBase::from_vector( self * right.vector), self.clone()); [ref val] => Isometry::from_parts(Translation::from_vector( self * right.vector), self.clone());
[val ref] => IsometryBase::from_parts(TranslationBase::from_vector(&self * &right.vector), self); [val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self);
[ref ref] => IsometryBase::from_parts(TranslationBase::from_vector( self * &right.vector), self.clone()); [ref ref] => Isometry::from_parts(Translation::from_vector( self * &right.vector), self.clone());
); );
// RotationBase × IsometryBase // Rotation × Isometry
isometry_from_composition_impl_all!( isometry_from_composition_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, U1) for D: DimName; (D, D), (D, U1) for D: DimName;
self: RotationBase<N, D, SA>, right: IsometryBase<N, D, SB, RotationBase<N, D, SA>>, self: Rotation<N, D>, right: Isometry<N, D, Rotation<N, D>>,
Output = IsometryBase<N, D, SB, RotationBase<N, D, SA>>; Output = Isometry<N, D, Rotation<N, D>>;
[val val] => &self * &right; [val val] => &self * &right;
[ref val] => self * &right; [ref val] => self * &right;
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let shift = self * &right.translation.vector; 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!( isometry_from_composition_impl_all!(
Div, div; Div, div;
(D, D), (D, U1) for D: DimName; (D, D), (D, U1) for D: DimName;
self: RotationBase<N, D, SA>, right: IsometryBase<N, D, SB, RotationBase<N, D, SA>>, self: Rotation<N, D>, right: Isometry<N, D, Rotation<N, D>>,
Output = IsometryBase<N, D, SB, RotationBase<N, D, SA>>; Output = Isometry<N, D, Rotation<N, D>>;
// FIXME: don't call iverse explicitly? // FIXME: don't call iverse explicitly?
[val val] => self * right.inverse(); [val val] => self * right.inverse();
[ref 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!( isometry_from_composition_impl_all!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, right: IsometryBase<N, U3, SB, UnitQuaternionBase<N, SA>>, self: UnitQuaternion<N>, right: Isometry<N, U3, UnitQuaternion<N>>,
Output = IsometryBase<N, U3, SB, UnitQuaternionBase<N, SA>>; Output = Isometry<N, U3, UnitQuaternion<N>>;
[val val] => &self * &right; [val val] => &self * &right;
[ref val] => self * &right; [ref val] => self * &right;
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let shift = self * &right.translation.vector; 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!( isometry_from_composition_impl_all!(
Div, div; Div, div;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, right: IsometryBase<N, U3, SB, UnitQuaternionBase<N, SA>>, self: UnitQuaternion<N>, right: Isometry<N, U3, UnitQuaternion<N>>,
Output = IsometryBase<N, U3, SB, UnitQuaternionBase<N, SA>>; Output = Isometry<N, U3, UnitQuaternion<N>>;
// FIXME: don't call inverse explicitly? // FIXME: don't call inverse explicitly?
[val val] => self * right.inverse(); [val val] => self * right.inverse();
[ref val] => self * right.inverse(); [ref val] => self * right.inverse();

View File

@ -14,7 +14,7 @@ mod point_coordinates;
mod rotation; mod rotation;
mod rotation_construction; mod rotation_construction;
mod rotation_ops; mod rotation_ops;
mod rotation_alga; // FIXME: implement RotationBase methods. mod rotation_alga; // FIXME: implement Rotation methods.
mod rotation_conversion; mod rotation_conversion;
mod rotation_alias; mod rotation_alias;
mod rotation_specialization; mod rotation_specialization;
@ -23,9 +23,8 @@ mod quaternion;
mod quaternion_construction; mod quaternion_construction;
mod quaternion_ops; mod quaternion_ops;
mod quaternion_alga; mod quaternion_alga;
mod quaternion_alias;
mod quaternion_coordinates;
mod quaternion_conversion; mod quaternion_conversion;
mod quaternion_coordinates;
mod unit_complex; mod unit_complex;
mod unit_complex_construction; mod unit_complex_construction;
@ -61,6 +60,8 @@ mod transform_alga;
mod transform_conversion; mod transform_conversion;
mod transform_alias; mod transform_alias;
mod reflection;
mod orthographic; mod orthographic;
mod perspective; mod perspective;
@ -71,7 +72,6 @@ pub use self::rotation::*;
pub use self::rotation_alias::*; pub use self::rotation_alias::*;
pub use self::quaternion::*; pub use self::quaternion::*;
pub use self::quaternion_alias::*;
pub use self::unit_complex::*; pub use self::unit_complex::*;
@ -87,5 +87,7 @@ pub use self::similarity_alias::*;
pub use self::transform::*; pub use self::transform::*;
pub use self::transform_alias::*; pub use self::transform_alias::*;
pub use self::orthographic::{OrthographicBase, Orthographic3}; pub use self::reflection::*;
pub use self::perspective::{PerspectiveBase, Perspective3};
pub use self::orthographic::Orthographic3;
pub use self::perspective::Perspective3;

View File

@ -8,7 +8,7 @@ macro_rules! md_impl(
// Operator, operator method, and calar bounds. // Operator, operator method, and calar bounds.
$Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*;
// Storage dimensions, and dimension bounds. // 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. // [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 + output. // Argument identifiers and types + output.
@ -17,10 +17,11 @@ macro_rules! md_impl(
$action: expr; $action: expr;
// Lifetime. // Lifetime.
$($lives: tt),*) => { $($lives: tt),*) => {
impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$BoundParam>)*)*, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
where N: Scalar + Zero + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, where N: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*,
SA: Storage<N, $R1, $C1>, DefaultAllocator: Allocator<N, $R1, $C1> +
SB: Storage<N, $R2, $C2>, Allocator<N, $R2, $C2> +
Allocator<N, $R1, $C2>,
$( $ConstraintType: $ConstraintBound<$( $ConstraintBoundParams $( = $EqBound )*),*> ),* $( $ConstraintType: $ConstraintBound<$( $ConstraintBoundParams $( = $EqBound )*),*> ),*
{ {
type Output = $Result; type Output = $Result;
@ -41,7 +42,7 @@ macro_rules! md_impl_all(
// Operator, operator method, and calar bounds. // Operator, operator method, and calar bounds.
$Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*;
// Storage dimensions, and dimension bounds. // 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. // [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 + output. // Argument identifiers and types + output.
@ -54,28 +55,28 @@ macro_rules! md_impl_all(
md_impl!( md_impl!(
$Op, $op $(where N: $($ScalarBounds),*)*; $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 )*),*>)*; $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*;
$lhs: $Lhs, $rhs: $Rhs, Output = $Result; $lhs: $Lhs, $rhs: $Rhs, Output = $Result;
$action_val_val; ); $action_val_val; );
md_impl!( md_impl!(
$Op, $op $(where N: $($ScalarBounds),*)*; $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 )*),*>)*; $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*;
$lhs: &'a $Lhs, $rhs: $Rhs, Output = $Result; $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Result;
$action_ref_val; 'a); $action_ref_val; 'a);
md_impl!( md_impl!(
$Op, $op $(where N: $($ScalarBounds),*)*; $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 )*),*>)*; $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*;
$lhs: $Lhs, $rhs: &'b $Rhs, Output = $Result; $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Result;
$action_val_ref; 'b); $action_val_ref; 'b);
md_impl!( md_impl!(
$Op, $op $(where N: $($ScalarBounds),*)*; $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 )*),*>)*; $(where $ConstraintType: $ConstraintBound<$($ConstraintBoundParams $( = $EqBound )*),*>)*;
$lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Result; $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Result;
$action_ref_ref; 'a, 'b); $action_ref_ref; 'a, 'b);
@ -89,19 +90,18 @@ macro_rules! md_assign_impl(
// Operator, operator method, and scalar bounds. // Operator, operator method, and scalar bounds.
$Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*;
// Storage dimensions, and dimension bounds. // 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. // [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. // Argument identifiers and types.
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty;
// Actual implementation and lifetimes. // Actual implementation and lifetimes.
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$BoundParam>)*)*, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
where N: Scalar + Zero + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, where N: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*,
SA: OwnedStorage<N, $R1, $C1>, // FIXME: this is too restrictive. DefaultAllocator: Allocator<N, $R1, $C1> +
SB: Storage<N, $R2, $C2>, Allocator<N, $R2, $C2>,
SA::Alloc: OwnedAllocator<N, $R1, $C1, SA>, $( $ConstraintType: $ConstraintBound $(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),*
$( $ConstraintType: $ConstraintBound<$( $ConstraintBoundParams $( = $EqBound )*),*> ),*
{ {
#[inline] #[inline]
fn $op(&mut $lhs, $rhs: $Rhs) { fn $op(&mut $lhs, $rhs: $Rhs) {
@ -118,9 +118,9 @@ macro_rules! md_assign_impl_all(
// Operator, operator method, and scalar bounds. // Operator, operator method, and scalar bounds.
$Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*;
// Storage dimensions, and dimension bounds. // 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. // [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. // Argument identifiers and types.
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty;
// Actual implementation and lifetimes. // Actual implementation and lifetimes.
@ -128,15 +128,15 @@ macro_rules! md_assign_impl_all(
[ref] => $action_ref: expr;) => { [ref] => $action_ref: expr;) => {
md_assign_impl!( md_assign_impl!(
$Op, $op $(where N: $($ScalarBounds),*)*; $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 )*),*>)*; $(where $ConstraintType: $ConstraintBound $(<$($ConstraintBoundParams $( = $EqBound )*),*>)*)*;
$lhs: $Lhs, $rhs: $Rhs; $lhs: $Lhs, $rhs: $Rhs;
$action_val; ); $action_val; );
md_assign_impl!( md_assign_impl!(
$Op, $op $(where N: $($ScalarBounds),*)*; $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 )*),*>)*; $(where $ConstraintType: $ConstraintBound $(<$($ConstraintBoundParams $( = $EqBound )*),*>)*)*;
$lhs: $Lhs, $rhs: &'b $Rhs; $lhs: $Lhs, $rhs: &'b $Rhs;
$action_ref; 'b); $action_ref; 'b);
} }
@ -146,14 +146,14 @@ macro_rules! md_assign_impl_all(
/// Macro for the implementation of addition and subtraction. /// Macro for the implementation of addition and subtraction.
macro_rules! add_sub_impl( macro_rules! add_sub_impl(
($Op: ident, $op: ident, $bound: ident; ($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; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
where N: Scalar + $bound, where N: Scalar + $bound,
SA: Storage<N, $R1, $C1>, DefaultAllocator: Allocator<N, $R1, $C1> +
SB: Storage<N, $R2, $C2>, Allocator<N, $R2, $C2> +
SA::Alloc: SameShapeAllocator<N, $R1, $C1, $R2, $C2, SA>, SameShapeAllocator<N, $R1, $C1, $R2, $C2>,
ShapeConstraint: SameNumberOfRows<$R1, $R2 $(, Representative = $RRes)*> + ShapeConstraint: SameNumberOfRows<$R1, $R2 $(, Representative = $RRes)*> +
SameNumberOfColumns<$C1, $C2> { SameNumberOfColumns<$C1, $C2> {
type Output = $Result; 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),+; ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident),+;
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs
where N: Scalar + $bound, where N: Scalar + $bound,
SA: OwnedStorage<N, $R1, $C1>, // FIXME: this is too restrictive. DefaultAllocator: Allocator<N, $R1, $C1> +
SB: Storage<N, $R2, $C2>, Allocator<N, $R2, $C2>,
SA::Alloc: OwnedAllocator<N, $R1, $C1, SA>,
ShapeConstraint: SameNumberOfRows<$R1, $R2> + SameNumberOfColumns<$C1, $C2> { ShapeConstraint: SameNumberOfRows<$R1, $R2> + SameNumberOfColumns<$C1, $C2> {
#[inline] #[inline]
fn $op(&mut $lhs, $rhs: $Rhs) { fn $op(&mut $lhs, $rhs: $Rhs) {

View File

@ -1,70 +1,65 @@
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use rand::{Rand, Rng}; use rand::{Rand, Rng};
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer}; use serde;
use std::fmt;
use alga::general::Real; use alga::general::Real;
use core::{Scalar, SquareMatrix, OwnedSquareMatrix, ColumnVector, OwnedColumnVector, MatrixArray}; use core::{Matrix4, Vector, Vector3};
use core::dimension::{U1, U3, U4}; use core::dimension::U3;
use core::storage::{OwnedStorage, Storage, StorageMut}; use core::storage::Storage;
use core::allocator::OwnedAllocator;
use core::helper; use core::helper;
use geometry::{PointBase, OwnedPoint}; use geometry::Point3;
/// A 3D orthographic projection stored as an homogeneous 4x4 matrix. /// A 3D orthographic projection stored as an homogeneous 4x4 matrix.
#[derive(Debug, Clone, Copy)] // FIXME: Hash pub struct Orthographic3<N: Real> {
pub struct OrthographicBase<N: Scalar, S: Storage<N, U4, U4>> { matrix: Matrix4<N>
matrix: SquareMatrix<N, U4, S>
} }
#[cfg(feature = "serde-serialize")] impl<N: Real> Copy for Orthographic3<N> { }
impl<N, S> Serialize for OrthographicBase<N, S>
where N: Scalar, impl<N: Real> Clone for Orthographic3<N> {
S: Storage<N, U4, U4>, #[inline]
SquareMatrix<N, U4, S>: Serialize, fn clone(&self) -> Self {
{ Orthographic3::from_matrix_unchecked(self.matrix.clone())
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
where T: Serializer
{
self.matrix.serialize(serializer)
} }
} }
#[cfg(feature = "serde-serialize")] impl<N: Real> fmt::Debug for Orthographic3<N> {
impl<'de, N, S> Deserialize<'de> for OrthographicBase<N, S> fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
where N: Scalar, self.matrix.fmt(f)
S: Storage<N, U4, U4>,
SquareMatrix<N, U4, S>: Deserialize<'de>,
{
fn deserialize<T>(deserializer: T) -> Result<Self, T::Error>
where T: Deserializer<'de>
{
SquareMatrix::deserialize(deserializer).map(|x| OrthographicBase { matrix: x })
} }
} }
/// A 3D orthographic projection stored as a static homogeneous 4x4 matrix. impl<N: Real> PartialEq for Orthographic3<N> {
pub type Orthographic3<N> = OrthographicBase<N, MatrixArray<N, U4, U4>>;
impl<N, S> Eq for OrthographicBase<N, S>
where N: Scalar + Eq,
S: Storage<N, U4, U4> { }
impl<N: Scalar, S: Storage<N, U4, U4>> PartialEq for OrthographicBase<N, S> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix self.matrix == right.matrix
} }
} }
impl<N, S> OrthographicBase<N, S> #[cfg(feature = "serde-serialize")]
where N: Real, impl<N: Real + serde::Serialize> serde::Serialize for Orthographic3<N> {
S: OwnedStorage<N, U4, U4>, fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
S::Alloc: OwnedAllocator<N, U4, U4, S> { where S: serde::Serializer {
self.matrix.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize")]
impl<'a, N: Real + serde::Deserialize<'a>> serde::Deserialize<'a> for Orthographic3<N> {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where Des: serde::Deserializer<'a> {
let matrix = Matrix4::<N>::deserialize(deserializer)?;
Ok(Orthographic3::from_matrix_unchecked(matrix))
}
}
impl<N: Real> Orthographic3<N> {
/// Creates a new orthographic projection matrix. /// Creates a new orthographic projection matrix.
#[inline] #[inline]
pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self { pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
@ -72,7 +67,7 @@ impl<N, S> OrthographicBase<N, S>
assert!(bottom < top, "The top corner must be higher than the bottom corner."); 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."); assert!(znear < zfar, "The far plane must be farther than the near plane.");
let matrix = SquareMatrix::<N, U4, S>::identity(); let matrix = Matrix4::<N>::identity();
let mut res = Self::from_matrix_unchecked(matrix); let mut res = Self::from_matrix_unchecked(matrix);
res.set_left_and_right(left, right); res.set_left_and_right(left, right);
@ -87,8 +82,8 @@ impl<N, S> OrthographicBase<N, S>
/// It is not checked whether or not the given matrix actually represents an orthographic /// It is not checked whether or not the given matrix actually represents an orthographic
/// projection. /// projection.
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: SquareMatrix<N, U4, S>) -> Self { pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self {
OrthographicBase { Orthographic3 {
matrix: matrix matrix: matrix
} }
} }
@ -105,24 +100,10 @@ impl<N, S> OrthographicBase<N, S>
Self::new(-width * half, width * half, -height * half, height * half, znear, zfar) Self::new(-width * half, width * half, -height * half, height * half, znear, zfar)
} }
}
impl<N: Real, S: Storage<N, U4, U4>> OrthographicBase<N, S> {
/// A reference to the underlying homogeneous transformation matrix.
#[inline]
pub fn as_matrix(&self) -> &SquareMatrix<N, U4, S> {
&self.matrix
}
/// Retrieves the underlying homogeneous matrix.
#[inline]
pub fn unwrap(self) -> SquareMatrix<N, U4, S> {
self.matrix
}
/// Retrieves the inverse of the underlying homogeneous matrix. /// Retrieves the inverse of the underlying homogeneous matrix.
#[inline] #[inline]
pub fn inverse(&self) -> OwnedSquareMatrix<N, U4, S::Alloc> { pub fn inverse(&self) -> Matrix4<N> {
let mut res = self.to_homogeneous(); let mut res = self.to_homogeneous();
let inv_m11 = N::one() / self.matrix[(0, 0)]; let inv_m11 = N::one() / self.matrix[(0, 0)];
@ -142,10 +123,22 @@ impl<N: Real, S: Storage<N, U4, U4>> OrthographicBase<N, S> {
/// Computes the corresponding homogeneous matrix. /// Computes the corresponding homogeneous matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, U4, S::Alloc> { pub fn to_homogeneous(&self) -> Matrix4<N> {
self.matrix.clone_owned() self.matrix.clone_owned()
} }
/// A reference to the underlying homogeneous transformation matrix.
#[inline]
pub fn as_matrix(&self) -> &Matrix4<N> {
&self.matrix
}
/// Retrieves the underlying homogeneous matrix.
#[inline]
pub fn unwrap(self) -> Matrix4<N> {
self.matrix
}
/// The smallest x-coordinate of the view cuboid. /// The smallest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn left(&self) -> N { pub fn left(&self) -> N {
@ -185,10 +178,8 @@ impl<N: Real, S: Storage<N, U4, U4>> OrthographicBase<N, S> {
// FIXME: when we get specialization, specialize the Mul impl instead. // FIXME: when we get specialization, specialize the Mul impl instead.
/// Projects a point. Faster than matrix multiplication. /// Projects a point. Faster than matrix multiplication.
#[inline] #[inline]
pub fn project_point<SB>(&self, p: &PointBase<N, U3, SB>) -> OwnedPoint<N, U3, SB::Alloc> pub fn project_point(&self, p: &Point3<N>) -> Point3<N> {
where SB: Storage<N, U3, U1> { Point3::new(
OwnedPoint::<N, U3, SB::Alloc>::new(
self.matrix[(0, 0)] * p[0] + self.matrix[(0, 3)], self.matrix[(0, 0)] * p[0] + self.matrix[(0, 3)],
self.matrix[(1, 1)] * p[1] + self.matrix[(1, 3)], self.matrix[(1, 1)] * p[1] + self.matrix[(1, 3)],
self.matrix[(2, 2)] * p[2] + self.matrix[(2, 3)] self.matrix[(2, 2)] * p[2] + self.matrix[(2, 3)]
@ -197,10 +188,9 @@ impl<N: Real, S: Storage<N, U4, U4>> OrthographicBase<N, S> {
/// Un-projects a point. Faster than multiplication by the underlying matrix inverse. /// Un-projects a point. Faster than multiplication by the underlying matrix inverse.
#[inline] #[inline]
pub fn unproject_point<SB>(&self, p: &PointBase<N, U3, SB>) -> OwnedPoint<N, U3, SB::Alloc> pub fn unproject_point(&self, p: &Point3<N>) -> Point3<N> {
where SB: Storage<N, U3, U1> {
OwnedPoint::<N, U3, SB::Alloc>::new( Point3::new(
(p[0] - self.matrix[(0, 3)]) / self.matrix[(0, 0)], (p[0] - self.matrix[(0, 3)]) / self.matrix[(0, 0)],
(p[1] - self.matrix[(1, 3)]) / self.matrix[(1, 1)], (p[1] - self.matrix[(1, 3)]) / self.matrix[(1, 1)],
(p[2] - self.matrix[(2, 3)]) / self.matrix[(2, 2)] (p[2] - self.matrix[(2, 3)]) / self.matrix[(2, 2)]
@ -210,18 +200,16 @@ impl<N: Real, S: Storage<N, U4, U4>> OrthographicBase<N, S> {
// FIXME: when we get specialization, specialize the Mul impl instead. // FIXME: when we get specialization, specialize the Mul impl instead.
/// Projects a vector. Faster than matrix multiplication. /// Projects a vector. Faster than matrix multiplication.
#[inline] #[inline]
pub fn project_vector<SB>(&self, p: &ColumnVector<N, U3, SB>) -> OwnedColumnVector<N, U3, SB::Alloc> pub fn project_vector<SB>(&self, p: &Vector<N, U3, SB>) -> Vector3<N>
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
OwnedColumnVector::<N, U3, SB::Alloc>::new( Vector3::new(
self.matrix[(0, 0)] * p[0], self.matrix[(0, 0)] * p[0],
self.matrix[(1, 1)] * p[1], self.matrix[(1, 1)] * p[1],
self.matrix[(2, 2)] * p[2] self.matrix[(2, 2)] * p[2]
) )
} }
}
impl<N: Real, S: StorageMut<N, U4, U4>> OrthographicBase<N, S> {
/// Sets the smallest x-coordinate of the view cuboid. /// Sets the smallest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn set_left(&mut self, left: N) { pub fn set_left(&mut self, left: N) {
@ -289,10 +277,7 @@ impl<N: Real, S: StorageMut<N, U4, U4>> OrthographicBase<N, S> {
} }
} }
impl<N, S> Rand for OrthographicBase<N, S> impl<N: Real + Rand> Rand for Orthographic3<N> {
where N: Real + Rand,
S: OwnedStorage<N, U4, U4>,
S::Alloc: OwnedAllocator<N, U4, U4, S> {
fn rand<R: Rng>(r: &mut R) -> Self { fn rand<R: Rng>(r: &mut R) -> Self {
let left = Rand::rand(r); let left = Rand::rand(r);
let right = helper::reject_rand(r, |x: &N| *x > left); let right = helper::reject_rand(r, |x: &N| *x > left);
@ -306,10 +291,8 @@ impl<N, S> Rand for OrthographicBase<N, S>
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N, S> Arbitrary for OrthographicBase<N, S> impl<N: Real + Arbitrary> Arbitrary for Orthographic3<N>
where N: Real + Arbitrary, where Matrix4<N>: Send {
S: OwnedStorage<N, U4, U4> + Send,
S::Alloc: OwnedAllocator<N, U4, U4, S> {
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
let left = Arbitrary::arbitrary(g); let left = Arbitrary::arbitrary(g);
let right = helper::reject(g, |x: &N| *x > left); let right = helper::reject(g, |x: &N| *x > left);

View File

@ -3,77 +3,71 @@ use quickcheck::{Arbitrary, Gen};
use rand::{Rand, Rng}; use rand::{Rand, Rng};
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer}; use serde;
use std::fmt;
use alga::general::Real; use alga::general::Real;
use core::{Scalar, SquareMatrix, OwnedSquareMatrix, ColumnVector, OwnedColumnVector, MatrixArray}; use core::{Scalar, Matrix4, Vector, Vector3};
use core::dimension::{U1, U3, U4}; use core::dimension::U3;
use core::storage::{OwnedStorage, Storage, StorageMut}; use core::storage::Storage;
use core::allocator::OwnedAllocator;
use core::helper; use core::helper;
use geometry::{PointBase, OwnedPoint}; use geometry::Point3;
/// A 3D perspective projection stored as an homogeneous 4x4 matrix. /// A 3D perspective projection stored as an homogeneous 4x4 matrix.
#[derive(Debug, Clone, Copy)] // FIXME: Hash pub struct Perspective3<N: Scalar> {
pub struct PerspectiveBase<N: Scalar, S: Storage<N, U4, U4>> { matrix: Matrix4<N>
matrix: SquareMatrix<N, U4, S>
} }
#[cfg(feature = "serde-serialize")] impl<N: Real> Copy for Perspective3<N> { }
impl<N, S> Serialize for PerspectiveBase<N, S>
where N: Scalar, impl<N: Real> Clone for Perspective3<N> {
S: Storage<N, U4, U4>, #[inline]
SquareMatrix<N, U4, S>: Serialize, fn clone(&self) -> Self {
{ Perspective3::from_matrix_unchecked(self.matrix.clone())
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
where T: Serializer
{
self.matrix.serialize(serializer)
} }
} }
#[cfg(feature = "serde-serialize")] impl<N: Real> fmt::Debug for Perspective3<N> {
impl<'de, N, S> Deserialize<'de> for PerspectiveBase<N, S> fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
where N: Scalar, self.matrix.fmt(f)
S: Storage<N, U4, U4>,
SquareMatrix<N, U4, S>: Deserialize<'de>,
{
fn deserialize<T>(deserializer: T) -> Result<Self, T::Error>
where T: Deserializer<'de>
{
SquareMatrix::deserialize(deserializer).map(|x| PerspectiveBase { matrix: x })
} }
} }
/// A 3D perspective projection stored as a static homogeneous 4x4 matrix. impl<N: Real> PartialEq for Perspective3<N> {
pub type Perspective3<N> = PerspectiveBase<N, MatrixArray<N, U4, U4>>;
impl<N, S> Eq for PerspectiveBase<N, S>
where N: Scalar + Eq,
S: Storage<N, U4, U4> { }
impl<N, S> PartialEq for PerspectiveBase<N, S>
where N: Scalar,
S: Storage<N, U4, U4> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix self.matrix == right.matrix
} }
} }
impl<N, S> PerspectiveBase<N, S> #[cfg(feature = "serde-serialize")]
where N: Real, impl<N: Real + serde::Serialize> serde::Serialize for Perspective3<N> {
S: OwnedStorage<N, U4, U4>, fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
S::Alloc: OwnedAllocator<N, U4, U4, S> { where S: serde::Serializer {
self.matrix.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize")]
impl<'a, N: Real + serde::Deserialize<'a>> serde::Deserialize<'a> for Perspective3<N> {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where Des: serde::Deserializer<'a> {
let matrix = Matrix4::<N>::deserialize(deserializer)?;
Ok(Perspective3::from_matrix_unchecked(matrix))
}
}
impl<N: Real> Perspective3<N> {
/// Creates a new perspective matrix from the aspect ratio, y field of view, and near/far planes. /// 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 { 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!(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."); assert!(!relative_eq!(aspect, N::zero()), "The apsect ratio must not be zero.");
let matrix = SquareMatrix::<N, U4, S>::identity(); let matrix = Matrix4::identity();
let mut res = PerspectiveBase::from_matrix_unchecked(matrix); let mut res = Perspective3::from_matrix_unchecked(matrix);
res.set_fovy(fovy); res.set_fovy(fovy);
res.set_aspect(aspect); res.set_aspect(aspect);
@ -91,32 +85,15 @@ impl<N, S> PerspectiveBase<N, S>
/// It is not checked whether or not the given matrix actually represents an orthographic /// It is not checked whether or not the given matrix actually represents an orthographic
/// projection. /// projection.
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: SquareMatrix<N, U4, S>) -> Self { pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self {
PerspectiveBase { Perspective3 {
matrix: matrix matrix: matrix
} }
} }
}
impl<N, S> PerspectiveBase<N, S>
where N: Real,
S: Storage<N, U4, U4> {
/// A reference to the underlying homogeneous transformation matrix.
#[inline]
pub fn as_matrix(&self) -> &SquareMatrix<N, U4, S> {
&self.matrix
}
/// Retrieves the underlying homogeneous matrix.
#[inline]
pub fn unwrap(self) -> SquareMatrix<N, U4, S> {
self.matrix
}
/// Retrieves the inverse of the underlying homogeneous matrix. /// Retrieves the inverse of the underlying homogeneous matrix.
#[inline] #[inline]
pub fn inverse(&self) -> OwnedSquareMatrix<N, U4, S::Alloc> { pub fn inverse(&self) -> Matrix4<N> {
let mut res = self.to_homogeneous(); let mut res = self.to_homogeneous();
res[(0, 0)] = N::one() / self.matrix[(0, 0)]; res[(0, 0)] = N::one() / self.matrix[(0, 0)];
@ -135,10 +112,22 @@ impl<N, S> PerspectiveBase<N, S>
/// Computes the corresponding homogeneous matrix. /// Computes the corresponding homogeneous matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, U4, S::Alloc> { pub fn to_homogeneous(&self) -> Matrix4<N> {
self.matrix.clone_owned() self.matrix.clone_owned()
} }
/// A reference to the underlying homogeneous transformation matrix.
#[inline]
pub fn as_matrix(&self) -> &Matrix4<N> {
&self.matrix
}
/// Retrieves the underlying homogeneous matrix.
#[inline]
pub fn unwrap(self) -> Matrix4<N> {
self.matrix
}
/// Gets the `width / height` aspect ratio of the view frustrum. /// Gets the `width / height` aspect ratio of the view frustrum.
#[inline] #[inline]
pub fn aspect(&self) -> N { pub fn aspect(&self) -> N {
@ -174,11 +163,9 @@ impl<N, S> PerspectiveBase<N, S>
// FIXME: when we get specialization, specialize the Mul impl instead. // FIXME: when we get specialization, specialize the Mul impl instead.
/// Projects a point. Faster than matrix multiplication. /// Projects a point. Faster than matrix multiplication.
#[inline] #[inline]
pub fn project_point<SB>(&self, p: &PointBase<N, U3, SB>) -> OwnedPoint<N, U3, SB::Alloc> pub fn project_point(&self, p: &Point3<N>) -> Point3<N> {
where SB: Storage<N, U3, U1> {
let inverse_denom = -N::one() / p[2]; let inverse_denom = -N::one() / p[2];
OwnedPoint::<N, U3, SB::Alloc>::new( Point3::new(
self.matrix[(0, 0)] * p[0] * inverse_denom, self.matrix[(0, 0)] * p[0] * inverse_denom,
self.matrix[(1, 1)] * p[1] * inverse_denom, self.matrix[(1, 1)] * p[1] * inverse_denom,
(self.matrix[(2, 2)] * p[2] + self.matrix[(2, 3)]) * inverse_denom (self.matrix[(2, 2)] * p[2] + self.matrix[(2, 3)]) * inverse_denom
@ -187,12 +174,10 @@ impl<N, S> PerspectiveBase<N, S>
/// Un-projects a point. Faster than multiplication by the matrix inverse. /// Un-projects a point. Faster than multiplication by the matrix inverse.
#[inline] #[inline]
pub fn unproject_point<SB>(&self, p: &PointBase<N, U3, SB>) -> OwnedPoint<N, U3, SB::Alloc> pub fn unproject_point(&self, p: &Point3<N>) -> Point3<N> {
where SB: Storage<N, U3, U1> {
let inverse_denom = self.matrix[(2, 3)] / (p[2] + self.matrix[(2, 2)]); let inverse_denom = self.matrix[(2, 3)] / (p[2] + self.matrix[(2, 2)]);
OwnedPoint::<N, U3, SB::Alloc>::new( Point3::new(
p[0] * inverse_denom / self.matrix[(0, 0)], p[0] * inverse_denom / self.matrix[(0, 0)],
p[1] * inverse_denom / self.matrix[(1, 1)], p[1] * inverse_denom / self.matrix[(1, 1)],
-inverse_denom -inverse_denom
@ -202,22 +187,17 @@ impl<N, S> PerspectiveBase<N, S>
// FIXME: when we get specialization, specialize the Mul impl instead. // FIXME: when we get specialization, specialize the Mul impl instead.
/// Projects a vector. Faster than matrix multiplication. /// Projects a vector. Faster than matrix multiplication.
#[inline] #[inline]
pub fn project_vector<SB>(&self, p: &ColumnVector<N, U3, SB>) -> OwnedColumnVector<N, U3, SB::Alloc> pub fn project_vector<SB>(&self, p: &Vector<N, U3, SB>) -> Vector3<N>
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
let inverse_denom = -N::one() / p[2]; let inverse_denom = -N::one() / p[2];
OwnedColumnVector::<N, U3, SB::Alloc>::new( Vector3::new(
self.matrix[(0, 0)] * p[0] * inverse_denom, self.matrix[(0, 0)] * p[0] * inverse_denom,
self.matrix[(1, 1)] * p[1] * inverse_denom, self.matrix[(1, 1)] * p[1] * inverse_denom,
self.matrix[(2, 2)] self.matrix[(2, 2)]
) )
} }
}
impl<N, S> PerspectiveBase<N, S>
where N: Real,
S: StorageMut<N, U4, U4> {
/// Updates this perspective matrix with a new `width / height` aspect ratio of the view /// Updates this perspective matrix with a new `width / height` aspect ratio of the view
/// frustrum. /// frustrum.
#[inline] #[inline]
@ -256,10 +236,7 @@ impl<N, S> PerspectiveBase<N, S>
} }
} }
impl<N, S> Rand for PerspectiveBase<N, S> impl<N: Real + Rand> Rand for Perspective3<N> {
where N: Real + Rand,
S: OwnedStorage<N, U4, U4>,
S::Alloc: OwnedAllocator<N, U4, U4, S> {
fn rand<R: Rng>(r: &mut R) -> Self { fn rand<R: Rng>(r: &mut R) -> Self {
let znear = Rand::rand(r); let znear = Rand::rand(r);
let zfar = helper::reject_rand(r, |&x: &N| !(x - znear).is_zero()); let zfar = helper::reject_rand(r, |&x: &N| !(x - znear).is_zero());
@ -270,10 +247,7 @@ impl<N, S> Rand for PerspectiveBase<N, S>
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N, S> Arbitrary for PerspectiveBase<N, S> impl<N: Real + Arbitrary> Arbitrary for Perspective3<N> {
where N: Real + Arbitrary,
S: OwnedStorage<N, U4, U4> + Send,
S::Alloc: OwnedAllocator<N, U4, U4, S> {
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
let znear = Arbitrary::arbitrary(g); let znear = Arbitrary::arbitrary(g);
let zfar = helper::reject(g, |&x: &N| !(x - znear).is_zero()); let zfar = helper::reject(g, |&x: &N| !(x - znear).is_zero());

View File

@ -1,101 +1,103 @@
use num::One; use num::One;
use std::hash;
use std::fmt; use std::fmt;
use std::cmp::Ordering; use std::cmp::Ordering;
use approx::ApproxEq; use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[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::iter::{MatrixIter, MatrixIterMut};
use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1};
use core::storage::{Storage, StorageMut, MulStorage}; use core::allocator::Allocator;
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<N, D1, D2, SA> =
PointBase<N, SameShapeR<D1, D2>,
<<SA as Storage<N, D1, U1>>::Alloc as Allocator<N, SameShapeR<D1, D2>, U1>>::Buffer>;
/// The type of the result of the multiplication of a point by a matrix.
pub type PointMul<N, R1, C1, SA> = PointBase<N, R1, MulStorage<N, R1, C1, U1, SA>>;
/// A point with an owned storage.
pub type OwnedPoint<N, D, A> = PointBase<N, D, <A as Allocator<N, D, U1>>::Buffer>;
/// A point in a n-dimensional euclidean space. /// A point in a n-dimensional euclidean space.
#[repr(C)] #[repr(C)]
#[derive(Hash, Debug)] #[derive(Debug)]
pub struct PointBase<N: Scalar, D: DimName, S: Storage<N, D, U1>> { pub struct Point<N: Scalar, D: DimName>
where DefaultAllocator: Allocator<N, D> {
/// The coordinates of this point, i.e., the shift from the origin. /// The coordinates of this point, i.e., the shift from the origin.
pub coords: ColumnVector<N, D, S> pub coords: VectorN<N, D>
} }
impl<N, D, S> Copy for PointBase<N, D, S> impl<N: Scalar + hash::Hash, D: DimName + hash::Hash> hash::Hash for Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D>,
D: DimName, <DefaultAllocator as Allocator<N, D>>::Buffer: hash::Hash {
S: Storage<N, D, U1> + Copy { } fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.coords.hash(state)
}
}
impl<N, D, S> Clone for PointBase<N, D, S> impl<N: Scalar, D: DimName> Copy for Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D>,
D: DimName, <DefaultAllocator as Allocator<N, D>>::Buffer: Copy { }
S: Storage<N, D, U1> + Clone {
impl<N: Scalar, D: DimName> Clone for Point<N, D>
where DefaultAllocator: Allocator<N, D>,
<DefaultAllocator as Allocator<N, D>>::Buffer: Clone {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
PointBase::from_coordinates(self.coords.clone()) Point::from_coordinates(self.coords.clone())
} }
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<N, D, S> Serialize for PointBase<N, D, S> impl<N: Scalar, D: DimName> serde::Serialize for Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D>,
D: DimName, <DefaultAllocator as Allocator<N, D>>::Buffer: serde::Serialize {
S: Storage<N, D, U1>,
ColumnVector<N, D, S>: Serialize,
{
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
where T: Serializer
{
self.coords.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize")] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
impl<'de, N, D, S> Deserialize<'de> for PointBase<N, D, S> where S: serde::Serializer {
where N: Scalar, self.coords.serialize(serializer)
D: DimName,
S: Storage<N, D, U1>,
ColumnVector<N, D, S>: Deserialize<'de>,
{
fn deserialize<T>(deserializer: T) -> Result<Self, T::Error>
where T: Deserializer<'de>
{
ColumnVector::deserialize(deserializer).map(|x| PointBase { coords: x })
}
}
impl<N: Scalar, D: DimName, S: Storage<N, D, U1>> PointBase<N, D, S> {
/// Creates a new point with the given coordinates.
#[inline]
pub fn from_coordinates(coords: ColumnVector<N, D, S>) -> PointBase<N, D, S> {
PointBase {
coords: coords
} }
}
} }
impl<N: Scalar, D: DimName, S: Storage<N, D, U1>> PointBase<N, D, S> { #[cfg(feature = "serde-serialize")]
/// Moves this point into one that owns its data. impl<'a, N: Scalar, D: DimName> serde::Deserialize<'a> for Point<N, D>
#[inline] where DefaultAllocator: Allocator<N, D>,
pub fn into_owned(self) -> OwnedPoint<N, D, S::Alloc> { <DefaultAllocator as Allocator<N, D>>::Buffer: serde::Deserialize<'a> {
PointBase::from_coordinates(self.coords.into_owned())
} fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where Des: serde::Deserializer<'a> {
let coords = VectorN::<N, D>::deserialize(deserializer)?;
Ok(Point::from_coordinates(coords))
}
}
impl<N: Scalar, D: DimName> Point<N, D>
where DefaultAllocator: Allocator<N, D> {
/// Clones this point into one that owns its data. /// Clones this point into one that owns its data.
#[inline] #[inline]
pub fn clone_owned(&self) -> OwnedPoint<N, D, S::Alloc> { pub fn clone(&self) -> Point<N, D> {
PointBase::from_coordinates(self.coords.clone_owned()) 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<N, DimNameSum<D, U1>>
where N: One,
D: DimNameAdd<U1>,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>> {
let mut res = unsafe {
VectorN::<_, DimNameSum<D, U1>>::new_uninitialized()
};
res.fixed_slice_mut::<D, U1>(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<N, D>) -> Point<N, D> {
Point {
coords: coords
}
} }
/// The dimension of this point. /// The dimension of this point.
@ -113,44 +115,26 @@ impl<N: Scalar, D: DimName, S: Storage<N, D, U1>> PointBase<N, D, S> {
/// Iterates through this point coordinates. /// Iterates through this point coordinates.
#[inline] #[inline]
pub fn iter(&self) -> MatrixIter<N, D, U1, S> { pub fn iter(&self) -> MatrixIter<N, D, U1, <DefaultAllocator as Allocator<N, D>>::Buffer> {
self.coords.iter() self.coords.iter()
} }
/// Gets a reference to i-th element of this point without bound-checking. /// Gets a reference to i-th element of this point without bound-checking.
#[inline] #[inline]
pub unsafe fn get_unchecked(&self, i: usize) -> &N { 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<N, DimNameSum<D, U1>, S::Alloc>
where N: One,
D: DimNameAdd<U1>,
S::Alloc: Allocator<N, DimNameSum<D, U1>, U1> {
let mut res = unsafe { OwnedColumnVector::<N, _, S::Alloc>::new_uninitialized() };
res.fixed_slice_mut::<D, U1>(0, 0).copy_from(&self.coords);
res[(D::dim(), 0)] = N::one();
res
}
}
impl<N: Scalar, D: DimName, S: StorageMut<N, D, U1>> PointBase<N, D, S> {
/// Mutably iterates through this point coordinates. /// Mutably iterates through this point coordinates.
#[inline] #[inline]
pub fn iter_mut(&mut self) -> MatrixIterMut<N, D, U1, S> { pub fn iter_mut(&mut self) -> MatrixIterMut<N, D, U1, <DefaultAllocator as Allocator<N, D>>::Buffer> {
self.coords.iter_mut() self.coords.iter_mut()
} }
/// Gets a mutable reference to i-th element of this point without bound-checking. /// Gets a mutable reference to i-th element of this point without bound-checking.
#[inline] #[inline]
pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut N { 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. /// Swaps two entries without bound-checking.
@ -160,9 +144,8 @@ impl<N: Scalar, D: DimName, S: StorageMut<N, D, U1>> PointBase<N, D, S> {
} }
} }
impl<N, D: DimName, S> ApproxEq for PointBase<N, D, S> impl<N: Scalar + ApproxEq, D: DimName> ApproxEq for Point<N, D>
where N: Scalar + ApproxEq, where DefaultAllocator: Allocator<N, D>,
S: Storage<N, D, U1>,
N::Epsilon: Copy { N::Epsilon: Copy {
type Epsilon = N::Epsilon; type Epsilon = N::Epsilon;
@ -192,22 +175,19 @@ impl<N, D: DimName, S> ApproxEq for PointBase<N, D, S>
} }
} }
impl<N, D: DimName, S> Eq for PointBase<N, D, S> impl<N: Scalar + Eq, D: DimName> Eq for Point<N, D>
where N: Scalar + Eq, where DefaultAllocator: Allocator<N, D> { }
S: Storage<N, D, U1> { }
impl<N, D: DimName, S> PartialEq for PointBase<N, D, S> impl<N: Scalar, D: DimName> PartialEq for Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.coords == right.coords self.coords == right.coords
} }
} }
impl<N, D: DimName, S> PartialOrd for PointBase<N, D, S> impl<N: Scalar + PartialOrd, D: DimName> PartialOrd for Point<N, D>
where N: Scalar + PartialOrd, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
#[inline] #[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.coords.partial_cmp(&other.coords) self.coords.partial_cmp(&other.coords)
@ -239,9 +219,8 @@ impl<N, D: DimName, S> PartialOrd for PointBase<N, D, S>
* Display * Display
* *
*/ */
impl<N, D: DimName, S> fmt::Display for PointBase<N, D, S> impl<N: Scalar + fmt::Display, D: DimName> fmt::Display for Point<N, D>
where N: Scalar + fmt::Display, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{")); try!(write!(f, "{{"));

View File

@ -1,26 +1,22 @@
use alga::general::{Field, Real, MeetSemilattice, JoinSemilattice, Lattice}; use alga::general::{Field, Real, MeetSemilattice, JoinSemilattice, Lattice};
use alga::linear::{AffineSpace, EuclideanSpace}; use alga::linear::{AffineSpace, EuclideanSpace};
use core::{ColumnVector, Scalar}; use core::{DefaultAllocator, Scalar, VectorN};
use core::dimension::{DimName, U1}; use core::dimension::DimName;
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::PointBase; use geometry::Point;
impl<N, D: DimName, S> AffineSpace for PointBase<N, D, S> impl<N: Scalar + Field, D: DimName> AffineSpace for Point<N, D>
where N: Scalar + Field, where N: Scalar + Field,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
S::Alloc: OwnedAllocator<N, D, U1, S> { type Translation = VectorN<N, D>;
type Translation = ColumnVector<N, D, S>;
} }
impl<N, D: DimName, S> EuclideanSpace for PointBase<N, D, S> impl<N: Real, D: DimName> EuclideanSpace for Point<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>, type Coordinates = VectorN<N, D>;
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Coordinates = ColumnVector<N, D, S>;
type Real = N; type Real = N;
#[inline] #[inline]
@ -49,35 +45,32 @@ impl<N, D: DimName, S> EuclideanSpace for PointBase<N, D, S>
* Ordering * Ordering
* *
*/ */
impl<N, D: DimName, S> MeetSemilattice for PointBase<N, D, S> impl<N, D: DimName> MeetSemilattice for Point<N, D>
where N: Scalar + MeetSemilattice, where N: Scalar + MeetSemilattice,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn meet(&self, other: &Self) -> Self { fn meet(&self, other: &Self) -> Self {
PointBase::from_coordinates(self.coords.meet(&other.coords)) Point::from_coordinates(self.coords.meet(&other.coords))
} }
} }
impl<N, D: DimName, S> JoinSemilattice for PointBase<N, D, S> impl<N, D: DimName> JoinSemilattice for Point<N, D>
where N: Scalar + JoinSemilattice, where N: Scalar + JoinSemilattice,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn join(&self, other: &Self) -> Self { fn join(&self, other: &Self) -> Self {
PointBase::from_coordinates(self.coords.join(&other.coords)) Point::from_coordinates(self.coords.join(&other.coords))
} }
} }
impl<N, D: DimName, S> Lattice for PointBase<N, D, S> impl<N, D: DimName> Lattice for Point<N, D>
where N: Scalar + Lattice, where N: Scalar + Lattice,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn meet_join(&self, other: &Self) -> (Self, Self) { fn meet_join(&self, other: &Self) -> (Self, Self) {
let (meet, join) = self.coords.meet_join(&other.coords); 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))
} }
} }

View File

@ -1,10 +1,6 @@
use core::MatrixArray;
use core::dimension::{U1, U2, U3, U4, U5, U6}; use core::dimension::{U1, U2, U3, U4, U5, U6};
use geometry::PointBase; use geometry::Point;
/// A statically sized D-dimensional column point.
pub type Point<N, D> = PointBase<N, D, MatrixArray<N, D, U1>>;
/// A statically sized 1-dimensional column point. /// A statically sized 1-dimensional column point.
pub type Point1<N> = Point<N, U1>; pub type Point1<N> = Point<N, U1>;

View File

@ -5,28 +5,25 @@ use rand::{Rand, Rng};
use num::{Zero, One, Bounded}; use num::{Zero, One, Bounded};
use alga::general::ClosedDiv; use alga::general::ClosedDiv;
use core::{Scalar, ColumnVector}; use core::{DefaultAllocator, Scalar, VectorN};
use core::storage::{Storage, OwnedStorage}; use core::allocator::Allocator;
use core::allocator::{Allocator, OwnedAllocator};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3, U4, U5, U6}; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3, U4, U5, U6};
use geometry::PointBase; use geometry::Point;
impl<N, D: DimName, S> PointBase<N, D, S> impl<N: Scalar, D: DimName> Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// Creates a new point with uninitialized coordinates. /// Creates a new point with uninitialized coordinates.
#[inline] #[inline]
pub unsafe fn new_uninitialized() -> Self { 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. /// Creates a new point with all coordinates equal to zero.
#[inline] #[inline]
pub fn origin() -> Self pub fn origin() -> Self
where N: Zero { 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. /// Creates a new point from its homogeneous vector representation.
@ -34,11 +31,10 @@ impl<N, D: DimName, S> PointBase<N, D, S>
/// In practice, this builds a D-dimensional points with the same first D component as `v` /// 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. /// divided by the last component of `v`. Returns `None` if this divisor is zero.
#[inline] #[inline]
pub fn from_homogeneous<SB>(v: ColumnVector<N, DimNameSum<D, U1>, SB>) -> Option<Self> pub fn from_homogeneous(v: VectorN<N, DimNameSum<D, U1>>) -> Option<Self>
where N: Scalar + Zero + One + ClosedDiv, where N: Scalar + Zero + One + ClosedDiv,
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
SB: Storage<N, DimNameSum<D, U1>, U1, Alloc = S::Alloc>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>> {
S::Alloc: Allocator<N, DimNameSum<D, U1>, U1> {
if !v[D::dim()].is_zero() { if !v[D::dim()].is_zero() {
let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()]; let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
@ -56,39 +52,34 @@ impl<N, D: DimName, S> PointBase<N, D, S>
* Traits that buid points. * Traits that buid points.
* *
*/ */
impl<N, D: DimName, S> Bounded for PointBase<N, D, S> impl<N: Scalar + Bounded, D: DimName> Bounded for Point<N, D>
where N: Scalar + Bounded, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn max_value() -> Self { fn max_value() -> Self {
Self::from_coordinates(ColumnVector::max_value()) Self::from_coordinates(VectorN::max_value())
} }
#[inline] #[inline]
fn min_value() -> Self { fn min_value() -> Self {
Self::from_coordinates(ColumnVector::min_value()) Self::from_coordinates(VectorN::min_value())
} }
} }
impl<N, D: DimName, S> Rand for PointBase<N, D, S> impl<N: Scalar + Rand, D: DimName> Rand for Point<N, D>
where N: Scalar + Rand, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn rand<G: Rng>(rng: &mut G) -> Self { fn rand<G: Rng>(rng: &mut G) -> Self {
PointBase::from_coordinates(rng.gen()) Point::from_coordinates(rng.gen())
} }
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N, D: DimName, S> Arbitrary for PointBase<N, D, S> impl<N: Scalar + Arbitrary + Send, D: DimName> Arbitrary for Point<N, D>
where N: Scalar + Arbitrary + Send, where DefaultAllocator: Allocator<N, D>,
S: OwnedStorage<N, D, U1> + Send, <DefaultAllocator as Allocator<N, D>>::Buffer: Send {
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
PointBase::from_coordinates(ColumnVector::arbitrary(g)) Point::from_coordinates(VectorN::arbitrary(g))
} }
} }
@ -99,13 +90,11 @@ impl<N, D: DimName, S> Arbitrary for PointBase<N, D, S>
*/ */
macro_rules! componentwise_constructors_impl( macro_rules! componentwise_constructors_impl(
($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$( ($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<N, S> PointBase<N, $D, S> impl<N: Scalar> Point<N, $D>
where N: Scalar, where DefaultAllocator: Allocator<N, $D> {
S: OwnedStorage<N, $D, U1>,
S::Alloc: OwnedAllocator<N, $D, U1, S> {
/// Initializes this matrix from its components. /// Initializes this matrix from its components.
#[inline] #[inline]
pub fn new($($args: N),*) -> PointBase<N, $D, S> { pub fn new($($args: N),*) -> Point<N, $D> {
unsafe { unsafe {
let mut res = Self::new_uninitialized(); let mut res = Self::new_uninitialized();
$( *res.get_unchecked_mut($irow) = $args; )* $( *res.get_unchecked_mut($irow) = $args; )*

View File

@ -1,72 +1,67 @@
use num::{One, Zero}; use num::{One, Zero};
use alga::general::{SubsetOf, SupersetOf, ClosedDiv}; 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::dimension::{DimName, DimNameSum, DimNameAdd, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::{Allocator, OwnedAllocator};
use geometry::{PointBase, OwnedPoint}; use geometry::Point;
/* /*
* This file provides the following conversions: * This file provides the following conversions:
* ============================================= * =============================================
* *
* PointBase -> PointBase * Point -> Point
* PointBase -> ColumnVector (homogeneous) * Point -> Vector (homogeneous)
*/ */
impl<N1, N2, D, SA, SB> SubsetOf<PointBase<N2, D, SB>> for PointBase<N1, D, SA> impl<N1, N2, D> SubsetOf<Point<N2, D>> for Point<N1, D>
where D: DimName, where D: DimName,
N1: Scalar, N1: Scalar,
N2: Scalar + SupersetOf<N1>, N2: Scalar + SupersetOf<N1>,
SA: OwnedStorage<N1, D, U1>, DefaultAllocator: Allocator<N2, D> +
SB: OwnedStorage<N2, D, U1>, Allocator<N1, D> {
SB::Alloc: OwnedAllocator<N2, D, U1, SB>,
SA::Alloc: OwnedAllocator<N1, D, U1, SA> {
#[inline] #[inline]
fn to_superset(&self) -> PointBase<N2, D, SB> { fn to_superset(&self) -> Point<N2, D> {
PointBase::from_coordinates(self.coords.to_superset()) Point::from_coordinates(self.coords.to_superset())
} }
#[inline] #[inline]
fn is_in_subset(m: &PointBase<N2, D, SB>) -> bool { fn is_in_subset(m: &Point<N2, D>) -> bool {
// FIXME: is there a way to reuse the `.is_in_subset` from the matrix implementation of // FIXME: is there a way to reuse the `.is_in_subset` from the matrix implementation of
// SubsetOf? // SubsetOf?
m.iter().all(|e| e.is_in_subset()) m.iter().all(|e| e.is_in_subset())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &PointBase<N2, D, SB>) -> Self { unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self {
PointBase::from_coordinates(Matrix::from_superset_unchecked(&m.coords)) Point::from_coordinates(Matrix::from_superset_unchecked(&m.coords))
} }
} }
impl<N1, N2, D, SA, SB> SubsetOf<ColumnVector<N2, DimNameSum<D, U1>, SB>> for PointBase<N1, D, SA> impl<N1, N2, D> SubsetOf<VectorN<N2, DimNameSum<D, U1>>> for Point<N1, D>
where D: DimNameAdd<U1>, where D: DimNameAdd<U1>,
N1: Scalar, N1: Scalar,
N2: Scalar + Zero + One + ClosedDiv + SupersetOf<N1>, N2: Scalar + Zero + One + ClosedDiv + SupersetOf<N1>,
SA: OwnedStorage<N1, D, U1>, DefaultAllocator: Allocator<N1, D> +
SB: OwnedStorage<N2, DimNameSum<D, U1>, U1>, Allocator<N1, DimNameSum<D, U1>> +
SA::Alloc: OwnedAllocator<N1, D, U1, SA> + Allocator<N2, DimNameSum<D, U1>> +
Allocator<N1, DimNameSum<D, U1>, U1>, Allocator<N2, D> {
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, U1, SB> +
Allocator<N2, D, U1> {
#[inline] #[inline]
fn to_superset(&self) -> ColumnVector<N2, DimNameSum<D, U1>, SB> { fn to_superset(&self) -> VectorN<N2, DimNameSum<D, U1>> {
let p: OwnedPoint<N2, D, SB::Alloc> = self.to_superset(); let p: Point<N2, D> = self.to_superset();
p.to_homogeneous() p.to_homogeneous()
} }
#[inline] #[inline]
fn is_in_subset(v: &ColumnVector<N2, DimNameSum<D, U1>, SB>) -> bool { fn is_in_subset(v: &VectorN<N2, DimNameSum<D, U1>>) -> bool {
::is_convertible::<_, OwnedColumnVector<N1, DimNameSum<D, U1>, SA::Alloc>>(v) && ::is_convertible::<_, VectorN<N1, DimNameSum<D, U1>>>(v) &&
!v[D::dim()].is_zero() !v[D::dim()].is_zero()
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(v: &ColumnVector<N2, DimNameSum<D, U1>, SB>) -> Self { unsafe fn from_superset_unchecked(v: &VectorN<N2, DimNameSum<D, U1>>) -> Self {
let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()]; let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
Self::from_coordinates(::convert_unchecked(coords)) Self::from_coordinates(::convert_unchecked(coords))
} }

View File

@ -1,25 +1,23 @@
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use core::Scalar; use core::{DefaultAllocator, Scalar};
use core::dimension::{U1, U2, U3, U4, U5, U6}; use core::dimension::{U1, U2, U3, U4, U5, U6};
use core::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; use core::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
use core::allocator::OwnedAllocator; use core::allocator::Allocator;
use core::storage::OwnedStorage;
use geometry::PointBase; use geometry::Point;
/* /*
* *
* Give coordinates to PointBase{1 .. 6} * Give coordinates to Point{1 .. 6}
* *
*/ */
macro_rules! deref_impl( macro_rules! deref_impl(
($D: ty, $Target: ident $(, $comps: ident)*) => { ($D: ty, $Target: ident $(, $comps: ident)*) => {
impl<N: Scalar, S> Deref for PointBase<N, $D, S> impl<N: Scalar> Deref for Point<N, $D>
where S: OwnedStorage<N, $D, U1>, where DefaultAllocator: Allocator<N, $D> {
S::Alloc: OwnedAllocator<N, $D, U1, S> {
type Target = $Target<N>; type Target = $Target<N>;
#[inline] #[inline]
@ -28,9 +26,8 @@ macro_rules! deref_impl(
} }
} }
impl<N: Scalar, S> DerefMut for PointBase<N, $D, S> impl<N: Scalar> DerefMut for Point<N, $D>
where S: OwnedStorage<N, $D, U1>, where DefaultAllocator: Allocator<N, $D> {
S::Alloc: OwnedAllocator<N, $D, U1, S> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self) }

View File

@ -1,15 +1,15 @@
use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Index, IndexMut}; 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 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::dimension::{Dim, DimName, U1};
use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns, AreMultipliable};
use core::storage::{Storage, StorageMut}; use core::storage::Storage;
use core::allocator::{SameShapeAllocator, Allocator}; use core::allocator::{SameShapeAllocator, Allocator};
use geometry::{PointBase, OwnedPoint, PointMul}; use geometry::Point;
/* /*
@ -17,9 +17,8 @@ use geometry::{PointBase, OwnedPoint, PointMul};
* Indexing. * Indexing.
* *
*/ */
impl<N, D: DimName, S> Index<usize> for PointBase<N, D, S> impl<N: Scalar, D: DimName> Index<usize> for Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
type Output = N; type Output = N;
#[inline] #[inline]
@ -28,9 +27,8 @@ impl<N, D: DimName, S> Index<usize> for PointBase<N, D, S>
} }
} }
impl<N, D: DimName, S> IndexMut<usize> for PointBase<N, D, S> impl<N: Scalar, D: DimName> IndexMut<usize> for Point<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D> {
S: StorageMut<N, D, U1> {
#[inline] #[inline]
fn index_mut(&mut self, i: usize) -> &mut Self::Output { fn index_mut(&mut self, i: usize) -> &mut Self::Output {
&mut self.coords[i] &mut self.coords[i]
@ -38,28 +36,27 @@ impl<N, D: DimName, S> IndexMut<usize> for PointBase<N, D, S>
} }
/* /*
*
* Neg. * Neg.
* *
*/ */
impl<N, D: DimName, S> Neg for PointBase<N, D, S> impl<N: Scalar + ClosedNeg, D: DimName> Neg for Point<N, D>
where N: Scalar + ClosedNeg, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> { type Output = Point<N, D>;
type Output = OwnedPoint<N, D, S::Alloc>;
#[inline] #[inline]
fn neg(self) -> Self::Output { 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<N, D, S> impl<'a, N: Scalar + ClosedNeg, D: DimName> Neg for &'a Point<N, D>
where N: Scalar + ClosedNeg, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> { type Output = Point<N, D>;
type Output = OwnedPoint<N, D, S::Alloc>;
#[inline] #[inline]
fn neg(self) -> Self::Output { 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<N, D, S>
* *
*/ */
// PointBase - PointBase // Point - Point
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D, U1), (D, U1) for D: DimName; (D, U1), (D, U1) for D: DimName;
self: &'a PointBase<N, D, SA>, right: &'b PointBase<N, D, SB>, Output = ColumnVectorSum<N, D, D, SA>; self: &'a Point<N, D>, right: &'b Point<N, D>, Output = VectorSum<N, D, D>;
&self.coords - &right.coords; 'a, 'b); &self.coords - &right.coords; 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D, U1), (D, U1) for D: DimName; (D, U1), (D, U1) for D: DimName;
self: &'a PointBase<N, D, SB>, right: PointBase<N, D, SA>, Output = ColumnVectorSum<N, D, D, SA>; self: &'a Point<N, D>, right: Point<N, D>, Output = VectorSum<N, D, D>;
&self.coords - right.coords; 'a); &self.coords - right.coords; 'a);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D, U1), (D, U1) for D: DimName; (D, U1), (D, U1) for D: DimName;
self: PointBase<N, D, SA>, right: &'b PointBase<N, D, SB>, Output = ColumnVectorSum<N, D, D, SA>; self: Point<N, D>, right: &'b Point<N, D>, Output = VectorSum<N, D, D>;
self.coords - &right.coords; 'b); self.coords - &right.coords; 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D, U1), (D, U1) for D: DimName; (D, U1), (D, U1) for D: DimName;
self: PointBase<N, D, SA>, right: PointBase<N, D, SB>, Output = ColumnVectorSum<N, D, D, SA>; self: Point<N, D>, right: Point<N, D>, Output = VectorSum<N, D, D>;
self.coords - right.coords; ); self.coords - right.coords; );
// PointBase - Vector // Point - Vector
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a PointBase<N, D1, SA>, right: &'b ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: &'a Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords - right); 'a, 'b); Self::Output::from_coordinates(&self.coords - right); 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a PointBase<N, D1, SA>, right: ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: &'a Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords - &right); 'a); // FIXME: should not be a ref to `right`. Self::Output::from_coordinates(&self.coords - &right); 'a); // FIXME: should not be a ref to `right`.
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: PointBase<N, D1, SA>, right: &'b ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords - right); 'b); Self::Output::from_coordinates(self.coords - right); 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: PointBase<N, D1, SA>, right: ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords - right); ); Self::Output::from_coordinates(self.coords - right); );
// PointBase + Vector // Point + Vector
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a PointBase<N, D1, SA>, right: &'b ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: &'a Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords + right); 'a, 'b); Self::Output::from_coordinates(&self.coords + right); 'a, 'b);
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a PointBase<N, D1, SA>, right: ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: &'a Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords + &right); 'a); // FIXME: should not be a ref to `right`. Self::Output::from_coordinates(&self.coords + &right); 'a); // FIXME: should not be a ref to `right`.
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: PointBase<N, D1, SA>, right: &'b ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords + right); 'b); Self::Output::from_coordinates(self.coords + right); 'b);
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: PointBase<N, D1, SA>, right: ColumnVector<N, D2, SB>, Output = OwnedPoint<N, D1, SA::Alloc>; self: Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords + right); ); Self::Output::from_coordinates(self.coords + right); );
// XXX: replace by the shared macro: add_sub_assign_impl // XXX: replace by the shared macro: add_sub_assign_impl
macro_rules! op_assign_impl( macro_rules! op_assign_impl(
($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$( ($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$(
impl<'b, N, D1: DimName, D2: Dim, SA, SB> $TraitAssign<&'b ColumnVector<N, D2, SB>> for PointBase<N, D1, SA> impl<'b, N, D1: DimName, D2: Dim, SB> $TraitAssign<&'b Vector<N, D2, SB>> for Point<N, D1>
where N: Scalar + $bound, where N: Scalar + $bound,
SA: StorageMut<N, D1, U1>, SB: Storage<N, D2>,
SB: Storage<N, D2, U1>, DefaultAllocator: Allocator<N, D1>,
ShapeConstraint: SameNumberOfRows<D1, D2> { ShapeConstraint: SameNumberOfRows<D1, D2> {
#[inline] #[inline]
fn $method_assign(&mut self, right: &'b ColumnVector<N, D2, SB>) { fn $method_assign(&mut self, right: &'b Vector<N, D2, SB>) {
self.coords.$method_assign(right) self.coords.$method_assign(right)
} }
} }
impl<N, D1: DimName, D2: Dim, SA, SB> $TraitAssign<ColumnVector<N, D2, SB>> for PointBase<N, D1, SA> impl<N, D1: DimName, D2: Dim, SB> $TraitAssign<Vector<N, D2, SB>> for Point<N, D1>
where N: Scalar + $bound, where N: Scalar + $bound,
SA: StorageMut<N, D1, U1>, SB: Storage<N, D2>,
SB: Storage<N, D2, U1>, DefaultAllocator: Allocator<N, D1>,
ShapeConstraint: SameNumberOfRows<D1, D2> { ShapeConstraint: SameNumberOfRows<D1, D2> {
#[inline] #[inline]
fn $method_assign(&mut self, right: ColumnVector<N, D2, SB>) { fn $method_assign(&mut self, right: Vector<N, D2, SB>) {
self.coords.$method_assign(right) self.coords.$method_assign(right)
} }
} }
@ -171,56 +168,52 @@ op_assign_impl!(
/* /*
* *
* Matrix × PointBase * Matrix × Point
* *
*/ */
md_impl_all!( md_impl_all!(
Mul, mul; Mul, mul;
(R1, C1), (D2, U1) for R1: DimName, C1: Dim, D2: DimName (R1, C1), (D2, U1) for R1: DimName, C1: Dim, D2: DimName, SA: Storage<N, R1, C1>
where SA::Alloc: Allocator<N, R1, U1>
where ShapeConstraint: AreMultipliable<R1, C1, D2, U1>; where ShapeConstraint: AreMultipliable<R1, C1, D2, U1>;
self: Matrix<N, R1, C1, SA>, right: PointBase<N, D2, SB>, Output = PointMul<N, R1, C1, SA>; self: Matrix<N, R1, C1, SA>, right: Point<N, D2>, Output = Point<N, R1>;
[val val] => PointBase::from_coordinates(self * right.coords); [val val] => Point::from_coordinates(self * right.coords);
[ref val] => PointBase::from_coordinates(self * right.coords); [ref val] => Point::from_coordinates(self * right.coords);
[val ref] => PointBase::from_coordinates(self * &right.coords); [val ref] => Point::from_coordinates(self * &right.coords);
[ref ref] => PointBase::from_coordinates(self * &right.coords); [ref ref] => Point::from_coordinates(self * &right.coords);
); );
/* /*
* *
* PointBase ×/÷ Scalar * Point ×/÷ Scalar
* *
*/ */
macro_rules! componentwise_scalarop_impl( macro_rules! componentwise_scalarop_impl(
($Trait: ident, $method: ident, $bound: ident; ($Trait: ident, $method: ident, $bound: ident;
$TraitAssign: ident, $method_assign: ident) => { $TraitAssign: ident, $method_assign: ident) => {
impl<N, D: DimName, S> $Trait<N> for PointBase<N, D, S> impl<N: Scalar + $bound, D: DimName> $Trait<N> for Point<N, D>
where N: Scalar + $bound, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> { type Output = Point<N, D>;
type Output = OwnedPoint<N, D, S::Alloc>;
#[inline] #[inline]
fn $method(self, right: N) -> Self::Output { 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<N> for &'a PointBase<N, D, S> impl<'a, N: Scalar + $bound, D: DimName> $Trait<N> for &'a Point<N, D>
where N: Scalar + $bound, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> { type Output = Point<N, D>;
type Output = OwnedPoint<N, D, S::Alloc>;
#[inline] #[inline]
fn $method(self, right: N) -> Self::Output { fn $method(self, right: N) -> Self::Output {
PointBase::from_coordinates((&self.coords).$method(right)) Point::from_coordinates((&self.coords).$method(right))
} }
} }
impl<N, D: DimName, S> $TraitAssign<N> for PointBase<N, D, S> impl<N: Scalar + $bound, D: DimName> $TraitAssign<N> for Point<N, D>
where N: Scalar + $bound, where DefaultAllocator: Allocator<N, D> {
S: StorageMut<N, D, U1> {
#[inline] #[inline]
fn $method_assign(&mut self, right: N) { fn $method_assign(&mut self, right: N) {
self.coords.$method_assign(right) self.coords.$method_assign(right)
@ -234,23 +227,23 @@ componentwise_scalarop_impl!(Div, div, ClosedDiv; DivAssign, div_assign);
macro_rules! left_scalar_mul_impl( macro_rules! left_scalar_mul_impl(
($($T: ty),* $(,)*) => {$( ($($T: ty),* $(,)*) => {$(
impl<D: DimName, S> Mul<PointBase<$T, D, S>> for $T impl<D: DimName> Mul<Point<$T, D>> for $T
where S: Storage<$T, D, U1> { where DefaultAllocator: Allocator<$T, D> {
type Output = OwnedPoint<$T, D, S::Alloc>; type Output = Point<$T, D>;
#[inline] #[inline]
fn mul(self, right: PointBase<$T, D, S>) -> Self::Output { fn mul(self, right: Point<$T, D>) -> Self::Output {
PointBase::from_coordinates(self * right.coords) Point::from_coordinates(self * right.coords)
} }
} }
impl<'b, D: DimName, S> Mul<&'b PointBase<$T, D, S>> for $T impl<'b, D: DimName> Mul<&'b Point<$T, D>> for $T
where S: Storage<$T, D, U1> { where DefaultAllocator: Allocator<$T, D> {
type Output = OwnedPoint<$T, D, S::Alloc>; type Output = Point<$T, D>;
#[inline] #[inline]
fn mul(self, right: &'b PointBase<$T, D, S>) -> Self::Output { fn mul(self, right: &'b Point<$T, D>) -> Self::Output {
PointBase::from_coordinates(self * &right.coords) Point::from_coordinates(self * &right.coords)
} }
} }
)*} )*}

View File

@ -1,70 +1,34 @@
use std::fmt; use std::fmt;
use std::hash;
use num::Zero; use num::Zero;
use approx::ApproxEq; use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[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 alga::general::Real;
use core::{Unit, ColumnVector, OwnedColumnVector, MatrixSlice, MatrixSliceMut, SquareMatrix, use core::{Unit, Vector3, Vector4, MatrixSlice, MatrixSliceMut, SquareMatrix, MatrixN};
OwnedSquareMatrix};
use core::storage::{Storage, StorageMut};
use core::allocator::Allocator;
use core::dimension::{U1, U3, U4}; 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`. /// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
pub type OwnedQuaternionBase<N, A> = QuaternionBase<N, <A as Allocator<N, U4, U1>>::Buffer>;
/// A unit quaternion with an owned storage allocated by `A`.
pub type OwnedUnitQuaternionBase<N, A> = UnitQuaternionBase<N, <A as Allocator<N, U4, U1>>::Buffer>;
/// A quaternion. See the type alias `UnitQuaternionBase = Unit<QuaternionBase>` for a quaternion
/// that may be used as a rotation. /// that may be used as a rotation.
#[repr(C)] #[repr(C)]
#[derive(Hash, Debug, Copy, Clone)] #[derive(Debug)]
pub struct QuaternionBase<N: Real, S: Storage<N, U4, U1>> { pub struct Quaternion<N: Real> {
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
pub coords: ColumnVector<N, U4, S> pub coords: Vector4<N>
} }
#[cfg(feature = "serde-serialize")] impl<N: Real + Eq> Eq for Quaternion<N> {
impl<N, S> Serialize for QuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1>,
ColumnVector<N, U4, S>: Serialize,
{
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
where T: Serializer
{
self.coords.serialize(serializer)
}
} }
#[cfg(feature = "serde-serialize")] impl<N: Real> PartialEq for Quaternion<N> {
impl<'de, N, S> Deserialize<'de> for QuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1>,
ColumnVector<N, U4, S>: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
ColumnVector::deserialize(deserializer).map(|x| QuaternionBase { coords: x })
}
}
impl<N, S> Eq for QuaternionBase<N, S>
where N: Real + Eq,
S: Storage<N, U4, U1> {
}
impl<N, S> PartialEq for QuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1> {
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
self.coords == rhs.coords || self.coords == rhs.coords ||
// Account for the double-covering of S², i.e. q = -q // Account for the double-covering of S², i.e. q = -q
@ -72,24 +36,91 @@ impl<N, S> PartialEq for QuaternionBase<N, S>
} }
} }
impl<N, S> QuaternionBase<N, S> impl<N: Real + hash::Hash> hash::Hash for Quaternion<N> {
where N: Real, fn hash<H: hash::Hasher>(&self, state: &mut H) {
S: Storage<N, U4, U1> { self.coords.hash(state)
/// Moves this quaternion into one that owns its data. }
}
impl<N: Real> Copy for Quaternion<N> { }
impl<N: Real> Clone for Quaternion<N> {
#[inline] #[inline]
pub fn into_owned(self) -> OwnedQuaternionBase<N, S::Alloc> { fn clone(&self) -> Self {
QuaternionBase::from_vector(self.coords.into_owned()) Quaternion::from_vector(self.coords.clone())
}
}
#[cfg(feature = "serde-serialize")]
impl<N: Real> serde::Serialize for Quaternion<N>
where Owned<N, U4>: serde::Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
self.coords.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize")]
impl<'a, N: Real> serde::Deserialize<'a> for Quaternion<N>
where Owned<N, U4>: serde::Deserialize<'a> {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where Des: serde::Deserializer<'a> {
let coords = Vector4::<N>::deserialize(deserializer)?;
Ok(Quaternion::from_vector(coords))
}
}
impl<N: Real> Quaternion<N> {
/// Moves this unit quaternion into one that owns its data.
#[inline]
pub fn into_owned(self) -> Quaternion<N> {
self
} }
/// Clones this quaternion into one that owns its data. /// Clones this unit quaternion into one that owns its data.
#[inline] #[inline]
pub fn clone_owned(&self) -> OwnedQuaternionBase<N, S::Alloc> { pub fn clone_owned(&self) -> Quaternion<N> {
QuaternionBase::from_vector(self.coords.clone_owned()) Quaternion::from_vector(self.coords.clone_owned())
}
/// Normalizes this quaternion.
#[inline]
pub fn normalize(&self) -> Quaternion<N> {
Quaternion::from_vector(self.coords.normalize())
}
/// Compute the conjugate of this quaternion.
#[inline]
pub fn conjugate(&self) -> Quaternion<N> {
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<Quaternion<N>> {
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<N>, t: N) -> Quaternion<N> {
self * (N::one() - t) + other * t
} }
/// The vector part `(i, j, k)` of this quaternion. /// The vector part `(i, j, k)` of this quaternion.
#[inline] #[inline]
pub fn vector(&self) -> MatrixSlice<N, U3, U1, S::RStride, S::CStride, S::Alloc> { pub fn vector(&self) -> MatrixSlice<N, U3, U1, RStride<N, U4, U1>, CStride<N, U4, U1>> {
self.coords.fixed_rows::<U3>(0) self.coords.fixed_rows::<U3>(0)
} }
@ -101,7 +132,7 @@ impl<N, S> QuaternionBase<N, S>
/// Reinterprets this quaternion as a 4D vector. /// Reinterprets this quaternion as a 4D vector.
#[inline] #[inline]
pub fn as_vector(&self) -> &ColumnVector<N, U4, S> { pub fn as_vector(&self) -> &Vector4<N> {
&self.coords &self.coords
} }
@ -117,53 +148,11 @@ impl<N, S> QuaternionBase<N, S>
self.coords.norm_squared() self.coords.norm_squared()
} }
/// Normalizes this quaternion.
#[inline]
pub fn normalize(&self) -> OwnedQuaternionBase<N, S::Alloc> {
QuaternionBase::from_vector(self.coords.normalize())
}
/// Compute the conjugate of this quaternion.
#[inline]
pub fn conjugate(&self) -> OwnedQuaternionBase<N, S::Alloc> {
let v = OwnedColumnVector::<N, U4, S::Alloc>::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<OwnedQuaternionBase<N, S::Alloc>> {
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<S2>(&self, other: &QuaternionBase<N, S2>, t: N) -> OwnedQuaternionBase<N, S::Alloc>
where S2: Storage<N, U4, U1> {
self * (N::one() - t) + other * t
}
}
impl<N, S> QuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1>,
S::Alloc: Allocator<N, U3, U1> {
/// The polar decomposition of this quaternion. /// The polar decomposition of this quaternion.
/// ///
/// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation /// 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`. /// axis. If the rotation angle is zero, the rotation axis is set to `None`.
pub fn polar_decomposition(&self) -> (N, N, Option<Unit<OwnedColumnVector<N, U3, S::Alloc>>>) { pub fn polar_decomposition(&self) -> (N, N, Option<Unit<Vector3<N>>>) {
if let Some((q, n)) = Unit::try_new_and_get(self.clone_owned(), N::zero()) { 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()) { if let Some(axis) = Unit::try_new(self.vector().clone_owned(), N::zero()) {
let angle = q.angle() / ::convert(2.0f64); let angle = q.angle() / ::convert(2.0f64);
@ -181,51 +170,47 @@ impl<N, S> QuaternionBase<N, S>
/// Compute the exponential of a quaternion. /// Compute the exponential of a quaternion.
#[inline] #[inline]
pub fn exp(&self) -> OwnedQuaternionBase<N, S::Alloc> { pub fn exp(&self) -> Quaternion<N> {
let v = self.vector(); let v = self.vector();
let nn = v.norm_squared(); let nn = v.norm_squared();
if relative_eq!(nn, N::zero()) { if relative_eq!(nn, N::zero()) {
QuaternionBase::identity() Quaternion::identity()
} }
else { else {
let w_exp = self.scalar().exp(); let w_exp = self.scalar().exp();
let n = nn.sqrt(); let n = nn.sqrt();
let nv = v * (w_exp * n.sin() / n); 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. /// Compute the natural logarithm of a quaternion.
#[inline] #[inline]
pub fn ln(&self) -> OwnedQuaternionBase<N, S::Alloc> { pub fn ln(&self) -> Quaternion<N> {
let n = self.norm(); let n = self.norm();
let v = self.vector(); let v = self.vector();
let s = self.scalar(); 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. /// Raise the quaternion to a given floating power.
#[inline] #[inline]
pub fn powf(&self, n: N) -> OwnedQuaternionBase<N, S::Alloc> { pub fn powf(&self, n: N) -> Quaternion<N> {
(self.ln() * n).exp() (self.ln() * n).exp()
} }
}
impl<N, S> QuaternionBase<N, S>
where N: Real,
S: StorageMut<N, U4, U1> {
/// Transforms this quaternion into its 4D vector form (Vector part, Scalar part). /// Transforms this quaternion into its 4D vector form (Vector part, Scalar part).
#[inline] #[inline]
pub fn as_vector_mut(&mut self) -> &mut ColumnVector<N, U4, S> { pub fn as_vector_mut(&mut self) -> &mut Vector4<N> {
&mut self.coords &mut self.coords
} }
/// The mutable vector part `(i, j, k)` of this quaternion. /// The mutable vector part `(i, j, k)` of this quaternion.
#[inline] #[inline]
pub fn vector_mut(&mut self) -> MatrixSliceMut<N, U3, U1, S::RStride, S::CStride, S::Alloc> { pub fn vector_mut(&mut self) -> MatrixSliceMut<N, U3, U1, RStride<N, U4, U1>, CStride<N, U4, U1>> {
self.coords.fixed_rows_mut::<U3>(0) self.coords.fixed_rows_mut::<U3>(0)
} }
@ -260,9 +245,7 @@ impl<N, S> QuaternionBase<N, S>
} }
} }
impl<N, S> ApproxEq for QuaternionBase<N, S> impl<N: Real + ApproxEq<Epsilon = N>> ApproxEq for Quaternion<N> {
where N: Real + ApproxEq<Epsilon = N>,
S: Storage<N, U4, U1> {
type Epsilon = N; type Epsilon = N;
#[inline] #[inline]
@ -296,9 +279,7 @@ impl<N, S> ApproxEq for QuaternionBase<N, S>
} }
impl<N, S> fmt::Display for QuaternionBase<N, S> impl<N: Real + fmt::Display> fmt::Display for Quaternion<N> {
where N: Real + fmt::Display,
S: Storage<N, U4, U1> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Quaternion {} ({}, {}, {})", self[3], self[0], self[1], self[2]) write!(f, "Quaternion {} ({}, {}, {})", self[3], self[0], self[1], self[2])
} }
@ -325,118 +306,115 @@ impl<N, S> fmt::Display for QuaternionBase<N, S>
/// <code>fn <a class="fnname">angle</a>(&self) -> N</code> /// <code>fn <a class="fnname">angle</a>(&self) -> N</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">angle_to</a>(&self, other: &UnitQuaternionBase) -> N</code> /// <code>fn <a class="fnname">angle_to</a>(&self, other: &UnitQuaternion) -> N</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">axis</a>(&self) -> Option&lt;Unit&lt;OwnedColumnVector&gt;&gt;</code> /// <code>fn <a class="fnname">axis</a>(&self) -> Option&lt;Unit&lt;Vector3&gt;&gt;</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">clone_owned</a>(&self) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">clone_owned</a>(&self) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">conjugate_mut</a>(&mut self)</code> /// <code>fn <a class="fnname">conjugate_mut</a>(&mut self)</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">conjugate</a>(&self) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">conjugate</a>(&self) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">exp</a>(&self) -> OwnedQuaternionBase</code> /// <code>fn <a class="fnname">exp</a>(&self) -> Quaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">from_axis_angle</a>(axis: &Unit&lt;ColumnVector&gt;, angle: N) -> Self</code> /// <code>fn <a class="fnname">from_axis_angle</a>(axis: &Unit&lt;Vector&gt;, angle: N) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">from_euler_angles</a>(roll: N, pitch: N, yaw: N) -> Self</code> /// <code>fn <a class="fnname">from_euler_angles</a>(roll: N, pitch: N, yaw: N) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">from_quaternion</a>(q: QuaternionBase) -> Self</code> /// <code>fn <a class="fnname">from_quaternion</a>(q: Quaternion) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">from_rotation_matrix</a>(rotmat: &RotationBase) -> Self</code> /// <code>fn <a class="fnname">from_rotation_matrix</a>(rotmat: &Rotation) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">from_scaled_axis</a>(axisangle: ColumnVector) -> Self</code> /// <code>fn <a class="fnname">from_scaled_axis</a>(axisangle: Vector) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">identity</a>() -> Self</code> /// <code>fn <a class="fnname">identity</a>() -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">into_owned</a>(self) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">into_owned</a>(self) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">inverse_mut</a>(&mut self)</code> /// <code>fn <a class="fnname">inverse_mut</a>(&mut self)</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">inverse</a>(&self) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">inverse</a>(&self) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">lerp</a>(&self, other: &UnitQuaternionBase, t: N) -> OwnedQuaternionBase</code> /// <code>fn <a class="fnname">lerp</a>(&self, other: &UnitQuaternion, t: N) -> Quaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">ln</a>(&self) -> OwnedQuaternionBase</code> /// <code>fn <a class="fnname">ln</a>(&self) -> Quaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">look_at_lh</a>(dir: &ColumnVector, up: &ColumnVector) -> Self</code> /// <code>fn <a class="fnname">look_at_lh</a>(dir: &Vector, up: &Vector) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">look_at_rh</a>(dir: &ColumnVector, up: &ColumnVector) -> Self</code> /// <code>fn <a class="fnname">look_at_rh</a>(dir: &Vector, up: &Vector) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">new</a>(axisangle: ColumnVector) -> Self</code> /// <code>fn <a class="fnname">new</a>(axisangle: Vector) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">new_observer_frame</a>(dir: &ColumnVector, up: &ColumnVector) -> Self</code> /// <code>fn <a class="fnname">new_observer_frame</a>(dir: &Vector, up: &Vector) -> Self</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">nlerp</a>(&self, other: &UnitQuaternionBase, t: N) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">nlerp</a>(&self, other: &UnitQuaternion, t: N) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">powf</a>(&self, n: N) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">powf</a>(&self, n: N) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">quaternion</a>(&self) -> &QuaternionBase</code> /// <code>fn <a class="fnname">quaternion</a>(&self) -> &Quaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">rotation_between</a>(a: &ColumnVector, b: &ColumnVector) -> Option&lt;Self&gt;</code> /// <code>fn <a class="fnname">rotation_between</a>(a: &Vector, b: &Vector) -> Option&lt;Self&gt;</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">rotation_to</a>(&self, other: &UnitQuaternionBase) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">rotation_to</a>(&self, other: &UnitQuaternion) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">scaled_axis</a>(&self) -> OwnedColumnVector</code> /// <code>fn <a class="fnname">scaled_axis</a>(&self) -> Vector3</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">scaled_rotation_between</a>(a: &ColumnVector, b: &ColumnVector, s: N) -> Option&lt;Self&gt;</code> /// <code>fn <a class="fnname">scaled_rotation_between</a>(a: &Vector, b: &Vector, s: N) -> Option&lt;Self&gt;</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">slerp</a>(&self, other: &UnitQuaternionBase, t: N) -> OwnedUnitQuaternionBase</code> /// <code>fn <a class="fnname">slerp</a>(&self, other: &UnitQuaternion, t: N) -> UnitQuaternion</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">to_homogeneous</a>(&self) -> OwnedSquareMatrix</code> /// <code>fn <a class="fnname">to_homogeneous</a>(&self) -> MatrixN</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">to_rotation_matrix</a>(&self) -> OwnedRotation</code> /// <code>fn <a class="fnname">to_rotation_matrix</a>(&self) -> Rotation</code>
/// </h4> /// </h4>
/// <h4 class="method"><span class="invisible"> /// <h4 class="method"><span class="invisible">
/// <code>fn <a class="fnname">try_slerp</a>(&self, other: &UnitQuaternionBase, t: N, epsilon: N) -> Option&lt;OwnedUnitQuaternionBase&gt;</code> /// <code>fn <a class="fnname">try_slerp</a>(&self, other: &UnitQuaternion, t: N, epsilon: N) -> Option&lt;UnitQuaternion&gt;</code>
/// </h4> /// </h4>
pub type UnitQuaternionBase<N, S> = Unit<QuaternionBase<N, S>>; pub type UnitQuaternion<N> = Unit<Quaternion<N>>;
impl<N: Real> UnitQuaternion<N> {
impl<N, S> UnitQuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1> {
/// Moves this unit quaternion into one that owns its data. /// Moves this unit quaternion into one that owns its data.
#[inline] #[inline]
pub fn into_owned(self) -> OwnedUnitQuaternionBase<N, S::Alloc> { pub fn into_owned(self) -> UnitQuaternion<N> {
UnitQuaternionBase::new_unchecked(self.unwrap().into_owned()) self
} }
/// Clones this unit quaternion into one that owns its data. /// Clones this unit quaternion into one that owns its data.
#[inline] #[inline]
pub fn clone_owned(&self) -> OwnedUnitQuaternionBase<N, S::Alloc> { pub fn clone_owned(&self) -> UnitQuaternion<N> {
UnitQuaternionBase::new_unchecked(self.as_ref().clone_owned()) UnitQuaternion::new_unchecked(self.as_ref().clone_owned())
} }
/// The rotation angle in [0; pi] of this unit quaternion. /// The rotation angle in [0; pi] of this unit quaternion.
@ -457,26 +435,25 @@ impl<N, S> UnitQuaternionBase<N, S>
/// ///
/// Same as `self.as_ref()`. /// Same as `self.as_ref()`.
#[inline] #[inline]
pub fn quaternion(&self) -> &QuaternionBase<N, S> { pub fn quaternion(&self) -> &Quaternion<N> {
self.as_ref() self.as_ref()
} }
/// Compute the conjugate of this unit quaternion. /// Compute the conjugate of this unit quaternion.
#[inline] #[inline]
pub fn conjugate(&self) -> OwnedUnitQuaternionBase<N, S::Alloc> { pub fn conjugate(&self) -> UnitQuaternion<N> {
UnitQuaternionBase::new_unchecked(self.as_ref().conjugate()) UnitQuaternion::new_unchecked(self.as_ref().conjugate())
} }
/// Inverts this quaternion if it is not zero. /// Inverts this quaternion if it is not zero.
#[inline] #[inline]
pub fn inverse(&self) -> OwnedUnitQuaternionBase<N, S::Alloc> { pub fn inverse(&self) -> UnitQuaternion<N> {
self.conjugate() self.conjugate()
} }
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
#[inline] #[inline]
pub fn angle_to<S2>(&self, other: &UnitQuaternionBase<N, S2>) -> N pub fn angle_to(&self, other: &UnitQuaternion<N>) -> N {
where S2: Storage<N, U4, U1> {
let delta = self.rotation_to(other); let delta = self.rotation_to(other);
delta.angle() delta.angle()
} }
@ -485,8 +462,7 @@ impl<N, S> UnitQuaternionBase<N, S>
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
#[inline] #[inline]
pub fn rotation_to<S2>(&self, other: &UnitQuaternionBase<N, S2>) -> OwnedUnitQuaternionBase<N, S2::Alloc> pub fn rotation_to(&self, other: &UnitQuaternion<N>) -> UnitQuaternion<N> {
where S2: Storage<N, U4, U1> {
other / self other / self
} }
@ -494,19 +470,17 @@ impl<N, S> UnitQuaternionBase<N, S>
/// ///
/// The result is not normalized. /// The result is not normalized.
#[inline] #[inline]
pub fn lerp<S2>(&self, other: &UnitQuaternionBase<N, S2>, t: N) -> OwnedQuaternionBase<N, S::Alloc> pub fn lerp(&self, other: &UnitQuaternion<N>, t: N) -> Quaternion<N> {
where S2: Storage<N, U4, U1> {
self.as_ref().lerp(other.as_ref(), t) self.as_ref().lerp(other.as_ref(), t)
} }
/// Normalized linear interpolation between two unit quaternions. /// Normalized linear interpolation between two unit quaternions.
#[inline] #[inline]
pub fn nlerp<S2>(&self, other: &UnitQuaternionBase<N, S2>, t: N) -> OwnedUnitQuaternionBase<N, S::Alloc> pub fn nlerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> {
where S2: Storage<N, U4, U1> {
let mut res = self.lerp(other, t); let mut res = self.lerp(other, t);
let _ = res.normalize_mut(); let _ = res.normalize_mut();
UnitQuaternionBase::new_unchecked(res) UnitQuaternion::new_unchecked(res)
} }
/// Spherical linear interpolation between two unit quaternions. /// Spherical linear interpolation between two unit quaternions.
@ -514,8 +488,7 @@ impl<N, S> UnitQuaternionBase<N, S>
/// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation /// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation
/// is not well-defined). /// is not well-defined).
#[inline] #[inline]
pub fn slerp<S2>(&self, other: &UnitQuaternionBase<N, S2>, t: N) -> OwnedUnitQuaternionBase<N, S::Alloc> pub fn slerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> {
where S2: Storage<N, U4, U1, Alloc = S::Alloc> {
self.try_slerp(other, t, N::zero()).expect( self.try_slerp(other, t, N::zero()).expect(
"Unable to perform a spherical quaternion interpolation when they \ "Unable to perform a spherical quaternion interpolation when they \
are 180 degree apart (the result is not unique).") are 180 degree apart (the result is not unique).")
@ -532,9 +505,7 @@ impl<N, S> UnitQuaternionBase<N, S>
/// * `epsilon`: the value bellow which the sinus of the angle separating both quaternion /// * `epsilon`: the value bellow which the sinus of the angle separating both quaternion
/// must be to return `None`. /// must be to return `None`.
#[inline] #[inline]
pub fn try_slerp<S2>(&self, other: &UnitQuaternionBase<N, S2>, t: N, epsilon: N) pub fn try_slerp(&self, other: &UnitQuaternion<N>, t: N, epsilon: N) -> Option<UnitQuaternion<N>> {
-> Option<OwnedUnitQuaternionBase<N, S::Alloc>>
where S2: Storage<N, U4, U1, Alloc = S::Alloc> {
let c_hang = self.coords.dot(&other.coords); let c_hang = self.coords.dot(&other.coords);
@ -555,14 +526,10 @@ impl<N, S> UnitQuaternionBase<N, S>
let tb = (t * hang).sin() / s_hang; let tb = (t * hang).sin() / s_hang;
let res = self.as_ref() * ta + other.as_ref() * tb; let res = self.as_ref() * ta + other.as_ref() * tb;
Some(UnitQuaternionBase::new_unchecked(res)) Some(UnitQuaternion::new_unchecked(res))
} }
} }
}
impl<N, S> UnitQuaternionBase<N, S>
where N: Real,
S: StorageMut<N, U4, U1> {
/// Compute the conjugate of this unit quaternion in-place. /// Compute the conjugate of this unit quaternion in-place.
#[inline] #[inline]
pub fn conjugate_mut(&mut self) { pub fn conjugate_mut(&mut self) {
@ -574,15 +541,10 @@ impl<N, S> UnitQuaternionBase<N, S>
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
self.as_mut_unchecked().conjugate_mut() self.as_mut_unchecked().conjugate_mut()
} }
}
impl<N, S> UnitQuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1>,
S::Alloc: Allocator<N, U3, U1> {
/// The rotation axis of this unit quaternion or `None` if the rotation is zero. /// The rotation axis of this unit quaternion or `None` if the rotation is zero.
#[inline] #[inline]
pub fn axis(&self) -> Option<Unit<OwnedColumnVector<N, U3, S::Alloc>>> { pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
let v = let v =
if self.quaternion().scalar() >= N::zero() { if self.quaternion().scalar() >= N::zero() {
self.as_ref().vector().clone_owned() self.as_ref().vector().clone_owned()
@ -597,35 +559,35 @@ impl<N, S> UnitQuaternionBase<N, S>
/// The rotation axis of this unit quaternion multiplied by the rotation agle. /// The rotation axis of this unit quaternion multiplied by the rotation agle.
#[inline] #[inline]
pub fn scaled_axis(&self) -> OwnedColumnVector<N, U3, S::Alloc> { pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
axis.unwrap() * self.angle() axis.unwrap() * self.angle()
} }
else { else {
ColumnVector::zero() Vector3::zero()
} }
} }
/// Compute the exponential of a quaternion. /// Compute the exponential of a quaternion.
/// ///
/// Note that this function yields a `QuaternionBase<N>` because it looses the unit property. /// Note that this function yields a `Quaternion<N>` because it looses the unit property.
#[inline] #[inline]
pub fn exp(&self) -> OwnedQuaternionBase<N, S::Alloc> { pub fn exp(&self) -> Quaternion<N> {
self.as_ref().exp() self.as_ref().exp()
} }
/// Compute the natural logarithm of a quaternion. /// Compute the natural logarithm of a quaternion.
/// ///
/// Note that this function yields a `QuaternionBase<N>` because it looses the unit property. /// Note that this function yields a `Quaternion<N>` because it looses the unit property.
/// The vector part of the return value corresponds to the axis-angle representation (divided /// The vector part of the return value corresponds to the axis-angle representation (divided
/// by 2.0) of this unit quaternion. /// by 2.0) of this unit quaternion.
#[inline] #[inline]
pub fn ln(&self) -> OwnedQuaternionBase<N, S::Alloc> { pub fn ln(&self) -> Quaternion<N> {
if let Some(v) = self.axis() { 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 { else {
QuaternionBase::zero() Quaternion::zero()
} }
} }
@ -634,23 +596,18 @@ impl<N, S> UnitQuaternionBase<N, S>
/// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and /// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and
/// angle `self.angle() × n`. /// angle `self.angle() × n`.
#[inline] #[inline]
pub fn powf(&self, n: N) -> OwnedUnitQuaternionBase<N, S::Alloc> { pub fn powf(&self, n: N) -> UnitQuaternion<N> {
if let Some(v) = self.axis() { if let Some(v) = self.axis() {
UnitQuaternionBase::from_axis_angle(&v, self.angle() * n) UnitQuaternion::from_axis_angle(&v, self.angle() * n)
} }
else { else {
UnitQuaternionBase::identity() UnitQuaternion::identity()
} }
} }
}
impl<N, S> UnitQuaternionBase<N, S>
where N: Real,
S: Storage<N, U4, U1>,
S::Alloc: Allocator<N, U3, U3> {
/// Builds a rotation matrix from this unit quaternion. /// Builds a rotation matrix from this unit quaternion.
#[inline] #[inline]
pub fn to_rotation_matrix(&self) -> OwnedRotation<N, U3, S::Alloc> { pub fn to_rotation_matrix(&self) -> Rotation<N, U3> {
let i = self.as_ref()[0]; let i = self.as_ref()[0];
let j = self.as_ref()[1]; let j = self.as_ref()[1];
let k = self.as_ref()[2]; let k = self.as_ref()[2];
@ -667,7 +624,7 @@ impl<N, S> UnitQuaternionBase<N, S>
let jk = j * k * ::convert(2.0f64); let jk = j * k * ::convert(2.0f64);
let wi = w * i * ::convert(2.0f64); let wi = w * i * ::convert(2.0f64);
RotationBase::from_matrix_unchecked( Rotation::from_matrix_unchecked(
SquareMatrix::<_, U3, _>::new( SquareMatrix::<_, U3, _>::new(
ww + ii - jj - kk, ij - wk, wj + ik, ww + ii - jj - kk, ij - wk, wj + ik,
wk + ij, ww - ii + jj - kk, jk - wi, wk + ij, ww - ii + jj - kk, jk - wi,
@ -678,17 +635,13 @@ impl<N, S> UnitQuaternionBase<N, S>
/// Converts this unit quaternion into its equivalent homogeneous transformation matrix. /// Converts this unit quaternion into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, U4, S::Alloc> pub fn to_homogeneous(&self) -> MatrixN<N, U4> {
where S::Alloc: Allocator<N, U4, U4> {
self.to_rotation_matrix().to_homogeneous() self.to_rotation_matrix().to_homogeneous()
} }
} }
impl<N, S> fmt::Display for UnitQuaternionBase<N, S> impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> {
where N: Real + fmt::Display,
S: Storage<N, U4, U1>,
S::Alloc: Allocator<N, U3, U1> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
let axis = axis.unwrap(); let axis = axis.unwrap();
@ -700,9 +653,7 @@ impl<N, S> fmt::Display for UnitQuaternionBase<N, S>
} }
} }
impl<N, S> ApproxEq for UnitQuaternionBase<N, S> impl<N: Real + ApproxEq<Epsilon = N>> ApproxEq for UnitQuaternion<N> {
where N: Real + ApproxEq<Epsilon = N>,
S: Storage<N, U4, U1> {
type Epsilon = N; type Epsilon = N;
#[inline] #[inline]

View File

@ -7,57 +7,39 @@ use alga::linear::{Transformation, AffineTransformation, Similarity, Isometry, D
OrthogonalTransformation, VectorSpace, FiniteDimVectorSpace, NormedSpace, OrthogonalTransformation, VectorSpace, FiniteDimVectorSpace, NormedSpace,
Rotation, ProjectiveTransformation}; Rotation, ProjectiveTransformation};
use core::ColumnVector; use core::{Vector3, Vector4};
use core::storage::OwnedStorage; use geometry::{Point3, Quaternion, UnitQuaternion};
use core::allocator::{Allocator, OwnedAllocator};
use core::dimension::{U1, U3, U4};
use geometry::{PointBase, QuaternionBase, UnitQuaternionBase};
impl<N, S> Identity<Multiplicative> for QuaternionBase<N, S> impl<N: Real> Identity<Multiplicative> for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, S> Identity<Additive> for QuaternionBase<N, S> impl<N: Real> Identity<Additive> for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::zero() Self::zero()
} }
} }
impl<N, S> AbstractMagma<Multiplicative> for QuaternionBase<N, S> impl<N: Real> AbstractMagma<Multiplicative> for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
} }
} }
impl<N, S> AbstractMagma<Additive> for QuaternionBase<N, S> impl<N: Real> AbstractMagma<Additive> for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self + rhs self + rhs
} }
} }
impl<N, S> Inverse<Additive> for QuaternionBase<N, S> impl<N: Real> Inverse<Additive> for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
-self -self
@ -66,15 +48,12 @@ impl<N, S> Inverse<Additive> for QuaternionBase<N, S>
macro_rules! impl_structures( macro_rules! impl_structures(
($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( ($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, S> $marker<$operator> for $Quaternion<N, S> impl<N: Real> $marker<$operator> for $Quaternion<N> { }
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> { }
)*} )*}
); );
impl_structures!( impl_structures!(
QuaternionBase; Quaternion;
AbstractSemigroup<Multiplicative>, AbstractSemigroup<Multiplicative>,
AbstractMonoid<Multiplicative>, AbstractMonoid<Multiplicative>,
@ -92,10 +71,7 @@ impl_structures!(
* Vector space. * Vector space.
* *
*/ */
impl<N, S> AbstractModule for QuaternionBase<N, S> impl<N: Real> AbstractModule for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
type AbstractRing = N; type AbstractRing = N;
#[inline] #[inline]
@ -104,24 +80,15 @@ impl<N, S> AbstractModule for QuaternionBase<N, S>
} }
} }
impl<N, S> Module for QuaternionBase<N, S> impl<N: Real> Module for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
type Ring = N; type Ring = N;
} }
impl<N, S> VectorSpace for QuaternionBase<N, S> impl<N: Real> VectorSpace for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
type Field = N; type Field = N;
} }
impl<N, S> FiniteDimVectorSpace for QuaternionBase<N, S> impl<N: Real> FiniteDimVectorSpace for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn dimension() -> usize { fn dimension() -> usize {
4 4
@ -129,7 +96,7 @@ impl<N, S> FiniteDimVectorSpace for QuaternionBase<N, S>
#[inline] #[inline]
fn canonical_basis_element(i: usize) -> Self { fn canonical_basis_element(i: usize) -> Self {
Self::from_vector(ColumnVector::canonical_basis_element(i)) Self::from_vector(Vector4::canonical_basis_element(i))
} }
#[inline] #[inline]
@ -148,10 +115,7 @@ impl<N, S> FiniteDimVectorSpace for QuaternionBase<N, S>
} }
} }
impl<N, S> NormedSpace for QuaternionBase<N, S> impl<N: Real> NormedSpace for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn norm_squared(&self) -> N { fn norm_squared(&self) -> N {
self.coords.norm_squared() self.coords.norm_squared()
@ -191,33 +155,24 @@ impl<N, S> NormedSpace for QuaternionBase<N, S>
/* /*
* *
* Implementations for UnitQuaternionBase. * Implementations for UnitQuaternion.
* *
*/ */
impl<N, S> Identity<Multiplicative> for UnitQuaternionBase<N, S> impl<N: Real> Identity<Multiplicative> for UnitQuaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, S> AbstractMagma<Multiplicative> for UnitQuaternionBase<N, S> impl<N: Real> AbstractMagma<Multiplicative> for UnitQuaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
} }
} }
impl<N, S> Inverse<Multiplicative> for UnitQuaternionBase<N, S> impl<N: Real> Inverse<Multiplicative> for UnitQuaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
self.inverse() self.inverse()
@ -230,7 +185,7 @@ impl<N, S> Inverse<Multiplicative> for UnitQuaternionBase<N, S>
} }
impl_structures!( impl_structures!(
UnitQuaternionBase; UnitQuaternion;
AbstractSemigroup<Multiplicative>, AbstractSemigroup<Multiplicative>,
AbstractQuasigroup<Multiplicative>, AbstractQuasigroup<Multiplicative>,
AbstractMonoid<Multiplicative>, AbstractMonoid<Multiplicative>,
@ -238,48 +193,33 @@ impl_structures!(
AbstractGroup<Multiplicative> AbstractGroup<Multiplicative>
); );
impl<N, SA, SB> Transformation<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA> impl<N: Real> Transformation<Point3<N>> for UnitQuaternion<N> {
where N: Real,
SA: OwnedStorage<N, U4, U1>,
SB: OwnedStorage<N, U3, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> {
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, U3, SB>) -> PointBase<N, U3, SB> { fn transform_point(&self, pt: &Point3<N>) -> Point3<N> {
self * pt self * pt
} }
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, U3, SB>) -> ColumnVector<N, U3, SB> { fn transform_vector(&self, v: &Vector3<N>) -> Vector3<N> {
self * v self * v
} }
} }
impl<N, SA, SB> ProjectiveTransformation<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA> impl<N: Real> ProjectiveTransformation<Point3<N>> for UnitQuaternion<N> {
where N: Real,
SA: OwnedStorage<N, U4, U1>,
SB: OwnedStorage<N, U3, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &PointBase<N, U3, SB>) -> PointBase<N, U3, SB> { fn inverse_transform_point(&self, pt: &Point3<N>) -> Point3<N> {
// FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement
// the inverse transformation explicitly here) ? // the inverse transformation explicitly here) ?
self.inverse() * pt self.inverse() * pt
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &ColumnVector<N, U3, SB>) -> ColumnVector<N, U3, SB> { fn inverse_transform_vector(&self, v: &Vector3<N>) -> Vector3<N> {
self.inverse() * v self.inverse() * v
} }
} }
impl<N, SA, SB> AffineTransformation<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA> impl<N: Real> AffineTransformation<Point3<N>> for UnitQuaternion<N> {
where N: Real,
SA: OwnedStorage<N, U4, U1>,
SB: OwnedStorage<N, U3, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> {
type Rotation = Self; type Rotation = Self;
type NonUniformScaling = Id; type NonUniformScaling = Id;
type Translation = Id; type Translation = Id;
@ -320,12 +260,7 @@ impl<N, SA, SB> AffineTransformation<PointBase<N, U3, SB>> for UnitQuaternionBas
} }
} }
impl<N, SA, SB> Similarity<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA> impl<N: Real> Similarity<Point3<N>> for UnitQuaternion<N> {
where N: Real,
SA: OwnedStorage<N, U4, U1>,
SB: OwnedStorage<N, U3, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> {
type Scaling = Id; type Scaling = Id;
#[inline] #[inline]
@ -346,12 +281,7 @@ impl<N, SA, SB> Similarity<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA>
macro_rules! marker_impl( macro_rules! marker_impl(
($($Trait: ident),*) => {$( ($($Trait: ident),*) => {$(
impl<N, SA, SB> $Trait<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA> impl<N: Real> $Trait<Point3<N>> for UnitQuaternion<N> { }
where N: Real,
SA: OwnedStorage<N, U4, U1>,
SB: OwnedStorage<N, U3, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> { }
)*} )*}
); );
@ -359,24 +289,19 @@ marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation);
impl<N, SA, SB> Rotation<PointBase<N, U3, SB>> for UnitQuaternionBase<N, SA> impl<N: Real> Rotation<Point3<N>> for UnitQuaternion<N> {
where N: Real,
SA: OwnedStorage<N, U4, U1>,
SB: OwnedStorage<N, U3, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, U4, U1, SA> + Allocator<N, U3, U1>,
SB::Alloc: OwnedAllocator<N, U3, U1, SB> {
#[inline] #[inline]
fn powf(&self, n: N) -> Option<Self> { fn powf(&self, n: N) -> Option<Self> {
Some(self.powf(n)) Some(self.powf(n))
} }
#[inline] #[inline]
fn rotation_between(a: &ColumnVector<N, U3, SB>, b: &ColumnVector<N, U3, SB>) -> Option<Self> { fn rotation_between(a: &Vector3<N>, b: &Vector3<N>) -> Option<Self> {
Self::rotation_between(a, b) Self::rotation_between(a, b)
} }
#[inline] #[inline]
fn scaled_rotation_between(a: &ColumnVector<N, U3, SB>, b: &ColumnVector<N, U3, SB>, s: N) -> Option<Self> { fn scaled_rotation_between(a: &Vector3<N>, b: &Vector3<N>, s: N) -> Option<Self> {
Self::scaled_rotation_between(a, b, s) Self::scaled_rotation_between(a, b, s)
} }
} }

View File

@ -1,10 +0,0 @@
use core::MatrixArray;
use core::dimension::{U1, U4};
use geometry::{QuaternionBase, UnitQuaternionBase};
/// A statically-allocated quaternion.
pub type Quaternion<N> = QuaternionBase<N, MatrixArray<N, U4, U1>>;
/// A statically-allocated unit quaternion.
pub type UnitQuaternion<N> = UnitQuaternionBase<N, MatrixArray<N, U4, U1>>;

View File

@ -1,42 +1,38 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
#[cfg(feature = "arbitrary")]
use core::storage::Owned;
#[cfg(feature = "arbitrary")]
use core::dimension::U4;
use rand::{Rand, Rng}; use rand::{Rand, Rng};
use num::{Zero, One}; use num::{Zero, One};
use alga::general::Real; use alga::general::Real;
use core::{Unit, ColumnVector, Vector3}; use core::{Unit, Vector, Vector4, Vector3};
use core::storage::{Storage, OwnedStorage}; use core::storage::Storage;
use core::allocator::{Allocator, OwnedAllocator}; use core::dimension::U3;
use core::dimension::{U1, U3, U4};
use geometry::{QuaternionBase, UnitQuaternionBase, RotationBase, OwnedRotation}; use geometry::{Quaternion, UnitQuaternion, Rotation};
impl<N, S> QuaternionBase<N, S> impl<N: Real> Quaternion<N> {
where N: Real,
S: Storage<N, U4, U1> {
/// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w` /// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w`
/// vector component. /// vector component.
#[inline] #[inline]
pub fn from_vector(vector: ColumnVector<N, U4, S>) -> Self { pub fn from_vector(vector: Vector4<N>) -> Self {
QuaternionBase { Quaternion {
coords: vector coords: vector
} }
} }
}
impl<N, S> QuaternionBase<N, S>
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
/// Creates a new quaternion from its individual components. Note that the arguments order does /// Creates a new quaternion from its individual components. Note that the arguments order does
/// **not** follow the storage order. /// **not** follow the storage order.
/// ///
/// The storage order is `[ x, y, z, w ]`. /// The storage order is `[ x, y, z, w ]`.
#[inline] #[inline]
pub fn new(w: N, x: N, y: N, z: N) -> Self { pub fn new(w: N, x: N, y: N, z: N) -> Self {
let v = ColumnVector::<N, U4, S>::new(x, y, z, w); let v = Vector4::<N>::new(x, y, z, w);
Self::from_vector(v) Self::from_vector(v)
} }
@ -46,8 +42,8 @@ impl<N, S> QuaternionBase<N, S>
/// The storage order is [ vector, scalar ]. /// The storage order is [ vector, scalar ].
#[inline] #[inline]
// FIXME: take a reference to `vector`? // FIXME: take a reference to `vector`?
pub fn from_parts<SB>(scalar: N, vector: ColumnVector<N, U3, SB>) -> Self pub fn from_parts<SB>(scalar: N, vector: Vector<N, U3, SB>) -> Self
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
Self::new(scalar, vector[0], vector[1], vector[2]) Self::new(scalar, vector[0], vector[1], vector[2])
} }
@ -56,9 +52,9 @@ impl<N, S> QuaternionBase<N, S>
/// ///
/// Note that `axis` is assumed to be a unit vector. /// Note that `axis` is assumed to be a unit vector.
// FIXME: take a reference to `axis`? // FIXME: take a reference to `axis`?
pub fn from_polar_decomposition<SB>(scale: N, theta: N, axis: Unit<ColumnVector<N, U3, SB>>) -> Self pub fn from_polar_decomposition<SB>(scale: N, theta: N, axis: Unit<Vector<N, U3, SB>>) -> Self
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
let rot = UnitQuaternionBase::<N, S>::from_axis_angle(&axis, theta * ::convert(2.0f64)); let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64));
rot.unwrap() * scale rot.unwrap() * scale
} }
@ -70,20 +66,14 @@ impl<N, S> QuaternionBase<N, S>
} }
} }
impl<N, S> One for QuaternionBase<N, S> impl<N: Real> One for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, S> Zero for QuaternionBase<N, S> impl<N: Real> Zero for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn zero() -> Self { fn zero() -> Self {
Self::new(N::zero(), N::zero(), N::zero(), N::zero()) Self::new(N::zero(), N::zero(), N::zero(), N::zero())
@ -95,46 +85,38 @@ impl<N, S> Zero for QuaternionBase<N, S>
} }
} }
impl<N, S> Rand for QuaternionBase<N, S> impl<N: Real + Rand> Rand for Quaternion<N> {
where N: Real + Rand,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Self { fn rand<R: Rng>(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")] #[cfg(feature="arbitrary")]
impl<N, S> Arbitrary for QuaternionBase<N, S> impl<N: Real + Arbitrary> Arbitrary for Quaternion<N>
where N: Real + Arbitrary, where Owned<N, U4>: Send {
S: OwnedStorage<N, U4, U1> + Send,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(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)) N::arbitrary(g), N::arbitrary(g))
} }
} }
impl<N, S> UnitQuaternionBase<N, S> impl<N: Real> UnitQuaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
/// The quaternion multiplicative identity. /// The quaternion multiplicative identity.
#[inline] #[inline]
pub fn identity() -> Self { 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 /// Creates a new quaternion from a unit vector (the rotation axis) and an angle
/// (the rotation angle). /// (the rotation angle).
#[inline] #[inline]
pub fn from_axis_angle<SB>(axis: &Unit<ColumnVector<N, U3, SB>>, angle: N) -> Self pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
let (sang, cang) = (angle / ::convert(2.0f64)).sin_cos(); 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) Self::new_unchecked(q)
} }
@ -142,7 +124,7 @@ impl<N, S> UnitQuaternionBase<N, S>
/// ///
/// The input quaternion will be normalized. /// The input quaternion will be normalized.
#[inline] #[inline]
pub fn from_quaternion(q: QuaternionBase<N, S>) -> Self { pub fn from_quaternion(q: Quaternion<N>) -> Self {
Self::new_normalize(q) Self::new_normalize(q)
} }
@ -155,7 +137,7 @@ impl<N, S> UnitQuaternionBase<N, S>
let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos(); let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos();
let (sy, cy) = (yaw * ::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, cr * cp * cy + sr * sp * sy,
sr * cp * cy - cr * sp * sy, sr * cp * cy - cr * sp * sy,
cr * sp * cy + sr * cp * sy, cr * sp * cy + sr * cp * sy,
@ -166,10 +148,7 @@ impl<N, S> UnitQuaternionBase<N, S>
/// Builds an unit quaternion from a rotation matrix. /// Builds an unit quaternion from a rotation matrix.
#[inline] #[inline]
pub fn from_rotation_matrix<SB>(rotmat: &RotationBase<N, U3, SB>) -> Self pub fn from_rotation_matrix(rotmat: &Rotation<N, U3>) -> Self {
where SB: Storage<N, U3, U3>,
SB::Alloc: Allocator<N, U3, U1> {
// Robust matrix to quaternion transformation. // Robust matrix to quaternion transformation.
// See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion // See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion
let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)]; let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)];
@ -179,28 +158,28 @@ impl<N, S> UnitQuaternionBase<N, S>
if tr > N::zero() { if tr > N::zero() {
let denom = (tr + N::one()).sqrt() * ::convert(2.0); 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[(2, 1)] - rotmat[(1, 2)]) / denom,
(rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom,
(rotmat[(1, 0)] - rotmat[(0, 1)]) / denom); (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom);
} }
else if rotmat[(0, 0)] > rotmat[(1, 1)] && rotmat[(0, 0)] > rotmat[(2, 2)] { 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); 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, _0_25 * denom,
(rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom,
(rotmat[(0, 2)] + rotmat[(2, 0)]) / denom); (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom);
} }
else if rotmat[(1, 1)] > rotmat[(2, 2)] { 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); 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, (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom,
_0_25 * denom, _0_25 * denom,
(rotmat[(1, 2)] + rotmat[(2, 1)]) / denom); (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom);
} }
else { else {
let denom = (N::one() + rotmat[(2, 2)] - rotmat[(0, 0)] - rotmat[(1, 1)]).sqrt() * ::convert(2.0); 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[(0, 2)] + rotmat[(2, 0)]) / denom,
(rotmat[(1, 2)] + rotmat[(2, 1)]) / denom, (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom,
_0_25 * denom); _0_25 * denom);
@ -212,19 +191,22 @@ impl<N, S> UnitQuaternionBase<N, S>
/// The unit quaternion needed to make `a` and `b` be collinear and point toward the same /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same
/// direction. /// direction.
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &ColumnVector<N, U3, SB>, b: &ColumnVector<N, U3, SC>) -> Option<Self> pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1> { SC: Storage<N, U3> {
Self::scaled_rotation_between(a, b, N::one()) Self::scaled_rotation_between(a, b, N::one())
} }
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>(a: &ColumnVector<N, U3, SB>, b: &ColumnVector<N, U3, SC>, s: N) -> Option<Self> pub fn scaled_rotation_between<SB, SC>(a: &Vector<N, U3, SB>,
where SB: Storage<N, U3, U1>, b: &Vector<N, U3, SC>,
SC: Storage<N, U3, U1> { s: N)
// FIXME: code duplication with RotationBase. -> Option<Self>
where SB: Storage<N, U3>,
SC: Storage<N, U3> {
// FIXME: code duplication with Rotation.
if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) { if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) {
let c = na.cross(&nb); let c = na.cross(&nb);
@ -257,12 +239,10 @@ impl<N, S> UnitQuaternionBase<N, S>
/// collinear /// collinear
/// to `dir`. Non-collinearity is not checked. /// to `dir`. Non-collinearity is not checked.
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &ColumnVector<N, U3, SB>, up: &ColumnVector<N, U3, SC>) -> Self pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1>, SC: Storage<N, U3> {
S::Alloc: Allocator<N, U3, U3> + Self::from_rotation_matrix(&Rotation::<N, U3>::new_observer_frame(dir, up))
Allocator<N, U3, U1> {
Self::from_rotation_matrix(&OwnedRotation::<N, U3, S::Alloc>::new_observer_frame(dir, up))
} }
@ -277,11 +257,9 @@ impl<N, S> UnitQuaternionBase<N, S>
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_rh<SB, SC>(dir: &ColumnVector<N, U3, SB>, up: &ColumnVector<N, U3, SC>) -> Self pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1>, SC: Storage<N, U3> {
S::Alloc: Allocator<N, U3, U3> +
Allocator<N, U3, U1> {
Self::new_observer_frame(&-dir, up).inverse() Self::new_observer_frame(&-dir, up).inverse()
} }
@ -296,28 +274,20 @@ impl<N, S> UnitQuaternionBase<N, S>
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_lh<SB, SC>(dir: &ColumnVector<N, U3, SB>, up: &ColumnVector<N, U3, SC>) -> Self pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1>, SC: Storage<N, U3> {
S::Alloc: Allocator<N, U3, U3> +
Allocator<N, U3, U1> {
Self::new_observer_frame(dir, up).inverse() Self::new_observer_frame(dir, up).inverse()
} }
}
impl<N, S> UnitQuaternionBase<N, S>
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> +
Allocator<N, U3, U1> {
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
/// ///
/// If `axisangle` is zero, this returns the indentity rotation. /// If `axisangle` is zero, this returns the indentity rotation.
#[inline] #[inline]
pub fn new<SB>(axisangle: ColumnVector<N, U3, SB>) -> Self pub fn new<SB>(axisangle: Vector<N, U3, SB>) -> Self
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
let two: N = ::convert(2.0f64); let two: N = ::convert(2.0f64);
let q = QuaternionBase::<N, S>::from_parts(N::zero(), axisangle / two).exp(); let q = Quaternion::<N>::from_parts(N::zero(), axisangle / two).exp();
Self::new_unchecked(q) Self::new_unchecked(q)
} }
@ -326,44 +296,35 @@ impl<N, S> UnitQuaternionBase<N, S>
/// If `axisangle` is zero, this returns the indentity rotation. /// If `axisangle` is zero, this returns the indentity rotation.
/// Same as `Self::new(axisangle)`. /// Same as `Self::new(axisangle)`.
#[inline] #[inline]
pub fn from_scaled_axis<SB>(axisangle: ColumnVector<N, U3, SB>) -> Self pub fn from_scaled_axis<SB>(axisangle: Vector<N, U3, SB>) -> Self
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
Self::new(axisangle) Self::new(axisangle)
} }
} }
impl<N, S> One for UnitQuaternionBase<N, S> impl<N: Real> One for UnitQuaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, S> Rand for UnitQuaternionBase<N, S> impl<N: Real + Rand> Rand for UnitQuaternion<N> {
where N: Real + Rand,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> +
Allocator<N, U3, U1> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Self { fn rand<R: Rng>(rng: &mut R) -> Self {
let axisangle = Vector3::rand(rng); let axisangle = Vector3::rand(rng);
UnitQuaternionBase::from_scaled_axis(axisangle) UnitQuaternion::from_scaled_axis(axisangle)
} }
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N, S> Arbitrary for UnitQuaternionBase<N, S> impl<N: Real + Arbitrary> Arbitrary for UnitQuaternion<N>
where N: Real + Arbitrary, where Owned<N, U4>: Send,
S: OwnedStorage<N, U4, U1> + Send, Owned<N, U3>: Send {
S::Alloc: OwnedAllocator<N, U4, U1, S> +
Allocator<N, U3, U1> {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
let axisangle = Vector3::arbitrary(g); let axisangle = Vector3::arbitrary(g);
UnitQuaternionBase::from_scaled_axis(axisangle) UnitQuaternion::from_scaled_axis(axisangle)
} }
} }

View File

@ -3,12 +3,11 @@ use num::Zero;
use alga::general::{SubsetOf, SupersetOf, Real}; use alga::general::{SubsetOf, SupersetOf, Real};
use alga::linear::Rotation as AlgaRotation; use alga::linear::Rotation as AlgaRotation;
use core::{ColumnVector, SquareMatrix}; use core::{Vector4, Matrix4};
use core::dimension::{U1, U3, U4}; use core::dimension::U3;
use core::storage::OwnedStorage; use geometry::{Quaternion, UnitQuaternion, Rotation, Isometry, Similarity,
use core::allocator::{Allocator, OwnedAllocator}; Transform, SuperTCategoryOf, TAffine, Translation,
use geometry::{PointBase, QuaternionBase, UnitQuaternionBase, OwnedUnitQuaternionBase, RotationBase, Rotation3, Point3};
OwnedRotation, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine, TranslationBase};
/* /*
* This file provides the following conversions: * This file provides the following conversions:
@ -16,197 +15,154 @@ use geometry::{PointBase, QuaternionBase, UnitQuaternionBase, OwnedUnitQuaternio
* *
* Quaternion -> Quaternion * Quaternion -> Quaternion
* UnitQuaternion -> UnitQuaternion * UnitQuaternion -> UnitQuaternion
* UnitQuaternion -> RotationBase<U3> * UnitQuaternion -> Rotation<U3>
* UnitQuaternion -> IsometryBase<U3> * UnitQuaternion -> Isometry<U3>
* UnitQuaternion -> SimilarityBase<U3> * UnitQuaternion -> Similarity<U3>
* UnitQuaternion -> TransformBase<U3> * UnitQuaternion -> Transform<U3>
* UnitQuaternion -> Matrix<U4> (homogeneous) * UnitQuaternion -> Matrix<U4> (homogeneous)
* *
* NOTE: * NOTE:
* UnitQuaternion -> Quaternion is already provided by: Unit<T> -> T * UnitQuaternion -> Quaternion is already provided by: Unit<T> -> T
*/ */
impl<N1, N2, SA, SB> SubsetOf<QuaternionBase<N2, SB>> for QuaternionBase<N1, SA> impl<N1, N2> SubsetOf<Quaternion<N2>> for Quaternion<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1> {
SA: OwnedStorage<N1, U4, U1>,
SB: OwnedStorage<N2, U4, U1>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N2, U4, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> QuaternionBase<N2, SB> { fn to_superset(&self) -> Quaternion<N2> {
QuaternionBase::from_vector(self.coords.to_superset()) Quaternion::from_vector(self.coords.to_superset())
} }
#[inline] #[inline]
fn is_in_subset(q: &QuaternionBase<N2, SB>) -> bool { fn is_in_subset(q: &Quaternion<N2>) -> bool {
::is_convertible::<_, ColumnVector<N1, U4, SA>>(&q.coords) ::is_convertible::<_, Vector4<N1>>(&q.coords)
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(q: &QuaternionBase<N2, SB>) -> Self { unsafe fn from_superset_unchecked(q: &Quaternion<N2>) -> Self {
Self::from_vector(q.coords.to_subset_unchecked()) Self::from_vector(q.coords.to_subset_unchecked())
} }
} }
impl<N1, N2, SA, SB> SubsetOf<UnitQuaternionBase<N2, SB>> for UnitQuaternionBase<N1, SA> impl<N1, N2> SubsetOf<UnitQuaternion<N2>> for UnitQuaternion<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1> {
SA: OwnedStorage<N1, U4, U1>,
SB: OwnedStorage<N2, U4, U1>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N2, U4, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> UnitQuaternionBase<N2, SB> { fn to_superset(&self) -> UnitQuaternion<N2> {
UnitQuaternionBase::new_unchecked(self.as_ref().to_superset()) UnitQuaternion::new_unchecked(self.as_ref().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(uq: &UnitQuaternionBase<N2, SB>) -> bool { fn is_in_subset(uq: &UnitQuaternion<N2>) -> bool {
::is_convertible::<_, QuaternionBase<N1, SA>>(uq.as_ref()) ::is_convertible::<_, Quaternion<N1>>(uq.as_ref())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(uq: &UnitQuaternionBase<N2, SB>) -> Self { unsafe fn from_superset_unchecked(uq: &UnitQuaternion<N2>) -> Self {
Self::new_unchecked(::convert_ref_unchecked(uq.as_ref())) Self::new_unchecked(::convert_ref_unchecked(uq.as_ref()))
} }
} }
impl<N1, N2, SA, SB> SubsetOf<RotationBase<N2, U3, SB>> for UnitQuaternionBase<N1, SA> impl<N1, N2> SubsetOf<Rotation<N2, U3>> for UnitQuaternion<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1> {
SA: OwnedStorage<N1, U4, U1>,
SB: OwnedStorage<N2, U3, U3>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA> +
Allocator<N1, U3, U3>,
SB::Alloc: OwnedAllocator<N2, U3, U3, SB> +
Allocator<N2, U4, U1> +
Allocator<N2, U3, U1> {
#[inline] #[inline]
fn to_superset(&self) -> RotationBase<N2, U3, SB> { fn to_superset(&self) -> Rotation3<N2> {
let q: OwnedUnitQuaternionBase<N2, SB::Alloc> = self.to_superset(); let q: UnitQuaternion<N2> = self.to_superset();
q.to_rotation_matrix() q.to_rotation_matrix()
} }
#[inline] #[inline]
fn is_in_subset(rot: &RotationBase<N2, U3, SB>) -> bool { fn is_in_subset(rot: &Rotation3<N2>) -> bool {
::is_convertible::<_, OwnedRotation<N1, U3, SA::Alloc>>(rot) ::is_convertible::<_, Rotation3<N1>>(rot)
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(rot: &RotationBase<N2, U3, SB>) -> Self { unsafe fn from_superset_unchecked(rot: &Rotation3<N2>) -> Self {
let q = OwnedUnitQuaternionBase::<N2, SB::Alloc>::from_rotation_matrix(rot); let q = UnitQuaternion::<N2>::from_rotation_matrix(rot);
::convert_unchecked(q) ::convert_unchecked(q)
} }
} }
impl<N1, N2, SA, SB, R> SubsetOf<IsometryBase<N2, U3, SB, R>> for UnitQuaternionBase<N1, SA> impl<N1, N2, R> SubsetOf<Isometry<N2, U3, R>> for UnitQuaternion<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, U4, U1>, R: AlgaRotation<Point3<N2>> + SupersetOf<UnitQuaternion<N1>> {
SB: OwnedStorage<N2, U3, U1>,
R: AlgaRotation<PointBase<N2, U3, SB>> + SupersetOf<UnitQuaternionBase<N1, SA>>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N2, U3, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> IsometryBase<N2, U3, SB, R> { fn to_superset(&self) -> Isometry<N2, U3, R> {
IsometryBase::from_parts(TranslationBase::identity(), ::convert_ref(self)) Isometry::from_parts(Translation::identity(), ::convert_ref(self))
} }
#[inline] #[inline]
fn is_in_subset(iso: &IsometryBase<N2, U3, SB, R>) -> bool { fn is_in_subset(iso: &Isometry<N2, U3, R>) -> bool {
iso.translation.vector.is_zero() iso.translation.vector.is_zero()
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(iso: &IsometryBase<N2, U3, SB, R>) -> Self { unsafe fn from_superset_unchecked(iso: &Isometry<N2, U3, R>) -> Self {
::convert_ref_unchecked(&iso.rotation) ::convert_ref_unchecked(&iso.rotation)
} }
} }
impl<N1, N2, SA, SB, R> SubsetOf<SimilarityBase<N2, U3, SB, R>> for UnitQuaternionBase<N1, SA> impl<N1, N2, R> SubsetOf<Similarity<N2, U3, R>> for UnitQuaternion<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, U4, U1>, R: AlgaRotation<Point3<N2>> + SupersetOf<UnitQuaternion<N1>> {
SB: OwnedStorage<N2, U3, U1>,
R: AlgaRotation<PointBase<N2, U3, SB>> + SupersetOf<UnitQuaternionBase<N1, SA>>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA>,
SB::Alloc: OwnedAllocator<N2, U3, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> SimilarityBase<N2, U3, SB, R> { fn to_superset(&self) -> Similarity<N2, U3, R> {
SimilarityBase::from_isometry(::convert_ref(self), N2::one()) Similarity::from_isometry(::convert_ref(self), N2::one())
} }
#[inline] #[inline]
fn is_in_subset(sim: &SimilarityBase<N2, U3, SB, R>) -> bool { fn is_in_subset(sim: &Similarity<N2, U3, R>) -> bool {
sim.isometry.translation.vector.is_zero() && sim.isometry.translation.vector.is_zero() &&
sim.scaling() == N2::one() sim.scaling() == N2::one()
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(sim: &SimilarityBase<N2, U3, SB, R>) -> Self { unsafe fn from_superset_unchecked(sim: &Similarity<N2, U3, R>) -> Self {
::convert_ref_unchecked(&sim.isometry) ::convert_ref_unchecked(&sim.isometry)
} }
} }
impl<N1, N2, SA, SB, C> SubsetOf<TransformBase<N2, U3, SB, C>> for UnitQuaternionBase<N1, SA> impl<N1, N2, C> SubsetOf<Transform<N2, U3, C>> for UnitQuaternion<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, U4, U1>, C: SuperTCategoryOf<TAffine> {
SB: OwnedStorage<N2, U4, U4>,
C: SuperTCategoryOf<TAffine>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA> +
Allocator<N1, U3, U3> +
Allocator<N1, U3, U1> +
Allocator<N1, U4, U4>,
SB::Alloc: OwnedAllocator<N2, U4, U4, SB> +
Allocator<N2, U3, U3> +
Allocator<N2, U1, U3> {
#[inline] #[inline]
fn to_superset(&self) -> TransformBase<N2, U3, SB, C> { fn to_superset(&self) -> Transform<N2, U3, C> {
TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(t: &TransformBase<N2, U3, SB, C>) -> bool { fn is_in_subset(t: &Transform<N2, U3, C>) -> bool {
<Self as SubsetOf<_>>::is_in_subset(t.matrix()) <Self as SubsetOf<_>>::is_in_subset(t.matrix())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(t: &TransformBase<N2, U3, SB, C>) -> Self { unsafe fn from_superset_unchecked(t: &Transform<N2, U3, C>) -> Self {
Self::from_superset_unchecked(t.matrix()) Self::from_superset_unchecked(t.matrix())
} }
} }
impl<N1, N2, SA, SB> SubsetOf<SquareMatrix<N2, U4, SB>> for UnitQuaternionBase<N1, SA> impl<N1: Real, N2: Real + SupersetOf<N1>> SubsetOf<Matrix4<N2>> for UnitQuaternion<N1> {
where N1: Real,
N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, U4, U1>,
SB: OwnedStorage<N2, U4, U4>,
SA::Alloc: OwnedAllocator<N1, U4, U1, SA> +
Allocator<N1, U3, U3> +
Allocator<N1, U3, U1> +
Allocator<N1, U4, U4>,
SB::Alloc: OwnedAllocator<N2, U4, U4, SB> +
Allocator<N2, U3, U3> +
Allocator<N2, U1, U3> {
#[inline] #[inline]
fn to_superset(&self) -> SquareMatrix<N2, U4, SB> { fn to_superset(&self) -> Matrix4<N2> {
self.to_homogeneous().to_superset() self.to_homogeneous().to_superset()
} }
#[inline] #[inline]
fn is_in_subset(m: &SquareMatrix<N2, U4, SB>) -> bool { fn is_in_subset(m: &Matrix4<N2>) -> bool {
::is_convertible::<_, OwnedRotation<N1, U3, SA::Alloc>>(m) ::is_convertible::<_, Rotation3<N1>>(m)
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &SquareMatrix<N2, U4, SB>) -> Self { unsafe fn from_superset_unchecked(m: &Matrix4<N2>) -> Self {
let rot: OwnedRotation<N1, U3, SA::Alloc> = ::convert_ref_unchecked(m); let rot: Rotation3<N1> = ::convert_ref_unchecked(m);
Self::from_rotation_matrix(&rot) Self::from_rotation_matrix(&rot)
} }
} }

View File

@ -4,17 +4,11 @@ use std::ops::{Deref, DerefMut};
use alga::general::Real; use alga::general::Real;
use core::coordinates::IJKW; use core::coordinates::IJKW;
use core::storage::OwnedStorage;
use core::allocator::OwnedAllocator;
use core::dimension::{U1, U4};
use geometry::QuaternionBase; use geometry::Quaternion;
impl<N, S> Deref for QuaternionBase<N, S> impl<N: Real> Deref for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
type Target = IJKW<N>; type Target = IJKW<N>;
#[inline] #[inline]
@ -23,10 +17,7 @@ impl<N, S> Deref for QuaternionBase<N, S>
} }
} }
impl<N, S> DerefMut for QuaternionBase<N, S> impl<N: Real> DerefMut for Quaternion<N> {
where N: Real,
S: OwnedStorage<N, U4, U1>,
S::Alloc: OwnedAllocator<N, U4, U1, S> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self) }

View File

@ -17,17 +17,17 @@
* *
* (Unit Quaternion) * (Unit Quaternion)
* UnitQuaternion × UnitQuaternion * UnitQuaternion × UnitQuaternion
* UnitQuaternion × RotationBase -> UnitQuaternion * UnitQuaternion × Rotation -> UnitQuaternion
* RotationBase × UnitQuaternion -> UnitQuaternion * Rotation × UnitQuaternion -> UnitQuaternion
* *
* UnitQuaternion ÷ UnitQuaternion * UnitQuaternion ÷ UnitQuaternion
* UnitQuaternion ÷ RotationBase -> UnitQuaternion * UnitQuaternion ÷ Rotation -> UnitQuaternion
* RotationBase ÷ UnitQuaternion -> UnitQuaternion * Rotation ÷ UnitQuaternion -> UnitQuaternion
* *
* *
* UnitQuaternion × PointBase * UnitQuaternion × Point
* UnitQuaternion × ColumnVector * UnitQuaternion × Vector
* UnitQuaternion × Unit<ColumnVector> * UnitQuaternion × Unit<Vector>
* *
* NOTE: -UnitQuaternion is already provided by `Unit<T>`. * NOTE: -UnitQuaternion is already provided by `Unit<T>`.
* *
@ -40,31 +40,28 @@
* Quaternion -= Quaternion * Quaternion -= Quaternion
* *
* UnitQuaternion ×= UnitQuaternion * UnitQuaternion ×= UnitQuaternion
* UnitQuaternion ×= RotationBase * UnitQuaternion ×= Rotation
* *
* UnitQuaternion ÷= UnitQuaternion * UnitQuaternion ÷= UnitQuaternion
* UnitQuaternion ÷= RotationBase * UnitQuaternion ÷= Rotation
* *
* FIXME: RotationBase ×= UnitQuaternion * FIXME: Rotation ×= UnitQuaternion
* FIXME: RotationBase ÷= 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 alga::general::Real;
use core::{ColumnVector, OwnedColumnVector, Unit}; use core::{DefaultAllocator, Vector, Vector3, Unit};
use core::storage::{Storage, StorageMut}; use core::storage::Storage;
use core::allocator::Allocator; use core::allocator::Allocator;
use core::dimension::{U1, U3, U4}; use core::dimension::{U1, U3, U4};
use geometry::{QuaternionBase, OwnedQuaternionBase, UnitQuaternionBase, OwnedUnitQuaternionBase, use geometry::{Quaternion, UnitQuaternion, Point3, Rotation};
PointBase, OwnedPoint, RotationBase};
impl<N, S> Index<usize> for QuaternionBase<N, S> impl<N: Real> Index<usize> for Quaternion<N> {
where N: Real,
S: Storage<N, U4, U1> {
type Output = N; type Output = N;
#[inline] #[inline]
@ -73,10 +70,7 @@ impl<N, S> Index<usize> for QuaternionBase<N, S>
} }
} }
impl<N, S> IndexMut<usize> for QuaternionBase<N, S> impl<N: Real> IndexMut<usize> for Quaternion<N> {
where N: Real,
S: StorageMut<N, U4, U1> {
#[inline] #[inline]
fn index_mut(&mut self, i: usize) -> &mut N { fn index_mut(&mut self, i: usize) -> &mut N {
&mut self.coords[i] &mut self.coords[i]
@ -85,15 +79,13 @@ impl<N, S> IndexMut<usize> for QuaternionBase<N, S>
macro_rules! quaternion_op_impl( macro_rules! quaternion_op_impl(
($Op: ident, $op: ident; ($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)*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty $(=> $VDimA: ty, $VDimB: ty)*;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N: Real $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs
where N: Real, where DefaultAllocator: Allocator<N, $LhsRDim, $LhsCDim> +
SA: Storage<N, $LhsRDim, $LhsCDim>, Allocator<N, $RhsRDim, $RhsCDim> {
SB: Storage<N, $RhsRDim, $RhsCDim>,
$(SA::Alloc: Allocator<N, $VDimA, U1>,
SB::Alloc: Allocator<N, $VDimB, U1>)* {
type Output = $Result; type Output = $Result;
#[inline] #[inline]
@ -109,29 +101,29 @@ macro_rules! quaternion_op_impl(
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(&self.coords + &rhs.coords); Quaternion::from_vector(&self.coords + &rhs.coords);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SB::Alloc>; self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(&self.coords + rhs.coords); Quaternion::from_vector(&self.coords + rhs.coords);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(self.coords + &rhs.coords); Quaternion::from_vector(self.coords + &rhs.coords);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(self.coords + rhs.coords); Quaternion::from_vector(self.coords + rhs.coords);
); );
@ -139,29 +131,29 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(&self.coords - &rhs.coords); Quaternion::from_vector(&self.coords - &rhs.coords);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SB::Alloc>; self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(&self.coords - rhs.coords); Quaternion::from_vector(&self.coords - rhs.coords);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(self.coords - &rhs.coords); Quaternion::from_vector(self.coords - &rhs.coords);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::from_vector(self.coords - rhs.coords); Quaternion::from_vector(self.coords - rhs.coords);
); );
@ -169,8 +161,8 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
QuaternionBase::new( Quaternion::new(
self[3] * rhs[3] - self[0] * rhs[0] - self[1] * rhs[1] - self[2] * rhs[2], 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[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], 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!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
self * &rhs; self * &rhs;
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
&self * rhs; &self * rhs;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>, Output = OwnedQuaternionBase<N, SA::Alloc>; self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
&self * &rhs; &self * &rhs;
); );
@ -202,28 +194,28 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: &'a UnitQuaternion<N>, rhs: &'b UnitQuaternion<N>, Output = UnitQuaternion<N>;
UnitQuaternionBase::new_unchecked(self.quaternion() * rhs.quaternion()); UnitQuaternion::new_unchecked(self.quaternion() * rhs.quaternion());
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a UnitQuaternionBase<N, SA>, rhs: UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: &'a UnitQuaternion<N>, rhs: UnitQuaternion<N>, Output = UnitQuaternion<N>;
self * &rhs; self * &rhs;
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: &'b UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: UnitQuaternion<N>, rhs: &'b UnitQuaternion<N>, Output = UnitQuaternion<N>;
&self * rhs; &self * rhs;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: UnitQuaternion<N>, rhs: UnitQuaternion<N>, Output = UnitQuaternion<N>;
&self * &rhs; &self * &rhs;
); );
@ -231,173 +223,173 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: &'a UnitQuaternion<N>, rhs: &'b UnitQuaternion<N>, Output = UnitQuaternion<N>;
self * rhs.inverse(); self * rhs.inverse();
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a UnitQuaternionBase<N, SA>, rhs: UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: &'a UnitQuaternion<N>, rhs: UnitQuaternion<N>, Output = UnitQuaternion<N>;
self / &rhs; self / &rhs;
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: &'b UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: UnitQuaternion<N>, rhs: &'b UnitQuaternion<N>, Output = UnitQuaternion<N>;
&self / rhs; &self / rhs;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: UnitQuaternionBase<N, SB>, Output = OwnedUnitQuaternionBase<N, SA::Alloc>; self: UnitQuaternion<N>, rhs: UnitQuaternion<N>, Output = UnitQuaternion<N>;
&self / &rhs; &self / &rhs;
); );
// UnitQuaternion × RotationBase // UnitQuaternion × Rotation
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b RotationBase<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: &'b Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
// FIXME: can we avoid the conversion from a rotation matrix? // FIXME: can we avoid the conversion from a rotation matrix?
self * OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(rhs); self * UnitQuaternion::<N>::from_rotation_matrix(rhs);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: &'a UnitQuaternionBase<N, SA>, rhs: RotationBase<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
self * OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(&rhs); self * UnitQuaternion::<N>::from_rotation_matrix(&rhs);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: &'b RotationBase<N, U3, SB>, self: UnitQuaternion<N>, rhs: &'b Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
self * OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(rhs); self * UnitQuaternion::<N>::from_rotation_matrix(rhs);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: RotationBase<N, U3, SB>, self: UnitQuaternion<N>, rhs: Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
self * OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(&rhs); self * UnitQuaternion::<N>::from_rotation_matrix(&rhs);
); );
// UnitQuaternion ÷ RotationBase // UnitQuaternion ÷ Rotation
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b RotationBase<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: &'b Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
// FIXME: can we avoid the conversion to a rotation matrix? // FIXME: can we avoid the conversion to a rotation matrix?
self / OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(rhs); self / UnitQuaternion::<N>::from_rotation_matrix(rhs);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: &'a UnitQuaternionBase<N, SA>, rhs: RotationBase<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
self / OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(&rhs); self / UnitQuaternion::<N>::from_rotation_matrix(&rhs);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: &'b RotationBase<N, U3, SB>, self: UnitQuaternion<N>, rhs: &'b Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
self / OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(rhs); self / UnitQuaternion::<N>::from_rotation_matrix(rhs);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: RotationBase<N, U3, SB>, self: UnitQuaternion<N>, rhs: Rotation<N, U3>,
Output = OwnedUnitQuaternionBase<N, SA::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
self / OwnedUnitQuaternionBase::<N, SA::Alloc>::from_rotation_matrix(&rhs); self / UnitQuaternion::<N>::from_rotation_matrix(&rhs);
); );
// RotationBase × UnitQuaternion // Rotation × UnitQuaternion
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: &'a RotationBase<N, U3, SA>, rhs: &'b UnitQuaternionBase<N, SB>, self: &'a Rotation<N, U3>, rhs: &'b UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
// FIXME: can we avoid the conversion from a rotation matrix? // FIXME: can we avoid the conversion from a rotation matrix?
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(self) * rhs; UnitQuaternion::<N>::from_rotation_matrix(self) * rhs;
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: &'a RotationBase<N, U3, SA>, rhs: UnitQuaternionBase<N, SB>, self: &'a Rotation<N, U3>, rhs: UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(self) * rhs; UnitQuaternion::<N>::from_rotation_matrix(self) * rhs;
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: RotationBase<N, U3, SA>, rhs: &'b UnitQuaternionBase<N, SB>, self: Rotation<N, U3>, rhs: &'b UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(&self) * rhs; UnitQuaternion::<N>::from_rotation_matrix(&self) * rhs;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: RotationBase<N, U3, SA>, rhs: UnitQuaternionBase<N, SB>, self: Rotation<N, U3>, rhs: UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(&self) * rhs; UnitQuaternion::<N>::from_rotation_matrix(&self) * rhs;
); );
// RotationBase ÷ UnitQuaternion // Rotation ÷ UnitQuaternion
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: &'a RotationBase<N, U3, SA>, rhs: &'b UnitQuaternionBase<N, SB>, self: &'a Rotation<N, U3>, rhs: &'b UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
// FIXME: can we avoid the conversion from a rotation matrix? // FIXME: can we avoid the conversion from a rotation matrix?
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(self) / rhs; UnitQuaternion::<N>::from_rotation_matrix(self) / rhs;
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: &'a RotationBase<N, U3, SA>, rhs: UnitQuaternionBase<N, SB>, self: &'a Rotation<N, U3>, rhs: UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(self) / rhs; UnitQuaternion::<N>::from_rotation_matrix(self) / rhs;
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: RotationBase<N, U3, SA>, rhs: &'b UnitQuaternionBase<N, SB>, self: Rotation<N, U3>, rhs: &'b UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(&self) / rhs; UnitQuaternion::<N>::from_rotation_matrix(&self) / rhs;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Div, div; Div, div;
(U3, U3), (U4, U1); (U3, U3), (U4, U1);
self: RotationBase<N, U3, SA>, rhs: UnitQuaternionBase<N, SB>, self: Rotation<N, U3>, rhs: UnitQuaternion<N>,
Output = OwnedUnitQuaternionBase<N, SB::Alloc> => U3, U3; Output = UnitQuaternion<N> => U3, U3;
OwnedUnitQuaternionBase::<N, SB::Alloc>::from_rotation_matrix(&self) / rhs; UnitQuaternion::<N>::from_rotation_matrix(&self) / rhs;
); );
// UnitQuaternion × Vector // UnitQuaternion × Vector
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b ColumnVector<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: &'b Vector<N, U3, SB>,
Output = OwnedColumnVector<N, U3, SA::Alloc> => U3, U4; Output = Vector3<N> => U3, U4;
{ {
let two: N = ::convert(2.0f64); let two: N = ::convert(2.0f64);
let t = self.as_ref().vector().cross(rhs) * two; let t = self.as_ref().vector().cross(rhs) * two;
@ -409,91 +401,91 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: &'a UnitQuaternionBase<N, SA>, rhs: ColumnVector<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: Vector<N, U3, SB>,
Output = OwnedColumnVector<N, U3, SA::Alloc> => U3, U4; Output = Vector3<N> => U3, U4;
self * &rhs; self * &rhs;
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternionBase<N, SA>, rhs: &'b ColumnVector<N, U3, SB>, self: UnitQuaternion<N>, rhs: &'b Vector<N, U3, SB>,
Output = OwnedColumnVector<N, U3, SA::Alloc> => U3, U4; Output = Vector3<N> => U3, U4;
&self * rhs; &self * rhs;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternionBase<N, SA>, rhs: ColumnVector<N, U3, SB>, self: UnitQuaternion<N>, rhs: Vector<N, U3, SB>,
Output = OwnedColumnVector<N, U3, SA::Alloc> => U3, U4; Output = Vector3<N> => U3, U4;
&self * &rhs; &self * &rhs;
); );
// UnitQuaternion × PointBase // UnitQuaternion × Point
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b PointBase<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: &'b Point3<N>,
Output = OwnedPoint<N, U3, SA::Alloc> => U3, U4; Output = Point3<N> => U3, U4;
PointBase::from_coordinates(self * &rhs.coords); Point3::from_coordinates(self * &rhs.coords);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: &'a UnitQuaternionBase<N, SA>, rhs: PointBase<N, U3, SB>, self: &'a UnitQuaternion<N>, rhs: Point3<N>,
Output = OwnedPoint<N, U3, SA::Alloc> => U3, U4; Output = Point3<N> => U3, U4;
PointBase::from_coordinates(self * rhs.coords); Point3::from_coordinates(self * rhs.coords);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, rhs: &'b PointBase<N, U3, SB>, self: UnitQuaternion<N>, rhs: &'b Point3<N>,
Output = OwnedPoint<N, U3, SA::Alloc> => U3, U4; Output = Point3<N> => U3, U4;
PointBase::from_coordinates(self * &rhs.coords); Point3::from_coordinates(self * &rhs.coords);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, rhs: PointBase<N, U3, SB>, self: UnitQuaternion<N>, rhs: Point3<N>,
Output = OwnedPoint<N, U3, SA::Alloc> => U3, U4; Output = Point3<N> => U3, U4;
PointBase::from_coordinates(self * rhs.coords); Point3::from_coordinates(self * rhs.coords);
); );
// UnitQuaternion × Unit<Vector> // UnitQuaternion × Unit<Vector>
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: &'a UnitQuaternionBase<N, SA>, rhs: &'b Unit<ColumnVector<N, U3, SB>>, self: &'a UnitQuaternion<N>, rhs: &'b Unit<Vector<N, U3, SB>>,
Output = Unit<OwnedColumnVector<N, U3, SA::Alloc>> => U3, U4; Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.as_ref()); Unit::new_unchecked(self * rhs.as_ref());
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: &'a UnitQuaternionBase<N, SA>, rhs: Unit<ColumnVector<N, U3, SB>>, self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<OwnedColumnVector<N, U3, SA::Alloc>> => U3, U4; Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap()); Unit::new_unchecked(self * rhs.unwrap());
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternionBase<N, SA>, rhs: &'b Unit<ColumnVector<N, U3, SB>>, self: UnitQuaternion<N>, rhs: &'b Unit<Vector<N, U3, SB>>,
Output = Unit<OwnedColumnVector<N, U3, SA::Alloc>> => U3, U4; Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.as_ref()); Unit::new_unchecked(self * rhs.as_ref());
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternionBase<N, SA>, rhs: Unit<ColumnVector<N, U3, SB>>, self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<OwnedColumnVector<N, U3, SA::Alloc>> => U3, U4; Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap()); Unit::new_unchecked(self * rhs.unwrap());
); );
@ -501,31 +493,25 @@ quaternion_op_impl!(
macro_rules! scalar_op_impl( macro_rules! scalar_op_impl(
($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$( ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$(
impl<N, S> $Op<N> for QuaternionBase<N, S> impl<N: Real> $Op<N> for Quaternion<N> {
where N: Real, type Output = Quaternion<N>;
S: Storage<N, U4, U1> {
type Output = OwnedQuaternionBase<N, S::Alloc>;
#[inline] #[inline]
fn $op(self, n: N) -> Self::Output { 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<N> for &'a QuaternionBase<N, S> impl<'a, N: Real> $Op<N> for &'a Quaternion<N> {
where N: Real, type Output = Quaternion<N>;
S: Storage<N, U4, U1> {
type Output = OwnedQuaternionBase<N, S::Alloc>;
#[inline] #[inline]
fn $op(self, n: N) -> Self::Output { fn $op(self, n: N) -> Self::Output {
QuaternionBase::from_vector((&self.coords).$op(n)) Quaternion::from_vector((&self.coords).$op(n))
} }
} }
impl<N, S> $OpAssign<N> for QuaternionBase<N, S> impl<N: Real> $OpAssign<N> for Quaternion<N> {
where N: Real,
S: StorageMut<N, U4, U1> {
#[inline] #[inline]
fn $op_assign(&mut self, n: N) { fn $op_assign(&mut self, n: N) {
@ -542,23 +528,21 @@ scalar_op_impl!(
macro_rules! left_scalar_mul_impl( macro_rules! left_scalar_mul_impl(
($($T: ty),* $(,)*) => {$( ($($T: ty),* $(,)*) => {$(
impl<S> Mul<QuaternionBase<$T, S>> for $T impl Mul<Quaternion<$T>> for $T {
where S: Storage<$T, U4, U1> { type Output = Quaternion<$T>;
type Output = OwnedQuaternionBase<$T, S::Alloc>;
#[inline] #[inline]
fn mul(self, right: QuaternionBase<$T, S>) -> Self::Output { fn mul(self, right: Quaternion<$T>) -> Self::Output {
QuaternionBase::from_vector(self * right.coords) Quaternion::from_vector(self * right.coords)
} }
} }
impl<'b, S> Mul<&'b QuaternionBase<$T, S>> for $T impl<'b> Mul<&'b Quaternion<$T>> for $T {
where S: Storage<$T, U4, U1> { type Output = Quaternion<$T>;
type Output = OwnedQuaternionBase<$T, S::Alloc>;
#[inline] #[inline]
fn mul(self, right: &'b QuaternionBase<$T, S>) -> Self::Output { fn mul(self, right: &'b Quaternion<$T>) -> Self::Output {
QuaternionBase::from_vector(self * &right.coords) Quaternion::from_vector(self * &right.coords)
} }
} }
)*} )*}
@ -566,25 +550,21 @@ macro_rules! left_scalar_mul_impl(
left_scalar_mul_impl!(f32, f64); left_scalar_mul_impl!(f32, f64);
impl<N, S> Neg for QuaternionBase<N, S> impl<N: Real> Neg for Quaternion<N> {
where N: Real, type Output = Quaternion<N>;
S: Storage<N, U4, U1> {
type Output = OwnedQuaternionBase<N, S::Alloc>;
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
QuaternionBase::from_vector(-self.coords) Quaternion::from_vector(-self.coords)
} }
} }
impl<'a, N, S> Neg for &'a QuaternionBase<N, S> impl<'a, N: Real> Neg for &'a Quaternion<N> {
where N: Real, type Output = Quaternion<N>;
S: Storage<N, U4, U1> {
type Output = OwnedQuaternionBase<N, S::Alloc>;
#[inline] #[inline]
fn neg(self) -> Self::Output { 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); ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident);
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N, SA, SB> $OpAssign<$Rhs> for $Lhs impl<$($lives ,)* N: Real> $OpAssign<$Rhs> for $Lhs
where N: Real, where DefaultAllocator: Allocator<N, $LhsRDim, $LhsCDim> +
SA: StorageMut<N, $LhsRDim, $LhsCDim>, Allocator<N, $RhsRDim, $RhsCDim> {
SB: Storage<N, $RhsRDim, $RhsCDim>,
$(SA::Alloc: Allocator<N, $VDimA, U1> + Allocator<N, U4, U1>,
// ^^^^^^^^^^^^^^^^^^^^
// 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<N, $VDimB, U1>)* {
#[inline] #[inline]
fn $op_assign(&mut $lhs, $rhs: $Rhs) { fn $op_assign(&mut $lhs, $rhs: $Rhs) {
@ -617,14 +589,14 @@ macro_rules! quaternion_op_impl(
quaternion_op_impl!( quaternion_op_impl!(
AddAssign, add_assign; AddAssign, add_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>; self: Quaternion<N>, rhs: &'b Quaternion<N>;
self.coords += &rhs.coords; self.coords += &rhs.coords;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
AddAssign, add_assign; AddAssign, add_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>; self: Quaternion<N>, rhs: Quaternion<N>;
self.coords += rhs.coords; ); self.coords += rhs.coords; );
@ -632,21 +604,21 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
SubAssign, sub_assign; SubAssign, sub_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>; self: Quaternion<N>, rhs: &'b Quaternion<N>;
self.coords -= &rhs.coords; self.coords -= &rhs.coords;
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
SubAssign, sub_assign; SubAssign, sub_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>; self: Quaternion<N>, rhs: Quaternion<N>;
self.coords -= rhs.coords; ); self.coords -= rhs.coords; );
// Quaternion ×= Quaternion // Quaternion ×= Quaternion
quaternion_op_impl!( quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: &'b QuaternionBase<N, SB>; self: Quaternion<N>, rhs: &'b Quaternion<N>;
{ {
let res = &*self * rhs; let res = &*self * rhs;
// FIXME: will this be optimized away? // FIXME: will this be optimized away?
@ -657,14 +629,14 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: QuaternionBase<N, SA>, rhs: QuaternionBase<N, SB>; self: Quaternion<N>, rhs: Quaternion<N>;
*self *= &rhs; ); *self *= &rhs; );
// UnitQuaternion ×= UnitQuaternion // UnitQuaternion ×= UnitQuaternion
quaternion_op_impl!( quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: &'b UnitQuaternionBase<N, SB>; self: UnitQuaternion<N>, rhs: &'b UnitQuaternion<N>;
{ {
let res = &*self * rhs; let res = &*self * rhs;
self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
@ -674,14 +646,14 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: UnitQuaternionBase<N, SB>; self: UnitQuaternion<N>, rhs: UnitQuaternion<N>;
*self *= &rhs; ); *self *= &rhs; );
// UnitQuaternion ÷= UnitQuaternion // UnitQuaternion ÷= UnitQuaternion
quaternion_op_impl!( quaternion_op_impl!(
DivAssign, div_assign; DivAssign, div_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: &'b UnitQuaternionBase<N, SB>; self: UnitQuaternion<N>, rhs: &'b UnitQuaternion<N>;
{ {
let res = &*self / rhs; let res = &*self / rhs;
self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
@ -691,14 +663,14 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
DivAssign, div_assign; DivAssign, div_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitQuaternionBase<N, SA>, rhs: UnitQuaternionBase<N, SB>; self: UnitQuaternion<N>, rhs: UnitQuaternion<N>;
*self /= &rhs; ); *self /= &rhs; );
// UnitQuaternion ×= RotationBase // UnitQuaternion ×= Rotation
quaternion_op_impl!( quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: &'b RotationBase<N, U3, SB> => U3, U3; self: UnitQuaternion<N>, rhs: &'b Rotation<N, U3> => U3, U3;
{ {
let res = &*self * rhs; let res = &*self * rhs;
self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
@ -708,14 +680,14 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: RotationBase<N, U3, SB> => U3, U3; self: UnitQuaternion<N>, rhs: Rotation<N, U3> => U3, U3;
*self *= &rhs; ); *self *= &rhs; );
// UnitQuaternion ÷= RotationBase // UnitQuaternion ÷= Rotation
quaternion_op_impl!( quaternion_op_impl!(
DivAssign, div_assign; DivAssign, div_assign;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: &'b RotationBase<N, U3, SB> => U3, U3; self: UnitQuaternion<N>, rhs: &'b Rotation<N, U3> => U3, U3;
{ {
let res = &*self / rhs; let res = &*self / rhs;
self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords);
@ -725,5 +697,5 @@ quaternion_op_impl!(
quaternion_op_impl!( quaternion_op_impl!(
DivAssign, div_assign; DivAssign, div_assign;
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitQuaternionBase<N, SA>, rhs: RotationBase<N, U3, SB> => U3, U3; self: UnitQuaternion<N>, rhs: Rotation<N, U3> => U3, U3;
*self /= &rhs; ); *self /= &rhs; );

View File

@ -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<N: Scalar, D: Dim, S: Storage<N, D>> {
axis: Vector<N, D, S>,
bias: N
}
impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
/// 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<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> {
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<Vector<N, D, S>>, pt: &Point<N, D>) -> Reflection<N, D, S>
where D: DimName,
DefaultAllocator: Allocator<N, D> {
let bias = pt.coords.dot(axis.as_ref());
Self::new(axis, bias)
}
/// The reflexion axis.
pub fn axis(&self) -> &Vector<N, D, S> {
&self.axis
}
// FIXME: naming convension: reflect_to, reflect_assign ?
/// Applies the reflection to the columns of `rhs`.
pub fn reflect<R2: Dim, C2: Dim, S2>(&self, rhs: &mut Matrix<N, R2, C2, S2>)
where S2: StorageMut<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R2, D> {
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<R2: Dim, C2: Dim, S2, S3>(&self,
rhs: &mut Matrix<N, R2, C2, S2>,
work: &mut Vector<N, R2, S3>)
where S2: StorageMut<N, R2, C2>,
S3: StorageMut<N, R2>,
ShapeConstraint: DimEq<C2, D> + AreMultipliable<R2, C2, D, U1> {
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());
}
}

View File

@ -1,60 +1,79 @@
use num::{Zero, One}; use num::{Zero, One};
use std::hash;
use std::fmt; use std::fmt;
use approx::ApproxEq; use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[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 alga::general::Real;
use core::{SquareMatrix, Scalar, OwnedSquareMatrix}; use core::{DefaultAllocator, Scalar, MatrixN};
use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1};
use core::storage::{Storage, StorageMut};
use core::allocator::Allocator; use core::allocator::Allocator;
/// A rotation matrix with an owned storage.
pub type OwnedRotation<N, D, A> = RotationBase<N, D, <A as Allocator<N, D, D>>::Buffer>;
/// A rotation matrix. /// A rotation matrix.
#[repr(C)] #[repr(C)]
#[derive(Hash, Debug, Clone, Copy)] #[derive(Debug)]
pub struct RotationBase<N: Scalar, D: DimName, S> { pub struct Rotation<N: Scalar, D: DimName>
matrix: SquareMatrix<N, D, S> where DefaultAllocator: Allocator<N, D, D> {
matrix: MatrixN<N, D>
} }
#[cfg(feature = "serde-serialize")] impl<N: Scalar + hash::Hash, D: DimName + hash::Hash> hash::Hash for Rotation<N, D>
impl<N, D, S> Serialize for RotationBase<N, D, S> where DefaultAllocator: Allocator<N, D, D>,
where N: Scalar, <DefaultAllocator as Allocator<N, D, D>>::Buffer: hash::Hash {
D: DimName, fn hash<H: hash::Hasher>(&self, state: &mut H) {
SquareMatrix<N, D, S>: Serialize, self.matrix.hash(state)
{ }
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error> }
where T: Serializer
{ impl<N: Scalar, D: DimName> Copy for Rotation<N, D>
self.matrix.serialize(serializer) where DefaultAllocator: Allocator<N, D, D>,
<DefaultAllocator as Allocator<N, D, D>>::Buffer: Copy { }
impl<N: Scalar, D: DimName> Clone for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D>,
<DefaultAllocator as Allocator<N, D, D>>::Buffer: Clone {
#[inline]
fn clone(&self) -> Self {
Rotation::from_matrix_unchecked(self.matrix.clone())
} }
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<'de, N, D, S> Deserialize<'de> for RotationBase<N, D, S> impl<N: Scalar, D: DimName> serde::Serialize for Rotation<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D, D>,
D: DimName, Owned<N, D, D>: serde::Serialize {
SquareMatrix<N, D, S>: Deserialize<'de>,
{ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn deserialize<T>(deserializer: T) -> Result<Self, T::Error> where S: serde::Serializer {
where T: Deserializer<'de> self.matrix.serialize(serializer)
{ }
SquareMatrix::deserialize(deserializer).map(|x| RotationBase { matrix: x })
}
} }
impl<N: Scalar, D: DimName, S: Storage<N, D, D>> RotationBase<N, D, S> #[cfg(feature = "serde-serialize")]
where N: Scalar, impl<'a, N: Scalar, D: DimName> serde::Deserialize<'a> for Rotation<N, D>
S: Storage<N, D, D> { where DefaultAllocator: Allocator<N, D, D>,
Owned<N, D, D>: serde::Deserialize<'a> {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where Des: serde::Deserializer<'a> {
let matrix = MatrixN::<N, D>::deserialize(deserializer)?;
Ok(Rotation::from_matrix_unchecked(matrix))
}
}
impl<N: Scalar, D: DimName> Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> {
/// A reference to the underlying matrix representation of this rotation. /// A reference to the underlying matrix representation of this rotation.
#[inline] #[inline]
pub fn matrix(&self) -> &SquareMatrix<N, D, S> { pub fn matrix(&self) -> &MatrixN<N, D> {
&self.matrix &self.matrix
} }
@ -64,57 +83,52 @@ impl<N: Scalar, D: DimName, S: Storage<N, D, D>> RotationBase<N, D, S>
/// non-square, non-inversible, or non-orthonormal. If one of those properties is broken, /// non-square, non-inversible, or non-orthonormal. If one of those properties is broken,
/// subsequent method calls may be UB. /// subsequent method calls may be UB.
#[inline] #[inline]
pub unsafe fn matrix_mut(&mut self) -> &mut SquareMatrix<N, D, S> { pub unsafe fn matrix_mut(&mut self) -> &mut MatrixN<N, D> {
&mut self.matrix &mut self.matrix
} }
/// Unwraps the underlying matrix. /// Unwraps the underlying matrix.
#[inline] #[inline]
pub fn unwrap(self) -> SquareMatrix<N, D, S> { pub fn unwrap(self) -> MatrixN<N, D> {
self.matrix self.matrix
} }
/// Converts this rotation into its equivalent homogeneous transformation matrix. /// Converts this rotation into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where N: Zero + One, where N: Zero + One,
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
S::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
let mut res = OwnedSquareMatrix::<N, _, S::Alloc>::identity(); let mut res = MatrixN::<N, DimNameSum<D, U1>>::identity();
res.fixed_slice_mut::<D, D>(0, 0).copy_from(&self.matrix); res.fixed_slice_mut::<D, D>(0, 0).copy_from(&self.matrix);
res res
} }
}
impl<N: Scalar, D: DimName, S: Storage<N, D, D>> RotationBase<N, D, S> {
/// Creates a new rotation from the given square matrix. /// Creates a new rotation from the given square matrix.
/// ///
/// The matrix squareness is checked but not its orthonormality. /// The matrix squareness is checked but not its orthonormality.
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: SquareMatrix<N, D, S>) -> RotationBase<N, D, S> { pub fn from_matrix_unchecked(matrix: MatrixN<N, D>) -> Rotation<N, D> {
assert!(matrix.is_square(), "Unable to create a rotation from a non-square matrix."); assert!(matrix.is_square(), "Unable to create a rotation from a non-square matrix.");
RotationBase { Rotation {
matrix: matrix matrix: matrix
} }
} }
/// Transposes `self`. /// Transposes `self`.
#[inline] #[inline]
pub fn transpose(&self) -> OwnedRotation<N, D, S::Alloc> { pub fn transpose(&self) -> Rotation<N, D> {
RotationBase::from_matrix_unchecked(self.matrix.transpose()) Rotation::from_matrix_unchecked(self.matrix.transpose())
} }
/// Inverts `self`. /// Inverts `self`.
#[inline] #[inline]
pub fn inverse(&self) -> OwnedRotation<N, D, S::Alloc> { pub fn inverse(&self) -> Rotation<N, D> {
self.transpose() self.transpose()
} }
}
impl<N: Scalar, D: DimName, S: StorageMut<N, D, D>> RotationBase<N, D, S> {
/// Transposes `self` in-place. /// Transposes `self` in-place.
#[inline] #[inline]
pub fn transpose_mut(&mut self) { pub fn transpose_mut(&mut self) {
@ -128,18 +142,20 @@ impl<N: Scalar, D: DimName, S: StorageMut<N, D, D>> RotationBase<N, D, S> {
} }
} }
impl<N: Scalar + Eq, D: DimName, S: Storage<N, D, D>> Eq for RotationBase<N, D, S> { } impl<N: Scalar + Eq, D: DimName> Eq for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> { }
impl<N: Scalar + PartialEq, D: DimName, S: Storage<N, D, D>> PartialEq for RotationBase<N, D, S> { impl<N: Scalar + PartialEq, D: DimName> PartialEq for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> {
#[inline] #[inline]
fn eq(&self, right: &RotationBase<N, D, S>) -> bool { fn eq(&self, right: &Rotation<N, D>) -> bool {
self.matrix == right.matrix self.matrix == right.matrix
} }
} }
impl<N, D: DimName, S> ApproxEq for RotationBase<N, D, S> impl<N, D: DimName> ApproxEq for Rotation<N, D>
where N: Scalar + ApproxEq, where N: Scalar + ApproxEq,
S: Storage<N, D, D>, DefaultAllocator: Allocator<N, D, D>,
N::Epsilon: Copy { N::Epsilon: Copy {
type Epsilon = N::Epsilon; type Epsilon = N::Epsilon;
@ -174,14 +190,14 @@ impl<N, D: DimName, S> ApproxEq for RotationBase<N, D, S>
* Display * Display
* *
*/ */
impl<N, D: DimName, S> fmt::Display for RotationBase<N, D, S> impl<N, D: DimName> fmt::Display for Rotation<N, D>
where N: Real + fmt::Display, where N: Real + fmt::Display,
S: Storage<N, D, D>, DefaultAllocator: Allocator<N, D, D> +
S::Alloc: Allocator<usize, D, D> { Allocator<usize, D, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let precision = f.precision().unwrap_or(3); let precision = f.precision().unwrap_or(3);
try!(writeln!(f, "RotationBase matrix {{")); try!(writeln!(f, "Rotation matrix {{"));
try!(write!(f, "{:.*}", precision, self.matrix)); try!(write!(f, "{:.*}", precision, self.matrix));
writeln!(f, "}}") writeln!(f, "}}")
} }

View File

@ -1,14 +1,13 @@
use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id}; AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id};
use alga::linear::{Transformation, Similarity, AffineTransformation, Isometry, DirectIsometry, use alga::linear::{self, Transformation, Similarity, AffineTransformation, Isometry,
OrthogonalTransformation, ProjectiveTransformation, Rotation}; DirectIsometry, OrthogonalTransformation, ProjectiveTransformation};
use core::ColumnVector; use core::{DefaultAllocator, VectorN};
use core::dimension::{DimName, U1}; use core::dimension::DimName;
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::{RotationBase, PointBase}; use geometry::{Rotation, Point};
@ -17,20 +16,16 @@ use geometry::{RotationBase, PointBase};
* Algebraic structures. * Algebraic structures.
* *
*/ */
impl<N, D: DimName, S> Identity<Multiplicative> for RotationBase<N, D, S> impl<N: Real, D: DimName> Identity<Multiplicative> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> {
S: OwnedStorage<N, D, D>,
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, D: DimName, S> Inverse<Multiplicative> for RotationBase<N, D, S> impl<N: Real, D: DimName> Inverse<Multiplicative> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> {
S: OwnedStorage<N, D, D>,
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
self.transpose() self.transpose()
@ -42,10 +37,8 @@ impl<N, D: DimName, S> Inverse<Multiplicative> for RotationBase<N, D, S>
} }
} }
impl<N, D: DimName, S> AbstractMagma<Multiplicative> for RotationBase<N, D, S> impl<N: Real, D: DimName> AbstractMagma<Multiplicative> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> {
S: OwnedStorage<N, D, D>,
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
@ -54,10 +47,8 @@ impl<N, D: DimName, S> AbstractMagma<Multiplicative> for RotationBase<N, D, S>
macro_rules! impl_multiplicative_structures( macro_rules! impl_multiplicative_structures(
($($marker: ident<$operator: ident>),* $(,)*) => {$( ($($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, D: DimName, S> $marker<$operator> for RotationBase<N, D, S> impl<N: Real, D: DimName> $marker<$operator> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> { }
S: OwnedStorage<N, D, D>,
S::Alloc: OwnedAllocator<N, D, D, S> { }
)*} )*}
); );
@ -74,46 +65,37 @@ impl_multiplicative_structures!(
* Transformation groups. * Transformation groups.
* *
*/ */
impl<N, D: DimName, SA, SB> Transformation<PointBase<N, D, SB>> for RotationBase<N, D, SA> impl<N: Real, D: DimName> Transformation<Point<N, D>> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
SA: OwnedStorage<N, D, D>, Allocator<N, D> {
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA>,
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, D, SB>) -> PointBase<N, D, SB> { fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self * pt self * pt
} }
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, D, SB>) -> ColumnVector<N, D, SB> { fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self * v self * v
} }
} }
impl<N, D: DimName, SA, SB> ProjectiveTransformation<PointBase<N, D, SB>> for RotationBase<N, D, SA> impl<N: Real, D: DimName> ProjectiveTransformation<Point<N, D>> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
SA: OwnedStorage<N, D, D>, Allocator<N, D> {
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA>,
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &PointBase<N, D, SB>) -> PointBase<N, D, SB> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
PointBase::from_coordinates(self.inverse_transform_vector(&pt.coords)) Point::from_coordinates(self.inverse_transform_vector(&pt.coords))
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &ColumnVector<N, D, SB>) -> ColumnVector<N, D, SB> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self.matrix().tr_mul(v) self.matrix().tr_mul(v)
} }
} }
impl<N, D: DimName, SA, SB> AffineTransformation<PointBase<N, D, SB>> for RotationBase<N, D, SA> impl<N: Real, D: DimName> AffineTransformation<Point<N, D>> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
SA: OwnedStorage<N, D, D>, Allocator<N, D> {
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA>,
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
type Rotation = Self; type Rotation = Self;
type NonUniformScaling = Id; type NonUniformScaling = Id;
type Translation = Id; type Translation = Id;
@ -155,12 +137,9 @@ impl<N, D: DimName, SA, SB> AffineTransformation<PointBase<N, D, SB>> for Rotati
} }
impl<N, D: DimName, SA, SB> Similarity<PointBase<N, D, SB>> for RotationBase<N, D, SA> impl<N: Real, D: DimName> Similarity<Point<N, D>> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
SA: OwnedStorage<N, D, D>, Allocator<N, D> {
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA>,
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
type Scaling = Id; type Scaling = Id;
#[inline] #[inline]
@ -181,12 +160,9 @@ impl<N, D: DimName, SA, SB> Similarity<PointBase<N, D, SB>> for RotationBase<N,
macro_rules! marker_impl( macro_rules! marker_impl(
($($Trait: ident),*) => {$( ($($Trait: ident),*) => {$(
impl<N, D: DimName, SA, SB> $Trait<PointBase<N, D, SB>> for RotationBase<N, D, SA> impl<N: Real, D: DimName> $Trait<Point<N, D>> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
SA: OwnedStorage<N, D, D>, Allocator<N, D> { }
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA>,
SB::Alloc: OwnedAllocator<N, D, U1, SB> { }
)*} )*}
); );
@ -194,12 +170,9 @@ marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation);
/// Subgroups of the n-dimensional rotation group `SO(n)`. /// Subgroups of the n-dimensional rotation group `SO(n)`.
impl<N, D: DimName, SA, SB> Rotation<PointBase<N, D, SB>> for RotationBase<N, D, SA> impl<N: Real, D: DimName> linear::Rotation<Point<N, D>> for Rotation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D, D> +
SA: OwnedStorage<N, D, D>, Allocator<N, D> {
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, D, D, SA>,
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
#[inline] #[inline]
fn powf(&self, _: N) -> Option<Self> { fn powf(&self, _: N) -> Option<Self> {
// XXX: Add the general case. // XXX: Add the general case.
@ -208,14 +181,14 @@ impl<N, D: DimName, SA, SB> Rotation<PointBase<N, D, SB>> for RotationBase<N, D,
} }
#[inline] #[inline]
fn rotation_between(_: &ColumnVector<N, D, SB>, _: &ColumnVector<N, D, SB>) -> Option<Self> { fn rotation_between(_: &VectorN<N, D>, _: &VectorN<N, D>) -> Option<Self> {
// XXX: Add the general case. // XXX: Add the general case.
// XXX: Use specialization for 2D and 3D. // XXX: Use specialization for 2D and 3D.
unimplemented!() unimplemented!()
} }
#[inline] #[inline]
fn scaled_rotation_between(_: &ColumnVector<N, D, SB>, _: &ColumnVector<N, D, SB>, _: N) -> Option<Self> { fn scaled_rotation_between(_: &VectorN<N, D>, _: &VectorN<N, D>, _: N) -> Option<Self> {
// XXX: Add the general case. // XXX: Add the general case.
// XXX: Use specialization for 2D and 3D. // XXX: Use specialization for 2D and 3D.
unimplemented!() unimplemented!()
@ -223,7 +196,7 @@ impl<N, D: DimName, SA, SB> Rotation<PointBase<N, D, SB>> for RotationBase<N, D,
} }
/* /*
impl<N: Real> Matrix for RotationBase<N> { impl<N: Real> Matrix for Rotation<N> {
type Field = N; type Field = N;
type Row = Matrix<N>; type Row = Matrix<N>;
type Column = Matrix<N>; type Column = Matrix<N>;
@ -261,11 +234,11 @@ impl<N: Real> Matrix for RotationBase<N> {
#[inline] #[inline]
fn transpose(&self) -> Self::Transpose { fn transpose(&self) -> Self::Transpose {
RotationBase::from_matrix_unchecked(self.submatrix.transpose()) Rotation::from_matrix_unchecked(self.submatrix.transpose())
} }
} }
impl<N: Real> SquareMatrix for RotationBase<N> { impl<N: Real> SquareMatrix for Rotation<N> {
type Vector = Matrix<N>; type Vector = Matrix<N>;
#[inline] #[inline]
@ -295,7 +268,7 @@ impl<N: Real> SquareMatrix for RotationBase<N> {
} }
} }
impl<N: Real> InversibleSquareMatrix for RotationBase<N> { } impl<N: Real> InversibleSquareMatrix for Rotation<N> { }
*/ */

View File

@ -1,10 +1,6 @@
use core::MatrixArray;
use core::dimension::{U2, U3}; use core::dimension::{U2, U3};
use geometry::RotationBase; use geometry::Rotation;
/// A D-dimensional rotation matrix.
pub type Rotation<N, D> = RotationBase<N, D, MatrixArray<N, D, D>>;
/// A 2-dimensional rotation matrix. /// A 2-dimensional rotation matrix.
pub type Rotation2<N> = Rotation<N, U2>; pub type Rotation2<N> = Rotation<N, U2>;

View File

@ -2,28 +2,25 @@ use num::{Zero, One};
use alga::general::{ClosedAdd, ClosedMul}; use alga::general::{ClosedAdd, ClosedMul};
use core::{SquareMatrix, Scalar}; use core::{DefaultAllocator, MatrixN, Scalar};
use core::dimension::DimName; use core::dimension::DimName;
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::RotationBase; use geometry::Rotation;
impl<N, D: DimName, S> RotationBase<N, D, S> impl<N, D: DimName> Rotation<N, D>
where N: Scalar + Zero + One, where N: Scalar + Zero + One,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
/// Creates a new square identity rotation of the given `dimension`. /// Creates a new square identity rotation of the given `dimension`.
#[inline] #[inline]
pub fn identity() -> RotationBase<N, D, S> { pub fn identity() -> Rotation<N, D> {
Self::from_matrix_unchecked(SquareMatrix::<N, D, S>::identity()) Self::from_matrix_unchecked(MatrixN::<N, D>::identity())
} }
} }
impl<N, D: DimName, S> One for RotationBase<N, D, S> impl<N, D: DimName> One for Rotation<N, D>
where N: Scalar + Zero + One + ClosedAdd + ClosedMul, where N: Scalar + Zero + One + ClosedAdd + ClosedMul,
S: OwnedStorage<N, D, D>, DefaultAllocator: Allocator<N, D, D> {
S::Alloc: OwnedAllocator<N, D, D, S> {
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
Self::identity() Self::identity()

View File

@ -3,178 +3,186 @@ use num::Zero;
use alga::general::{Real, SubsetOf, SupersetOf}; use alga::general::{Real, SubsetOf, SupersetOf};
use alga::linear::Rotation as AlgaRotation; use alga::linear::Rotation as AlgaRotation;
use core::{Matrix, SquareMatrix}; use core::{DefaultAllocator, MatrixN};
use core::dimension::{DimName, DimNameSum, DimNameAdd, U1, U3, U4}; use core::dimension::{DimName, DimNameSum, DimNameAdd, DimMin, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::{OwnedAllocator, Allocator};
use geometry::{PointBase, TranslationBase, RotationBase, UnitQuaternionBase, OwnedUnitQuaternionBase, IsometryBase, use geometry::{Point, Translation, Rotation, UnitQuaternion, UnitComplex, Isometry,
SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; Similarity, Transform, SuperTCategoryOf, TAffine,
Rotation2, Rotation3};
/* /*
* This file provides the following conversions: * This file provides the following conversions:
* ============================================= * =============================================
* *
* RotationBase -> RotationBase * Rotation -> Rotation
* Rotation3 -> UnitQuaternion * Rotation3 -> UnitQuaternion
* RotationBase -> IsometryBase * Rotation2 -> UnitComplex
* RotationBase -> SimilarityBase * Rotation -> Isometry
* RotationBase -> TransformBase * Rotation -> Similarity
* RotationBase -> Matrix (homogeneous) * Rotation -> Transform
* Rotation -> Matrix (homogeneous)
*/ */
impl<N1, N2, D: DimName, SA, SB> SubsetOf<RotationBase<N2, D, SB>> for RotationBase<N1, D, SA> impl<N1, N2, D: DimName> SubsetOf<Rotation<N2, D>> for Rotation<N1, D>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, D>, DefaultAllocator: Allocator<N1, D, D> +
SB: OwnedStorage<N2, D, D>, Allocator<N2, D, D> {
SA::Alloc: OwnedAllocator<N1, D, D, SA>,
SB::Alloc: OwnedAllocator<N2, D, D, SB> {
#[inline] #[inline]
fn to_superset(&self) -> RotationBase<N2, D, SB> { fn to_superset(&self) -> Rotation<N2, D> {
RotationBase::from_matrix_unchecked(self.matrix().to_superset()) Rotation::from_matrix_unchecked(self.matrix().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(rot: &RotationBase<N2, D, SB>) -> bool { fn is_in_subset(rot: &Rotation<N2, D>) -> bool {
::is_convertible::<_, Matrix<N1, D, D, SA>>(rot.matrix()) ::is_convertible::<_, MatrixN<N1, D>>(rot.matrix())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(rot: &RotationBase<N2, D, SB>) -> Self { unsafe fn from_superset_unchecked(rot: &Rotation<N2, D>) -> Self {
RotationBase::from_matrix_unchecked(rot.matrix().to_subset_unchecked()) Rotation::from_matrix_unchecked(rot.matrix().to_subset_unchecked())
} }
} }
impl<N1, N2, SA, SB> SubsetOf<UnitQuaternionBase<N2, SB>> for RotationBase<N1, U3, SA> impl<N1, N2> SubsetOf<UnitQuaternion<N2>> for Rotation3<N1>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1> {
SA: OwnedStorage<N1, U3, U3>,
SB: OwnedStorage<N2, U4, U1>,
SA::Alloc: OwnedAllocator<N1, U3, U3, SA> +
Allocator<N1, U4, U1> +
Allocator<N1, U3, U1>,
SB::Alloc: OwnedAllocator<N2, U4, U1, SB> +
Allocator<N2, U3, U3> {
#[inline] #[inline]
fn to_superset(&self) -> UnitQuaternionBase<N2, SB> { fn to_superset(&self) -> UnitQuaternion<N2> {
let q = OwnedUnitQuaternionBase::<N1, SA::Alloc>::from_rotation_matrix(self); let q = UnitQuaternion::<N1>::from_rotation_matrix(self);
q.to_superset() q.to_superset()
} }
#[inline] #[inline]
fn is_in_subset(q: &UnitQuaternionBase<N2, SB>) -> bool { fn is_in_subset(q: &UnitQuaternion<N2>) -> bool {
::is_convertible::<_, OwnedUnitQuaternionBase<N1, SA::Alloc>>(q) ::is_convertible::<_, UnitQuaternion<N1>>(q)
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(q: &UnitQuaternionBase<N2, SB>) -> Self { unsafe fn from_superset_unchecked(q: &UnitQuaternion<N2>) -> Self {
let q: OwnedUnitQuaternionBase<N1, SA::Alloc> = ::convert_ref_unchecked(q); let q: UnitQuaternion<N1> = ::convert_ref_unchecked(q);
q.to_rotation_matrix()
}
}
impl<N1, N2> SubsetOf<UnitComplex<N2>> for Rotation2<N1>
where N1: Real,
N2: Real + SupersetOf<N1> {
#[inline]
fn to_superset(&self) -> UnitComplex<N2> {
let q = UnitComplex::<N1>::from_rotation_matrix(self);
q.to_superset()
}
#[inline]
fn is_in_subset(q: &UnitComplex<N2>) -> bool {
::is_convertible::<_, UnitComplex<N1>>(q)
}
#[inline]
unsafe fn from_superset_unchecked(q: &UnitComplex<N2>) -> Self {
let q: UnitComplex<N1> = ::convert_ref_unchecked(q);
q.to_rotation_matrix() q.to_rotation_matrix()
} }
} }
impl<N1, N2, D: DimName, SA, SB, R> SubsetOf<IsometryBase<N2, D, SB, R>> for RotationBase<N1, D, SA>
impl<N1, N2, D: DimName, R> SubsetOf<Isometry<N2, D, R>> for Rotation<N1, D>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, D>, R: AlgaRotation<Point<N2, D>> + SupersetOf<Rotation<N1, D>>,
SB: OwnedStorage<N2, D, U1>, DefaultAllocator: Allocator<N1, D, D> +
R: AlgaRotation<PointBase<N2, D, SB>> + SupersetOf<RotationBase<N1, D, SA>>, Allocator<N2, D> {
SA::Alloc: OwnedAllocator<N1, D, D, SA>,
SB::Alloc: OwnedAllocator<N2, D, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> IsometryBase<N2, D, SB, R> { fn to_superset(&self) -> Isometry<N2, D, R> {
IsometryBase::from_parts(TranslationBase::identity(), ::convert_ref(self)) Isometry::from_parts(Translation::identity(), ::convert_ref(self))
} }
#[inline] #[inline]
fn is_in_subset(iso: &IsometryBase<N2, D, SB, R>) -> bool { fn is_in_subset(iso: &Isometry<N2, D, R>) -> bool {
iso.translation.vector.is_zero() iso.translation.vector.is_zero()
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(iso: &IsometryBase<N2, D, SB, R>) -> Self { unsafe fn from_superset_unchecked(iso: &Isometry<N2, D, R>) -> Self {
::convert_ref_unchecked(&iso.rotation) ::convert_ref_unchecked(&iso.rotation)
} }
} }
impl<N1, N2, D: DimName, SA, SB, R> SubsetOf<SimilarityBase<N2, D, SB, R>> for RotationBase<N1, D, SA> impl<N1, N2, D: DimName, R> SubsetOf<Similarity<N2, D, R>> for Rotation<N1, D>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, D>, R: AlgaRotation<Point<N2, D>> + SupersetOf<Rotation<N1, D>>,
SB: OwnedStorage<N2, D, U1>, DefaultAllocator: Allocator<N1, D, D> +
R: AlgaRotation<PointBase<N2, D, SB>> + SupersetOf<RotationBase<N1, D, SA>>, Allocator<N2, D> {
SA::Alloc: OwnedAllocator<N1, D, D, SA>,
SB::Alloc: OwnedAllocator<N2, D, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> SimilarityBase<N2, D, SB, R> { fn to_superset(&self) -> Similarity<N2, D, R> {
SimilarityBase::from_parts(TranslationBase::identity(), ::convert_ref(self), N2::one()) Similarity::from_parts(Translation::identity(), ::convert_ref(self), N2::one())
} }
#[inline] #[inline]
fn is_in_subset(sim: &SimilarityBase<N2, D, SB, R>) -> bool { fn is_in_subset(sim: &Similarity<N2, D, R>) -> bool {
sim.isometry.translation.vector.is_zero() && sim.isometry.translation.vector.is_zero() &&
sim.scaling() == N2::one() sim.scaling() == N2::one()
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(sim: &SimilarityBase<N2, D, SB, R>) -> Self { unsafe fn from_superset_unchecked(sim: &Similarity<N2, D, R>) -> Self {
::convert_ref_unchecked(&sim.isometry.rotation) ::convert_ref_unchecked(&sim.isometry.rotation)
} }
} }
impl<N1, N2, D, SA, SB, C> SubsetOf<TransformBase<N2, D, SB, C>> for RotationBase<N1, D, SA> impl<N1, N2, D, C> SubsetOf<Transform<N2, D, C>> for Rotation<N1, D>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, D>,
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>,
C: SuperTCategoryOf<TAffine>, C: SuperTCategoryOf<TAffine>,
D: DimNameAdd<U1>, D: DimNameAdd<U1> +
SA::Alloc: OwnedAllocator<N1, D, D, SA> + DimMin<D, Output = D>, // needed by .is_special_orthogonal()
Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N1, D, D> +
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB> + Allocator<N2, D, D> +
Allocator<N2, D, D> + Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N2, U1, D> { Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<(usize, usize), D> { // needed by .is_special_orthogonal()
#[inline] #[inline]
fn to_superset(&self) -> TransformBase<N2, D, SB, C> { fn to_superset(&self) -> Transform<N2, D, C> {
TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(t: &TransformBase<N2, D, SB, C>) -> bool { fn is_in_subset(t: &Transform<N2, D, C>) -> bool {
<Self as SubsetOf<_>>::is_in_subset(t.matrix()) <Self as SubsetOf<_>>::is_in_subset(t.matrix())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(t: &TransformBase<N2, D, SB, C>) -> Self { unsafe fn from_superset_unchecked(t: &Transform<N2, D, C>) -> Self {
Self::from_superset_unchecked(t.matrix()) Self::from_superset_unchecked(t.matrix())
} }
} }
impl<N1, N2, D, SA, SB> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for RotationBase<N1, D, SA> impl<N1, N2, D> SubsetOf<MatrixN<N2, DimNameSum<D, U1>>> for Rotation<N1, D>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, D>, D: DimNameAdd<U1> +
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, DimMin<D, Output = D>, // needed by .is_special_orthogonal()
D: DimNameAdd<U1>, DefaultAllocator: Allocator<N1, D, D> +
SA::Alloc: OwnedAllocator<N1, D, D, SA> + Allocator<N2, D, D> +
Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>>, Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> +
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB> + Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N2, D, D> + Allocator<(usize, usize), D> { // needed by .is_special_orthogonal()
Allocator<N2, U1, D> {
#[inline] #[inline]
fn to_superset(&self) -> SquareMatrix<N2, DimNameSum<D, U1>, SB> { fn to_superset(&self) -> MatrixN<N2, DimNameSum<D, U1>> {
self.to_homogeneous().to_superset() self.to_homogeneous().to_superset()
} }
#[inline] #[inline]
fn is_in_subset(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> bool { fn is_in_subset(m: &MatrixN<N2, DimNameSum<D, U1>>) -> bool {
let rot = m.fixed_slice::<D, D>(0, 0); let rot = m.fixed_slice::<D, D>(0, 0);
let bottom = m.fixed_slice::<U1, D>(D::dim(), 0); let bottom = m.fixed_slice::<U1, D>(D::dim(), 0);
@ -188,7 +196,7 @@ impl<N1, N2, D, SA, SB> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for Ro
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self {
let r = m.fixed_slice::<D, D>(0, 0); let r = m.fixed_slice::<D, D>(0, 0);
Self::from_matrix_unchecked(::convert_unchecked(r.into_owned())) Self::from_matrix_unchecked(::convert_unchecked(r.into_owned()))
} }

View File

@ -4,33 +4,34 @@
* *
* Index<(usize, usize)> * Index<(usize, usize)>
* *
* RotationBase × RotationBase * Rotation × Rotation
* RotationBase ÷ RotationBase * Rotation ÷ Rotation
* RotationBase × Matrix * Rotation × Matrix
* Matrix × RotationBase * Matrix × Rotation
* Matrix ÷ RotationBase * Matrix ÷ Rotation
* RotationBase × PointBase * Rotation × Point
* *
* *
* RotationBase ×= RotationBase * Rotation ×= Rotation
* Matrix ×= RotationBase * Matrix ×= Rotation
*/ */
use std::ops::{Mul, MulAssign, Div, DivAssign, Index}; use std::ops::{Mul, MulAssign, Div, DivAssign, Index};
use num::Zero; use num::{Zero, One};
use alga::general::{ClosedMul, ClosedAdd}; use alga::general::{ClosedMul, ClosedAdd};
use core::{Scalar, Matrix, MatrixMul}; use core::{DefaultAllocator, Scalar, Matrix, MatrixMN};
use core::dimension::{Dim, DimName, U1}; use core::dimension::{Dim, DimName, U1};
use core::constraint::{ShapeConstraint, AreMultipliable}; use core::constraint::{ShapeConstraint, AreMultipliable};
use core::storage::{OwnedStorage, Storage}; use core::storage::Storage;
use core::allocator::{OwnedAllocator, Allocator}; use core::allocator::Allocator;
use geometry::{PointBase, PointMul, RotationBase, OwnedRotation}; use geometry::{Point, Rotation};
impl<N: Scalar, D: DimName, S: Storage<N, D, D>> Index<(usize, usize)> for RotationBase<N, D, S> { impl<N: Scalar, D: DimName> Index<(usize, usize)> for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> {
type Output = N; type Output = N;
#[inline] #[inline]
@ -39,62 +40,62 @@ impl<N: Scalar, D: DimName, S: Storage<N, D, D>> Index<(usize, usize)> for Rotat
} }
} }
// RotationBase × RotationBase // Rotation × Rotation
md_impl_all!( md_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, D) for D: DimName; (D, D), (D, D) for D: DimName;
self: RotationBase<N, D, SA>, right: RotationBase<N, D, SB>, Output = OwnedRotation<N, D, SA::Alloc>; self: Rotation<N, D>, right: Rotation<N, D>, Output = Rotation<N, D>;
[val val] => RotationBase::from_matrix_unchecked(self.unwrap() * right.unwrap()); [val val] => Rotation::from_matrix_unchecked(self.unwrap() * right.unwrap());
[ref val] => RotationBase::from_matrix_unchecked(self.matrix() * right.unwrap()); [ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.unwrap());
[val ref] => RotationBase::from_matrix_unchecked(self.unwrap() * right.matrix()); [val ref] => Rotation::from_matrix_unchecked(self.unwrap() * right.matrix());
[ref ref] => RotationBase::from_matrix_unchecked(self.matrix() * 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? // FIXME: instead of calling inverse explicitely, could we just add a `mul_tr` or `mul_inv` method?
md_impl_all!( md_impl_all!(
Div, div; Div, div;
(D, D), (D, D) for D: DimName; (D, D), (D, D) for D: DimName;
self: RotationBase<N, D, SA>, right: RotationBase<N, D, SB>, Output = OwnedRotation<N, D, SA::Alloc>; self: Rotation<N, D>, right: Rotation<N, D>, Output = Rotation<N, D>;
[val val] => self * right.inverse(); [val val] => self * right.inverse();
[ref val] => self * right.inverse(); [ref val] => self * right.inverse();
[val ref] => self * right.inverse(); [val ref] => self * right.inverse();
[ref ref] => self * right.inverse(); [ref ref] => self * right.inverse();
); );
// RotationBase × Matrix // Rotation × Matrix
md_impl_all!( md_impl_all!(
Mul, mul; Mul, mul;
(D1, D1), (R2, C2) for D1: DimName, R2: Dim, C2: Dim (D1, D1), (R2, C2) for D1: DimName, R2: Dim, C2: Dim, SB: Storage<N, R2, C2>
where SA::Alloc: Allocator<N, D1, C2> where DefaultAllocator: Allocator<N, D1, C2>
where ShapeConstraint: AreMultipliable<D1, D1, R2, C2>; where ShapeConstraint: AreMultipliable<D1, D1, R2, C2>;
self: RotationBase<N, D1, SA>, right: Matrix<N, R2, C2, SB>, Output = MatrixMul<N, D1, D1, C2 , SA>; self: Rotation<N, D1>, right: Matrix<N, R2, C2, SB>, Output = MatrixMN<N, D1, C2>;
[val val] => self.unwrap() * right; [val val] => self.unwrap() * right;
[ref val] => self.matrix() * right; [ref val] => self.matrix() * right;
[val ref] => self.unwrap() * right; [val ref] => self.unwrap() * right;
[ref ref] => self.matrix() * right; [ref ref] => self.matrix() * right;
); );
// Matrix × RotationBase // Matrix × Rotation
md_impl_all!( md_impl_all!(
Mul, mul; Mul, mul;
(R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName (R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName, SA: Storage<N, R1, C1>
where SA::Alloc: Allocator<N, R1, D2> where DefaultAllocator: Allocator<N, R1, D2>
where ShapeConstraint: AreMultipliable<R1, C1, D2, D2>; where ShapeConstraint: AreMultipliable<R1, C1, D2, D2>;
self: Matrix<N, R1, C1, SA>, right: RotationBase<N, D2, SB>, Output = MatrixMul<N, R1, C1, D2, SA>; self: Matrix<N, R1, C1, SA>, right: Rotation<N, D2>, Output = MatrixMN<N, R1, D2>;
[val val] => self * right.unwrap(); [val val] => self * right.unwrap();
[ref val] => self * right.unwrap(); [ref val] => self * right.unwrap();
[val ref] => self * right.matrix(); [val ref] => self * right.matrix();
[ref ref] => self * right.matrix(); [ref ref] => self * right.matrix();
); );
// Matrix ÷ RotationBase // Matrix ÷ Rotation
md_impl_all!( md_impl_all!(
Div, div; Div, div;
(R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName (R1, C1), (D2, D2) for R1: Dim, C1: Dim, D2: DimName, SA: Storage<N, R1, C1>
where SA::Alloc: Allocator<N, R1, D2> where DefaultAllocator: Allocator<N, R1, D2>
where ShapeConstraint: AreMultipliable<R1, C1, D2, D2>; where ShapeConstraint: AreMultipliable<R1, C1, D2, D2>;
self: Matrix<N, R1, C1, SA>, right: RotationBase<N, D2, SB>, Output = MatrixMul<N, R1, C1, D2, SA>; self: Matrix<N, R1, C1, SA>, right: Rotation<N, D2>, Output = MatrixMN<N, R1, D2>;
[val val] => self * right.inverse(); [val val] => self * right.inverse();
[ref val] => self * right.inverse(); [ref val] => self * right.inverse();
[val ref] => 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 // FIXME: we don't handle properly non-zero origins here. Do we want this to be the intended
// behavior? // behavior?
md_impl_all!( md_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, U1) for D: DimName (D, D), (D, U1) for D: DimName
where SA::Alloc: Allocator<N, D, U1> where DefaultAllocator: Allocator<N, D>
where ShapeConstraint: AreMultipliable<D, D, D, U1>; where ShapeConstraint: AreMultipliable<D, D, D, U1>;
self: RotationBase<N, D, SA>, right: PointBase<N, D, SB>, Output = PointMul<N, D, D, SA>; self: Rotation<N, D>, right: Point<N, D>, Output = Point<N, D>;
[val val] => self.unwrap() * right; [val val] => self.unwrap() * right;
[ref val] => self.matrix() * right; [ref val] => self.matrix() * right;
[val ref] => self.unwrap() * right; [val ref] => self.unwrap() * right;
@ -118,13 +119,13 @@ md_impl_all!(
); );
// RotationBase ×= RotationBase // Rotation ×= Rotation
// FIXME: try not to call `inverse()` explicitly. // FIXME: try not to call `inverse()` explicitly.
md_assign_impl_all!( md_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
(D, D), (D, D) for D: DimName; (D, D), (D, D) for D: DimName;
self: RotationBase<N, D, SA>, right: RotationBase<N, D, SB>; self: Rotation<N, D>, right: Rotation<N, D>;
[val] => unsafe { self.matrix_mut().mul_assign(right.unwrap()) }; [val] => unsafe { self.matrix_mut().mul_assign(right.unwrap()) };
[ref] => unsafe { self.matrix_mut().mul_assign(right.matrix()) }; [ref] => unsafe { self.matrix_mut().mul_assign(right.matrix()) };
); );
@ -133,12 +134,12 @@ md_assign_impl_all!(
md_assign_impl_all!( md_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
(D, D), (D, D) for D: DimName; (D, D), (D, D) for D: DimName;
self: RotationBase<N, D, SA>, right: RotationBase<N, D, SB>; self: Rotation<N, D>, right: Rotation<N, D>;
[val] => unsafe { self.matrix_mut().mul_assign(right.inverse().unwrap()) }; [val] => unsafe { self.matrix_mut().mul_assign(right.inverse().unwrap()) };
[ref] => unsafe { self.matrix_mut().mul_assign(right.inverse().matrix()) }; [ref] => unsafe { self.matrix_mut().mul_assign(right.inverse().matrix()) };
); );
// Matrix *= RotationBase // Matrix *= Rotation
// FIXME: try not to call `inverse()` explicitly. // FIXME: try not to call `inverse()` explicitly.
// FIXME: this shares the same limitations as for the current impl. of MulAssign for matrices. // 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, // (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!( md_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
(R1, C1), (C1, C1) for R1: DimName, C1: DimName; (R1, C1), (C1, C1) for R1: DimName, C1: DimName;
self: Matrix<N, R1, C1, SA>, right: RotationBase<N, C1, SB>; self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
[val] => self.mul_assign(right.unwrap()); [val] => self.mul_assign(right.unwrap());
[ref] => self.mul_assign(right.matrix()); [ref] => self.mul_assign(right.matrix());
); );
@ -156,7 +157,7 @@ md_assign_impl_all!(
md_assign_impl_all!( md_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
(R1, C1), (C1, C1) for R1: DimName, C1: DimName; (R1, C1), (C1, C1) for R1: DimName, C1: DimName;
self: Matrix<N, R1, C1, SA>, right: RotationBase<N, C1, SB>; self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
[val] => self.mul_assign(right.inverse().unwrap()); [val] => self.mul_assign(right.inverse().unwrap());
[ref] => self.mul_assign(right.inverse().matrix()); [ref] => self.mul_assign(right.inverse().matrix());
); );

View File

@ -1,39 +1,37 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
#[cfg(feature = "arbitrary")]
use core::storage::Owned;
use std::ops::Neg; use std::ops::Neg;
use num::Zero; use num::Zero;
use rand::{Rand, Rng}; use rand::{Rand, Rng};
use alga::general::Real; 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::dimension::{U1, U2, U3};
use core::storage::{Storage, OwnedStorage}; use core::storage::Storage;
use core::allocator::{Allocator, OwnedAllocator};
use geometry::{RotationBase, OwnedRotation, UnitComplex}; use geometry::{UnitComplex, Rotation2, Rotation3};
/* /*
* *
* 2D RotationBase matrix. * 2D Rotation matrix.
* *
*/ */
impl<N, S> RotationBase<N, U2, S> impl<N: Real> Rotation2<N> {
where N: Real,
S: OwnedStorage<N, U2, U2>,
S::Alloc: OwnedAllocator<N, U2, U2, S> {
/// Builds a 2 dimensional rotation matrix from an angle in radian. /// Builds a 2 dimensional rotation matrix from an angle in radian.
pub fn new(angle: N) -> Self { pub fn new(angle: N) -> Self {
let (sia, coa) = angle.sin_cos(); let (sia, coa) = angle.sin_cos();
Self::from_matrix_unchecked(SquareMatrix::<N, U2, S>::new(coa, -sia, sia, coa)) Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa))
} }
/// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector. /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector.
/// ///
/// Equivalent to `Self::new(axisangle[0])`. /// Equivalent to `Self::new(axisangle[0])`.
#[inline] #[inline]
pub fn from_scaled_axis<SB: Storage<N, U1, U1>>(axisangle: ColumnVector<N, U1, SB>) -> Self { pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self {
Self::new(axisangle[0]) 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()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &ColumnVector<N, U2, SB>, b: &ColumnVector<N, U2, SC>) -> Self pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self
where SB: Storage<N, U2, U1>, where SB: Storage<N, U2>,
SC: Storage<N, U2, U1> { SC: Storage<N, U2> {
::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix()) ::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix())
} }
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>(a: &ColumnVector<N, U2, SB>, b: &ColumnVector<N, U2, SC>, s: N) -> Self pub fn scaled_rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>, s: N) -> Self
where SB: Storage<N, U2, U1>, where SB: Storage<N, U2>,
SC: Storage<N, U2, U1> { SC: Storage<N, U2> {
::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) ::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix())
} }
} }
impl<N, S> RotationBase<N, U2, S> impl<N: Real> Rotation2<N> {
where N: Real,
S: Storage<N, U2, U2> {
/// The rotation angle. /// The rotation angle.
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
@ -68,7 +64,7 @@ where N: Real,
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
#[inline] #[inline]
pub fn angle_to<SB: Storage<N, U2, U2>>(&self, other: &RotationBase<N, U2, SB>) -> N { pub fn angle_to(&self, other: &Rotation2<N>) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
} }
@ -76,30 +72,25 @@ where N: Real,
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
#[inline] #[inline]
pub fn rotation_to<SB>(&self, other: &RotationBase<N, U2, SB>) -> OwnedRotation<N, U2, SB::Alloc> pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> {
where SB: Storage<N, U2, U2> {
other * self.inverse() other * self.inverse()
} }
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle
/// of `self` multiplied by `n`. /// of `self` multiplied by `n`.
#[inline] #[inline]
pub fn powf(&self, n: N) -> OwnedRotation<N, U2, S::Alloc> { pub fn powf(&self, n: N) -> Rotation2<N> {
OwnedRotation::<_, _, S::Alloc>::new(self.angle() * n) Self::new(self.angle() * n)
} }
/// The rotation angle returned as a 1-dimensional vector. /// The rotation angle returned as a 1-dimensional vector.
#[inline] #[inline]
pub fn scaled_axis(&self) -> OwnedColumnVector<N, U1, S::Alloc> pub fn scaled_axis(&self) -> VectorN<N, U1> {
where S::Alloc: Allocator<N, U1, U1> { Vector::<_, U1, _>::new(self.angle())
ColumnVector::<_, U1, _>::new(self.angle())
} }
} }
impl<N, S> Rand for RotationBase<N, U2, S> impl<N: Real + Rand> Rand for Rotation2<N> {
where N: Real + Rand,
S: OwnedStorage<N, U2, U2>,
S::Alloc: OwnedAllocator<N, U2, U2, S> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Self { fn rand<R: Rng>(rng: &mut R) -> Self {
Self::new(rng.gen()) Self::new(rng.gen())
@ -107,10 +98,8 @@ where N: Real + Rand,
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N, S> Arbitrary for RotationBase<N, U2, S> impl<N: Real + Arbitrary> Arbitrary for Rotation2<N>
where N: Real + Arbitrary, where Owned<N, U2, U2>: Send {
S: OwnedStorage<N, U2, U2> + Send,
S::Alloc: OwnedAllocator<N, U2, U2, S> {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self::new(N::arbitrary(g)) Self::new(N::arbitrary(g))
@ -120,32 +109,29 @@ where N: Real + Arbitrary,
/* /*
* *
* 3D RotationBase matrix. * 3D Rotation matrix.
* *
*/ */
impl<N, S> RotationBase<N, U3, S> impl<N: Real> Rotation3<N> {
where N: Real,
S: OwnedStorage<N, U3, U3>,
S::Alloc: OwnedAllocator<N, U3, U3, S> {
/// Builds a 3 dimensional rotation matrix from an axis and an angle. /// Builds a 3 dimensional rotation matrix from an axis and an angle.
/// ///
/// # Arguments /// # Arguments
/// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
/// in radian. Its direction is the axis of rotation. /// in radian. Its direction is the axis of rotation.
pub fn new<SB: Storage<N, U3, U1>>(axisangle: ColumnVector<N, U3, SB>) -> Self { pub fn new<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
let (axis, angle) = Unit::new_and_get(axisangle.into_owned()); let axisangle = axisangle.into_owned();
let (axis, angle) = Unit::new_and_get(axisangle);
Self::from_axis_angle(&axis, angle) Self::from_axis_angle(&axis, angle)
} }
/// Builds a 3D rotation matrix from an axis scaled by the rotation angle. /// Builds a 3D rotation matrix from an axis scaled by the rotation angle.
pub fn from_scaled_axis<SB: Storage<N, U3, U1>>(axisangle: ColumnVector<N, U3, SB>) -> Self { pub fn from_scaled_axis<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
Self::new(axisangle) Self::new(axisangle)
} }
/// Builds a 3D rotation matrix from an axis and a rotation angle. /// Builds a 3D rotation matrix from an axis and a rotation angle.
pub fn from_axis_angle<SB>(axis: &Unit<ColumnVector<N, U3, SB>>, angle: N) -> Self pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
where SB: Storage<N, U3, U1> { where SB: Storage<N, U3> {
if angle.is_zero() { if angle.is_zero() {
Self::identity() Self::identity()
} }
@ -160,7 +146,7 @@ where N: Real,
let one_m_cos = N::one() - cos; let one_m_cos = N::one() - cos;
Self::from_matrix_unchecked( Self::from_matrix_unchecked(
SquareMatrix::<N, U3, S>::new( MatrixN::<N, U3>::new(
(sqx + (N::one() - sqx) * cos), (sqx + (N::one() - sqx) * cos),
(ux * uy * one_m_cos - uz * sin), (ux * uy * one_m_cos - uz * sin),
(ux * uz * one_m_cos + uy * sin), (ux * uz * one_m_cos + uy * sin),
@ -184,7 +170,7 @@ where N: Real,
let (sy, cy) = yaw.sin_cos(); let (sy, cy) = yaw.sin_cos();
Self::from_matrix_unchecked( Self::from_matrix_unchecked(
SquareMatrix::<N, U3, S>::new( MatrixN::<N, U3>::new(
cy * cp, cy * sp * sr - sy * cr, cy * sp * cr + sy * sr, cy * cp, cy * sp * sr - sy * cr, cy * sp * cr + sy * sr,
sy * cp, sy * sp * sr + cy * cr, sy * sp * cr - cy * sr, sy * cp, sy * sp * sr + cy * cr, sy * sp * cr - cy * sr,
-sp, cp * sr, cp * cr) -sp, cp * sr, cp * cr)
@ -202,14 +188,14 @@ where N: Real,
/// collinear /// collinear
/// to `dir`. Non-collinearity is not checked. /// to `dir`. Non-collinearity is not checked.
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &ColumnVector<N, U3, SB>, up: &ColumnVector<N, U3, SC>) -> Self pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1> { SC: Storage<N, U3> {
let zaxis = dir.normalize(); let zaxis = dir.normalize();
let xaxis = up.cross(&zaxis).normalize(); let xaxis = up.cross(&zaxis).normalize();
let yaxis = zaxis.cross(&xaxis).normalize(); let yaxis = zaxis.cross(&xaxis).normalize();
Self::from_matrix_unchecked(SquareMatrix::<N, U3, S>::new( Self::from_matrix_unchecked(MatrixN::<N, U3>::new(
xaxis.x, yaxis.x, zaxis.x, xaxis.x, yaxis.x, zaxis.x,
xaxis.y, yaxis.y, zaxis.y, xaxis.y, yaxis.y, zaxis.y,
xaxis.z, yaxis.z, zaxis.z)) 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 /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_rh<SB, SC>(dir: &ColumnVector<N, U3, SB>, up: &ColumnVector<N, U3, SC>) -> Self pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1> { SC: Storage<N, U3> {
Self::new_observer_frame(&dir.neg(), up).inverse() 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 /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_lh<SB, SC>(dir: &ColumnVector<N, U3, SB>, up: &ColumnVector<N, U3, SC>) -> Self pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1> { SC: Storage<N, U3> {
Self::new_observer_frame(dir, up).inverse() 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()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &ColumnVector<N, U3, SB>, b: &ColumnVector<N, U3, SC>) -> Option<Self> pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1> { SC: Storage<N, U3> {
Self::scaled_rotation_between(a, b, N::one()) Self::scaled_rotation_between(a, b, N::one())
} }
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>(a: &ColumnVector<N, U3, SB>, b: &ColumnVector<N, U3, SC>, n: N) pub fn scaled_rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>, n: N)
-> Option<Self> -> Option<Self>
where SB: Storage<N, U3, U1>, where SB: Storage<N, U3>,
SC: Storage<N, U3, U1> { SC: Storage<N, U3> {
// FIXME: code duplication with RotationBase. // FIXME: code duplication with Rotation.
if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) { if let (Some(na), Some(nb)) = (a.try_normalize(N::zero()), b.try_normalize(N::zero())) {
let c = na.cross(&nb); let c = na.cross(&nb);
@ -287,26 +273,17 @@ where N: Real,
Some(Self::identity()) Some(Self::identity())
} }
}
impl<N, S> RotationBase<N, U3, S>
where N: Real,
S: Storage<N, U3, U3> {
/// The rotation angle. /// The rotation angle.
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) / ::convert(2.0)).acos() ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) / ::convert(2.0)).acos()
} }
}
impl<N, S> RotationBase<N, U3, S>
where N: Real,
S: Storage<N, U3, U3>,
S::Alloc: Allocator<N, U3, U1> {
/// The rotation axis. Returns `None` if the rotation angle is zero or PI. /// The rotation axis. Returns `None` if the rotation angle is zero or PI.
#[inline] #[inline]
pub fn axis(&self) -> Option<Unit<OwnedColumnVector<N, U3, S::Alloc>>> { pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
let axis = OwnedColumnVector::<N, U3, S::Alloc>::new( let axis = VectorN::<N, U3>::new(
self.matrix()[(2, 1)] - self.matrix()[(1, 2)], self.matrix()[(2, 1)] - self.matrix()[(1, 2)],
self.matrix()[(0, 2)] - self.matrix()[(2, 0)], self.matrix()[(0, 2)] - self.matrix()[(2, 0)],
self.matrix()[(1, 0)] - self.matrix()[(0, 1)]); self.matrix()[(1, 0)] - self.matrix()[(0, 1)]);
@ -316,18 +293,18 @@ where N: Real,
/// The rotation axis multiplied by the rotation angle. /// The rotation axis multiplied by the rotation angle.
#[inline] #[inline]
pub fn scaled_axis(&self) -> OwnedColumnVector<N, U3, S::Alloc> { pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
axis.unwrap() * self.angle() axis.unwrap() * self.angle()
} }
else { else {
ColumnVector::zero() Vector::zero()
} }
} }
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
#[inline] #[inline]
pub fn angle_to<SB: Storage<N, U3, U3>>(&self, other: &RotationBase<N, U3, SB>) -> N { pub fn angle_to(&self, other: &Rotation3<N>) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
} }
@ -335,47 +312,40 @@ where N: Real,
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
#[inline] #[inline]
pub fn rotation_to<SB>(&self, other: &RotationBase<N, U3, SB>) -> OwnedRotation<N, U3, SB::Alloc> pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> {
where SB: Storage<N, U3, U3> {
other * self.inverse() other * self.inverse()
} }
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the same /// 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`. /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`.
#[inline] #[inline]
pub fn powf(&self, n: N) -> OwnedRotation<N, U3, S::Alloc> { pub fn powf(&self, n: N) -> Rotation3<N> {
if let Some(axis) = self.axis() { 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() { else if self.matrix()[(0, 0)] < N::zero() {
let minus_id = OwnedSquareMatrix::<N, U3, S::Alloc>::from_diagonal_element(-N::one()); let minus_id = MatrixN::<N, U3>::from_diagonal_element(-N::one());
OwnedRotation::<_, _, S::Alloc>::from_matrix_unchecked(minus_id) Self::from_matrix_unchecked(minus_id)
} }
else { else {
OwnedRotation::<_, _, S::Alloc>::identity() Self::identity()
} }
} }
} }
impl<N, S> Rand for RotationBase<N, U3, S> impl<N: Real + Rand> Rand for Rotation3<N> {
where N: Real + Rand,
S: OwnedStorage<N, U3, U3>,
S::Alloc: OwnedAllocator<N, U3, U3, S> +
Allocator<N, U3, U1> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Self { fn rand<R: Rng>(rng: &mut R) -> Self {
Self::new(Vector3::rand(rng)) Self::new(VectorN::rand(rng))
} }
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N, S> Arbitrary for RotationBase<N, U3, S> impl<N: Real + Arbitrary> Arbitrary for Rotation3<N>
where N: Real + Arbitrary, where Owned<N, U3, U3>: Send,
S: OwnedStorage<N, U3, U3> + Send, Owned<N, U3>: Send {
S::Alloc: OwnedAllocator<N, U3, U3, S> +
Allocator<N, U3, U1> {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self::new(Vector3::arbitrary(g)) Self::new(VectorN::arbitrary(g))
} }
} }

View File

@ -1,47 +1,80 @@
use std::fmt; use std::fmt;
use std::hash;
use approx::ApproxEq; 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 alga::linear::Rotation;
use core::{Scalar, OwnedSquareMatrix}; use core::{DefaultAllocator, MatrixN};
use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1};
use core::storage::{Storage, OwnedStorage}; use core::storage::Owned;
use core::allocator::{Allocator, OwnedAllocator}; use core::allocator::Allocator;
use geometry::{PointBase, TranslationBase, IsometryBase}; use geometry::{Point, Translation, Isometry};
/// A similarity that uses a data storage deduced from the allocator `A`.
pub type OwnedSimilarityBase<N, D, A, R> =
SimilarityBase<N, D, <A as Allocator<N, D, U1>>::Buffer, R>;
/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation.
#[repr(C)] #[repr(C)]
#[derive(Hash, Debug, Clone, Copy)] #[derive(Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct SimilarityBase<N: Scalar, D: DimName, S, R> { #[cfg_attr(feature = "serde-serialize",
serde(bound(
serialize = "N: serde::Serialize,
R: serde::Serialize,
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: serde::Serialize")))]
#[cfg_attr(feature = "serde-serialize",
serde(bound(
deserialize = "N: serde::Deserialize<'de>,
R: serde::Deserialize<'de>,
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: serde::Deserialize<'de>")))]
pub struct Similarity<N: Real, D: DimName, R>
where DefaultAllocator: Allocator<N, D> {
/// The part of this similarity that does not include the scaling factor. /// The part of this similarity that does not include the scaling factor.
pub isometry: IsometryBase<N, D, S, R>, pub isometry: Isometry<N, D, R>,
scaling: N scaling: N
} }
impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R> impl<N: Real + hash::Hash, D: DimName + hash::Hash, R: hash::Hash> hash::Hash for Similarity<N, D, R>
where N: Real, where DefaultAllocator: Allocator<N, D>,
S: OwnedStorage<N, D, U1>, Owned<N, D>: hash::Hash {
R: Rotation<PointBase<N, D, S>>, fn hash<H: hash::Hasher>(&self, state: &mut H) {
S::Alloc: OwnedAllocator<N, D, U1, S> { self.isometry.hash(state);
self.scaling.hash(state);
}
}
impl<N: Real, D: DimName + Copy, R: Rotation<Point<N, D>> + Copy> Copy for Similarity<N, D, R>
where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy {
}
impl<N: Real, D: DimName, R: Rotation<Point<N, D>> + Clone> Clone for Similarity<N, D, R>
where DefaultAllocator: Allocator<N, D> {
#[inline]
fn clone(&self) -> Self {
Similarity::from_isometry(self.isometry.clone(), self.scaling)
}
}
impl<N: Real, D: DimName, R> Similarity<N, D, R>
where R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D> {
/// Creates a new similarity from its rotational and translational parts. /// Creates a new similarity from its rotational and translational parts.
#[inline] #[inline]
pub fn from_parts(translation: TranslationBase<N, D, S>, rotation: R, scaling: N) -> SimilarityBase<N, D, S, R> { pub fn from_parts(translation: Translation<N, D>, rotation: R, scaling: N) -> Similarity<N, D, R> {
SimilarityBase::from_isometry(IsometryBase::from_parts(translation, rotation), scaling) Similarity::from_isometry(Isometry::from_parts(translation, rotation), scaling)
} }
/// Creates a new similarity from its rotational and translational parts. /// Creates a new similarity from its rotational and translational parts.
#[inline] #[inline]
pub fn from_isometry(isometry: IsometryBase<N, D, S, R>, scaling: N) -> SimilarityBase<N, D, S, R> { pub fn from_isometry(isometry: Isometry<N, D, R>, scaling: N) -> Similarity<N, D, R> {
assert!(!relative_eq!(scaling, N::zero()), "The scaling factor must not be zero."); assert!(!relative_eq!(scaling, N::zero()), "The scaling factor must not be zero.");
SimilarityBase { Similarity {
isometry: isometry, isometry: isometry,
scaling: scaling scaling: scaling
} }
@ -49,13 +82,13 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
/// Creates a new similarity that applies only a scaling factor. /// Creates a new similarity that applies only a scaling factor.
#[inline] #[inline]
pub fn from_scaling(scaling: N) -> SimilarityBase<N, D, S, R> { pub fn from_scaling(scaling: N) -> Similarity<N, D, R> {
Self::from_isometry(IsometryBase::identity(), scaling) Self::from_isometry(Isometry::identity(), scaling)
} }
/// Inverts `self`. /// Inverts `self`.
#[inline] #[inline]
pub fn inverse(&self) -> SimilarityBase<N, D, S, R> { pub fn inverse(&self) -> Similarity<N, D, R> {
let mut res = self.clone(); let mut res = self.clone();
res.inverse_mut(); res.inverse_mut();
res res
@ -77,6 +110,12 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
self.scaling = scaling; 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`. /// The similarity transformation that applies a scaling factor `scaling` before `self`.
#[inline] #[inline]
pub fn prepend_scaling(&self, scaling: N) -> Self { pub fn prepend_scaling(&self, scaling: N) -> Self {
@ -91,7 +130,7 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
assert!(!relative_eq!(scaling, N::zero()), "The similarity scaling factor must not be zero."); assert!(!relative_eq!(scaling, N::zero()), "The similarity scaling factor must not be zero.");
Self::from_parts( Self::from_parts(
TranslationBase::from_vector(&self.isometry.translation.vector * scaling), Translation::from_vector(&self.isometry.translation.vector * scaling),
self.isometry.rotation.clone(), self.isometry.rotation.clone(),
self.scaling * scaling) self.scaling * scaling)
} }
@ -115,7 +154,7 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
/// Appends to `self` the given translation in-place. /// Appends to `self` the given translation in-place.
#[inline] #[inline]
pub fn append_translation_mut(&mut self, t: &TranslationBase<N, D, S>) { pub fn append_translation_mut(&mut self, t: &Translation<N, D>) {
self.isometry.append_translation_mut(t) self.isometry.append_translation_mut(t)
} }
@ -128,7 +167,7 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
/// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that
/// lets `p` invariant. /// lets `p` invariant.
#[inline] #[inline]
pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &PointBase<N, D, S>) { pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point<N, D>) {
self.isometry.append_rotation_wrt_point_mut(r, p) self.isometry.append_rotation_wrt_point_mut(r, p)
} }
@ -145,16 +184,14 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
// and makes it harde to use it, e.g., for Transform × Isometry implementation. // 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 // 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). // explicit struct construction is prevented by the private scaling factor).
impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Similarity<N, D, R>
where N: Scalar + ClosedMul, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
/// Converts this similarity into its equivalent homogeneous transformation matrix. /// Converts this similarity into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where D: DimNameAdd<U1>, where D: DimNameAdd<U1>,
R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc>>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>>>,
S::Alloc: Allocator<N, D, D> + DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
let mut res = self.isometry.to_homogeneous(); let mut res = self.isometry.to_homogeneous();
for e in res.fixed_slice_mut::<D, D>(0, 0).iter_mut() { for e in res.fixed_slice_mut::<D, D>(0, 0).iter_mut() {
@ -163,38 +200,26 @@ impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R>
res res
} }
/// The scaling factor of this similarity transformation.
#[inline]
pub fn scaling(&self) -> N {
self.scaling
}
} }
impl<N, D: DimName, S, R> Eq for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Eq for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>> + Eq,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>> + Eq,
S::Alloc: OwnedAllocator<N, D, U1, S> {
} }
impl<N, D: DimName, S, R> PartialEq for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> PartialEq for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>> + PartialEq,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>> + PartialEq,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn eq(&self, right: &SimilarityBase<N, D, S, R>) -> bool { fn eq(&self, right: &Similarity<N, D, R>) -> bool {
self.isometry == right.isometry && self.scaling == right.scaling self.isometry == right.isometry && self.scaling == right.scaling
} }
} }
impl<N, D: DimName, S, R> ApproxEq for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> ApproxEq for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>> + ApproxEq<Epsilon = N::Epsilon>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D>,
R: Rotation<PointBase<N, D, S>> + ApproxEq<Epsilon = N::Epsilon>,
S::Alloc: OwnedAllocator<N, D, U1, S>,
N::Epsilon: Copy { N::Epsilon: Copy {
type Epsilon = N::Epsilon; type Epsilon = N::Epsilon;
@ -231,46 +256,16 @@ impl<N, D: DimName, S, R> ApproxEq for SimilarityBase<N, D, S, R>
* Display * Display
* *
*/ */
impl<N, D: DimName, S, R> fmt::Display for SimilarityBase<N, D, S, R> impl<N, D: DimName, R> fmt::Display for Similarity<N, D, R>
where N: Real + fmt::Display, where N: Real + fmt::Display,
S: OwnedStorage<N, D, U1>, R: Rotation<Point<N, D>> + fmt::Display,
R: Rotation<PointBase<N, D, S>> + fmt::Display, DefaultAllocator: Allocator<N, D> + Allocator<usize, D> {
S::Alloc: OwnedAllocator<N, D, U1, S> + Allocator<usize, D, U1> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let precision = f.precision().unwrap_or(3); let precision = f.precision().unwrap_or(3);
try!(writeln!(f, "SimilarityBase {{")); try!(writeln!(f, "Similarity {{"));
try!(write!(f, "{:.*}", precision, self.isometry)); try!(write!(f, "{:.*}", precision, self.isometry));
try!(write!(f, "Scaling: {:.*}", precision, self.scaling)); try!(write!(f, "Scaling: {:.*}", precision, self.scaling));
writeln!(f, "}}") writeln!(f, "}}")
} }
} }
/*
// /*
// *
// * ToHomogeneous
// *
// */
// impl<N: Real> ToHomogeneous<$homogeneous<N>> for $t<N> {
// #[inline]
// fn to_homogeneous(&self) -> $homogeneous<N> {
// self.vector.to_homogeneous()
// }
// }
// /*
// *
// * Absolute
// *
// */
// impl<N: Absolute> Absolute for $t<N> {
// type AbsoluteValue = $submatrix<N::AbsoluteValue>;
//
// #[inline]
// fn abs(m: &$t<N>) -> $submatrix<N::AbsoluteValue> {
// Absolute::abs(&m.submatrix)
// }
// }
*/

View File

@ -1,13 +1,13 @@
use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Real, Inverse, Multiplicative, Identity}; 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::{DefaultAllocator, VectorN};
use core::dimension::{DimName, U1}; use core::dimension::DimName;
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::{SimilarityBase, TranslationBase, PointBase}; use geometry::{Similarity, Translation, Point};
/* /*
@ -15,22 +15,18 @@ use geometry::{SimilarityBase, TranslationBase, PointBase};
* Algebraic structures. * Algebraic structures.
* *
*/ */
impl<N, D: DimName, S, R> Identity<Multiplicative> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Identity<Multiplicative> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, D: DimName, S, R> Inverse<Multiplicative> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
self.inverse() self.inverse()
@ -42,11 +38,9 @@ impl<N, D: DimName, S, R> Inverse<Multiplicative> for SimilarityBase<N, D, S, R>
} }
} }
impl<N, D: DimName, S, R> AbstractMagma<Multiplicative> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> AbstractMagma<Multiplicative> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
@ -55,11 +49,9 @@ impl<N, D: DimName, S, R> AbstractMagma<Multiplicative> for SimilarityBase<N, D,
macro_rules! impl_multiplicative_structures( macro_rules! impl_multiplicative_structures(
($($marker: ident<$operator: ident>),* $(,)*) => {$( ($($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, D: DimName, S, R> $marker<$operator> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> $marker<$operator> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> { }
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> { }
)*} )*}
); );
@ -76,49 +68,43 @@ impl_multiplicative_structures!(
* Transformation groups. * Transformation groups.
* *
*/ */
impl<N, D: DimName, S, R> Transformation<PointBase<N, D, S>> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Transformation<Point<N, D>> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, D, S>) -> PointBase<N, D, S> { fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self * pt self * pt
} }
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, D, S>) -> ColumnVector<N, D, S> { fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self * v self * v
} }
} }
impl<N, D: DimName, S, R> ProjectiveTransformation<PointBase<N, D, S>> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> ProjectiveTransformation<Point<N, D>> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &PointBase<N, D, S>) -> PointBase<N, D, S> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self.isometry.inverse_transform_point(pt) / self.scaling() self.isometry.inverse_transform_point(pt) / self.scaling()
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &ColumnVector<N, D, S>) -> ColumnVector<N, D, S> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self.isometry.inverse_transform_vector(v) / self.scaling() self.isometry.inverse_transform_vector(v) / self.scaling()
} }
} }
impl<N, D: DimName, S, R> AffineTransformation<PointBase<N, D, S>> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> AffineTransformation<Point<N, D>> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type NonUniformScaling = N; type NonUniformScaling = N;
type Rotation = R; type Rotation = R;
type Translation = TranslationBase<N, D, S>; type Translation = Translation<N, D>;
#[inline] #[inline]
fn decompose(&self) -> (TranslationBase<N, D, S>, R, N, R) { fn decompose(&self) -> (Translation<N, D>, R, N, R) {
(self.isometry.translation.clone(), self.isometry.rotation.clone(), self.scaling(), R::identity()) (self.isometry.translation.clone(), self.isometry.rotation.clone(), self.scaling(), R::identity())
} }
@ -134,7 +120,7 @@ impl<N, D: DimName, S, R> AffineTransformation<PointBase<N, D, S>> for Similarit
#[inline] #[inline]
fn append_rotation(&self, r: &Self::Rotation) -> Self { 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] #[inline]
@ -153,22 +139,20 @@ impl<N, D: DimName, S, R> AffineTransformation<PointBase<N, D, S>> for Similarit
} }
#[inline] #[inline]
fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &PointBase<N, D, S>) -> Option<Self> { fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &Point<N, D>) -> Option<Self> {
let mut res = self.clone(); let mut res = self.clone();
res.append_rotation_wrt_point_mut(r, p); res.append_rotation_wrt_point_mut(r, p);
Some(res) Some(res)
} }
} }
impl<N, D: DimName, S, R> Similarity<PointBase<N, D, S>> for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> AlgaSimilarity<Point<N, D>> for Similarity<N, D, R>
where N: Real, where R: Rotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Scaling = N; type Scaling = N;
#[inline] #[inline]
fn translation(&self) -> TranslationBase<N, D, S> { fn translation(&self) -> Translation<N, D> {
self.isometry.translation() self.isometry.translation()
} }

View File

@ -1,19 +1,15 @@
use core::MatrixArray; use core::dimension::{U2, U3};
use core::dimension::{U1, U2, U3};
use geometry::{Rotation, SimilarityBase, UnitQuaternion, UnitComplex}; use geometry::{Similarity, UnitQuaternion, UnitComplex, Rotation2, Rotation3};
/// A D-dimensional similarity.
pub type Similarity<N, D> = SimilarityBase<N, D, MatrixArray<N, D, U1>, Rotation<N, D>>;
/// A 2-dimensional similarity. /// A 2-dimensional similarity.
pub type Similarity2<N> = SimilarityBase<N, U2, MatrixArray<N, U2, U1>, UnitComplex<N>>; pub type Similarity2<N> = Similarity<N, U2, UnitComplex<N>>;
/// A 3-dimensional similarity. /// A 3-dimensional similarity.
pub type Similarity3<N> = SimilarityBase<N, U3, MatrixArray<N, U3, U1>, UnitQuaternion<N>>; pub type Similarity3<N> = Similarity<N, U3, UnitQuaternion<N>>;
/// A 2-dimensional similarity using a rotation matrix for its rotation part. /// A 2-dimensional similarity using a rotation matrix for its rotation part.
pub type SimilarityMatrix2<N> = Similarity<N, U2>; pub type SimilarityMatrix2<N> = Similarity<N, U2, Rotation2<N>>;
/// A 3-dimensional similarity using a rotation matrix for its rotation part. /// A 3-dimensional similarity using a rotation matrix for its rotation part.
pub type SimilarityMatrix3<N> = Similarity<N, U3>; pub type SimilarityMatrix3<N> = Similarity<N, U3, Rotation3<N>>;

View File

@ -1,5 +1,7 @@
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
#[cfg(feature = "arbitrary")]
use core::storage::Owned;
use num::One; use num::One;
use rand::{Rng, Rand}; use rand::{Rng, Rand};
@ -7,32 +9,27 @@ use rand::{Rng, Rand};
use alga::general::Real; use alga::general::Real;
use alga::linear::Rotation as AlgaRotation; use alga::linear::Rotation as AlgaRotation;
use core::ColumnVector; use core::{DefaultAllocator, Vector2, Vector3};
use core::dimension::{DimName, U1, U2, U3, U4}; use core::dimension::{DimName, U2, U3};
use core::allocator::{OwnedAllocator, Allocator}; use core::allocator::Allocator;
use core::storage::OwnedStorage;
use geometry::{PointBase, TranslationBase, RotationBase, SimilarityBase, use geometry::{Point, Translation, Similarity, UnitComplex, UnitQuaternion, Isometry,
UnitComplex, UnitQuaternionBase, IsometryBase}; Point3, Rotation2, Rotation3};
impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Similarity<N, D, R>
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: AlgaRotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// Creates a new identity similarity. /// Creates a new identity similarity.
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::from_isometry(IsometryBase::identity(), N::one()) Self::from_isometry(Isometry::identity(), N::one())
} }
} }
impl<N, D: DimName, S, R> One for SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> One for Similarity<N, D, R>
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: AlgaRotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// Creates a new identity similarity. /// Creates a new identity similarity.
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {
@ -40,11 +37,9 @@ impl<N, D: DimName, S, R> One for SimilarityBase<N, D, S, R>
} }
} }
impl<N, D: DimName, S, R> Rand for SimilarityBase<N, D, S, R> impl<N: Real + Rand, D: DimName, R> Rand for Similarity<N, D, R>
where N: Real + Rand, where R: AlgaRotation<Point<N, D>> + Rand,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: AlgaRotation<PointBase<N, D, S>> + Rand,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn rand<G: Rng>(rng: &mut G) -> Self { fn rand<G: Rng>(rng: &mut G) -> Self {
let mut s = rng.gen(); let mut s = rng.gen();
@ -56,26 +51,24 @@ impl<N, D: DimName, S, R> Rand for SimilarityBase<N, D, S, R>
} }
} }
impl<N, D: DimName, S, R> SimilarityBase<N, D, S, R> impl<N: Real, D: DimName, R> Similarity<N, D, R>
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: AlgaRotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
/// The similarity that applies tha scaling factor `scaling`, followed by the rotation `r` with /// The similarity that applies tha scaling factor `scaling`, followed by the rotation `r` with
/// its axis passing through the point `p`. /// its axis passing through the point `p`.
#[inline] #[inline]
pub fn rotation_wrt_point(r: R, p: PointBase<N, D, S>, scaling: N) -> Self { pub fn rotation_wrt_point(r: R, p: Point<N, D>, scaling: N) -> Self {
let shift = r.transform_vector(&-&p.coords); 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")] #[cfg(feature = "arbitrary")]
impl<N, D: DimName, S, R> Arbitrary for SimilarityBase<N, D, S, R> impl<N, D: DimName, R> Arbitrary for Similarity<N, D, R>
where N: Real + Arbitrary + Send, where N: Real + Arbitrary + Send,
S: OwnedStorage<N, D, U1> + Send, R: AlgaRotation<Point<N, D>> + Arbitrary + Send,
R: AlgaRotation<PointBase<N, D, S>> + Arbitrary + Send, DefaultAllocator: Allocator<N, D>,
S::Alloc: OwnedAllocator<N, D, U1, S> { Owned<N, D>: Send {
#[inline] #[inline]
fn arbitrary<G: Gen>(rng: &mut G) -> Self { fn arbitrary<G: Gen>(rng: &mut G) -> Self {
let mut s = Arbitrary::arbitrary(rng); let mut s = Arbitrary::arbitrary(rng);
@ -94,45 +87,31 @@ impl<N, D: DimName, S, R> Arbitrary for SimilarityBase<N, D, S, R>
*/ */
// 2D rotation. // 2D rotation.
impl<N, S, SR> SimilarityBase<N, U2, S, RotationBase<N, U2, SR>> impl<N: Real> Similarity<N, U2, Rotation2<N>> {
where N: Real,
S: OwnedStorage<N, U2, U1, Alloc = SR::Alloc>,
SR: OwnedStorage<N, U2, U2>,
S::Alloc: OwnedAllocator<N, U2, U1, S>,
SR::Alloc: OwnedAllocator<N, U2, U2, SR> {
/// Creates a new similarity from a translation and a rotation angle. /// Creates a new similarity from a translation and a rotation angle.
#[inline] #[inline]
pub fn new(translation: ColumnVector<N, U2, S>, angle: N, scaling: N) -> Self { pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self {
Self::from_parts(TranslationBase::from_vector(translation), RotationBase::<N, U2, SR>::new(angle), scaling) Self::from_parts(Translation::from_vector(translation), Rotation2::new(angle), scaling)
} }
} }
impl<N, S> SimilarityBase<N, U2, S, UnitComplex<N>> impl<N: Real> Similarity<N, U2, UnitComplex<N>> {
where N: Real,
S: OwnedStorage<N, U2, U1>,
S::Alloc: OwnedAllocator<N, U2, U1, S> {
/// Creates a new similarity from a translation and a rotation angle. /// Creates a new similarity from a translation and a rotation angle.
#[inline] #[inline]
pub fn new(translation: ColumnVector<N, U2, S>, angle: N, scaling: N) -> Self { pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self {
Self::from_parts(TranslationBase::from_vector(translation), UnitComplex::new(angle), scaling) Self::from_parts(Translation::from_vector(translation), UnitComplex::new(angle), scaling)
} }
} }
// 3D rotation. // 3D rotation.
macro_rules! similarity_construction_impl( macro_rules! similarity_construction_impl(
($Rot: ty, $RotId: ident, $RRDim: ty, $RCDim: ty) => { ($Rot: ty) => {
impl<N, S, SR> SimilarityBase<N, U3, S, $Rot> impl<N: Real> Similarity<N, U3, $Rot> {
where N: Real,
S: OwnedStorage<N, U3, U1, Alloc = SR::Alloc>,
SR: OwnedStorage<N, $RRDim, $RCDim>,
S::Alloc: OwnedAllocator<N, U3, U1, S>,
SR::Alloc: OwnedAllocator<N, $RRDim, $RCDim, SR> +
Allocator<N, U3, U3> {
/// Creates a new similarity from a translation, rotation axis-angle, and scaling /// Creates a new similarity from a translation, rotation axis-angle, and scaling
/// factor. /// factor.
#[inline] #[inline]
pub fn new(translation: ColumnVector<N, U3, S>, axisangle: ColumnVector<N, U3, S>, scaling: N) -> Self { pub fn new(translation: Vector3<N>, axisangle: Vector3<N>, scaling: N) -> Self {
Self::from_isometry(IsometryBase::<_, _, _, $Rot>::new(translation, axisangle), scaling) 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 /// 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 /// * up - Vertical direction. The only requirement of this parameter is to not be collinear
/// to `eye - at`. Non-collinearity is not checked. /// to `eye - at`. Non-collinearity is not checked.
#[inline] #[inline]
pub fn new_observer_frame(eye: &PointBase<N, U3, S>, pub fn new_observer_frame(eye: &Point3<N>,
target: &PointBase<N, U3, S>, target: &Point3<N>,
up: &ColumnVector<N, U3, S>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> 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. /// 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 /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_rh(eye: &PointBase<N, U3, S>, pub fn look_at_rh(eye: &Point3<N>,
target: &PointBase<N, U3, S>, target: &Point3<N>,
up: &ColumnVector<N, U3, S>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> 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. /// 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 /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
#[inline] #[inline]
pub fn look_at_lh(eye: &PointBase<N, U3, S>, pub fn look_at_lh(eye: &Point3<N>,
target: &PointBase<N, U3, S>, target: &Point3<N>,
up: &ColumnVector<N, U3, S>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> 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<N, U3, SR>, RotationBase, U3, U3); similarity_construction_impl!(Rotation3<N>);
similarity_construction_impl!(UnitQuaternionBase<N, SR>, UnitQuaternionBase, U4, U1); similarity_construction_impl!(UnitQuaternion<N>);

View File

@ -1,49 +1,46 @@
use alga::general::{Real, SubsetOf, SupersetOf}; use alga::general::{Real, SubsetOf, SupersetOf};
use alga::linear::Rotation; use alga::linear::Rotation;
use core::{SquareMatrix, OwnedSquareMatrix}; use core::{DefaultAllocator, MatrixN};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use core::dimension::{DimName, DimNameAdd, DimNameSum, DimMin, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::{Allocator, OwnedAllocator};
use geometry::{PointBase, TranslationBase, IsometryBase, SimilarityBase, TransformBase, SuperTCategoryOf, TAffine}; use geometry::{Point, Translation, Isometry, Similarity, Transform, SuperTCategoryOf, TAffine};
/* /*
* This file provides the following conversions: * This file provides the following conversions:
* ============================================= * =============================================
* *
* SimilarityBase -> SimilarityBase * Similarity -> Similarity
* SimilarityBase -> TransformBase * Similarity -> Transform
* SimilarityBase -> Matrix (homogeneous) * Similarity -> Matrix (homogeneous)
*/ */
impl<N1, N2, D: DimName, SA, SB, R1, R2> SubsetOf<SimilarityBase<N2, D, SB, R2>> for SimilarityBase<N1, D, SA, R1> impl<N1, N2, D: DimName, R1, R2> SubsetOf<Similarity<N2, D, R2>> for Similarity<N1, D, R1>
where N1: Real + SubsetOf<N2>, where N1: Real + SubsetOf<N2>,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R1: Rotation<PointBase<N1, D, SA>> + SubsetOf<R2>, R1: Rotation<Point<N1, D>> + SubsetOf<R2>,
R2: Rotation<PointBase<N2, D, SB>>, R2: Rotation<Point<N2, D>>,
SA: OwnedStorage<N1, D, U1>, DefaultAllocator: Allocator<N1, D> +
SB: OwnedStorage<N2, D, U1>, Allocator<N2, D> {
SA::Alloc: OwnedAllocator<N1, D, U1, SA>,
SB::Alloc: OwnedAllocator<N2, D, U1, SB> {
#[inline] #[inline]
fn to_superset(&self) -> SimilarityBase<N2, D, SB, R2> { fn to_superset(&self) -> Similarity<N2, D, R2> {
SimilarityBase::from_isometry( Similarity::from_isometry(
self.isometry.to_superset(), self.isometry.to_superset(),
self.scaling().to_superset() self.scaling().to_superset()
) )
} }
#[inline] #[inline]
fn is_in_subset(sim: &SimilarityBase<N2, D, SB, R2>) -> bool { fn is_in_subset(sim: &Similarity<N2, D, R2>) -> bool {
::is_convertible::<_, IsometryBase<N1, D, SA, R1>>(&sim.isometry) && ::is_convertible::<_, Isometry<N1, D, R1>>(&sim.isometry) &&
::is_convertible::<_, N1>(&sim.scaling()) ::is_convertible::<_, N1>(&sim.scaling())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(sim: &SimilarityBase<N2, D, SB, R2>) -> Self { unsafe fn from_superset_unchecked(sim: &Similarity<N2, D, R2>) -> Self {
SimilarityBase::from_isometry( Similarity::from_isometry(
sim.isometry.to_subset_unchecked(), sim.isometry.to_subset_unchecked(),
sim.scaling().to_subset_unchecked() sim.scaling().to_subset_unchecked()
) )
@ -51,65 +48,63 @@ impl<N1, N2, D: DimName, SA, SB, R1, R2> SubsetOf<SimilarityBase<N2, D, SB, R2>>
} }
impl<N1, N2, D, SA, SB, R, C> SubsetOf<TransformBase<N2, D, SB, C>> for SimilarityBase<N1, D, SA, R> impl<N1, N2, D, R, C> SubsetOf<Transform<N2, D, C>> for Similarity<N1, D, R>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, U1>,
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>,
C: SuperTCategoryOf<TAffine>, C: SuperTCategoryOf<TAffine>,
R: Rotation<PointBase<N1, D, SA>> + R: Rotation<Point<N1, D>> +
SubsetOf<OwnedSquareMatrix<N1, DimNameSum<D, U1>, SA::Alloc>> + // needed by: .to_homogeneous() SubsetOf<MatrixN<N1, DimNameSum<D, U1>>> +
SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>>, // needed by: ::convert_unchecked(mm) SubsetOf<MatrixN<N2, DimNameSum<D, U1>>>,
D: DimNameAdd<U1>, D: DimNameAdd<U1> +
SA::Alloc: OwnedAllocator<N1, D, U1, SA> + DimMin<D, Output = D>, // needed by .determinant()
Allocator<N1, D, D> + // needed by R DefaultAllocator: Allocator<N1, D> +
Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous() Allocator<N1, D, D> + // needed by R
Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, // needed by R Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous()
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB> + Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by R
Allocator<N2, D, D> + // needed by: mm.fixed_slice_mut Allocator<(usize, usize), D> + // needed by .determinant()
Allocator<N2, D, U1> + // needed by: m.fixed_slice Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N2, U1, D> { // needed by: m.fixed_slice Allocator<N2, D, D> +
Allocator<N2, D> {
#[inline] #[inline]
fn to_superset(&self) -> TransformBase<N2, D, SB, C> { fn to_superset(&self) -> Transform<N2, D, C> {
TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(t: &TransformBase<N2, D, SB, C>) -> bool { fn is_in_subset(t: &Transform<N2, D, C>) -> bool {
<Self as SubsetOf<_>>::is_in_subset(t.matrix()) <Self as SubsetOf<_>>::is_in_subset(t.matrix())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(t: &TransformBase<N2, D, SB, C>) -> Self { unsafe fn from_superset_unchecked(t: &Transform<N2, D, C>) -> Self {
Self::from_superset_unchecked(t.matrix()) Self::from_superset_unchecked(t.matrix())
} }
} }
impl<N1, N2, D, SA, SB, R> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for SimilarityBase<N1, D, SA, R> impl<N1, N2, D, R> SubsetOf<MatrixN<N2, DimNameSum<D, U1>>> for Similarity<N1, D, R>
where N1: Real, where N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
SA: OwnedStorage<N1, D, U1>, R: Rotation<Point<N1, D>> +
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, SubsetOf<MatrixN<N1, DimNameSum<D, U1>>> +
R: Rotation<PointBase<N1, D, SA>> + SubsetOf<MatrixN<N2, DimNameSum<D, U1>>>,
SubsetOf<OwnedSquareMatrix<N1, DimNameSum<D, U1>, SA::Alloc>> + // needed by: .to_homogeneous() D: DimNameAdd<U1> +
SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>>, // needed by: ::convert_unchecked(mm) DimMin<D, Output = D>, // needed by .determinant()
D: DimNameAdd<U1>, DefaultAllocator: Allocator<N1, D> +
SA::Alloc: OwnedAllocator<N1, D, U1, SA> + Allocator<N1, D, D> + // needed by R
Allocator<N1, D, D> + // needed by R Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by .to_homogeneous()
Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by: .to_homogeneous() Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> + // needed by R
Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, // needed by R Allocator<(usize, usize), D> + // needed by .determinant()
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB> + Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N2, D, D> + // needed by: mm.fixed_slice_mut Allocator<N2, D, D> +
Allocator<N2, D, U1> + // needed by: m.fixed_slice Allocator<N2, D> {
Allocator<N2, U1, D> { // needed by: m.fixed_slice
#[inline] #[inline]
fn to_superset(&self) -> SquareMatrix<N2, DimNameSum<D, U1>, SB> { fn to_superset(&self) -> MatrixN<N2, DimNameSum<D, U1>> {
self.to_homogeneous().to_superset() self.to_homogeneous().to_superset()
} }
#[inline] #[inline]
fn is_in_subset(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> bool { fn is_in_subset(m: &MatrixN<N2, DimNameSum<D, U1>>) -> bool {
let mut rot = m.fixed_slice::<D, D>(0, 0).clone_owned(); let mut rot = m.fixed_slice::<D, D>(0, 0).clone_owned();
if rot.fixed_columns_mut::<U1>(0).try_normalize_mut(N2::zero()).is_some() && if rot.fixed_columns_mut::<U1>(0).try_normalize_mut(N2::zero()).is_some() &&
rot.fixed_columns_mut::<U1>(1).try_normalize_mut(N2::zero()).is_some() && rot.fixed_columns_mut::<U1>(1).try_normalize_mut(N2::zero()).is_some() &&
@ -138,7 +133,7 @@ impl<N1, N2, D, SA, SB, R> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self {
let mut mm = m.clone_owned(); let mut mm = m.clone_owned();
let na = mm.fixed_slice_mut::<D, U1>(0, 0).normalize_mut(); let na = mm.fixed_slice_mut::<D, U1>(0, 0).normalize_mut();
let nb = mm.fixed_slice_mut::<D, U1>(0, 1).normalize_mut(); let nb = mm.fixed_slice_mut::<D, U1>(0, 1).normalize_mut();
@ -156,7 +151,7 @@ impl<N1, N2, D, SA, SB, R> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for
} }
let t = m.fixed_slice::<D, U1>(0, D::dim()).into_owned(); let t = m.fixed_slice::<D, U1>(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)) Self::from_parts(t, ::convert_unchecked(mm), ::convert_unchecked(scale))
} }

View File

@ -1,14 +1,13 @@
use std::ops::{Mul, MulAssign, Div, DivAssign}; use std::ops::{Mul, MulAssign, Div, DivAssign};
use alga::general::Real; 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::dimension::{DimName, U1, U3, U4};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
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 // 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>` // 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) * (Operators)
* *
* SimilarityBase × SimilarityBase * Similarity × Similarity
* SimilarityBase × R * Similarity × R
* SimilarityBase × IsometryBase * Similarity × Isometry
* *
* IsometryBase × SimilarityBase * Isometry × Similarity
* IsometryBase ÷ SimilarityBase * Isometry ÷ Similarity
* *
* *
* SimilarityBase ÷ SimilarityBase * Similarity ÷ Similarity
* SimilarityBase ÷ R * Similarity ÷ R
* SimilarityBase ÷ IsometryBase * Similarity ÷ Isometry
* *
* SimilarityBase × PointBase * Similarity × Point
* SimilarityBase × ColumnVector * Similarity × Vector
* *
* *
* SimilarityBase × TranslationBase * Similarity × Translation
* TranslationBase × SimilarityBase * Translation × Similarity
* *
* NOTE: The following are provided explicitly because we can't have R × SimilarityBase. * NOTE: The following are provided explicitly because we can't have R × Similarity.
* RotationBase × SimilarityBase<RotationBase> * Rotation × Similarity<Rotation>
* UnitQuaternion × SimilarityBase<UnitQuaternion> * UnitQuaternion × Similarity<UnitQuaternion>
* *
* RotationBase ÷ SimilarityBase<RotationBase> * Rotation ÷ Similarity<Rotation>
* UnitQuaternion ÷ SimilarityBase<UnitQuaternion> * UnitQuaternion ÷ Similarity<UnitQuaternion>
* *
* (Assignment Operators) * (Assignment Operators)
* *
* SimilarityBase ×= TranslationBase * Similarity ×= Translation
* *
* SimilarityBase ×= SimilarityBase * Similarity ×= Similarity
* SimilarityBase ×= IsometryBase * Similarity ×= Isometry
* SimilarityBase ×= R * Similarity ×= R
* *
* SimilarityBase ÷= SimilarityBase * Similarity ÷= Similarity
* SimilarityBase ÷= IsometryBase * Similarity ÷= Isometry
* SimilarityBase ÷= R * Similarity ÷= R
* *
*/ */
@ -68,11 +67,9 @@ macro_rules! similarity_binop_impl(
($Op: ident, $op: ident; ($Op: ident, $op: ident;
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N, D: DimName, S, R> $Op<$Rhs> for $Lhs impl<$($lives ,)* N: Real, D: DimName, R> $Op<$Rhs> for $Lhs
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
@ -117,22 +114,18 @@ macro_rules! similarity_binop_assign_impl_all(
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty;
[val] => $action_val: expr; [val] => $action_val: expr;
[ref] => $action_ref: expr;) => { [ref] => $action_ref: expr;) => {
impl<N, D: DimName, S, R> $OpAssign<$Rhs> for $Lhs impl<N: Real, D: DimName, R> $OpAssign<$Rhs> for $Lhs
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn $op_assign(&mut $lhs, $rhs: $Rhs) { fn $op_assign(&mut $lhs, $rhs: $Rhs) {
$action_val $action_val
} }
} }
impl<'b, N, D: DimName, S, R> $OpAssign<&'b $Rhs> for $Lhs impl<'b, N: Real, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs
where N: Real, where R: AlgaRotation<Point<N, D>>,
S: OwnedStorage<N, D, U1>, DefaultAllocator: Allocator<N, D> {
R: Rotation<PointBase<N, D, S>>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) {
$action_ref $action_ref
@ -141,11 +134,11 @@ macro_rules! similarity_binop_assign_impl_all(
} }
); );
// SimilarityBase × SimilarityBase // Similarity × Similarity
// SimilarityBase ÷ SimilarityBase // Similarity ÷ Similarity
similarity_binop_impl_all!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: SimilarityBase<N, D, S, R>, rhs: SimilarityBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Similarity<N, D, R>, Output = Similarity<N, D, R>;
[val val] => &self * &rhs; [val val] => &self * &rhs;
[ref val] => self * &rhs; [ref val] => self * &rhs;
[val ref] => &self * rhs; [val ref] => &self * rhs;
@ -159,7 +152,7 @@ similarity_binop_impl_all!(
similarity_binop_impl_all!( similarity_binop_impl_all!(
Div, div; Div, div;
self: SimilarityBase<N, D, S, R>, rhs: SimilarityBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Similarity<N, D, R>, Output = Similarity<N, D, R>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => 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!( similarity_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: SimilarityBase<N, D, S, R>, rhs: TranslationBase<N, D, S>; self: Similarity<N, D, R>, rhs: Translation<N, D>;
[val] => *self *= &rhs; [val] => *self *= &rhs;
[ref] => { [ref] => {
let shift = self.isometry.rotation.transform_vector(&rhs.vector) * self.scaling(); let shift = self.isometry.rotation.transform_vector(&rhs.vector) * self.scaling();
@ -179,11 +172,11 @@ similarity_binop_assign_impl_all!(
); );
// SimilarityBase ×= SimilarityBase // Similarity ×= Similarity
// SimilarityBase ÷= SimilarityBase // Similarity ÷= Similarity
similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: SimilarityBase<N, D, S, R>, rhs: SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Similarity<N, D, R>;
[val] => *self *= &rhs; [val] => *self *= &rhs;
[ref] => { [ref] => {
*self *= &rhs.isometry; *self *= &rhs.isometry;
@ -194,18 +187,18 @@ similarity_binop_assign_impl_all!(
similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: SimilarityBase<N, D, S, R>, rhs: SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Similarity<N, D, R>;
[val] => *self /= &rhs; [val] => *self /= &rhs;
// FIXME: don't invert explicitly. // FIXME: don't invert explicitly.
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse();
); );
// SimilarityBase ×= IsometryBase // Similarity ×= Isometry
// SimilarityBase ÷= IsometryBase // Similarity ÷= Isometry
similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: SimilarityBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Isometry<N, D, R>;
[val] => *self *= &rhs; [val] => *self *= &rhs;
[ref] => { [ref] => {
let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); 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!( similarity_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: SimilarityBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Isometry<N, D, R>;
[val] => *self /= &rhs; [val] => *self /= &rhs;
// FIXME: don't invert explicitly. // FIXME: don't invert explicitly.
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse();
); );
// SimilarityBase ×= R // Similarity ×= R
// SimilarityBase ÷= R // Similarity ÷= R
similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign;
self: SimilarityBase<N, D, S, R>, rhs: R; self: Similarity<N, D, R>, rhs: R;
[val] => self.isometry.rotation *= rhs; [val] => self.isometry.rotation *= rhs;
[ref] => self.isometry.rotation *= rhs.clone(); [ref] => self.isometry.rotation *= rhs.clone();
); );
@ -236,59 +229,59 @@ similarity_binop_assign_impl_all!(
similarity_binop_assign_impl_all!( similarity_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: SimilarityBase<N, D, S, R>, rhs: R; self: Similarity<N, D, R>, rhs: R;
// FIXME: don't invert explicitly? // FIXME: don't invert explicitly?
[val] => *self *= rhs.inverse(); [val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse();
); );
// SimilarityBase × R // Similarity × R
// SimilarityBase ÷ R // Similarity ÷ R
similarity_binop_impl_all!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: SimilarityBase<N, D, S, R>, rhs: R, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: R, Output = Similarity<N, D, R>;
[val val] => { [val val] => {
let scaling = self.scaling(); 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] => { [val ref] => {
let scaling = self.scaling(); 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!( similarity_binop_impl_all!(
Div, div; Div, div;
self: SimilarityBase<N, D, S, R>, rhs: R, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: R, Output = Similarity<N, D, R>;
[val val] => { [val val] => {
let scaling = self.scaling(); 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] => { [val ref] => {
let scaling = self.scaling(); 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 // Similarity × Isometry
// SimilarityBase ÷ IsometryBase // Similarity ÷ Isometry
similarity_binop_impl_all!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: SimilarityBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Isometry<N, D, R>, Output = Similarity<N, D, R>;
[val val] => &self * &rhs; [val val] => &self * &rhs;
[ref val] => self * &rhs; [ref val] => self * &rhs;
[val ref] => &self * rhs; [val ref] => &self * rhs;
[ref ref] => { [ref ref] => {
let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling();
SimilarityBase::from_parts( Similarity::from_parts(
TranslationBase::from_vector(&self.isometry.translation.vector + shift), Translation::from_vector(&self.isometry.translation.vector + shift),
self.isometry.rotation.clone() * rhs.rotation.clone(), self.isometry.rotation.clone() * rhs.rotation.clone(),
self.scaling()) self.scaling())
}; };
@ -298,40 +291,40 @@ similarity_binop_impl_all!(
similarity_binop_impl_all!( similarity_binop_impl_all!(
Div, div; Div, div;
self: SimilarityBase<N, D, S, R>, rhs: IsometryBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, rhs: Isometry<N, D, R>, Output = Similarity<N, D, R>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => self * rhs.inverse(); [val ref] => self * rhs.inverse();
[ref ref] => self * rhs.inverse(); [ref ref] => self * rhs.inverse();
); );
// IsometryBase × SimilarityBase // Isometry × Similarity
// IsometryBase ÷ SimilarityBase // Isometry ÷ Similarity
similarity_binop_impl_all!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: IsometryBase<N, D, S, R>, rhs: SimilarityBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: Similarity<N, D, R>, Output = Similarity<N, D, R>;
[val val] => { [val val] => {
let scaling = rhs.scaling(); let scaling = rhs.scaling();
SimilarityBase::from_isometry(self * rhs.isometry, scaling) Similarity::from_isometry(self * rhs.isometry, scaling)
}; };
[ref val] => { [ref val] => {
let scaling = rhs.scaling(); let scaling = rhs.scaling();
SimilarityBase::from_isometry(self * rhs.isometry, scaling) Similarity::from_isometry(self * rhs.isometry, scaling)
}; };
[val ref] => { [val ref] => {
let scaling = rhs.scaling(); let scaling = rhs.scaling();
SimilarityBase::from_isometry(self * &rhs.isometry, scaling) Similarity::from_isometry(self * &rhs.isometry, scaling)
}; };
[ref ref] => { [ref ref] => {
let scaling = rhs.scaling(); let scaling = rhs.scaling();
SimilarityBase::from_isometry(self * &rhs.isometry, scaling) Similarity::from_isometry(self * &rhs.isometry, scaling)
}; };
); );
similarity_binop_impl_all!( similarity_binop_impl_all!(
Div, div; Div, div;
self: IsometryBase<N, D, S, R>, rhs: SimilarityBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Isometry<N, D, R>, rhs: Similarity<N, D, R>, Output = Similarity<N, D, R>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => self * rhs.inverse(); [val ref] => self * rhs.inverse();
@ -339,10 +332,10 @@ similarity_binop_impl_all!(
); );
// SimilarityBase × PointBase // Similarity × Point
similarity_binop_impl_all!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: SimilarityBase<N, D, S, R>, right: PointBase<N, D, S>, Output = PointBase<N, D, S>; self: Similarity<N, D, R>, right: Point<N, D>, Output = Point<N, D>;
[val val] => { [val val] => {
let scaling = self.scaling(); let scaling = self.scaling();
self.isometry.translation * (self.isometry.rotation.transform_point(&right) * 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!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: SimilarityBase<N, D, S, R>, right: ColumnVector<N, D, S>, Output = ColumnVector<N, D, S>; self: Similarity<N, D, R>, right: VectorN<N, D>, Output = VectorN<N, D>;
[val val] => self.isometry.rotation.transform_vector(&right) * self.scaling(); [val val] => self.isometry.rotation.transform_vector(&right) * self.scaling();
[ref 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(); [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!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: SimilarityBase<N, D, S, R>, right: TranslationBase<N, D, S>, Output = SimilarityBase<N, D, S, R>; self: Similarity<N, D, R>, right: Translation<N, D>, Output = Similarity<N, D, R>;
[val val] => &self * &right; [val val] => &self * &right;
[ref val] => self * &right; [ref val] => self * &right;
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling(); let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling();
SimilarityBase::from_parts( Similarity::from_parts(
TranslationBase::from_vector(&self.isometry.translation.vector + shift), Translation::from_vector(&self.isometry.translation.vector + shift),
self.isometry.rotation.clone(), self.isometry.rotation.clone(),
self.scaling()) self.scaling())
}; };
); );
// TranslationBase × SimilarityBase // Translation × Similarity
similarity_binop_impl_all!( similarity_binop_impl_all!(
Mul, mul; Mul, mul;
self: TranslationBase<N, D, S>, right: SimilarityBase<N, D, S, R>, Output = SimilarityBase<N, D, S, R>; self: Translation<N, D>, right: Similarity<N, D, R>, Output = Similarity<N, D, R>;
[val val] => { [val val] => {
let scaling = right.scaling(); let scaling = right.scaling();
SimilarityBase::from_isometry(self * right.isometry, scaling) Similarity::from_isometry(self * right.isometry, scaling)
}; };
[ref val] => { [ref val] => {
let scaling = right.scaling(); 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()); [val ref] => Similarity::from_isometry(self * &right.isometry, right.scaling());
[ref ref] => SimilarityBase::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),*; ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(for $Dims: ident: $DimsBound: ident),*;
$lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty;
$action: expr; $($lives: tt),*) => { $action: expr; $($lives: tt),*) => {
impl<$($lives ,)* N $(, $Dims: $DimsBound)*, SA, SB> $Op<$Rhs> for $Lhs impl<$($lives ,)* N: Real $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs
where N: Real, where DefaultAllocator: Allocator<N, $R1, $C1> +
SA: OwnedStorage<N, $R1, $C1>, Allocator<N, $R2, $C2> {
SB: OwnedStorage<N, $R2, $C2, Alloc = SA::Alloc>,
SA::Alloc: OwnedAllocator<N, $R1, $C1, SA>,
SB::Alloc: OwnedAllocator<N, $R2, $C2, SB> {
type Output = $Output; type Output = $Output;
#[inline] #[inline]
@ -458,25 +448,25 @@ macro_rules! similarity_from_composition_impl_all(
); );
// RotationBase × SimilarityBase // Rotation × Similarity
similarity_from_composition_impl_all!( similarity_from_composition_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, U1) for D: DimName; (D, D), (D, U1) for D: DimName;
self: RotationBase<N, D, SA>, right: SimilarityBase<N, D, SB, RotationBase<N, D, SA>>, self: Rotation<N, D>, right: Similarity<N, D, Rotation<N, D>>,
Output = SimilarityBase<N, D, SB, RotationBase<N, D, SA>>; Output = Similarity<N, D, Rotation<N, D>>;
[val val] => &self * &right; [val val] => &self * &right;
[ref val] => self * &right; [ref val] => self * &right;
[val ref] => &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!( similarity_from_composition_impl_all!(
Div, div; Div, div;
(D, D), (D, U1) for D: DimName; (D, D), (D, U1) for D: DimName;
self: RotationBase<N, D, SA>, right: SimilarityBase<N, D, SB, RotationBase<N, D, SA>>, self: Rotation<N, D>, right: Similarity<N, D, Rotation<N, D>>,
Output = SimilarityBase<N, D, SB, RotationBase<N, D, SA>>; Output = Similarity<N, D, Rotation<N, D>>;
// FIXME: don't call iverse explicitly? // FIXME: don't call iverse explicitly?
[val val] => self * right.inverse(); [val val] => self * right.inverse();
[ref 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!( similarity_from_composition_impl_all!(
Mul, mul; Mul, mul;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, right: SimilarityBase<N, U3, SB, UnitQuaternionBase<N, SA>>, self: UnitQuaternion<N>, right: Similarity<N, U3, UnitQuaternion<N>>,
Output = SimilarityBase<N, U3, SB, UnitQuaternionBase<N, SA>>; Output = Similarity<N, U3, UnitQuaternion<N>>;
[val val] => &self * &right; [val val] => &self * &right;
[ref val] => self * &right; [ref val] => self * &right;
[val ref] => &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!( similarity_from_composition_impl_all!(
Div, div; Div, div;
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternionBase<N, SA>, right: SimilarityBase<N, U3, SB, UnitQuaternionBase<N, SA>>, self: UnitQuaternion<N>, right: Similarity<N, U3, UnitQuaternion<N>>,
Output = SimilarityBase<N, U3, SB, UnitQuaternionBase<N, SA>>; Output = Similarity<N, U3, UnitQuaternion<N>>;
// FIXME: don't call inverse explicitly? // FIXME: don't call inverse explicitly?
[val val] => self * right.inverse(); [val val] => self * right.inverse();
[ref val] => self * right.inverse(); [ref val] => self * right.inverse();

View File

@ -1,16 +1,15 @@
use std::any::Any; use std::any::Any;
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[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::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use core::storage::{Storage, StorageMut}; use core::storage::Owned;
use core::allocator::Allocator; use core::allocator::Allocator;
/// Trait implemented by phantom types identifying the projective transformation type. /// 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 /// Checks that the given matrix is a valid homogeneous representation of an element of the
/// category `Self`. /// category `Self`.
fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool fn check_homogeneous_invariants<N: Real, D: DimName>(mat: &MatrixN<N, D>) -> bool
where N: Scalar + Field + ApproxEq, where N::Epsilon: Copy,
D: DimName, DefaultAllocator: Allocator<N, D, D>;
S: Storage<N, D, D>,
N::Epsilon: Copy;
} }
/// Traits that gives the `Transform` category that is compatible with the result of the /// 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 { impl TCategory for TGeneral {
#[inline] #[inline]
fn check_homogeneous_invariants<N, D, S>(_: &SquareMatrix<N, D, S>) -> bool fn check_homogeneous_invariants<N: Real, D: DimName>(_: &MatrixN<N, D>) -> bool
where N: Scalar + Field + ApproxEq, where N::Epsilon: Copy,
D: DimName, DefaultAllocator: Allocator<N, D, D> {
S: Storage<N, D, D>,
N::Epsilon: Copy {
true true
} }
} }
impl TCategory for TProjective { impl TCategory for TProjective {
#[inline] #[inline]
fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool fn check_homogeneous_invariants<N: Real, D: DimName>(mat: &MatrixN<N, D>) -> bool
where N: Scalar + Field + ApproxEq, where N::Epsilon: Copy,
D: DimName, DefaultAllocator: Allocator<N, D, D> {
S: Storage<N, D, D>,
N::Epsilon: Copy {
mat.is_invertible() mat.is_invertible()
} }
} }
@ -95,11 +88,9 @@ impl TCategory for TAffine {
} }
#[inline] #[inline]
fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool fn check_homogeneous_invariants<N: Real, D: DimName>(mat: &MatrixN<N, D>) -> bool
where N: Scalar + Field + ApproxEq, where N::Epsilon: Copy,
D: DimName, DefaultAllocator: Allocator<N, D, D> {
S: Storage<N, D, D>,
N::Epsilon: Copy {
let last = D::dim() - 1; let last = D::dim() - 1;
mat.is_invertible() && mat.is_invertible() &&
mat[(last, last)] == N::one() && mat[(last, last)] == N::one() &&
@ -121,17 +112,17 @@ impl<T: TCategory> TCategoryMul<T> for T {
} }
category_mul_impl!( category_mul_impl!(
// TGeneral * TGeneral => TGeneral; // TGeneral * TGeneral => TGeneral;
TGeneral * TProjective => TGeneral; TGeneral * TProjective => TGeneral;
TGeneral * TAffine => TGeneral; TGeneral * TAffine => TGeneral;
TProjective * TGeneral => TGeneral; TProjective * TGeneral => TGeneral;
// TProjective * TProjective => TProjective; // TProjective * TProjective => TProjective;
TProjective * TAffine => TProjective; TProjective * TAffine => TProjective;
TAffine * TGeneral => TGeneral; TAffine * TGeneral => TGeneral;
TAffine * TProjective => TProjective; TAffine * TProjective => TProjective;
// TAffine * TAffine => TAffine; // TAffine * TAffine => TAffine;
); );
macro_rules! super_tcategory_impl( macro_rules! super_tcategory_impl(
@ -143,109 +134,104 @@ macro_rules! super_tcategory_impl(
impl<T: TCategory> SuperTCategoryOf<T> for T { } impl<T: TCategory> SuperTCategoryOf<T> for T { }
super_tcategory_impl!( super_tcategory_impl!(
TGeneral >= TProjective; TGeneral >= TProjective;
TGeneral >= TAffine; TGeneral >= TAffine;
TProjective >= TAffine; TProjective >= TAffine;
); );
/// A transformation matrix that owns its data.
pub type OwnedTransform<N, D, A, C>
= TransformBase<N, D, <A as Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>>::Buffer, C>;
/// A transformation matrix in homogeneous coordinates. /// 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 /// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
/// 3D transformation. /// 3D transformation.
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] // FIXME: Hash #[derive(Debug)]
pub struct TransformBase<N: Scalar, D: DimNameAdd<U1>, S, C: TCategory> { pub struct Transform<N: Real, D: DimNameAdd<U1>, C: TCategory>
matrix: SquareMatrix<N, DimNameSum<D, U1>, S>, where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
matrix: MatrixN<N, DimNameSum<D, U1>>,
_phantom: PhantomData<C> _phantom: PhantomData<C>
} }
#[cfg(feature = "serde-serialize")] // FIXME
impl<N, D, S, C> Serialize for TransformBase<N, D, S, C> // impl<N: Real + hash::Hash, D: DimNameAdd<U1> + hash::Hash, C: TCategory> hash::Hash for Transform<N, D, C>
where N: Scalar, // where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
D: DimNameAdd<U1>, // Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: hash::Hash {
C: TCategory, // fn hash<H: hash::Hasher>(&self, state: &mut H) {
SquareMatrix<N, DimNameSum<D, U1>, S>: Serialize, // self.matrix.hash(state);
{ // }
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error> // }
where T: Serializer
{ impl<N: Real, D: DimNameAdd<U1> + Copy, C: TCategory> Copy for Transform<N, D, C>
self.matrix.serialize(serializer) where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: Copy {
}
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Clone for Transform<N, D, C>
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
#[inline]
fn clone(&self) -> Self {
Transform::from_matrix_unchecked(self.matrix.clone())
} }
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<'de, N, D, S, C> Deserialize<'de> for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C: TCategory> serde::Serialize for Transform<N, D, C>
where N: Scalar, where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
D: DimNameAdd<U1>, Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: serde::Serialize {
C: TCategory,
SquareMatrix<N, DimNameSum<D, U1>, S>: Deserialize<'de>, fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
{ where S: serde::Serializer {
fn deserialize<T>(deserializer: T) -> Result<Self, T::Error> self.matrix.serialize(serializer)
where T: Deserializer<'de> }
{
SquareMatrix::deserialize(deserializer).map(|x| TransformBase { matrix: x, _phantom: PhantomData })
}
} }
// XXX: for some reasons, implementing Clone and Copy manually causes an ICE… #[cfg(feature = "serde-serialize")]
impl<'a, N: Real, D: DimNameAdd<U1>, C: TCategory> serde::Deserialize<'a> for Transform<N, D, C>
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: serde::Deserialize<'a> {
impl<N, D, S, C: TCategory> Eq for TransformBase<N, D, S, C> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where N: Scalar + Eq, where Des: serde::Deserializer<'a> {
D: DimNameAdd<U1>, let matrix = MatrixN::<N, DimNameSum<D, U1>>::deserialize(deserializer)?;
S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { }
impl<N, D, S, C: TCategory> PartialEq for TransformBase<N, D, S, C> Ok(Transform::from_matrix_unchecked(matrix))
where N: Scalar, }
D: DimNameAdd<U1>, }
S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
impl<N: Real + Eq, D: DimNameAdd<U1>, C: TCategory> Eq for Transform<N, D, C>
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { }
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> PartialEq for Transform<N, D, C>
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix self.matrix == right.matrix
} }
} }
impl<N, D, S, C: TCategory> TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Transform<N, D, C>
where N: Scalar, where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
D: DimNameAdd<U1>,
S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
/// Creates a new transformation from the given homogeneous matrix. The transformation category /// Creates a new transformation from the given homogeneous matrix. The transformation category
/// of `Self` is not checked to be verified by the given matrix. /// of `Self` is not checked to be verified by the given matrix.
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: SquareMatrix<N, DimNameSum<D, U1>, S>) -> Self { pub fn from_matrix_unchecked(matrix: MatrixN<N, DimNameSum<D, U1>>) -> Self {
TransformBase { Transform {
matrix: matrix, matrix: matrix,
_phantom: PhantomData _phantom: PhantomData
} }
} }
/// Moves this transform into one that owns its data.
#[inline]
pub fn into_owned(self) -> OwnedTransform<N, D, S::Alloc, C> {
TransformBase::from_matrix_unchecked(self.matrix.into_owned())
}
/// Clones this transform into one that owns its data.
#[inline]
pub fn clone_owned(&self) -> OwnedTransform<N, D, S::Alloc, C> {
TransformBase::from_matrix_unchecked(self.matrix.clone_owned())
}
/// The underlying matrix. /// The underlying matrix.
#[inline] #[inline]
pub fn unwrap(self) -> SquareMatrix<N, DimNameSum<D, U1>, S> { pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix self.matrix
} }
/// A reference to the underlynig matrix. /// A reference to the underlynig matrix.
#[inline] #[inline]
pub fn matrix(&self) -> &SquareMatrix<N, DimNameSum<D, U1>, S> { pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> {
&self.matrix &self.matrix
} }
@ -254,7 +240,7 @@ impl<N, D, S, C: TCategory> TransformBase<N, D, S, C>
/// It is `_unchecked` because direct modifications of this matrix may break invariants /// It is `_unchecked` because direct modifications of this matrix may break invariants
/// identified by this transformation category. /// identified by this transformation category.
#[inline] #[inline]
pub fn matrix_mut_unchecked(&mut self) -> &mut SquareMatrix<N, DimNameSum<D, U1>, S> { pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
&mut self.matrix &mut self.matrix
} }
@ -265,28 +251,28 @@ impl<N, D, S, C: TCategory> TransformBase<N, D, S, C>
/// `TAffine` because not all projective transformations are affine (the other way-round is /// `TAffine` because not all projective transformations are affine (the other way-round is
/// valid though). /// valid though).
#[inline] #[inline]
pub fn set_category<CNew: SuperTCategoryOf<C>>(self) -> TransformBase<N, D, S, CNew> { pub fn set_category<CNew: SuperTCategoryOf<C>>(self) -> Transform<N, D, CNew> {
TransformBase::from_matrix_unchecked(self.matrix) Transform::from_matrix_unchecked(self.matrix)
}
/// Clones this transform into one that owns its data.
#[inline]
pub fn clone_owned(&self) -> Transform<N, D, C> {
Transform::from_matrix_unchecked(self.matrix.clone_owned())
} }
/// Converts this transform into its equivalent homogeneous transformation matrix. /// Converts this transform into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> { pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix().clone_owned() self.matrix().clone_owned()
} }
}
impl<N, D, S, C> TransformBase<N, D, S, C>
where N: Scalar + Field + ApproxEq,
D: DimNameAdd<U1>,
C: TCategory,
S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
/// Attempts to invert this transformation. You may use `.inverse` instead of this /// Attempts to invert this transformation. You may use `.inverse` instead of this
/// transformation has a subcategory of `TProjective`. /// transformation has a subcategory of `TProjective`.
#[inline] #[inline]
pub fn try_inverse(self) -> Option<OwnedTransform<N, D, S::Alloc, C>> { pub fn try_inverse(self) -> Option<Transform<N, D, C>> {
if let Some(m) = self.matrix.try_inverse() { if let Some(m) = self.matrix.try_inverse() {
Some(TransformBase::from_matrix_unchecked(m)) Some(Transform::from_matrix_unchecked(m))
} }
else { else {
None None
@ -296,18 +282,12 @@ impl<N, D, S, C> TransformBase<N, D, S, C>
/// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral` /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
/// category (it may not be invertible). /// category (it may not be invertible).
#[inline] #[inline]
pub fn inverse(self) -> OwnedTransform<N, D, S::Alloc, C> pub fn inverse(self) -> Transform<N, D, C>
where C: SubTCategoryOf<TProjective> { where C: SubTCategoryOf<TProjective> {
// FIXME: specialize for TAffine? // FIXME: specialize for TAffine?
TransformBase::from_matrix_unchecked(self.matrix.try_inverse().unwrap()) Transform::from_matrix_unchecked(self.matrix.try_inverse().unwrap())
} }
}
impl<N, D, S, C> TransformBase<N, D, S, C>
where N: Scalar + Field + ApproxEq,
D: DimNameAdd<U1>,
C: TCategory,
S: StorageMut<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
/// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this /// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
/// transformation has a subcategory of `TProjective`. /// transformation has a subcategory of `TProjective`.
#[inline] #[inline]
@ -324,14 +304,12 @@ impl<N, D, S, C> TransformBase<N, D, S, C>
} }
} }
impl<N, D, S> TransformBase<N, D, S, TGeneral> impl<N: Real, D: DimNameAdd<U1>> Transform<N, D, TGeneral>
where N: Scalar, where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
D: DimNameAdd<U1>,
S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
/// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this
/// transformation category is not `TGeneral`. /// transformation category is not `TGeneral`.
#[inline] #[inline]
pub fn matrix_mut(&mut self) -> &mut SquareMatrix<N, DimNameSum<D, U1>, S> { pub fn matrix_mut(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
self.matrix_mut_unchecked() self.matrix_mut_unchecked()
} }
} }
@ -345,5 +323,4 @@ mod tests {
fn checks_homogeneous_invariants_of_square_identity_matrix() { fn checks_homogeneous_invariants_of_square_identity_matrix() {
assert!(TAffine::check_homogeneous_invariants(&Matrix4::<f32>::identity())); assert!(TAffine::check_homogeneous_invariants(&Matrix4::<f32>::identity()));
} }
} }

View File

@ -1,15 +1,12 @@
use approx::ApproxEq;
use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, 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 alga::linear::{Transformation, ProjectiveTransformation};
use core::{Scalar, ColumnVector}; use core::{DefaultAllocator, VectorN};
use core::dimension::{DimNameSum, DimNameAdd, U1}; use core::dimension::{DimNameSum, DimNameAdd, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::{Allocator, OwnedAllocator};
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. * Algebraic structures.
* *
*/ */
impl<N, D: DimNameAdd<U1>, S, C> Identity<Multiplicative> for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C> Identity<Multiplicative> for Transform<N, D, C>
where N: Scalar + Field, where C: TCategory,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
C: TCategory,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, D: DimNameAdd<U1>, S, C> Inverse<Multiplicative> for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C> Inverse<Multiplicative> for Transform<N, D, C>
where N: Scalar + Field + ApproxEq, where C: SubTCategoryOf<TProjective>,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
C: SubTCategoryOf<TProjective>,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
self.clone().inverse() self.clone().inverse()
@ -44,11 +37,9 @@ impl<N, D: DimNameAdd<U1>, S, C> Inverse<Multiplicative> for TransformBase<N, D,
} }
} }
impl<N, D: DimNameAdd<U1>, S, C> AbstractMagma<Multiplicative> for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C> AbstractMagma<Multiplicative> for Transform<N, D, C>
where N: Scalar + Field, where C: TCategory,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
C: TCategory,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
@ -57,21 +48,17 @@ impl<N, D: DimNameAdd<U1>, S, C> AbstractMagma<Multiplicative> for TransformBase
macro_rules! impl_multiplicative_structures( macro_rules! impl_multiplicative_structures(
($($marker: ident<$operator: ident>),* $(,)*) => {$( ($($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, D: DimNameAdd<U1>, S, C> $marker<$operator> for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C> $marker<$operator> for Transform<N, D, C>
where N: Scalar + Field, where C: TCategory,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { }
C: TCategory,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> { }
)*} )*}
); );
macro_rules! impl_inversible_multiplicative_structures( macro_rules! impl_inversible_multiplicative_structures(
($($marker: ident<$operator: ident>),* $(,)*) => {$( ($($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, D: DimNameAdd<U1>, S, C> $marker<$operator> for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C> $marker<$operator> for Transform<N, D, C>
where N: Scalar + Field + ApproxEq, where C: SubTCategoryOf<TProjective>,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { }
C: SubTCategoryOf<TProjective>,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> { }
)*} )*}
); );
@ -91,64 +78,54 @@ impl_inversible_multiplicative_structures!(
* Transformation groups. * Transformation groups.
* *
*/ */
impl<N, D: DimNameAdd<U1>, SA, SB, C> Transformation<PointBase<N, D, SB>> for TransformBase<N, D, SA, C> impl<N, D: DimNameAdd<U1>, C> Transformation<Point<N, D>> for Transform<N, D, C>
where N: Real, where N: Real,
SA: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
C: TCategory, C: TCategory,
SA::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, SA> + DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N, D, D> + Allocator<N, DimNameSum<D, U1>> +
Allocator<N, D, U1> + Allocator<N, D, D> +
Allocator<N, U1, D>, Allocator<N, D> {
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, D, SB>) -> PointBase<N, D, SB> { fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self * pt self * pt
} }
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, D, SB>) -> ColumnVector<N, D, SB> { fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self * v self * v
} }
} }
impl<N, D: DimNameAdd<U1>, SA, SB, C> ProjectiveTransformation<PointBase<N, D, SB>> for TransformBase<N, D, SA, C> impl<N, D: DimNameAdd<U1>, C> ProjectiveTransformation<Point<N, D>> for Transform<N, D, C>
where N: Real, where N: Real,
SA: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
C: SubTCategoryOf<TProjective>, C: SubTCategoryOf<TProjective>,
SA::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, SA> + DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> +
Allocator<N, D, D> + Allocator<N, DimNameSum<D, U1>> +
Allocator<N, D, U1> + Allocator<N, D, D> +
Allocator<N, U1, D>, Allocator<N, D> {
SB::Alloc: OwnedAllocator<N, D, U1, SB> {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &PointBase<N, D, SB>) -> PointBase<N, D, SB> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self.inverse() * pt self.inverse() * pt
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &ColumnVector<N, D, SB>) -> ColumnVector<N, D, SB> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self.inverse() * v self.inverse() * v
} }
} }
// FIXME: we need to implement an SVD for this. // FIXME: we need to implement an SVD for this.
// //
// impl<N, D: DimNameAdd<U1>, SA, SB, C> AffineTransformation<PointBase<N, D, SB>> for TransformBase<N, D, SA, C> // impl<N, D: DimNameAdd<U1>, C> AffineTransformation<Point<N, D>> for Transform<N, D, C>
// where N: Real, // where N: Real,
// SA: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
// SB: OwnedStorage<N, D, U1, Alloc = SA::Alloc>,
// C: SubTCategoryOf<TAffine>, // C: SubTCategoryOf<TAffine>,
// SA::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, SA> + // DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> +
// Allocator<N, D, D> + // Allocator<N, D, D> +
// Allocator<N, D, U1> + // Allocator<N, D> {
// Allocator<N, U1, D>, // type PreRotation = Rotation<N, D>;
// SB::Alloc: OwnedAllocator<N, D, U1, SB> { // type NonUniformScaling = VectorN<N, D>;
// type PreRotation = OwnedRotation<N, D, SA::Alloc>; // type PostRotation = Rotation<N, D>;
// type NonUniformScaling = OwnedColumnVector<N, D, SA::Alloc>; // type Translation = Translation<N, D>;
// type PostRotation = OwnedRotation<N, D, SA::Alloc>;
// type Translation = OwnedTranslation<N, D, SA::Alloc>;
// //
// #[inline] // #[inline]
// fn decompose(&self) -> (Self::Translation, Self::PostRotation, Self::NonUniformScaling, Self::PreRotation) { // fn decompose(&self) -> (Self::Translation, Self::PostRotation, Self::NonUniformScaling, Self::PreRotation) {

View File

@ -1,29 +1,17 @@
use core::MatrixArray; use core::dimension::{U2, U3};
use core::dimension::{U1, U2, U3, DimNameSum};
use geometry::{TransformBase, TGeneral, TProjective, TAffine}; use geometry::{Transform, 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<N, D> = TransformBase<N, D, MatrixArray<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, TGeneral>;
/// An inversible `D`-dimensional general transformation. Stored as an homogeneous
/// `(D + 1) × (D + 1)` matrix.
pub type Projective<N, D> = TransformBase<N, D, MatrixArray<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, TProjective>;
/// A `D`-dimensional affine transformation. Stored as an homogeneous `(D + 1) × (D + 1)` matrix.
pub type Affine<N, D> = TransformBase<N, D, MatrixArray<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, TAffine>;
/// A 2D general transformation that may not be inversible. Stored as an homogeneous 3x3 matrix. /// A 2D general transformation that may not be inversible. Stored as an homogeneous 3x3 matrix.
pub type Transform2<N> = Transform<N, U2>; pub type Transform2<N> = Transform<N, U2, TGeneral>;
/// An inversible 2D general transformation. Stored as an homogeneous 3x3 matrix. /// An inversible 2D general transformation. Stored as an homogeneous 3x3 matrix.
pub type Projective2<N> = Projective<N, U2>; pub type Projective2<N> = Transform<N, U2, TProjective>;
/// A 2D affine transformation. Stored as an homogeneous 3x3 matrix. /// A 2D affine transformation. Stored as an homogeneous 3x3 matrix.
pub type Affine2<N> = Affine<N, U2>; pub type Affine2<N> = Transform<N, U2, TAffine>;
/// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix. /// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix.
pub type Transform3<N> = Transform<N, U3>; pub type Transform3<N> = Transform<N, U3, TGeneral>;
/// An inversible 3D general transformation. Stored as an homogeneous 4x4 matrix. /// An inversible 3D general transformation. Stored as an homogeneous 4x4 matrix.
pub type Projective3<N> = Projective<N, U3>; pub type Projective3<N> = Transform<N, U3, TProjective>;
/// A 3D affine transformation. Stored as an homogeneous 4x4 matrix. /// A 3D affine transformation. Stored as an homogeneous 4x4 matrix.
pub type Affine3<N> = Affine<N, U3>; pub type Affine3<N> = Transform<N, U3, TAffine>;

View File

@ -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::dimension::{DimNameAdd, DimNameSum, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::{TransformBase, TCategory}; use geometry::{Transform, TCategory};
impl<N, D, S, C: TCategory> TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Transform<N, D, C>
where N: Scalar + Zero + One, where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
D: DimNameAdd<U1>,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> {
/// Creates a new identity transform. /// Creates a new identity transform.
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::from_matrix_unchecked(OwnedSquareMatrix::<N, _, S::Alloc>::identity()) Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity())
} }
} }
impl<N, D, S, C: TCategory> One for TransformBase<N, D, S, C> impl<N: Real, D: DimNameAdd<U1>, C: TCategory> One for Transform<N, D, C>
where N: Scalar + Field, where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
D: DimNameAdd<U1>,
S: OwnedStorage<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
S::Alloc: OwnedAllocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>, S> {
/// Creates a new identity transform. /// Creates a new identity transform.
#[inline] #[inline]
fn one() -> Self { fn one() -> Self {

View File

@ -1,67 +1,60 @@
use approx::ApproxEq; use alga::general::{SubsetOf, Real};
use alga::general::{SubsetOf, Field}; use core::{DefaultAllocator, MatrixN};
use core::{Scalar, SquareMatrix};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::{TransformBase, TCategory, SuperTCategoryOf}; use geometry::{Transform, TCategory, SuperTCategoryOf};
impl<N1, N2, D: DimName, SA, SB, C1, C2> SubsetOf<TransformBase<N2, D, SB, C2>> for TransformBase<N1, D, SA, C1> impl<N1, N2, D: DimName, C1, C2> SubsetOf<Transform<N2, D, C2>> for Transform<N1, D, C1>
where N1: Scalar + Field + ApproxEq + SubsetOf<N2>, where N1: Real + SubsetOf<N2>,
N2: Scalar + Field + ApproxEq, N2: Real,
C1: TCategory, C1: TCategory,
C2: SuperTCategoryOf<C1>, C2: SuperTCategoryOf<C1>,
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
SA: OwnedStorage<N1, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> +
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>,
SA::Alloc: OwnedAllocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>, SA>,
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB>,
N1::Epsilon: Copy, N1::Epsilon: Copy,
N2::Epsilon: Copy { N2::Epsilon: Copy {
#[inline] #[inline]
fn to_superset(&self) -> TransformBase<N2, D, SB, C2> { fn to_superset(&self) -> Transform<N2, D, C2> {
TransformBase::from_matrix_unchecked(self.to_homogeneous().to_superset()) Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
} }
#[inline] #[inline]
fn is_in_subset(t: &TransformBase<N2, D, SB, C2>) -> bool { fn is_in_subset(t: &Transform<N2, D, C2>) -> bool {
<Self as SubsetOf<_>>::is_in_subset(t.matrix()) <Self as SubsetOf<_>>::is_in_subset(t.matrix())
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(t: &TransformBase<N2, D, SB, C2>) -> Self { unsafe fn from_superset_unchecked(t: &Transform<N2, D, C2>) -> Self {
Self::from_superset_unchecked(t.matrix()) Self::from_superset_unchecked(t.matrix())
} }
} }
impl<N1, N2, D: DimName, SA, SB, C> SubsetOf<SquareMatrix<N2, DimNameSum<D, U1>, SB>> for TransformBase<N1, D, SA, C> impl<N1, N2, D: DimName, C> SubsetOf<MatrixN<N2, DimNameSum<D, U1>>> for Transform<N1, D, C>
where N1: Scalar + Field + ApproxEq + SubsetOf<N2>, where N1: Real + SubsetOf<N2>,
N2: Scalar + Field + ApproxEq, N2: Real,
C: TCategory, C: TCategory,
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
SA: OwnedStorage<N1, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>> +
SB: OwnedStorage<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>, Allocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>>,
SA::Alloc: OwnedAllocator<N1, DimNameSum<D, U1>, DimNameSum<D, U1>, SA>,
SB::Alloc: OwnedAllocator<N2, DimNameSum<D, U1>, DimNameSum<D, U1>, SB>,
N1::Epsilon: Copy, N1::Epsilon: Copy,
N2::Epsilon: Copy { N2::Epsilon: Copy {
#[inline] #[inline]
fn to_superset(&self) -> SquareMatrix<N2, DimNameSum<D, U1>, SB> { fn to_superset(&self) -> MatrixN<N2, DimNameSum<D, U1>> {
self.matrix().to_superset() self.matrix().to_superset()
} }
#[inline] #[inline]
fn is_in_subset(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> bool { fn is_in_subset(m: &MatrixN<N2, DimNameSum<D, U1>>) -> bool {
C::check_homogeneous_invariants(m) C::check_homogeneous_invariants(m)
} }
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &SquareMatrix<N2, DimNameSum<D, U1>, SB>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self {
TransformBase::from_matrix_unchecked(::convert_ref_unchecked(m)) Transform::from_matrix_unchecked(::convert_ref_unchecked(m))
} }
} }

View File

@ -1,17 +1,15 @@
use num::{Zero, One}; use num::{Zero, One};
use std::ops::{Index, IndexMut, Mul, MulAssign, Div, DivAssign}; 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::{DefaultAllocator, Scalar, VectorN, MatrixN};
use core::storage::{Storage, StorageMut, OwnedStorage}; use core::allocator::Allocator;
use core::allocator::{Allocator, OwnedAllocator};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1, U3, U4}; use core::dimension::{DimName, DimNameAdd, DimNameSum, U1, U3, U4};
use geometry::{PointBase, OwnedPoint, TransformBase, OwnedTransform, TCategory, TCategoryMul, use geometry::{Point, Transform, TCategory, TCategoryMul,
SubTCategoryOf, SuperTCategoryOf, TGeneral, TProjective, TAffine, RotationBase, SubTCategoryOf, SuperTCategoryOf, TGeneral, TProjective, TAffine, Rotation,
UnitQuaternionBase, IsometryBase, SimilarityBase, TranslationBase}; UnitQuaternion, Isometry, Similarity, Translation};
/* /*
* *
@ -23,55 +21,55 @@ use geometry::{PointBase, OwnedPoint, TransformBase, OwnedTransform, TCategory,
* *
* (Operators) * (Operators)
* *
* TransformBase × IsometryBase * Transform × Isometry
* TransformBase × RotationBase * Transform × Rotation
* TransformBase × SimilarityBase * Transform × Similarity
* TransformBase × TransformBase * Transform × Transform
* TransformBase × UnitQuaternion * Transform × UnitQuaternion
* FIXME: TransformBase × UnitComplex * FIXME: Transform × UnitComplex
* TransformBase × TranslationBase * Transform × Translation
* TransformBase × ColumnVector * Transform × Vector
* TransformBase × PointBase * Transform × Point
* *
* IsometryBase × TransformBase * Isometry × Transform
* RotationBase × TransformBase * Rotation × Transform
* SimilarityBase × TransformBase * Similarity × Transform
* TranslationBase × TransformBase * Translation × Transform
* UnitQuaternionBase × TransformBase * UnitQuaternion × Transform
* FIXME: UnitComplex × TransformBase * FIXME: UnitComplex × Transform
* *
* FIXME: TransformBase ÷ IsometryBase * FIXME: Transform ÷ Isometry
* TransformBase ÷ RotationBase * Transform ÷ Rotation
* FIXME: TransformBase ÷ SimilarityBase * FIXME: Transform ÷ Similarity
* TransformBase ÷ TransformBase * Transform ÷ Transform
* TransformBase ÷ UnitQuaternion * Transform ÷ UnitQuaternion
* TransformBase ÷ TranslationBase * Transform ÷ Translation
* *
* FIXME: IsometryBase ÷ TransformBase * FIXME: Isometry ÷ Transform
* RotationBase ÷ TransformBase * Rotation ÷ Transform
* FIXME: SimilarityBase ÷ TransformBase * FIXME: Similarity ÷ Transform
* TranslationBase ÷ TransformBase * Translation ÷ Transform
* UnitQuaternionBase ÷ TransformBase * UnitQuaternion ÷ Transform
* FIXME: UnitComplex ÷ TransformBase * FIXME: UnitComplex ÷ Transform
* *
* *
* (Assignment Operators) * (Assignment Operators)
* *
* *
* TransformBase ×= TransformBase * Transform ×= Transform
* TransformBase ×= SimilarityBase * Transform ×= Similarity
* TransformBase ×= IsometryBase * Transform ×= Isometry
* TransformBase ×= RotationBase * Transform ×= Rotation
* TransformBase ×= UnitQuaternionBase * Transform ×= UnitQuaternion
* FIXME: TransformBase ×= UnitComplex * FIXME: Transform ×= UnitComplex
* TransformBase ×= TranslationBase * Transform ×= Translation
* *
* TransformBase ÷= TransformBase * Transform ÷= Transform
* FIXME: TransformBase ÷= SimilarityBase * FIXME: Transform ÷= Similarity
* FIXME: TransformBase ÷= IsometryBase * FIXME: Transform ÷= Isometry
* TransformBase ÷= RotationBase * Transform ÷= Rotation
* TransformBase ÷= UnitQuaternionBase * Transform ÷= UnitQuaternion
* FIXME: TransformBase ÷= UnitComplex * FIXME: Transform ÷= UnitComplex
* *
*/ */
@ -80,10 +78,9 @@ use geometry::{PointBase, OwnedPoint, TransformBase, OwnedTransform, TCategory,
* Indexing. * Indexing.
* *
*/ */
impl<N, D, S, C: TCategory> Index<(usize, usize)> for TransformBase<N, D, S, C> impl<N: Real, D, C: TCategory> Index<(usize, usize)> for Transform<N, D, C>
where N: Scalar, where D: DimName + DimNameAdd<U1>,
D: DimName + DimNameAdd<U1>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
type Output = N; type Output = N;
#[inline] #[inline]
@ -93,10 +90,9 @@ impl<N, D, S, C: TCategory> Index<(usize, usize)> for TransformBase<N, D, S, C>
} }
// Only general transformations are mutably indexable. // Only general transformations are mutably indexable.
impl<N, D, S> IndexMut<(usize, usize)> for TransformBase<N, D, S, TGeneral> impl<N: Real, D> IndexMut<(usize, usize)> for Transform<N, D, TGeneral>
where N: Scalar, where D: DimName + DimNameAdd<U1>,
D: DimName + DimNameAdd<U1>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
S: StorageMut<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
#[inline] #[inline]
fn index_mut(&mut self, ij: (usize, usize)) -> &mut N { fn index_mut(&mut self, ij: (usize, usize)) -> &mut N {
self.matrix_mut().index_mut(ij) self.matrix_mut().index_mut(ij)
@ -104,14 +100,11 @@ impl<N, D, S> IndexMut<(usize, usize)> for TransformBase<N, D, S, TGeneral>
} }
// TransformBase × ColumnVector // Transform × Vector
md_impl_all!( md_impl_all!(
Mul, mul where N: Field; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory;
where SA::Alloc: Allocator<N, D, D> self: Transform<N, D, C>, rhs: VectorN<N, D>, Output = VectorN<N, D>;
where SA::Alloc: Allocator<N, D, U1>
where SA::Alloc: Allocator<N, U1, D>;
self: TransformBase<N, D, SA, C>, rhs: ColumnVector<N, D, SB>, Output = OwnedColumnVector<N, D, SA::Alloc>;
[val val] => &self * &rhs; [val val] => &self * &rhs;
[ref val] => self * &rhs; [ref val] => self * &rhs;
[val ref] => &self * rhs; [val ref] => &self * rhs;
@ -132,14 +125,12 @@ md_impl_all!(
); );
// TransformBase × PointBase // Transform × Point
md_impl_all!( md_impl_all!(
Mul, mul where N: Field; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory
where SA::Alloc: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>;
where SA::Alloc: Allocator<N, D, U1> self: Transform<N, D, C>, rhs: Point<N, D>, Output = Point<N, D>;
where SA::Alloc: Allocator<N, U1, D>;
self: TransformBase<N, D, SA, C>, rhs: PointBase<N, D, SB>, Output = OwnedPoint<N, D, SA::Alloc>;
[val val] => &self * &rhs; [val val] => &self * &rhs;
[ref val] => self * &rhs; [ref val] => self * &rhs;
[val ref] => &self * rhs; [val ref] => &self * rhs;
@ -161,11 +152,11 @@ md_impl_all!(
); );
// TransformBase × TransformBase // Transform × Transform
md_impl_all!( md_impl_all!(
Mul, mul; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory; (DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory;
self: TransformBase<N, D, SA, CA>, rhs: TransformBase<N, D, SB, CB>, Output = OwnedTransform<N, D, SA::Alloc, CA::Representative>; self: Transform<N, D, CA>, rhs: Transform<N, D, CB>, Output = Transform<N, D, CA::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.unwrap()); [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.unwrap());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.unwrap());
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.matrix()); [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!( md_impl_all!(
Mul, mul where N: One; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Transform<N, D, C>, rhs: Rotation<N, D>, Output = Transform<N, D, C::Representative>;
self: TransformBase<N, D, SA, C>, rhs: RotationBase<N, D, SB>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * 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()); [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!( md_impl_all!(
Mul, mul where N: One; Mul, mul where N: Real;
(D, D), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> (D, D), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Rotation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
self: RotationBase<N, D, SA>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref 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()); [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!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(U4, U4), (U4, U1) for C: TCategoryMul<TAffine> (U4, U4), (U4, U1) for C: TCategoryMul<TAffine>;
where SB::Alloc: Allocator<N, U3, U3> self: Transform<N, U3, C>, rhs: UnitQuaternion<N>, Output = Transform<N, U3, C::Representative>;
where SB::Alloc: Allocator<N, U4, U4>;
self: TransformBase<N, U3, SA, C>, rhs: UnitQuaternionBase<N, SB>, Output = OwnedTransform<N, U3, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * 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()); [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!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(U4, U1), (U4, U4) for C: TCategoryMul<TAffine> (U4, U1), (U4, U4) for C: TCategoryMul<TAffine>;
where SA::Alloc: Allocator<N, U3, U3> self: UnitQuaternion<N>, rhs: Transform<N, U3, C>, Output = Transform<N, U3, C::Representative>;
where SA::Alloc: Allocator<N, U4, U4>;
self: UnitQuaternionBase<N, SA>, rhs: TransformBase<N, U3, SB, C>, Output = OwnedTransform<N, U3, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref 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()); [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!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, C::Representative>;
self: TransformBase<N, D, SA, C>, rhs: IsometryBase<N, D, SB, R>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * 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()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
); );
// IsometryBase × TransformBase // Isometry × Transform
md_impl_all!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>) (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SA::Alloc> > for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
self: IsometryBase<N, D, SA, R>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref 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()); [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!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
where SB::Alloc: Allocator<N, D, D > self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, C::Representative>;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
self: TransformBase<N, D, SA, C>, rhs: SimilarityBase<N, D, SB, R>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * 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()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
); );
// SimilarityBase × TransformBase // Similarity × Transform
md_impl_all!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>) (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SA::Alloc> > for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
where SA::Alloc: Allocator<N, D, D > self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
self: SimilarityBase<N, D, SA, R>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref 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()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
@ -293,25 +272,23 @@ md_impl_all!(
* `DimNameAdd` requirement). * `DimNameAdd` requirement).
* *
*/ */
// TransformBase × TranslationBase // Transform × Translation
md_impl_all!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Transform<N, D, C>, rhs: Translation<N, D>, Output = Transform<N, D, C::Representative>;
self: TransformBase<N, D, SA, C>, rhs: TranslationBase<N, D, SB>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * 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()); [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
); );
// TranslationBase × TransformBase // Translation × Transform
md_impl_all!( md_impl_all!(
Mul, mul where N: Real; Mul, mul where N: Real;
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>) (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Translation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
self: TranslationBase<N, D, SA>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref 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()); [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!( md_impl_all!(
Div, div where N: ApproxEq, Field; Div, div where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>; (DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: SubTCategoryOf<TProjective>;
self: TransformBase<N, D, SA, CA>, rhs: TransformBase<N, D, SB, CB>, Output = OwnedTransform<N, D, SA::Alloc, CA::Representative>; self: Transform<N, D, CA>, rhs: Transform<N, D, CB>, Output = Transform<N, D, CA::Representative>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => self * rhs.clone_owned().inverse(); [val ref] => self * rhs.clone_owned().inverse();
[ref ref] => self * rhs.clone_owned().inverse(); [ref ref] => self * rhs.clone_owned().inverse();
); );
// TransformBase ÷ RotationBase // Transform ÷ Rotation
md_impl_all!( md_impl_all!(
Div, div where N: One; Div, div where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Transform<N, D, C>, rhs: Rotation<N, D>, Output = Transform<N, D, C::Representative>;
self: TransformBase<N, D, SA, C>, rhs: RotationBase<N, D, SB>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => self * rhs.inverse(); [val ref] => self * rhs.inverse();
@ -344,12 +320,11 @@ md_impl_all!(
); );
// RotationBase ÷ TransformBase // Rotation ÷ Transform
md_impl_all!( md_impl_all!(
Div, div where N: One; Div, div where N: Real;
(D, D), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> (D, D), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Rotation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
self: RotationBase<N, D, SA>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => self.inverse() * rhs; [val val] => self.inverse() * rhs;
[ref val] => self.inverse() * rhs; [ref val] => self.inverse() * rhs;
[val ref] => self.inverse() * rhs; [val ref] => self.inverse() * rhs;
@ -357,13 +332,11 @@ md_impl_all!(
); );
// TransformBase ÷ UnitQuaternionBase // Transform ÷ UnitQuaternion
md_impl_all!( md_impl_all!(
Div, div where N: Real; Div, div where N: Real;
(U4, U4), (U4, U1) for C: TCategoryMul<TAffine> (U4, U4), (U4, U1) for C: TCategoryMul<TAffine>;
where SB::Alloc: Allocator<N, U3, U3> self: Transform<N, U3, C>, rhs: UnitQuaternion<N>, Output = Transform<N, U3, C::Representative>;
where SB::Alloc: Allocator<N, U4, U4>;
self: TransformBase<N, U3, SA, C>, rhs: UnitQuaternionBase<N, SB>, Output = OwnedTransform<N, U3, SA::Alloc, C::Representative>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => self * rhs.inverse(); [val ref] => self * rhs.inverse();
@ -371,13 +344,11 @@ md_impl_all!(
); );
// UnitQuaternionBase ÷ TransformBase // UnitQuaternion ÷ Transform
md_impl_all!( md_impl_all!(
Div, div where N: Real; Div, div where N: Real;
(U4, U1), (U4, U4) for C: TCategoryMul<TAffine> (U4, U1), (U4, U4) for C: TCategoryMul<TAffine>;
where SA::Alloc: Allocator<N, U3, U3> self: UnitQuaternion<N>, rhs: Transform<N, U3, C>, Output = Transform<N, U3, C::Representative>;
where SA::Alloc: Allocator<N, U4, U4>;
self: UnitQuaternionBase<N, SA>, rhs: TransformBase<N, U3, SB, C>, Output = OwnedTransform<N, U3, SA::Alloc, C::Representative>;
[val val] => self.inverse() * rhs; [val val] => self.inverse() * rhs;
[ref val] => self.inverse() * rhs; [ref val] => self.inverse() * rhs;
[val ref] => self.inverse() * rhs; [val ref] => self.inverse() * rhs;
@ -386,26 +357,26 @@ md_impl_all!(
// // TransformBase ÷ IsometryBase // // Transform ÷ Isometry
// md_impl_all!( // md_impl_all!(
// Div, div where N: Real; // Div, div where N: Real;
// (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) // (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > // for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; // where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
// self: TransformBase<N, D, SA, C>, rhs: IsometryBase<N, D, SB, R>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>; // self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, C::Representative>;
// [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.inverse().to_homogeneous()); // [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()); // [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()); // [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()); // [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
// ); // );
// // IsometryBase ÷ TransformBase // // Isometry ÷ Transform
// md_impl_all!( // md_impl_all!(
// Div, div where N: Real; // Div, div where N: Real;
// (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>) // (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SA::Alloc> > // for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; // where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
// self: IsometryBase<N, D, SA, R>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>; // self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
// [ref 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()); // [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!( // md_impl_all!(
// Div, div where N: Real; // Div, div where N: Real;
// (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) // (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > // for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
// where SB::Alloc: Allocator<N, D, D > // where SB::Alloc: Allocator<N, D, D >
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; // where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
// self: TransformBase<N, D, SA, C>, rhs: SimilarityBase<N, D, SB, R>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>; // self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, C::Representative>;
// [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); // [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * 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()); // [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); // [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
// ); // );
// // SimilarityBase ÷ TransformBase // // Similarity ÷ Transform
// md_impl_all!( // md_impl_all!(
// Div, div where N: Real; // Div, div where N: Real;
// (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>) // (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SA::Alloc> > // for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
// where SA::Alloc: Allocator<N, D, D > // where SA::Alloc: Allocator<N, D, D >
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; // where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
// self: SimilarityBase<N, D, SA, R>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>; // self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
// [ref 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()); // [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!( md_impl_all!(
Div, div where N: Real; Div, div where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Transform<N, D, C>, rhs: Translation<N, D>, Output = Transform<N, D, C::Representative>;
self: TransformBase<N, D, SA, C>, rhs: TranslationBase<N, D, SB>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => self * rhs.inverse(); [val val] => self * rhs.inverse();
[ref val] => self * rhs.inverse(); [ref val] => self * rhs.inverse();
[val ref] => self * rhs.inverse(); [val ref] => self * rhs.inverse();
[ref ref] => self * rhs.inverse(); [ref ref] => self * rhs.inverse();
); );
// TranslationBase ÷ TransformBase // Translation ÷ Transform
md_impl_all!( md_impl_all!(
Div, div where N: Real; Div, div where N: Real;
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>) (D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine> for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Translation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
self: TranslationBase<N, D, SA>, rhs: TransformBase<N, D, SB, C>, Output = OwnedTransform<N, D, SA::Alloc, C::Representative>;
[val val] => self.inverse() * rhs; [val val] => self.inverse() * rhs;
[ref val] => self.inverse() * rhs; [ref val] => self.inverse() * rhs;
[val ref] => self.inverse() * rhs; [val ref] => self.inverse() * rhs;
@ -469,36 +438,33 @@ md_impl_all!(
); );
// TransformBase ×= TransformBase // Transform ×= Transform
md_assign_impl_all!( md_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>; (DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>;
self: TransformBase<N, D, SA, CA>, rhs: TransformBase<N, D, SB, CB>; self: Transform<N, D, CA>, rhs: Transform<N, D, CB>;
[val] => *self.matrix_mut_unchecked() *= rhs.unwrap(); [val] => *self.matrix_mut_unchecked() *= rhs.unwrap();
[ref] => *self.matrix_mut_unchecked() *= rhs.matrix(); [ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
); );
// TransformBase ×= SimilarityBase // Transform ×= Similarity
md_assign_impl_all!( md_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> > self: Transform<N, D, C>, rhs: Similarity<N, D, R>;
where SB::Alloc: Allocator<N, D, D>;
self: TransformBase<N, D, SA, C>, rhs: SimilarityBase<N, D, SB, R>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
); );
// TransformBase ×= IsometryBase // Transform ×= Isometry
md_assign_impl_all!( md_assign_impl_all!(
MulAssign, mul_assign; MulAssign, mul_assign where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; self: Transform<N, D, C>, rhs: Isometry<N, D, R>;
self: TransformBase<N, D, SA, C>, rhs: IsometryBase<N, D, SB, R>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *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). * `DimNameAdd` requirement).
* *
*/ */
// TransformBase ×= TranslationBase // Transform ×= Translation
md_assign_impl_all!(
MulAssign, mul_assign where N: One;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
self: TransformBase<N, D, SA, C>, rhs: TranslationBase<N, D, SB>;
[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<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategory
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
self: TransformBase<N, D, SA, C>, rhs: RotationBase<N, D, SB>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
);
// TransformBase ×= UnitQuaternionBase
md_assign_impl_all!( md_assign_impl_all!(
MulAssign, mul_assign where N: Real; MulAssign, mul_assign where N: Real;
(U4, U4), (U4, U1) for C: TCategory (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory;
where SB::Alloc: Allocator<N, U3, U3> self: Transform<N, D, C>, rhs: Translation<N, D>;
where SB::Alloc: Allocator<N, U4, U4>;
self: TransformBase<N, U3, SA, C>, rhs: UnitQuaternionBase<N, SB>;
[val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
[ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous();
); );
// TransformBase ÷= TransformBase // Transform ×= Rotation
md_assign_impl_all!( md_assign_impl_all!(
DivAssign, div_assign where N: Field, ApproxEq; MulAssign, mul_assign where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategory;
self: Transform<N, D, C>, rhs: Rotation<N, D>;
[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<N, U3, C>, rhs: UnitQuaternion<N>;
[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<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) (DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>)
for D: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>; for D: DimNameAdd<U1>, CA: SuperTCategoryOf<CB>, CB: SubTCategoryOf<TProjective>;
self: TransformBase<N, D, SA, CA>, rhs: TransformBase<N, D, SB, CB>; self: Transform<N, D, CA>, rhs: Transform<N, D, CB>;
[val] => *self *= rhs.clone_owned().inverse(); [val] => *self *= rhs.clone_owned().inverse();
[ref] => *self *= rhs.clone_owned().inverse(); [ref] => *self *= rhs.clone_owned().inverse();
); );
// // TransformBase ÷= SimilarityBase // // Transform ÷= Similarity
// md_assign_impl_all!( // md_assign_impl_all!(
// DivAssign, div_assign; // DivAssign, div_assign;
// (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) // (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
// for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > // for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> > // self: Transform<N, D, C>, rhs: Similarity<N, D, R>;
// where SB::Alloc: Allocator<N, D, D>;
// self: TransformBase<N, D, SA, C>, rhs: SimilarityBase<N, D, SB, R>;
// [val] => *self *= rhs.inverse(); // [val] => *self *= rhs.inverse();
// [ref] => *self *= rhs.inverse(); // [ref] => *self *= rhs.inverse();
// ); // );
// //
// //
// // TransformBase ÷= IsometryBase // // Transform ÷= Isometry
// md_assign_impl_all!( // md_assign_impl_all!(
// DivAssign, div_assign; // DivAssign, div_assign;
// (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) // (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
// for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<OwnedSquareMatrix<N, DimNameSum<D, U1>, SB::Alloc> > // for D: DimNameAdd<U1>, C: TCategory, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >; // self: Transform<N, D, C>, rhs: Isometry<N, D, R>;
// self: TransformBase<N, D, SA, C>, rhs: IsometryBase<N, D, SB, R>;
// [val] => *self *= rhs.inverse(); // [val] => *self *= rhs.inverse();
// [ref] => *self *= rhs.inverse(); // [ref] => *self *= rhs.inverse();
// ); // );
// TransformBase ÷= TranslationBase // Transform ÷= Translation
md_assign_impl_all!(
DivAssign, div_assign where N: One, ClosedNeg;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
self: TransformBase<N, D, SA, C>, rhs: TranslationBase<N, D, SB>;
[val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse();
);
// TransformBase ÷= RotationBase
md_assign_impl_all!(
DivAssign, div_assign where N: One;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategory
where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
self: TransformBase<N, D, SA, C>, rhs: RotationBase<N, D, SB>;
[val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse();
);
// TransformBase ÷= UnitQuaternionBase
md_assign_impl_all!( md_assign_impl_all!(
DivAssign, div_assign where N: Real; DivAssign, div_assign where N: Real;
(U4, U4), (U4, U1) for C: TCategory (DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategory;
where SB::Alloc: Allocator<N, U3, U3> self: Transform<N, D, C>, rhs: Translation<N, D>;
where SB::Alloc: Allocator<N, U4, U4>; [val] => *self *= rhs.inverse();
self: TransformBase<N, U3, SA, C>, rhs: UnitQuaternionBase<N, SB>; [ref] => *self *= rhs.inverse();
);
// Transform ÷= Rotation
md_assign_impl_all!(
DivAssign, div_assign where N: Real;
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategory;
self: Transform<N, D, C>, rhs: Rotation<N, D>;
[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<N, U3, C>, rhs: UnitQuaternion<N>;
[val] => *self *= rhs.inverse(); [val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.inverse();
); );

View File

@ -1,114 +1,124 @@
use num::{Zero, One}; use num::{Zero, One};
use std::hash;
use std::fmt; use std::fmt;
use approx::ApproxEq; use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer}; use serde;
use alga::general::{Real, ClosedNeg}; 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::dimension::{DimName, DimNameSum, DimNameAdd, U1};
use core::storage::{Storage, StorageMut, Owned}; use core::storage::Owned;
use core::allocator::Allocator; use core::allocator::Allocator;
/// A translation with an owned vector storage.
pub type OwnedTranslation<N, D, S> = TranslationBase<N, D, Owned<N, D, U1, <S as Storage<N, D, U1>>::Alloc>>;
/// A translation. /// A translation.
#[repr(C)] #[repr(C)]
#[derive(Hash, Debug, Clone, Copy)] #[derive(Debug)]
pub struct TranslationBase<N: Scalar, D: DimName, S/*: Storage<N, D, U1>*/> { pub struct Translation<N: Scalar, D: DimName>
where DefaultAllocator: Allocator<N, D> {
/// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// The translation coordinates, i.e., how much is added to a point's coordinates when it is
/// translated. /// translated.
pub vector: ColumnVector<N, D, S> pub vector: VectorN<N, D>
} }
#[cfg(feature = "serde-serialize")] impl<N: Scalar + hash::Hash, D: DimName + hash::Hash> hash::Hash for Translation<N, D>
impl<N, D, S> Serialize for TranslationBase<N, D, S> where DefaultAllocator: Allocator<N, D>,
where N: Scalar, Owned<N, D>: hash::Hash {
D: DimName, fn hash<H: hash::Hasher>(&self, state: &mut H) {
ColumnVector<N, D, S>: Serialize, self.vector.hash(state)
{ }
fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error> }
where T: Serializer
{ impl<N: Scalar, D: DimName> Copy for Translation<N, D>
self.vector.serialize(serializer) where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy { }
impl<N: Scalar, D: DimName> Clone for Translation<N, D>
where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Clone {
#[inline]
fn clone(&self) -> Self {
Translation::from_vector(self.vector.clone())
} }
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<'de, N, D, S> Deserialize<'de> for TranslationBase<N, D, S> impl<N: Scalar, D: DimName> serde::Serialize for Translation<N, D>
where N: Scalar, where DefaultAllocator: Allocator<N, D>,
D: DimName, Owned<N, D>: serde::Serialize {
ColumnVector<N, D, S>: Deserialize<'de>,
{ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn deserialize<T>(deserializer: T) -> Result<Self, T::Error> where S: serde::Serializer {
where T: Deserializer<'de> self.vector.serialize(serializer)
{ }
ColumnVector::deserialize(deserializer).map(|x| TranslationBase { vector: x })
}
} }
impl<N, D: DimName, S> TranslationBase<N, D, S> #[cfg(feature = "serde-serialize")]
where N: Scalar, impl<'a, N: Scalar, D: DimName> serde::Deserialize<'a> for Translation<N, D>
S: Storage<N, D, U1> { where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: serde::Deserialize<'a> {
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where Des: serde::Deserializer<'a> {
let matrix = VectorN::<N, D>::deserialize(deserializer)?;
Ok(Translation::from_vector(matrix))
}
}
impl<N: Scalar, D: DimName> Translation<N, D>
where DefaultAllocator: Allocator<N, D> {
/// Creates a new translation from the given vector. /// Creates a new translation from the given vector.
#[inline] #[inline]
pub fn from_vector(vector: ColumnVector<N, D, S>) -> TranslationBase<N, D, S> { pub fn from_vector(vector: VectorN<N, D>) -> Translation<N, D> {
TranslationBase { Translation {
vector: vector vector: vector
} }
} }
/// Inverts `self`. /// Inverts `self`.
#[inline] #[inline]
pub fn inverse(&self) -> OwnedTranslation<N, D, S> pub fn inverse(&self) -> Translation<N, D>
where N: ClosedNeg { where N: ClosedNeg {
TranslationBase::from_vector(-&self.vector) Translation::from_vector(-&self.vector)
} }
/// Converts this translation into its equivalent homogeneous transformation matrix. /// Converts this translation into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where N: Zero + One, where N: Zero + One,
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
S::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
let mut res = OwnedSquareMatrix::<N, _, S::Alloc>::identity(); let mut res = MatrixN::<N, DimNameSum<D, U1>>::identity();
res.fixed_slice_mut::<D, U1>(0, D::dim()).copy_from(&self.vector); res.fixed_slice_mut::<D, U1>(0, D::dim()).copy_from(&self.vector);
res res
} }
}
impl<N, D: DimName, S> TranslationBase<N, D, S>
where N: Scalar + ClosedNeg,
S: StorageMut<N, D, U1> {
/// Inverts `self` in-place. /// Inverts `self` in-place.
#[inline] #[inline]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self)
where N: ClosedNeg {
self.vector.neg_mut() self.vector.neg_mut()
} }
} }
impl<N, D: DimName, S> Eq for TranslationBase<N, D, S> impl<N: Scalar + Eq, D: DimName> Eq for Translation<N, D>
where N: Scalar + Eq, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
} }
impl<N, D: DimName, S> PartialEq for TranslationBase<N, D, S> impl<N: Scalar + PartialEq, D: DimName> PartialEq for Translation<N, D>
where N: Scalar + PartialEq, where DefaultAllocator: Allocator<N, D> {
S: Storage<N, D, U1> {
#[inline] #[inline]
fn eq(&self, right: &TranslationBase<N, D, S>) -> bool { fn eq(&self, right: &Translation<N, D>) -> bool {
self.vector == right.vector self.vector == right.vector
} }
} }
impl<N, D: DimName, S> ApproxEq for TranslationBase<N, D, S> impl<N: Scalar + ApproxEq, D: DimName> ApproxEq for Translation<N, D>
where N: Scalar + ApproxEq, where DefaultAllocator: Allocator<N, D>,
S: Storage<N, D, U1>,
N::Epsilon: Copy { N::Epsilon: Copy {
type Epsilon = N::Epsilon; type Epsilon = N::Epsilon;
@ -143,31 +153,14 @@ impl<N, D: DimName, S> ApproxEq for TranslationBase<N, D, S>
* Display * Display
* *
*/ */
impl<N, D: DimName, S> fmt::Display for TranslationBase<N, D, S> impl<N: Real + fmt::Display, D: DimName> fmt::Display for Translation<N, D>
where N: Real + fmt::Display, where DefaultAllocator: Allocator<N, D> +
S: Storage<N, D, U1>, Allocator<usize, D> {
S::Alloc: Allocator<usize, D, U1> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let precision = f.precision().unwrap_or(3); let precision = f.precision().unwrap_or(3);
try!(writeln!(f, "TranslationBase {{")); try!(writeln!(f, "Translation {{"));
try!(write!(f, "{:.*}", precision, self.vector)); try!(write!(f, "{:.*}", precision, self.vector));
writeln!(f, "}}") writeln!(f, "}}")
} }
} }
// // /*
// // *
// // * Absolute
// // *
// // */
// // impl<N: Absolute> Absolute for $t<N> {
// // type AbsoluteValue = $submatrix<N::AbsoluteValue>;
// //
// // #[inline]
// // fn abs(m: &$t<N>) -> $submatrix<N::AbsoluteValue> {
// // Absolute::abs(&m.submatrix)
// // }
// // }
// */

View File

@ -1,14 +1,14 @@
use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup, use alga::general::{AbstractMagma, AbstractGroup, AbstractLoop, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id}; AbstractSemigroup, Real, Inverse, Multiplicative, Identity, Id};
use alga::linear::{Transformation, ProjectiveTransformation, Similarity, AffineTransformation, use alga::linear::{Transformation, ProjectiveTransformation, Similarity, AffineTransformation,
Isometry, DirectIsometry, Translation}; Isometry, DirectIsometry};
use alga::linear::Translation as AlgaTranslation;
use core::ColumnVector; use core::{DefaultAllocator, VectorN};
use core::dimension::{DimName, U1}; use core::dimension::DimName;
use core::storage::OwnedStorage; use core::allocator::Allocator;
use core::allocator::OwnedAllocator;
use geometry::{TranslationBase, PointBase}; use geometry::{Translation, Point};
/* /*
@ -16,20 +16,16 @@ use geometry::{TranslationBase, PointBase};
* Algebraic structures. * Algebraic structures.
* *
*/ */
impl<N, D: DimName, S> Identity<Multiplicative> for TranslationBase<N, D, S> impl<N: Real, D: DimName> Identity<Multiplicative> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn identity() -> Self { fn identity() -> Self {
Self::identity() Self::identity()
} }
} }
impl<N, D: DimName, S> Inverse<Multiplicative> for TranslationBase<N, D, S> impl<N: Real, D: DimName> Inverse<Multiplicative> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn inverse(&self) -> Self {
self.inverse() self.inverse()
@ -41,10 +37,8 @@ impl<N, D: DimName, S> Inverse<Multiplicative> for TranslationBase<N, D, S>
} }
} }
impl<N, D: DimName, S> AbstractMagma<Multiplicative> for TranslationBase<N, D, S> impl<N: Real, D: DimName> AbstractMagma<Multiplicative> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn operate(&self, rhs: &Self) -> Self { fn operate(&self, rhs: &Self) -> Self {
self * rhs self * rhs
@ -53,10 +47,8 @@ impl<N, D: DimName, S> AbstractMagma<Multiplicative> for TranslationBase<N, D, S
macro_rules! impl_multiplicative_structures( macro_rules! impl_multiplicative_structures(
($($marker: ident<$operator: ident>),* $(,)*) => {$( ($($marker: ident<$operator: ident>),* $(,)*) => {$(
impl<N, D: DimName, S> $marker<$operator> for TranslationBase<N, D, S> impl<N: Real, D: DimName> $marker<$operator> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> { }
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> { }
)*} )*}
); );
@ -73,40 +65,34 @@ impl_multiplicative_structures!(
* Transformation groups. * Transformation groups.
* *
*/ */
impl<N, D: DimName, S> Transformation<PointBase<N, D, S>> for TranslationBase<N, D, S> impl<N: Real, D: DimName> Transformation<Point<N, D>> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn transform_point(&self, pt: &PointBase<N, D, S>) -> PointBase<N, D, S> { fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
pt + &self.vector pt + &self.vector
} }
#[inline] #[inline]
fn transform_vector(&self, v: &ColumnVector<N, D, S>) -> ColumnVector<N, D, S> { fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
v.clone() v.clone()
} }
} }
impl<N, D: DimName, S> ProjectiveTransformation<PointBase<N, D, S>> for TranslationBase<N, D, S> impl<N: Real, D: DimName> ProjectiveTransformation<Point<N, D>> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &PointBase<N, D, S>) -> PointBase<N, D, S> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
pt - &self.vector pt - &self.vector
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &ColumnVector<N, D, S>) -> ColumnVector<N, D, S> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
v.clone() v.clone()
} }
} }
impl<N, D: DimName, S> AffineTransformation<PointBase<N, D, S>> for TranslationBase<N, D, S> impl<N: Real, D: DimName> AffineTransformation<Point<N, D>> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Rotation = Id; type Rotation = Id;
type NonUniformScaling = Id; type NonUniformScaling = Id;
type Translation = Self; type Translation = Self;
@ -148,10 +134,9 @@ impl<N, D: DimName, S> AffineTransformation<PointBase<N, D, S>> for TranslationB
} }
impl<N, D: DimName, S> Similarity<PointBase<N, D, S>> for TranslationBase<N, D, S> impl<N: Real, D: DimName> Similarity<Point<N, D>> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
type Scaling = Id; type Scaling = Id;
#[inline] #[inline]
@ -172,10 +157,8 @@ impl<N, D: DimName, S> Similarity<PointBase<N, D, S>> for TranslationBase<N, D,
macro_rules! marker_impl( macro_rules! marker_impl(
($($Trait: ident),*) => {$( ($($Trait: ident),*) => {$(
impl<N, D: DimName, S> $Trait<PointBase<N, D, S>> for TranslationBase<N, D, S> impl<N: Real, D: DimName> $Trait<Point<N, D>> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> { }
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> { }
)*} )*}
); );
@ -183,17 +166,15 @@ marker_impl!(Isometry, DirectIsometry);
/// Subgroups of the n-dimensional translation group `T(n)`. /// Subgroups of the n-dimensional translation group `T(n)`.
impl<N, D: DimName, S> Translation<PointBase<N, D, S>> for TranslationBase<N, D, S> impl<N: Real, D: DimName> AlgaTranslation<Point<N, D>> for Translation<N, D>
where N: Real, where DefaultAllocator: Allocator<N, D> {
S: OwnedStorage<N, D, U1>,
S::Alloc: OwnedAllocator<N, D, U1, S> {
#[inline] #[inline]
fn to_vector(&self) -> ColumnVector<N, D, S> { fn to_vector(&self) -> VectorN<N, D> {
self.vector.clone() self.vector.clone()
} }
#[inline] #[inline]
fn from_vector(v: ColumnVector<N, D, S>) -> Option<Self> { fn from_vector(v: VectorN<N, D>) -> Option<Self> {
Some(Self::from_vector(v)) Some(Self::from_vector(v))
} }
@ -203,7 +184,7 @@ impl<N, D: DimName, S> Translation<PointBase<N, D, S>> for TranslationBase<N, D,
} }
#[inline] #[inline]
fn translation_between(a: &PointBase<N, D, S>, b: &PointBase<N, D, S>) -> Option<Self> { fn translation_between(a: &Point<N, D>, b: &Point<N, D>) -> Option<Self> {
Some(Self::from_vector(b - a)) Some(Self::from_vector(b - a))
} }
} }

Some files were not shown because too many files have changed in this diff Show More