Merge branch 'master' into as_ptr

This commit is contained in:
Sébastien Crozet 2019-02-03 16:55:54 +01:00 committed by GitHub
commit cc7bab9755
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 6440 additions and 1369 deletions

View File

@ -7,7 +7,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [0.17.0] - WIP ## [0.17.0] - WIP
### Added ### Added
* Add swizzling up to dimension 3. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.w)`. * Add swizzling up to dimension 3 for vectors. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.y)`.
* Add swizzling up to dimension 3 for points. For example, you can do `p.zxy()` as an equivalent to `Point3::new(p.z, p.x, p.y)`.
* Add `.copy_from_slice` to copy matrix components from a slice in column-major order. * Add `.copy_from_slice` to copy matrix components from a slice in column-major order.
* Add `.dot` to quaternions. * Add `.dot` to quaternions.
* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them. * Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them.
@ -25,6 +26,16 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Add impl `From<Vector>` for `Translation`. * Add impl `From<Vector>` for `Translation`.
* Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec` * Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec`
as-is for its storage). as-is for its storage).
* Add `.to_homogeneous` to square matrices (and with dimensions higher than 1x1). This will increase their number of row
and columns by 1. The new column and row are filled with 0, except for the diagonal element which is set to 1.
* Implement `Extend<Vec>` for matrices with a dynamic storage. The provided `Vec` is assumed to represent a column-major
matrix with the same number of rows as the one being extended. This will effectively append new columns on the right of
the matrix being extended.
* Implement `Extend<Vec>` for vectors with a dynamic storage. This will concatenate the vector with the given `Vec`.
* Implement `Extend<Matrix<...>>` for matrices with dynamic storage. This will concatenate the columns of both matrices.
* Implement `Into<Vec>` for the `MatrixVec` storage.
* Implement `Hash` for all matrices.
* Add a `.len()` method to retrieve the size of a `MatrixVec`.
### Modified ### Modified
* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The * The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The
@ -32,6 +43,17 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead. * The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead.
* The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not have to * The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not have to
explicitly import the `Transform` trait from the alga crate. explicitly import the `Transform` trait from the alga crate.
* Renamed the matrix storage types: `MatrixArray` -> `ArrayStorage` and `MatrixVec` -> `VecStorage`.
* Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type.
This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`.
* Deprecate several functions at the root of the crate (replaced by methods).
### Removed
* Remove the `Deref` impl for `MatrixVec` as it could cause hard-to-understand compilation errors.
### nalgebra-glm
* Add several alternative projection computations, e.g., `ortho_lh`, `ortho_lh_no`, `perspective_lh`, etc.
* Add features matching those of nalgebra, in particular: `serde-serialize`, `abmonation-serialize`, std` (enabled by default).
## [0.16.0] ## [0.16.0]
All dependencies have been updated to their latest versions. All dependencies have been updated to their latest versions.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra" name = "nalgebra"
version = "0.16.10" version = "0.16.13"
authors = [ "Sébastien Crozet <developer@crozet.re>" ] authors = [ "Sébastien Crozet <developer@crozet.re>" ]
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices." description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
@ -23,26 +23,31 @@ stdweb = [ "rand/stdweb" ]
arbitrary = [ "quickcheck" ] arbitrary = [ "quickcheck" ]
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
abomonation-serialize = [ "abomonation" ] abomonation-serialize = [ "abomonation" ]
sparse = [ ]
debug = [ ] debug = [ ]
alloc = [ ] alloc = [ ]
io = [ "pest", "pest_derive" ]
[dependencies] [dependencies]
typenum = "1.10" typenum = "1.10"
generic-array = "0.11" generic-array = "0.12"
rand = { version = "0.5", default-features = false } rand = { version = "0.6", default-features = false }
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
num-complex = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false }
approx = { version = "0.3", default-features = false } approx = { version = "0.3", default-features = false }
alga = { version = "0.7", default-features = false } alga = { version = "0.8", default-features = false }
matrixmultiply = { version = "0.1", optional = true } matrixmultiply = { version = "0.2", optional = true }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
abomonation = { version = "0.5", optional = true } abomonation = { version = "0.7", optional = true }
mint = { version = "0.5", optional = true } mint = { version = "0.5", optional = true }
quickcheck = { version = "0.6", optional = true } quickcheck = { version = "0.8", optional = true }
pest = { version = "2.0", optional = true }
pest_derive = { version = "2.0", optional = true }
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" serde_json = "1.0"
rand_xorshift = "0.1"
[workspace] [workspace]
members = [ "nalgebra-lapack", "nalgebra-glm" ] members = [ "nalgebra-lapack", "nalgebra-glm" ]

View File

@ -4,7 +4,8 @@ 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) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let a = rng.gen::<$t1>(); let a = rng.gen::<$t1>();
let b = rng.gen::<$t2>(); let b = rng.gen::<$t2>();
@ -19,7 +20,8 @@ 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) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let a = rng.gen::<$t1>(); let a = rng.gen::<$t1>();
let b = rng.gen::<$t2>(); let b = rng.gen::<$t2>();
@ -34,7 +36,8 @@ macro_rules! bench_binop_fn(
($name: ident, $t1: ty, $t2: ty, $binop: path) => { ($name: ident, $t1: ty, $t2: ty, $binop: path) => {
#[bench] #[bench]
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let a = rng.gen::<$t1>(); let a = rng.gen::<$t1>();
let b = rng.gen::<$t2>(); let b = rng.gen::<$t2>();
@ -51,7 +54,8 @@ macro_rules! bench_unop_na(
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
const LEN: usize = 1 << 13; const LEN: usize = 1 << 13;
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect(); let elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect();
let mut i = 0; let mut i = 0;
@ -73,7 +77,8 @@ macro_rules! bench_unop(
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
const LEN: usize = 1 << 13; const LEN: usize = 1 << 13;
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect(); let mut elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect();
let mut i = 0; let mut i = 0;
@ -95,7 +100,8 @@ macro_rules! bench_construction(
fn $name(bh: &mut Bencher) { fn $name(bh: &mut Bencher) {
const LEN: usize = 1 << 13; const LEN: usize = 1 << 13;
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
$(let $args: Vec<$types> = (0usize .. LEN).map(|_| rng.gen::<$types>()).collect();)* $(let $args: Vec<$types> = (0usize .. LEN).map(|_| rng.gen::<$types>()).collect();)*
let mut i = 0; let mut i = 0;

View File

@ -50,7 +50,8 @@ bench_binop_ref!(vec10000_dot_f32, VectorN<f32, U10000>, VectorN<f32, U10000>, d
#[bench] #[bench]
fn vec10000_axpy_f64(bh: &mut Bencher) { fn vec10000_axpy_f64(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut a = DVector::new_random(10000); let mut a = DVector::new_random(10000);
let b = DVector::new_random(10000); let b = DVector::new_random(10000);
let n = rng.gen::<f64>(); let n = rng.gen::<f64>();
@ -60,7 +61,8 @@ fn vec10000_axpy_f64(bh: &mut Bencher) {
#[bench] #[bench]
fn vec10000_axpy_beta_f64(bh: &mut Bencher) { fn vec10000_axpy_beta_f64(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut a = DVector::new_random(10000); let mut a = DVector::new_random(10000);
let b = DVector::new_random(10000); let b = DVector::new_random(10000);
let n = rng.gen::<f64>(); let n = rng.gen::<f64>();
@ -71,7 +73,8 @@ fn vec10000_axpy_beta_f64(bh: &mut Bencher) {
#[bench] #[bench]
fn vec10000_axpy_f64_slice(bh: &mut Bencher) { fn vec10000_axpy_f64_slice(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut a = DVector::new_random(10000); let mut a = DVector::new_random(10000);
let b = DVector::new_random(10000); let b = DVector::new_random(10000);
let n = rng.gen::<f64>(); let n = rng.gen::<f64>();
@ -86,7 +89,8 @@ fn vec10000_axpy_f64_slice(bh: &mut Bencher) {
#[bench] #[bench]
fn vec10000_axpy_f64_static(bh: &mut Bencher) { fn vec10000_axpy_f64_static(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut a = VectorN::<f64, U10000>::new_random(); let mut a = VectorN::<f64, U10000>::new_random();
let b = VectorN::<f64, U10000>::new_random(); let b = VectorN::<f64, U10000>::new_random();
let n = rng.gen::<f64>(); let n = rng.gen::<f64>();
@ -97,7 +101,8 @@ fn vec10000_axpy_f64_static(bh: &mut Bencher) {
#[bench] #[bench]
fn vec10000_axpy_f32(bh: &mut Bencher) { fn vec10000_axpy_f32(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut a = DVector::new_random(10000); let mut a = DVector::new_random(10000);
let b = DVector::new_random(10000); let b = DVector::new_random(10000);
let n = rng.gen::<f32>(); let n = rng.gen::<f32>();
@ -107,7 +112,8 @@ fn vec10000_axpy_f32(bh: &mut Bencher) {
#[bench] #[bench]
fn vec10000_axpy_beta_f32(bh: &mut Bencher) { fn vec10000_axpy_beta_f32(bh: &mut Bencher) {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
let mut a = DVector::new_random(10000); let mut a = DVector::new_random(10000);
let b = DVector::new_random(10000); let b = DVector::new_random(10000);
let n = rng.gen::<f32>(); let n = rng.gen::<f32>();

View File

@ -14,6 +14,7 @@ mod geometry;
mod linalg; mod linalg;
fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix<f64> { fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix<f64> {
let mut rng = IsaacRng::new_unseeded(); use rand::SeedableRng;
let mut rng = IsaacRng::seed_from_u64(0);
DMatrix::<f64>::from_fn(nrows, ncols, |_, _| rng.gen()) DMatrix::<f64>::from_fn(nrows, ncols, |_, _| rng.gen())
} }

View File

@ -11,7 +11,7 @@ if [ -z "$NO_STD" ]; then
cargo build --verbose -p nalgebra --features "serde-serialize"; cargo build --verbose -p nalgebra --features "serde-serialize";
cargo build --verbose -p nalgebra --features "abomonation-serialize"; cargo build --verbose -p nalgebra --features "abomonation-serialize";
cargo build --verbose -p nalgebra --features "debug"; cargo build --verbose -p nalgebra --features "debug";
cargo build --verbose -p nalgebra --features "debug arbitrary mint serde-serialize abomonation-serialize"; cargo build --verbose -p nalgebra --all-features
else else
cargo build -p nalgebra-lapack; cargo build -p nalgebra-lapack;
fi fi

View File

@ -3,7 +3,6 @@ extern crate alga;
extern crate approx; extern crate approx;
extern crate nalgebra as na; extern crate nalgebra as na;
use alga::linear::Transformation;
use na::{Matrix4, Point3, Vector3}; use na::{Matrix4, Point3, Vector3};
fn main() { fn main() {

View File

@ -1,7 +1,6 @@
extern crate alga; extern crate alga;
extern crate nalgebra as na; extern crate nalgebra as na;
use alga::linear::Transformation;
use na::{Matrix4, Point3, Vector3, Vector4}; use na::{Matrix4, Point3, Vector3, Vector4};
fn main() { fn main() {

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-glm" name = "nalgebra-glm"
version = "0.2.0" version = "0.2.1"
authors = ["sebcrozet <developer@crozet.re>"] authors = ["sebcrozet <developer@crozet.re>"]
description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library."
@ -12,8 +12,16 @@ categories = [ "science" ]
keywords = [ "linear", "algebra", "matrix", "vector", "math" ] keywords = [ "linear", "algebra", "matrix", "vector", "math" ]
license = "BSD-3-Clause" license = "BSD-3-Clause"
[features]
default = [ "std" ]
std = [ "nalgebra/std", "alga/std" ]
stdweb = [ "nalgebra/stdweb" ]
arbitrary = [ "nalgebra/arbitrary" ]
serde-serialize = [ "nalgebra/serde-serialize" ]
abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
[dependencies] [dependencies]
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
approx = { version = "0.3", default-features = false } approx = { version = "0.3", default-features = false }
alga = "0.7" alga = { version = "0.8", default-features = false }
nalgebra = { path = "..", version = "^0.16.4" } nalgebra = { path = "..", version = "^0.16.13", default-features = false }

View File

@ -1,5 +1,5 @@
use aliases::TMat4; use aliases::TMat4;
use na::{Orthographic3, Perspective3, Real}; use na::{Real};
//pub fn frustum<N: Real>(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4<N> { //pub fn frustum<N: Real>(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4<N> {
// unimplemented!() // unimplemented!()
@ -53,119 +53,644 @@ use na::{Orthographic3, Perspective3, Real};
// unimplemented!() // unimplemented!()
//} //}
/// Creates a matrix for an orthographic parallel viewing volume, using the right handedness and OpenGL near and far clip planes definition. /// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> { pub fn ortho<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap() ortho_rh_no(left, right, bottom, top, znear, zfar)
} }
//pub fn ortho_lh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> { /// Creates a left hand matrix for a orthographic-view frustum with a depth range of -1 to 1
// unimplemented!() ///
//} /// # Parameters
// ///
//pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> { /// * `left` - Coordinate for left bound of matrix
// unimplemented!() /// * `right` - Coordinate for right bound of matrix
//} /// * `bottom` - Coordinate for bottom bound of matrix
// /// * `top` - Coordinate for top bound of matrix
//pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> { /// * `znear` - Distance from the viewer to the near clipping plane
// unimplemented!() /// * `zfar` - Distance from the viewer to the far clipping plane
//} ///
// pub fn ortho_lh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
//pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> { ortho_lh_no(left, right, bottom, top, znear, zfar)
// unimplemented!() }
//}
//
//pub fn ortho_rh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_rh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_rh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
/// Creates a matrix for a perspective-view frustum based on the right handedness and OpenGL near and far clip planes definition. /// Creates a left hand matrix for a orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = -(right + left) / (right - left);
mat[(1, 1)] = two / (top-bottom);
mat[(1, 3)] = -(top + bottom) / (top - bottom);
mat[(2, 2)] = two / (zfar - znear);
mat[(2, 3)] = -(zfar + znear) / (zfar - znear);
mat
}
/// Creates a matrix for a left hand orthographic-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let one : N = N::one();
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = - (right + left) / (right - left);
mat[(1, 1)] = two / (top - bottom);
mat[(1, 3)] = - (top + bottom) / (top - bottom);
mat[(2, 2)] = one / (zfar - znear);
mat[(2, 3)] = - znear / (zfar - znear);
mat
}
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = - (right + left) / (right - left);
mat[(1, 1)] = two/(top-bottom);
mat[(1, 3)] = - (top + bottom) / (top - bottom);
mat[(2, 2)] = - two / (zfar - znear);
mat[(2, 3)] = - (zfar + znear) / (zfar - znear);
mat
}
/// Creates a right hand matrix for a orthographic-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let one : N = N::one();
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = - (right + left) / (right - left);
mat[(1, 1)] = two/(top-bottom);
mat[(1, 3)] = - (top + bottom) / (top - bottom);
mat[(2, 2)] = - one / (zfar - znear);
mat[(2, 3)] = - znear / (zfar - znear);
mat
}
/// Creates a right hand matrix for a orthographic-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_rh_zo(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_no(fov, width, height, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_lh_no(fov, width, height, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = (far + near) / (far - near);
mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near);
mat[(3, 2)] = N::one();
mat
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = far / (far - near);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = N::one();
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_no(fov, width, height, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_no(fov, width, height, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = - (far + near) / (far - near);
mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near);
mat[(3, 2)] = -N::one();
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = far / (near - far);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = -N::one();
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_zo(fov, width, height, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
/// ///
/// # Important note /// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> { pub fn perspective<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
Perspective3::new(aspect, fovy, near, far).unwrap() // TODO: Breaking change - revert back to proper glm conventions?
//
// Prior to changes to support configuring the behaviour of this function it was simply
// a wrapper around Perspective3::new(). The argument order for that function is different
// than the glm convention, but reordering the arguments would've caused pointlessly
// un-optimal code to be generated so they were rearranged so the function would just call
// straight through.
//
// Now this call to Perspective3::new() is no longer made so the functions can have their
// arguments reordered to the glm convention. Unfortunately this is a breaking change so
// can't be cleanly integrated into the existing library version without breaking other
// people's code. Reordering to glm isn't a huge deal but if it is done it will have to be
// in a major API breaking update.
//
perspective_rh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_lh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let one = N::one();
let two: N = ::convert( 2.0);
let mut mat : TMat4<N> = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = (far + near) / (far - near);
mat[(2, 3)] = -(two * far * near) / (far - near);
mat[(3, 2)] = one;
mat
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let one = N::one();
let two: N = ::convert( 2.0);
let mut mat: TMat4<N> = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = far / (far - near);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = one;
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_rh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_rh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let negone = -N::one();
let one = N::one();
let two: N = ::convert( 2.0);
let mut mat = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = - (far + near) / (far - near);
mat[(2, 3)] = -(two * far * near) / (far - near);
mat[(3, 2)] = negone;
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let negone = -N::one();
let one = N::one();
let two = ::convert( 2.0);
let mut mat = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = far / (near - far);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = negone;
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_rh_zo(aspect, fovy, near, far)
} }
//pub fn perspective_fov<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_lh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_lh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_lh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_rh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_rh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_rh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_lh<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_lh_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_lh_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_rh<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_rh_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_rh_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn tweaked_infinite_perspective<N: Real>(fovy: N, aspect: N, near: N) -> TMat4<N> { //pub fn tweaked_infinite_perspective<N: Real>(fovy: N, aspect: N, near: N) -> TMat4<N> {
// unimplemented!() // unimplemented!()
//} //}

View File

@ -24,7 +24,8 @@ pub fn pick_matrix<N: Real>(center: &TVec2<N>, delta: &TVec2<N>, viewport: &TVec
)) ))
} }
/// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates using OpenGL near and far clip planes definition. /// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates with a
/// depth range of -1 to 1
/// ///
/// # Parameters: /// # Parameters:
/// ///
@ -114,7 +115,8 @@ pub fn project_zo<N: Real>(
) )
} }
/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using OpenGL near and far clip planes definition. /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using a
/// depth range of -1 to 1
/// ///
/// # Parameters: /// # Parameters:
/// ///

View File

@ -1,6 +1,16 @@
//! (Reexported) Additional features not specified by GLSL specification //! (Reexported) Additional features not specified by GLSL specification
pub use self::matrix_clip_space::{ortho, perspective}; pub use self::matrix_clip_space::{
ortho, ortho_lh, ortho_lh_no, ortho_lh_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo,
ortho_zo,
perspective, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no,
perspective_rh, perspective_rh_no, perspective_rh_zo, perspective_zo,
perspective_fov, perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo,
perspective_fov_no, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo,
perspective_fov_zo,
};
pub use self::matrix_projection::{ pub use self::matrix_projection::{
pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo, pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo,
}; };

View File

@ -33,5 +33,5 @@ pub fn quat_lerp<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
pub fn quat_slerp<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> { pub fn quat_slerp<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
Unit::new_normalize(*x) Unit::new_normalize(*x)
.slerp(&Unit::new_normalize(*y), a) .slerp(&Unit::new_normalize(*y), a)
.unwrap() .into_inner()
} }

View File

@ -19,7 +19,7 @@ pub fn quat_pow<N: Real>(q: &Qua<N>, y: N) -> Qua<N> {
/// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`. /// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`.
pub fn quat_rotate<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> { pub fn quat_rotate<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> {
q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).unwrap() q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner()
} }
//pub fn quat_sqrt<N: Real>(q: &Qua<N>) -> Qua<N> { //pub fn quat_sqrt<N: Real>(q: &Qua<N>) -> Qua<N> {

View File

@ -9,13 +9,13 @@ pub fn quat_angle<N: Real>(x: &Qua<N>) -> N {
/// Creates a quaternion from an axis and an angle. /// Creates a quaternion from an axis and an angle.
pub fn quat_angle_axis<N: Real>(angle: N, axis: &TVec3<N>) -> Qua<N> { pub fn quat_angle_axis<N: Real>(angle: N, axis: &TVec3<N>) -> Qua<N> {
UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).unwrap() UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner()
} }
/// The rotation axis of a quaternion assumed to be normalized. /// The rotation axis of a quaternion assumed to be normalized.
pub fn quat_axis<N: Real>(x: &Qua<N>) -> TVec3<N> { pub fn quat_axis<N: Real>(x: &Qua<N>) -> TVec3<N> {
if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() { if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() {
a.unwrap() a.into_inner()
} else { } else {
TVec3::zeros() TVec3::zeros()
} }

View File

@ -5,7 +5,7 @@ use aliases::{Qua, TMat4, TVec, TVec3};
/// Euler angles of the quaternion `q` as (pitch, yaw, roll). /// Euler angles of the quaternion `q` as (pitch, yaw, roll).
pub fn quat_euler_angles<N: Real>(x: &Qua<N>) -> TVec3<N> { pub fn quat_euler_angles<N: Real>(x: &Qua<N>) -> TVec3<N> {
let q = UnitQuaternion::new_unchecked(*x); let q = UnitQuaternion::new_unchecked(*x);
let a = q.to_euler_angles(); let a = q.euler_angles();
TVec3::new(a.2, a.1, a.0) TVec3::new(a.2, a.1, a.0)
} }
@ -34,19 +34,25 @@ pub fn quat_cast<N: Real>(x: &Qua<N>) -> TMat4<N> {
::quat_to_mat4(x) ::quat_to_mat4(x)
} }
/// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix). /// Computes a right hand look-at quaternion
///
/// # Parameters
///
/// * `direction` - Direction vector point at where to look
/// * `up` - Object up vector
///
pub fn quat_look_at<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> { pub fn quat_look_at<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
quat_look_at_rh(direction, up) quat_look_at_rh(direction, up)
} }
/// Computes a left-handed look-at quaternion (equivalent to a left-handed look-at matrix). /// Computes a left-handed look-at quaternion (equivalent to a left-handed look-at matrix).
pub fn quat_look_at_lh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> { pub fn quat_look_at_lh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
UnitQuaternion::look_at_lh(direction, up).unwrap() UnitQuaternion::look_at_lh(direction, up).into_inner()
} }
/// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix). /// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix).
pub fn quat_look_at_rh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> { pub fn quat_look_at_rh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
UnitQuaternion::look_at_rh(direction, up).unwrap() UnitQuaternion::look_at_rh(direction, up).into_inner()
} }
/// The "roll" Euler angle of the quaternion `x` assumed to be normalized. /// The "roll" Euler angle of the quaternion `x` assumed to be normalized.

View File

@ -21,7 +21,7 @@ pub fn quat_extract_real_component<N: Real>(q: &Qua<N>) -> N {
pub fn quat_fast_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> { pub fn quat_fast_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
Unit::new_unchecked(*x) Unit::new_unchecked(*x)
.nlerp(&Unit::new_unchecked(*y), a) .nlerp(&Unit::new_unchecked(*y), a)
.unwrap() .into_inner()
} }
//pub fn quat_intermediate<N: Real>(prev: &Qua<N>, curr: &Qua<N>, next: &Qua<N>) -> Qua<N> { //pub fn quat_intermediate<N: Real>(prev: &Qua<N>, curr: &Qua<N>, next: &Qua<N>) -> Qua<N> {
@ -40,7 +40,7 @@ pub fn quat_magnitude2<N: Real>(q: &Qua<N>) -> N {
/// The quaternion representing the identity rotation. /// The quaternion representing the identity rotation.
pub fn quat_identity<N: Real>() -> Qua<N> { pub fn quat_identity<N: Real>() -> Qua<N> {
UnitQuaternion::identity().unwrap() UnitQuaternion::identity().into_inner()
} }
/// Rotates a vector by a quaternion assumed to be normalized. /// Rotates a vector by a quaternion assumed to be normalized.
@ -58,14 +58,14 @@ pub fn quat_rotate_vec<N: Real>(q: &Qua<N>, v: &TVec4<N>) -> TVec4<N> {
pub fn quat_rotation<N: Real>(orig: &TVec3<N>, dest: &TVec3<N>) -> Qua<N> { pub fn quat_rotation<N: Real>(orig: &TVec3<N>, dest: &TVec3<N>) -> Qua<N> {
UnitQuaternion::rotation_between(orig, dest) UnitQuaternion::rotation_between(orig, dest)
.unwrap_or_else(UnitQuaternion::identity) .unwrap_or_else(UnitQuaternion::identity)
.unwrap() .into_inner()
} }
/// The spherical linear interpolation between two quaternions. /// The spherical linear interpolation between two quaternions.
pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> { pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
Unit::new_normalize(*x) Unit::new_normalize(*x)
.slerp(&Unit::new_normalize(*y), a) .slerp(&Unit::new_normalize(*y), a)
.unwrap() .into_inner()
} }
//pub fn quat_squad<N: Real>(q1: &Qua<N>, q2: &Qua<N>, s1: &Qua<N>, s2: &Qua<N>, h: N) -> Qua<N> { //pub fn quat_squad<N: Real>(q1: &Qua<N>, q2: &Qua<N>, s1: &Qua<N>, s2: &Qua<N>, h: N) -> Qua<N> {
@ -76,7 +76,7 @@ pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
pub fn quat_to_mat3<N: Real>(x: &Qua<N>) -> TMat3<N> { pub fn quat_to_mat3<N: Real>(x: &Qua<N>) -> TMat3<N> {
UnitQuaternion::new_unchecked(*x) UnitQuaternion::new_unchecked(*x)
.to_rotation_matrix() .to_rotation_matrix()
.unwrap() .into_inner()
} }
/// Converts a quaternion to a rotation matrix in homogenous coordinates. /// Converts a quaternion to a rotation matrix in homogenous coordinates.
@ -87,7 +87,7 @@ pub fn quat_to_mat4<N: Real>(x: &Qua<N>) -> TMat4<N> {
/// Converts a rotation matrix to a quaternion. /// Converts a rotation matrix to a quaternion.
pub fn mat3_to_quat<N: Real>(x: &TMat3<N>) -> Qua<N> { pub fn mat3_to_quat<N: Real>(x: &TMat3<N>) -> Qua<N> {
let r = Rotation3::from_matrix_unchecked(*x); let r = Rotation3::from_matrix_unchecked(*x);
UnitQuaternion::from_rotation_matrix(&r).unwrap() UnitQuaternion::from_rotation_matrix(&r).into_inner()
} }
/// Converts a rotation matrix in homogeneous coordinates to a quaternion. /// Converts a rotation matrix in homogeneous coordinates to a quaternion.

View File

@ -21,5 +21,5 @@ pub fn rotate_normalized_axis<N: Real>(m: &TMat4<N>, angle: N, axis: &TVec3<N>)
/// * `angle` - Angle expressed in radians. /// * `angle` - Angle expressed in radians.
/// * `axis` - Normalized axis of the rotation, must be normalized. /// * `axis` - Normalized axis of the rotation, must be normalized.
pub fn quat_rotate_normalized_axis<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> { pub fn quat_rotate_normalized_axis<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> {
q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).unwrap() q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).into_inner()
} }

View File

@ -60,5 +60,5 @@ pub fn rotate_z_vec4<N: Real>(v: &TVec4<N>, angle: N) -> TVec4<N> {
pub fn slerp<N: Real>(x: &TVec3<N>, y: &TVec3<N>, a: N) -> TVec3<N> { pub fn slerp<N: Real>(x: &TVec3<N>, y: &TVec3<N>, a: N) -> TVec3<N> {
Unit::new_unchecked(*x) Unit::new_unchecked(*x)
.slerp(&Unit::new_unchecked(*y), a) .slerp(&Unit::new_unchecked(*y), a)
.unwrap() .into_inner()
} }

View File

@ -110,6 +110,9 @@
and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)). and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)).
*/ */
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate num_traits as num; extern crate num_traits as num;
#[macro_use] #[macro_use]
extern crate approx; extern crate approx;
@ -142,12 +145,17 @@ pub use ext::{
epsilon, equal_columns, equal_columns_eps, equal_columns_eps_vec, equal_eps, equal_eps_vec, epsilon, equal_columns, equal_columns_eps, equal_columns_eps_vec, equal_eps, equal_eps_vec,
identity, look_at, look_at_lh, look_at_rh, max, max2, max3, max3_scalar, max4, max4_scalar, identity, look_at, look_at_lh, look_at_rh, max, max2, max3, max3_scalar, max4, max4_scalar,
min, min2, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps, min, min2, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps,
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, pi, not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, perspective_fov,
pick_matrix, project, project_no, project_zo, quat_angle, quat_angle_axis, quat_axis, perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo, perspective_fov_no,
quat_conjugate, quat_cross, quat_dot, quat_equal, quat_equal_eps, quat_exp, quat_inverse, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, perspective_fov_zo,
quat_length, quat_lerp, quat_log, quat_magnitude, quat_normalize, quat_not_equal, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, perspective_rh,
quat_not_equal_eps, quat_pow, quat_rotate, quat_slerp, rotate, rotate_x, rotate_y, rotate_z, perspective_rh_no, perspective_rh_zo, perspective_zo, ortho_lh, ortho_lh_no, ortho_lh_zo,
scale, translate, unproject, unproject_no, unproject_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, ortho_zo, pi, pick_matrix, project, project_no,
project_zo, quat_angle, quat_angle_axis, quat_axis, quat_conjugate, quat_cross, quat_dot,
quat_equal, quat_equal_eps, quat_exp, quat_inverse, quat_length, quat_lerp, quat_log,
quat_magnitude, quat_normalize, quat_not_equal, quat_not_equal_eps, quat_pow, quat_rotate,
quat_slerp, rotate, rotate_x, rotate_y, rotate_z, scale, translate, unproject, unproject_no,
unproject_zo,
}; };
pub use gtc::{ pub use gtc::{
affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose, affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose,

55
nalgebra-glm/tests/lib.rs Normal file
View File

@ -0,0 +1,55 @@
extern crate nalgebra as na;
extern crate nalgebra_glm as glm;
use na::Perspective3;
use na::Orthographic3;
use glm::Mat4;
use glm::Vec4;
#[test]
pub fn orthographic_glm_nalgebra_same()
{
let na_mat : Mat4 = Orthographic3::new(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner();
let gl_mat : Mat4 = glm::ortho(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32);
assert_eq!(na_mat, gl_mat);
}
#[test]
pub fn perspective_glm_nalgebra_same()
{
let na_mat : Mat4 = Perspective3::new(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32).into_inner();
let gl_mat : Mat4 = glm::perspective(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32);
assert_eq!(na_mat, gl_mat);
}
#[test]
pub fn orthographic_glm_nalgebra_project_same()
{
let point = Vec4::new(1.0,0.0,-20.0,1.0);
let na_mat : Mat4 = Orthographic3::new(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner();
let gl_mat : Mat4 = glm::ortho(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32);
let na_pt = na_mat * point;
let gl_pt = gl_mat * point;
assert_eq!(na_mat, gl_mat);
assert_eq!(na_pt, gl_pt);
}
#[test]
pub fn perspective_glm_nalgebra_project_same()
{
let point = Vec4::new(1.0,0.0,-20.0,1.0);
let na_mat : Mat4 = Perspective3::new(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32).into_inner();
let gl_mat : Mat4 = glm::perspective(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32);
let na_pt = na_mat * point;
let gl_pt = gl_mat * point;
assert_eq!(na_mat, gl_mat);
assert_eq!(na_pt, gl_pt);
}

View File

@ -25,7 +25,7 @@ intel-mkl = ["lapack-src/intel-mkl"]
nalgebra = { version = "0.16", path = ".." } nalgebra = { version = "0.16", path = ".." }
num-traits = "0.2" num-traits = "0.2"
num-complex = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false }
alga = { version = "0.7", default-features = false } alga = { version = "0.8", default-features = false }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
lapack = { version = "0.16", default-features = false } lapack = { version = "0.16", default-features = false }
@ -34,6 +34,6 @@ lapack-src = { version = "0.2", default-features = false }
[dev-dependencies] [dev-dependencies]
nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] } nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] }
quickcheck = "0.6" quickcheck = "0.8"
approx = "0.3" approx = "0.3"
rand = "0.5" rand = "0.6"

View File

@ -160,7 +160,7 @@ where DefaultAllocator: Allocator<N, D, D>
// Copy lower triangle to upper triangle. // Copy lower triangle to upper triangle.
for i in 0..dim { for i in 0..dim {
for j in i + 1..dim { for j in i + 1..dim {
unsafe { *self.l.get_unchecked_mut(i, j) = *self.l.get_unchecked(j, i) }; unsafe { *self.l.get_unchecked_mut((i, j)) = *self.l.get_unchecked((j, i)) };
} }
} }

View File

@ -68,8 +68,10 @@
#![deny(unused_qualifications)] #![deny(unused_qualifications)]
#![deny(unused_results)] #![deny(unused_results)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico", #![doc(
html_root_url = "http://nalgebra.org/rustdoc")] html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc"
)]
extern crate alga; extern crate alga;
extern crate lapack; extern crate lapack;

View File

@ -2,7 +2,7 @@
use base::dimension::Dynamic; use base::dimension::Dynamic;
use base::dimension::{U1, U2, U3, U4, U5, U6}; use base::dimension::{U1, U2, U3, U4, U5, U6};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use base::matrix_vec::MatrixVec; use base::vec_storage::VecStorage;
use base::storage::Owned; use base::storage::Owned;
use base::Matrix; use base::Matrix;
@ -119,7 +119,7 @@ pub type Matrix6x5<N> = MatrixMN<N, U6, U5>;
*/ */
/// A dynamically sized column vector. /// A dynamically sized column vector.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub type DVector<N> = Matrix<N, Dynamic, U1, MatrixVec<N, Dynamic, U1>>; pub type DVector<N> = Matrix<N, Dynamic, U1, VecStorage<N, Dynamic, U1>>;
/// A statically sized D-dimensional column vector. /// A statically sized D-dimensional column vector.
pub type VectorN<N, D> = MatrixMN<N, D, U1>; pub type VectorN<N, D> = MatrixMN<N, D, U1>;
@ -146,7 +146,7 @@ pub type Vector6<N> = VectorN<N, U6>;
*/ */
/// A dynamically sized row vector. /// A dynamically sized row vector.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub type RowDVector<N> = Matrix<N, U1, Dynamic, MatrixVec<N, U1, Dynamic>>; pub type RowDVector<N> = Matrix<N, U1, Dynamic, VecStorage<N, U1, Dynamic>>;
/// A statically sized D-dimensional row vector. /// A statically sized D-dimensional row vector.
pub type RowVectorN<N, D> = MatrixMN<N, U1, D>; pub type RowVectorN<N, D> = MatrixMN<N, U1, D>;

View File

@ -175,24 +175,24 @@ pub type MatrixSliceXx6<'a, N, RStride = U1, CStride = Dynamic> =
MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>; MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>;
/// A column vector slice with `D` rows. /// A column vector slice with `D` rows.
pub type VectorSliceN<'a, N, D, Stride = U1> = pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> =
Matrix<N, D, U1, SliceStorage<'a, N, D, U1, Stride, D>>; Matrix<N, D, U1, SliceStorage<'a, N, D, U1, RStride, CStride>>;
/// A column vector slice dynamic numbers of rows and columns. /// A column vector slice dynamic numbers of rows and columns.
pub type DVectorSlice<'a, N, Stride = U1> = VectorSliceN<'a, N, Dynamic, Stride>; pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceN<'a, N, Dynamic, RStride, CStride>;
/// A 1D column vector slice. /// A 1D column vector slice.
pub type VectorSlice1<'a, N, Stride = U1> = VectorSliceN<'a, N, U1, Stride>; pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = VectorSliceN<'a, N, U1, RStride, CStride>;
/// A 2D column vector slice. /// A 2D column vector slice.
pub type VectorSlice2<'a, N, Stride = U1> = VectorSliceN<'a, N, U2, Stride>; pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = VectorSliceN<'a, N, U2, RStride, CStride>;
/// A 3D column vector slice. /// A 3D column vector slice.
pub type VectorSlice3<'a, N, Stride = U1> = VectorSliceN<'a, N, U3, Stride>; pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = VectorSliceN<'a, N, U3, RStride, CStride>;
/// A 4D column vector slice. /// A 4D column vector slice.
pub type VectorSlice4<'a, N, Stride = U1> = VectorSliceN<'a, N, U4, Stride>; pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = VectorSliceN<'a, N, U4, RStride, CStride>;
/// A 5D column vector slice. /// A 5D column vector slice.
pub type VectorSlice5<'a, N, Stride = U1> = VectorSliceN<'a, N, U5, Stride>; pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = VectorSliceN<'a, N, U5, RStride, CStride>;
/// A 6D column vector slice. /// A 6D column vector slice.
pub type VectorSlice6<'a, N, Stride = U1> = VectorSliceN<'a, N, U6, Stride>; pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = VectorSliceN<'a, N, U6, RStride, CStride>;
/* /*
* *
@ -367,21 +367,21 @@ pub type MatrixSliceMutXx6<'a, N, RStride = U1, CStride = Dynamic> =
MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>; MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>;
/// A mutable column vector slice with `D` rows. /// A mutable column vector slice with `D` rows.
pub type VectorSliceMutN<'a, N, D, Stride = U1> = pub type VectorSliceMutN<'a, N, D, RStride = U1, CStride = D> =
Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, Stride, D>>; Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, RStride, CStride>>;
/// A mutable column vector slice dynamic numbers of rows and columns. /// A mutable column vector slice dynamic numbers of rows and columns.
pub type DVectorSliceMut<'a, N, Stride = U1> = VectorSliceMutN<'a, N, Dynamic, Stride>; pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceMutN<'a, N, Dynamic, RStride, CStride>;
/// A 1D mutable column vector slice. /// A 1D mutable column vector slice.
pub type VectorSliceMut1<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U1, Stride>; pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = VectorSliceMutN<'a, N, U1, RStride, CStride>;
/// A 2D mutable column vector slice. /// A 2D mutable column vector slice.
pub type VectorSliceMut2<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U2, Stride>; pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = VectorSliceMutN<'a, N, U2, RStride, CStride>;
/// A 3D mutable column vector slice. /// A 3D mutable column vector slice.
pub type VectorSliceMut3<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U3, Stride>; pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = VectorSliceMutN<'a, N, U3, RStride, CStride>;
/// A 4D mutable column vector slice. /// A 4D mutable column vector slice.
pub type VectorSliceMut4<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U4, Stride>; pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = VectorSliceMutN<'a, N, U4, RStride, CStride>;
/// A 5D mutable column vector slice. /// A 5D mutable column vector slice.
pub type VectorSliceMut5<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U5, Stride>; pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = VectorSliceMutN<'a, N, U5, RStride, CStride>;
/// A 6D mutable column vector slice. /// A 6D mutable column vector slice.
pub type VectorSliceMut6<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U6, Stride>; pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = VectorSliceMutN<'a, N, U6, RStride, CStride>;

View File

@ -34,7 +34,7 @@ use base::Scalar;
*/ */
/// A array-based statically sized matrix data storage. /// A array-based statically sized matrix data storage.
#[repr(C)] #[repr(C)]
pub struct MatrixArray<N, R, C> pub struct ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,
@ -44,7 +44,11 @@ where
data: GenericArray<N, Prod<R::Value, C::Value>>, data: GenericArray<N, Prod<R::Value, C::Value>>,
} }
impl<N, R, C> Hash for MatrixArray<N, R, C> #[deprecated(note="renamed to `ArrayStorage`")]
/// Renamed to [ArrayStorage].
pub type MatrixArray<N, R, C> = ArrayStorage<N, R, C>;
impl<N, R, C> Hash for ArrayStorage<N, R, C>
where where
N: Hash, N: Hash,
R: DimName, R: DimName,
@ -57,7 +61,7 @@ where
} }
} }
impl<N, R, C> Deref for MatrixArray<N, R, C> impl<N, R, C> Deref for ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,
@ -72,7 +76,7 @@ where
} }
} }
impl<N, R, C> DerefMut for MatrixArray<N, R, C> impl<N, R, C> DerefMut for ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,
@ -85,7 +89,7 @@ where
} }
} }
impl<N, R, C> Debug for MatrixArray<N, R, C> impl<N, R, C> Debug for ArrayStorage<N, R, C>
where where
N: Debug, N: Debug,
R: DimName, R: DimName,
@ -99,7 +103,7 @@ where
} }
} }
impl<N, R, C> Copy for MatrixArray<N, R, C> impl<N, R, C> Copy for ArrayStorage<N, R, C>
where where
N: Copy, N: Copy,
R: DimName, R: DimName,
@ -109,7 +113,7 @@ where
GenericArray<N, Prod<R::Value, C::Value>>: Copy, GenericArray<N, Prod<R::Value, C::Value>>: Copy,
{} {}
impl<N, R, C> Clone for MatrixArray<N, R, C> impl<N, R, C> Clone for ArrayStorage<N, R, C>
where where
N: Clone, N: Clone,
R: DimName, R: DimName,
@ -119,13 +123,13 @@ where
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
MatrixArray { ArrayStorage {
data: self.data.clone(), data: self.data.clone(),
} }
} }
} }
impl<N, R, C> Eq for MatrixArray<N, R, C> impl<N, R, C> Eq for ArrayStorage<N, R, C>
where where
N: Eq, N: Eq,
R: DimName, R: DimName,
@ -134,7 +138,7 @@ where
Prod<R::Value, C::Value>: ArrayLength<N>, Prod<R::Value, C::Value>: ArrayLength<N>,
{} {}
impl<N, R, C> PartialEq for MatrixArray<N, R, C> impl<N, R, C> PartialEq for ArrayStorage<N, R, C>
where where
N: PartialEq, N: PartialEq,
R: DimName, R: DimName,
@ -148,7 +152,7 @@ where
} }
} }
unsafe impl<N, R, C> Storage<N, R, C> for MatrixArray<N, R, C> unsafe impl<N, R, C> Storage<N, R, C> for ArrayStorage<N, R, C>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -200,7 +204,7 @@ where
} }
} }
unsafe impl<N, R, C> StorageMut<N, R, C> for MatrixArray<N, R, C> unsafe impl<N, R, C> StorageMut<N, R, C> for ArrayStorage<N, R, C>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -220,7 +224,7 @@ where
} }
} }
unsafe impl<N, R, C> ContiguousStorage<N, R, C> for MatrixArray<N, R, C> unsafe impl<N, R, C> ContiguousStorage<N, R, C> for ArrayStorage<N, R, C>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -230,7 +234,7 @@ where
DefaultAllocator: Allocator<N, R, C, Buffer = Self>, DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{} {}
unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for MatrixArray<N, R, C> unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for ArrayStorage<N, R, C>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -247,7 +251,7 @@ where
*/ */
// XXX: open an issue for GenericArray so that it implements serde traits? // XXX: open an issue for GenericArray so that it implements serde traits?
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<N, R, C> Serialize for MatrixArray<N, R, C> impl<N, R, C> Serialize for ArrayStorage<N, R, C>
where where
N: Scalar + Serialize, N: Scalar + Serialize,
R: DimName, R: DimName,
@ -268,7 +272,7 @@ where
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Deserialize<'a> for MatrixArray<N, R, C> impl<'a, N, R, C> Deserialize<'a> for ArrayStorage<N, R, C>
where where
N: Scalar + Deserialize<'a>, N: Scalar + Deserialize<'a>,
R: DimName, R: DimName,
@ -278,18 +282,18 @@ where
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> { where D: Deserializer<'a> {
deserializer.deserialize_seq(MatrixArrayVisitor::new()) deserializer.deserialize_seq(ArrayStorageVisitor::new())
} }
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
/// A visitor that produces a matrix array. /// A visitor that produces a matrix array.
struct MatrixArrayVisitor<N, R, C> { struct ArrayStorageVisitor<N, R, C> {
marker: PhantomData<(N, R, C)>, marker: PhantomData<(N, R, C)>,
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<N, R, C> MatrixArrayVisitor<N, R, C> impl<N, R, C> ArrayStorageVisitor<N, R, C>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -299,14 +303,14 @@ where
{ {
/// Construct a new sequence visitor. /// Construct a new sequence visitor.
pub fn new() -> Self { pub fn new() -> Self {
MatrixArrayVisitor { ArrayStorageVisitor {
marker: PhantomData, marker: PhantomData,
} }
} }
} }
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Visitor<'a> for MatrixArrayVisitor<N, R, C> impl<'a, N, R, C> Visitor<'a> for ArrayStorageVisitor<N, R, C>
where where
N: Scalar + Deserialize<'a>, N: Scalar + Deserialize<'a>,
R: DimName, R: DimName,
@ -314,20 +318,20 @@ where
R::Value: Mul<C::Value>, R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>, Prod<R::Value, C::Value>: ArrayLength<N>,
{ {
type Value = MatrixArray<N, R, C>; type Value = ArrayStorage<N, R, C>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a matrix array") formatter.write_str("a matrix array")
} }
#[inline] #[inline]
fn visit_seq<V>(self, mut visitor: V) -> Result<MatrixArray<N, R, C>, V::Error> fn visit_seq<V>(self, mut visitor: V) -> Result<ArrayStorage<N, R, C>, V::Error>
where V: SeqAccess<'a> { where V: SeqAccess<'a> {
let mut out: Self::Value = unsafe { mem::uninitialized() }; let mut out: Self::Value = unsafe { mem::uninitialized() };
let mut curr = 0; let mut curr = 0;
while let Some(value) = try!(visitor.next_element()) { while let Some(value) = try!(visitor.next_element()) {
out[curr] = value; *out.get_mut(curr).ok_or_else(|| V::Error::invalid_length(curr, &self))? = value;
curr += 1; curr += 1;
} }
@ -340,7 +344,7 @@ where
} }
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for MatrixArray<N, R, C> impl<N, R, C> Abomonation for ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,

View File

@ -13,18 +13,18 @@ use base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector}; use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector};
impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S> { impl<N: Scalar + PartialOrd, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index of the vector component with the largest value. /// Computes the index and value of the vector component with the largest value.
/// ///
/// # Examples: /// # Examples:
/// ///
/// ``` /// ```
/// # use nalgebra::Vector3; /// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13); /// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.imax(), 2); /// assert_eq!(vec.argmax(), (2, 13));
/// ``` /// ```
#[inline] #[inline]
pub fn imax(&self) -> usize { pub fn argmax(&self) -> (usize, N) {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0) }; let mut the_max = unsafe { self.vget_unchecked(0) };
@ -39,7 +39,21 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
} }
} }
the_i (the_i, *the_max)
}
/// Computes the index of the vector component with the largest value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.imax(), 2);
/// ```
#[inline]
pub fn imax(&self) -> usize {
self.argmax().0
} }
/// Computes the index of the vector component with the largest absolute value. /// Computes the index of the vector component with the largest absolute value.
@ -52,7 +66,8 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// assert_eq!(vec.iamax(), 1); /// assert_eq!(vec.iamax(), 1);
/// ``` /// ```
#[inline] #[inline]
pub fn iamax(&self) -> usize { pub fn iamax(&self) -> usize
where N: Signed {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0).abs() }; let mut the_max = unsafe { self.vget_unchecked(0).abs() };
@ -70,6 +85,34 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
the_i the_i
} }
/// Computes the index and value of the vector component with the smallest value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.argmin(), (1, -15));
/// ```
#[inline]
pub fn argmin(&self) -> (usize, N) {
assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_min = unsafe { self.vget_unchecked(0) };
let mut the_i = 0;
for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i) };
if val < the_min {
the_min = val;
the_i = i;
}
}
(the_i, *the_min)
}
/// Computes the index of the vector component with the smallest value. /// Computes the index of the vector component with the smallest value.
/// ///
/// # Examples: /// # Examples:
@ -81,21 +124,7 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// ``` /// ```
#[inline] #[inline]
pub fn imin(&self) -> usize { pub fn imin(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty."); self.argmin().0
let mut the_max = unsafe { self.vget_unchecked(0) };
let mut the_i = 0;
for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i) };
if val < the_max {
the_max = val;
the_i = i;
}
}
the_i
} }
/// Computes the index of the vector component with the smallest absolute value. /// Computes the index of the vector component with the smallest absolute value.
@ -108,17 +137,18 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// assert_eq!(vec.iamin(), 0); /// assert_eq!(vec.iamin(), 0);
/// ``` /// ```
#[inline] #[inline]
pub fn iamin(&self) -> usize { pub fn iamin(&self) -> usize
where N: Signed {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0).abs() }; let mut the_min = unsafe { self.vget_unchecked(0).abs() };
let mut the_i = 0; let mut the_i = 0;
for i in 1..self.nrows() { for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i).abs() }; let val = unsafe { self.vget_unchecked(i).abs() };
if val < the_max { if val < the_min {
the_max = val; the_min = val;
the_i = i; the_i = i;
} }
} }
@ -142,12 +172,12 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
pub fn iamax_full(&self) -> (usize, usize) { pub fn iamax_full(&self) -> (usize, usize) {
assert!(!self.is_empty(), "The input matrix must not be empty."); 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_max = unsafe { self.get_unchecked((0, 0)).abs() };
let mut the_ij = (0, 0); let mut the_ij = (0, 0);
for j in 0..self.ncols() { for j in 0..self.ncols() {
for i in 0..self.nrows() { for i in 0..self.nrows() {
let val = unsafe { self.get_unchecked(i, j).abs() }; let val = unsafe { self.get_unchecked((i, j)).abs() };
if val > the_max { if val > the_max {
the_max = val; the_max = val;
@ -197,27 +227,27 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
// because the `for` loop below won't be very efficient on those. // because the `for` loop below won't be very efficient on those.
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) { if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe { unsafe {
let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0); 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 b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
return a + b; return a + b;
} }
} }
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) { if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe { unsafe {
let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0); 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 b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0); let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0));
return a + b + c; return a + b + c;
} }
} }
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) { if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe { unsafe {
let mut a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0); 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 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 c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0));
let d = *self.get_unchecked(3, 0) * *rhs.get_unchecked(3, 0); let d = *self.get_unchecked((3, 0)) * *rhs.get_unchecked((3, 0));
a += c; a += c;
b += d; b += d;
@ -257,14 +287,14 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
acc7 = N::zero(); acc7 = N::zero();
while self.nrows() - i >= 8 { while self.nrows() - i >= 8 {
acc0 += unsafe { *self.get_unchecked(i + 0, j) * *rhs.get_unchecked(i + 0, j) }; 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) }; 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) }; 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) }; 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) }; 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) }; 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) }; 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) }; acc7 += unsafe { *self.get_unchecked((i + 7, j)) * *rhs.get_unchecked((i + 7, j)) };
i += 8; i += 8;
} }
@ -274,7 +304,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
res += acc3 + acc7; res += acc3 + acc7;
for k in i..self.nrows() { for k in i..self.nrows() {
res += unsafe { *self.get_unchecked(k, j) * *rhs.get_unchecked(k, j) } res += unsafe { *self.get_unchecked((k, j)) * *rhs.get_unchecked((k, j)) }
} }
} }
@ -314,7 +344,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
for j in 0..self.nrows() { for j in 0..self.nrows() {
for i in 0..self.ncols() { for i in 0..self.ncols() {
res += unsafe { *self.get_unchecked(j, i) * *rhs.get_unchecked(i, j) } res += unsafe { *self.get_unchecked((j, i)) * *rhs.get_unchecked((i, j)) }
} }
} }
@ -627,7 +657,6 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4}; /// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity(); /// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0, /// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
@ -760,7 +789,6 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4}; /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity(); /// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix3x2::new(1.0, 4.0, /// let mat2 = Matrix3x2::new(1.0, 4.0,
@ -879,7 +907,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{DMatrix, DVector}; /// # use nalgebra::{DMatrix, DVector};
/// // Note that all those would also work with statically-sized matrices. /// // Note that all those would also work with statically-sized matrices.
/// // We use DMatrix/DVector since that's the only case where pre-allocating the /// // We use DMatrix/DVector since that's the only case where pre-allocating the
@ -934,7 +961,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2}; /// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
/// let mut mat = Matrix2::identity(); /// let mut mat = Matrix2::identity();
/// let lhs = Matrix2x3::new(1.0, 2.0, 3.0, /// let lhs = Matrix2x3::new(1.0, 2.0, 3.0,
@ -971,7 +997,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{DMatrix, DVector}; /// # use nalgebra::{DMatrix, DVector};
/// // Note that all those would also work with statically-sized matrices. /// // Note that all those would also work with statically-sized matrices.
/// // We use DMatrix/DVector since that's the only case where pre-allocating the /// // We use DMatrix/DVector since that's the only case where pre-allocating the
@ -1026,7 +1051,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3}; /// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
/// let mut mat = Matrix2::identity(); /// let mut mat = Matrix2::identity();
/// let rhs = Matrix3x2::new(1.0, 2.0, /// let rhs = Matrix3x2::new(1.0, 2.0,

View File

@ -115,13 +115,13 @@ impl<N: Real> Matrix4<N> {
/// 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 {
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap() Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner()
} }
/// 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 {
Perspective3::new(aspect, fovy, znear, zfar).unwrap() Perspective3::new(aspect, fovy, znear, zfar).into_inner()
} }
/// 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
@ -130,8 +130,14 @@ impl<N: Real> Matrix4<N> {
/// 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 face_towards(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
}
/// Deprecated: Use [Matrix4::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self { pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous() Matrix4::face_towards(eye, target, up)
} }
/// Builds a right-handed look-at view matrix. /// Builds a right-handed look-at view matrix.
@ -348,7 +354,7 @@ where DefaultAllocator: Allocator<N, D, D>
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);
let n = normalizer.tr_dot(&pt.coords) let n = normalizer.tr_dot(&pt.coords)
+ unsafe { *self.get_unchecked(D::dim() - 1, D::dim() - 1) }; + unsafe { *self.get_unchecked((D::dim() - 1, D::dim() - 1)) };
if !n.is_zero() { if !n.is_zero() {
return transform * (pt / n) + translation; return transform * (pt / n) + translation;

View File

@ -1,4 +1,4 @@
// Non-conventional componentwise operators. // Non-conventional component-wise operators.
use num::{Signed, Zero}; use num::{Signed, Zero};
use std::ops::{Add, Mul}; use std::ops::{Add, Mul};
@ -61,7 +61,7 @@ macro_rules! component_binop_impl(
for j in 0 .. res.ncols() { for j in 0 .. res.ncols() {
for i in 0 .. res.nrows() { for i in 0 .. res.nrows() {
unsafe { unsafe {
res.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j)); res.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j)));
} }
} }
} }
@ -89,8 +89,8 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j)); let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
*self.get_unchecked_mut(i, j) = res; *self.get_unchecked_mut((i, j)) = res;
} }
} }
} }
@ -99,8 +99,8 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j)); let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
*self.get_unchecked_mut(i, j) = beta * *self.get_unchecked(i, j) + res; *self.get_unchecked_mut((i, j)) = beta * *self.get_unchecked((i, j)) + res;
} }
} }
} }
@ -121,7 +121,7 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
self.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j)); self.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j)));
} }
} }
} }

View File

@ -82,7 +82,7 @@ where DefaultAllocator: Allocator<N, R, C>
for i in 0..nrows.value() { for i in 0..nrows.value() {
for j in 0..ncols.value() { for j in 0..ncols.value() {
unsafe { *res.get_unchecked_mut(i, j) = *iter.next().unwrap() } unsafe { *res.get_unchecked_mut((i, j)) = *iter.next().unwrap() }
} }
} }
@ -105,7 +105,7 @@ where DefaultAllocator: Allocator<N, R, C>
for j in 0..ncols.value() { for j in 0..ncols.value() {
for i in 0..nrows.value() { for i in 0..nrows.value() {
unsafe { *res.get_unchecked_mut(i, j) = f(i, j) } unsafe { *res.get_unchecked_mut((i, j)) = f(i, j) }
} }
} }
@ -132,7 +132,7 @@ where DefaultAllocator: Allocator<N, R, C>
let mut res = Self::zeros_generic(nrows, ncols); let mut res = Self::zeros_generic(nrows, ncols);
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 }
} }
res res
@ -152,7 +152,7 @@ where DefaultAllocator: Allocator<N, R, C>
); );
for (i, elt) in elts.iter().enumerate() { for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut(i, i) = *elt } unsafe { *res.get_unchecked_mut((i, i)) = *elt }
} }
res res
@ -270,7 +270,7 @@ where DefaultAllocator: Allocator<N, R, C>
/// let vec_ptr = vec.as_ptr(); /// let vec_ptr = vec.as_ptr();
/// ///
/// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec); /// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec);
/// let matrix_storage_ptr = matrix.data.as_ptr(); /// let matrix_storage_ptr = matrix.data.as_vec().as_ptr();
/// ///
/// // `matrix` is backed by exactly the same `Vec` as it was constructed from. /// // `matrix` is backed by exactly the same `Vec` as it was constructed from.
/// assert_eq!(matrix_storage_ptr, vec_ptr); /// assert_eq!(matrix_storage_ptr, vec_ptr);
@ -296,7 +296,7 @@ where
/// ///
/// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0)); /// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0));
/// // The two additional arguments represent the matrix dimensions. /// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(3, &[1.0, 2.0, 3.0])); /// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(&[1.0, 2.0, 3.0]));
/// ///
/// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
/// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 && /// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 &&
@ -313,7 +313,7 @@ where
for i in 0..diag.len() { for i in 0..diag.len() {
unsafe { unsafe {
*res.get_unchecked_mut(i, i) = *diag.vget_unchecked(i); *res.get_unchecked_mut((i, i)) = *diag.vget_unchecked(i);
} }
} }
@ -444,63 +444,6 @@ macro_rules! impl_constructors(
Self::from_iterator_generic($($gargs, )* iter) Self::from_iterator_generic($($gargs, )* iter)
} }
/// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_row_slice(3, &[0, 1, 2]);
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* slice)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_column_slice(3, &[0, 1, 2]);
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* slice)
}
/// Creates a matrix or vector filled with the results of a function applied to each of its /// Creates a matrix or vector filled with the results of a function applied to each of its
/// component coordinates. /// component coordinates.
/// ///
@ -612,32 +555,6 @@ macro_rules! impl_constructors(
) -> Self { ) -> Self {
Self::from_distribution_generic($($gargs, )* distribution, rng) Self::from_distribution_generic($($gargs, )* distribution, rng)
} }
/// Creates a matrix backed by a given `Vec`.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Matrix2x3};
///
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
///
///
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
#[cfg(feature = "std")]
pub fn from_vec($($args: usize,)* data: Vec<N>) -> Self {
Self::from_vec_generic($($gargs, )* data)
}
} }
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*> impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
@ -676,6 +593,125 @@ impl_constructors!(Dynamic, Dynamic;
Dynamic::new(nrows), Dynamic::new(ncols); Dynamic::new(nrows), Dynamic::new(ncols);
nrows, ncols); nrows, ncols);
/*
*
* Constructors that don't necessarily require all dimensions
* to be specified whon one dimension is already known.
*
*/
macro_rules! impl_constructors_from_data(
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where DefaultAllocator: Allocator<N $(, $Dims)*> {
/// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_row_slice(&[0, 1, 2]);
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_row_slice($($args: usize,)* $data: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* $data)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_column_slice(&[0, 1, 2]);
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_column_slice($($args: usize,)* $data: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* $data)
}
/// Creates a matrix backed by a given `Vec`.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Matrix2x3};
///
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
///
///
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
#[cfg(feature = "std")]
pub fn from_vec($($args: usize,)* $data: Vec<N>) -> Self {
Self::from_vec_generic($($gargs, )* $data)
}
}
}
);
// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors_from_data!(data; R, C; // Arguments for Matrix<N, ..., S>
=> R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
R::name(), C::name(); // Arguments for `_generic` constructors.
); // Arguments for non-generic constructors.
impl_constructors_from_data!(data; R, Dynamic;
=> R: DimName;
R::name(), Dynamic::new(data.len() / R::dim());
);
impl_constructors_from_data!(data; Dynamic, C;
=> C: DimName;
Dynamic::new(data.len() / C::dim()), C::name();
);
impl_constructors_from_data!(data; Dynamic, Dynamic;
;
Dynamic::new(nrows), Dynamic::new(ncols);
nrows, ncols);
/* /*
* *
* Zero, One, Rand traits. * Zero, One, Rand traits.
@ -791,7 +827,7 @@ macro_rules! componentwise_constructors_impl(
pub fn new($($args: N),*) -> Self { 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; )*
res res
} }

View File

@ -12,13 +12,15 @@ use typenum::Prod;
use base::allocator::{Allocator, SameShapeAllocator}; use base::allocator::{Allocator, SameShapeAllocator};
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{ use base::dimension::{
Dim, DimName, Dynamic, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
}; };
#[cfg(any(feature = "std", feature = "alloc"))]
use base::dimension::Dynamic;
use base::iter::{MatrixIter, MatrixIterMut}; use base::iter::{MatrixIter, MatrixIterMut};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use base::MatrixVec; use base::VecStorage;
use base::{DefaultAllocator, Matrix, MatrixArray, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar}; use base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
// 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> SubsetOf<MatrixMN<N2, R2, C2>> for MatrixMN<N1, R1, C1> impl<N1, N2, R1, C1, R2, C2> SubsetOf<MatrixMN<N2, R2, C2>> for MatrixMN<N1, R1, C1>
@ -42,7 +44,7 @@ where
let mut res = unsafe { MatrixMN::<N2, R2, C2>::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 { *res.get_unchecked_mut(i, j) = N2::from_subset(self.get_unchecked(i, j)) } unsafe { *res.get_unchecked_mut((i, j)) = N2::from_subset(self.get_unchecked((i, j))) }
} }
} }
@ -63,7 +65,7 @@ where
let mut res = Self::new_uninitialized_generic(nrows, ncols); let mut res = Self::new_uninitialized_generic(nrows, ncols);
for i in 0..nrows2 { for i in 0..nrows2 {
for j in 0..ncols2 { for j in 0..ncols2 {
*res.get_unchecked_mut(i, j) = m.get_unchecked(i, j).to_subset_unchecked() *res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked()
} }
} }
@ -336,7 +338,7 @@ impl_from_into_mint_2D!(
); );
impl<'a, N, R, C, RStride, CStride> From<MatrixSlice<'a, N, R, C, RStride, CStride>> impl<'a, N, R, C, RStride, CStride> From<MatrixSlice<'a, N, R, C, RStride, CStride>>
for Matrix<N, R, C, MatrixArray<N, R, C>> for Matrix<N, R, C, ArrayStorage<N, R, C>>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -353,7 +355,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, C, RStride, CStride> From<MatrixSlice<'a, N, Dynamic, C, RStride, CStride>> impl<'a, N, C, RStride, CStride> From<MatrixSlice<'a, N, Dynamic, C, RStride, CStride>>
for Matrix<N, Dynamic, C, MatrixVec<N, Dynamic, C>> for Matrix<N, Dynamic, C, VecStorage<N, Dynamic, C>>
where where
N: Scalar, N: Scalar,
C: Dim, C: Dim,
@ -367,7 +369,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, R, RStride, CStride> From<MatrixSlice<'a, N, R, Dynamic, RStride, CStride>> impl<'a, N, R, RStride, CStride> From<MatrixSlice<'a, N, R, Dynamic, RStride, CStride>>
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>> for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -380,7 +382,7 @@ where
} }
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>> impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
for Matrix<N, R, C, MatrixArray<N, R, C>> for Matrix<N, R, C, ArrayStorage<N, R, C>>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,
@ -397,7 +399,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, C, RStride, CStride> From<MatrixSliceMut<'a, N, Dynamic, C, RStride, CStride>> impl<'a, N, C, RStride, CStride> From<MatrixSliceMut<'a, N, Dynamic, C, RStride, CStride>>
for Matrix<N, Dynamic, C, MatrixVec<N, Dynamic, C>> for Matrix<N, Dynamic, C, VecStorage<N, Dynamic, C>>
where where
N: Scalar, N: Scalar,
C: Dim, C: Dim,
@ -411,7 +413,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>> impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>>
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>> for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,

View File

@ -18,9 +18,9 @@ use base::allocator::{Allocator, Reallocator};
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(any(feature = "alloc", feature = "std"))]
use base::dimension::Dynamic; use base::dimension::Dynamic;
use base::dimension::{Dim, DimName}; use base::dimension::{Dim, DimName};
use base::matrix_array::MatrixArray; use base::array_storage::ArrayStorage;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use base::matrix_vec::MatrixVec; use base::vec_storage::VecStorage;
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
use base::Scalar; use base::Scalar;
@ -29,7 +29,7 @@ use base::Scalar;
* Allocator. * Allocator.
* *
*/ */
/// An allocator based on `GenericArray` and `MatrixVec` for statically-sized and dynamically-sized /// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
/// matrices respectively. /// matrices respectively.
pub struct DefaultAllocator; pub struct DefaultAllocator;
@ -42,7 +42,7 @@ where
R::Value: Mul<C::Value>, R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>, Prod<R::Value, C::Value>: ArrayLength<N>,
{ {
type Buffer = MatrixArray<N, R, C>; type Buffer = ArrayStorage<N, R, C>;
#[inline] #[inline]
unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer { unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
@ -77,7 +77,7 @@ where
// Dynamic - Dynamic // Dynamic - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator { impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
type Buffer = MatrixVec<N, Dynamic, C>; type Buffer = VecStorage<N, Dynamic, C>;
#[inline] #[inline]
unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer { unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer {
@ -86,7 +86,7 @@ impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
res.reserve_exact(length); res.reserve_exact(length);
res.set_len(length); res.set_len(length);
MatrixVec::new(nrows, ncols, res) VecStorage::new(nrows, ncols, res)
} }
#[inline] #[inline]
@ -101,14 +101,14 @@ impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
assert!(res.len() == nrows.value() * ncols.value(), assert!(res.len() == nrows.value() * ncols.value(),
"Allocation from iterator error: the iterator did not yield the correct number of elements."); "Allocation from iterator error: the iterator did not yield the correct number of elements.");
MatrixVec::new(nrows, ncols, res) VecStorage::new(nrows, ncols, res)
} }
} }
// Static - Dynamic // Static - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator { impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
type Buffer = MatrixVec<N, R, Dynamic>; type Buffer = VecStorage<N, R, Dynamic>;
#[inline] #[inline]
unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer { unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer {
@ -117,7 +117,7 @@ impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
res.reserve_exact(length); res.reserve_exact(length);
res.set_len(length); res.set_len(length);
MatrixVec::new(nrows, ncols, res) VecStorage::new(nrows, ncols, res)
} }
#[inline] #[inline]
@ -132,7 +132,7 @@ impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
assert!(res.len() == nrows.value() * ncols.value(), assert!(res.len() == nrows.value() * ncols.value(),
"Allocation from iterator error: the iterator did not yield the correct number of elements."); "Allocation from iterator error: the iterator did not yield the correct number of elements.");
MatrixVec::new(nrows, ncols, res) VecStorage::new(nrows, ncols, res)
} }
} }
@ -157,7 +157,7 @@ where
rto: RTo, rto: RTo,
cto: CTo, cto: CTo,
buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer, buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer,
) -> MatrixArray<N, RTo, CTo> ) -> ArrayStorage<N, RTo, CTo>
{ {
let mut res = <Self as Allocator<N, RTo, CTo>>::allocate_uninitialized(rto, cto); let mut res = <Self as Allocator<N, RTo, CTo>>::allocate_uninitialized(rto, cto);
@ -185,8 +185,8 @@ where
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: Dynamic, rto: Dynamic,
cto: CTo, cto: CTo,
buf: MatrixArray<N, RFrom, CFrom>, buf: ArrayStorage<N, RFrom, CFrom>,
) -> MatrixVec<N, Dynamic, CTo> ) -> VecStorage<N, Dynamic, CTo>
{ {
let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto); let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto);
@ -214,8 +214,8 @@ where
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: RTo, rto: RTo,
cto: Dynamic, cto: Dynamic,
buf: MatrixArray<N, RFrom, CFrom>, buf: ArrayStorage<N, RFrom, CFrom>,
) -> MatrixVec<N, RTo, Dynamic> ) -> VecStorage<N, RTo, Dynamic>
{ {
let mut res = <Self as Allocator<N, RTo, Dynamic>>::allocate_uninitialized(rto, cto); let mut res = <Self as Allocator<N, RTo, Dynamic>>::allocate_uninitialized(rto, cto);
@ -238,11 +238,11 @@ impl<N: Scalar, CFrom: Dim, CTo: Dim> Reallocator<N, Dynamic, CFrom, Dynamic, CT
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: Dynamic, rto: Dynamic,
cto: CTo, cto: CTo,
buf: MatrixVec<N, Dynamic, CFrom>, buf: VecStorage<N, Dynamic, CFrom>,
) -> MatrixVec<N, Dynamic, CTo> ) -> VecStorage<N, Dynamic, CTo>
{ {
let new_buf = buf.resize(rto.value() * cto.value()); let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf) VecStorage::new(rto, cto, new_buf)
} }
} }
@ -254,11 +254,11 @@ impl<N: Scalar, CFrom: Dim, RTo: DimName> Reallocator<N, Dynamic, CFrom, RTo, Dy
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: RTo, rto: RTo,
cto: Dynamic, cto: Dynamic,
buf: MatrixVec<N, Dynamic, CFrom>, buf: VecStorage<N, Dynamic, CFrom>,
) -> MatrixVec<N, RTo, Dynamic> ) -> VecStorage<N, RTo, Dynamic>
{ {
let new_buf = buf.resize(rto.value() * cto.value()); let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf) VecStorage::new(rto, cto, new_buf)
} }
} }
@ -270,11 +270,11 @@ impl<N: Scalar, RFrom: DimName, CTo: Dim> Reallocator<N, RFrom, Dynamic, Dynamic
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: Dynamic, rto: Dynamic,
cto: CTo, cto: CTo,
buf: MatrixVec<N, RFrom, Dynamic>, buf: VecStorage<N, RFrom, Dynamic>,
) -> MatrixVec<N, Dynamic, CTo> ) -> VecStorage<N, Dynamic, CTo>
{ {
let new_buf = buf.resize(rto.value() * cto.value()); let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf) VecStorage::new(rto, cto, new_buf)
} }
} }
@ -286,10 +286,10 @@ impl<N: Scalar, RFrom: DimName, RTo: DimName> Reallocator<N, RFrom, Dynamic, RTo
unsafe fn reallocate_copy( unsafe fn reallocate_copy(
rto: RTo, rto: RTo,
cto: Dynamic, cto: Dynamic,
buf: MatrixVec<N, RFrom, Dynamic>, buf: VecStorage<N, RFrom, Dynamic>,
) -> MatrixVec<N, RTo, Dynamic> ) -> VecStorage<N, RTo, Dynamic>
{ {
let new_buf = buf.resize(rto.value() * cto.value()); let new_buf = buf.resize(rto.value() * cto.value());
MatrixVec::new(rto, cto, new_buf) VecStorage::new(rto, cto, new_buf)
} }
} }

View File

@ -181,7 +181,7 @@ dim_ops!(
DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod; DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod;
DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff; DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff;
DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot; DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot;
DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameNimimum, Minimum; DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum;
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum; DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
); );
@ -364,7 +364,8 @@ impl<
G: Bit + Any + Debug + Copy + PartialEq + Send + Sync, G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
> IsNotStaticOne > IsNotStaticOne
for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G> for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{} {
}
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim
for UInt<U, B> for UInt<U, B>
@ -405,4 +406,5 @@ impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Syn
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne
for UInt<U, B> for UInt<U, B>
{} {
}

View File

@ -1,12 +1,18 @@
use num::{One, Zero}; use num::{One, Zero};
use std::cmp; use std::cmp;
use std::ptr; use std::ptr;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::iter::ExactSizeIterator;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::mem;
use base::allocator::{Allocator, Reallocator}; use base::allocator::{Allocator, Reallocator};
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{ use base::dimension::{
Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, Dynamic, U1, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1,
}; };
#[cfg(any(feature = "std", feature = "alloc"))]
use base::dimension::Dynamic;
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use base::DMatrix; use base::DMatrix;
@ -23,7 +29,7 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res res
} }
/// Extracts the upper triangular part of this matrix (including the diagonal). /// Extracts the lower triangular part of this matrix (including the diagonal).
#[inline] #[inline]
pub fn lower_triangle(&self) -> MatrixMN<N, R, C> pub fn lower_triangle(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> { where DefaultAllocator: Allocator<N, R, C> {
@ -32,6 +38,54 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res res
} }
/// Creates a new matrix by extracting the given set of rows from `self`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn select_rows<'a, I>(&self, irows: I) -> MatrixMN<N, Dynamic, C>
where I: IntoIterator<Item = &'a usize>,
I::IntoIter: ExactSizeIterator + Clone,
DefaultAllocator: Allocator<N, Dynamic, C> {
let irows = irows.into_iter();
let ncols = self.data.shape().1;
let mut res = unsafe { MatrixMN::new_uninitialized_generic(Dynamic::new(irows.len()), ncols) };
// First, check that all the indices from irows are valid.
// This will allow us to use unchecked access in the inner loop.
for i in irows.clone() {
assert!(*i < self.nrows(), "Row index out of bounds.")
}
for j in 0..ncols.value() {
// FIXME: use unchecked column indexing
let mut res = res.column_mut(j);
let mut src = self.column(j);
for (destination, source) in irows.clone().enumerate() {
unsafe {
*res.vget_unchecked_mut(destination) = *src.vget_unchecked(*source)
}
}
}
res
}
/// Creates a new matrix by extracting the given set of columns from `self`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn select_columns<'a, I>(&self, icols: I) -> MatrixMN<N, R, Dynamic>
where I: IntoIterator<Item = &'a usize>,
I::IntoIter: ExactSizeIterator,
DefaultAllocator: Allocator<N, R, Dynamic> {
let icols = icols.into_iter();
let nrows = self.data.shape().0;
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, Dynamic::new(icols.len())) };
for (destination, source) in icols.enumerate() {
res.column_mut(destination).copy_from(&self.column(*source))
}
res
}
} }
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
@ -58,7 +112,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
let n = cmp::min(nrows, ncols); let n = cmp::min(nrows, ncols);
for i in 0..n { for i in 0..n {
unsafe { *self.get_unchecked_mut(i, i) = val } unsafe { *self.get_unchecked_mut((i, i)) = val }
} }
} }
@ -67,7 +121,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
pub fn fill_row(&mut self, i: usize, val: N) { pub fn fill_row(&mut self, i: usize, val: N) {
assert!(i < self.nrows(), "Row index out of bounds."); assert!(i < self.nrows(), "Row index out of bounds.");
for j in 0..self.ncols() { for j in 0..self.ncols() {
unsafe { *self.get_unchecked_mut(i, j) = val } unsafe { *self.get_unchecked_mut((i, j)) = val }
} }
} }
@ -76,7 +130,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
pub fn fill_column(&mut self, j: usize, val: N) { pub fn fill_column(&mut self, j: usize, val: N) {
assert!(j < self.ncols(), "Row index out of bounds."); assert!(j < self.ncols(), "Row index out of bounds.");
for i in 0..self.nrows() { for i in 0..self.nrows() {
unsafe { *self.get_unchecked_mut(i, j) = val } unsafe { *self.get_unchecked_mut((i, j)) = val }
} }
} }
@ -93,7 +147,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions."); assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
for i in 0..min_nrows_ncols { for i in 0..min_nrows_ncols {
unsafe { *self.get_unchecked_mut(i, i) = *diag.vget_unchecked(i) } unsafe { *self.get_unchecked_mut((i, i)) = *diag.vget_unchecked(i) }
} }
} }
@ -128,7 +182,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
pub fn fill_lower_triangle(&mut self, val: N, shift: usize) { pub fn fill_lower_triangle(&mut self, val: N, shift: usize) {
for j in 0..self.ncols() { for j in 0..self.ncols() {
for i in (j + shift)..self.nrows() { for i in (j + shift)..self.nrows() {
unsafe { *self.get_unchecked_mut(i, j) = val } unsafe { *self.get_unchecked_mut((i, j)) = val }
} }
} }
} }
@ -146,7 +200,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
// FIXME: is there a more efficient way to avoid the min ? // FIXME: is there a more efficient way to avoid the min ?
// (necessary for rectangular matrices) // (necessary for rectangular matrices)
for i in 0..cmp::min(j + 1 - shift, self.nrows()) { for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
unsafe { *self.get_unchecked_mut(i, j) = val } unsafe { *self.get_unchecked_mut((i, j)) = val }
} }
} }
} }
@ -191,7 +245,7 @@ impl<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
for j in 0..dim { for j in 0..dim {
for i in j + 1..dim { for i in j + 1..dim {
unsafe { unsafe {
*self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i); *self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i));
} }
} }
} }
@ -206,7 +260,7 @@ impl<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
for j in 1..self.ncols() { for j in 1..self.ncols() {
for i in 0..j { for i in 0..j {
unsafe { unsafe {
*self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i); *self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i));
} }
} }
} }
@ -248,6 +302,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included). /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included).
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic> pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic>
where where
C: DimSub<Dynamic, Output = Dynamic>, C: DimSub<Dynamic, Output = Dynamic>,
@ -330,6 +385,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included). /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included).
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C> pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C>
where where
R: DimSub<Dynamic, Output = Dynamic>, R: DimSub<Dynamic, Output = Dynamic>,
@ -407,6 +463,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Inserts `n` columns filled with `val` starting at the `i-th` position. /// Inserts `n` columns filled with `val` starting at the `i-th` position.
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic> pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic>
where where
C: DimAdd<Dynamic, Output = Dynamic>, C: DimAdd<Dynamic, Output = Dynamic>,
@ -484,6 +541,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Inserts `n` rows filled with `val` starting at the `i-th` position. /// Inserts `n` rows filled with `val` starting at the `i-th` position.
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C> pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C>
where where
R: DimAdd<Dynamic, Output = Dynamic>, R: DimAdd<Dynamic, Output = Dynamic>,
@ -549,6 +607,29 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val)
} }
/// Resizes this matrix vertically, i.e., so that it contains `new_nrows` rows while keeping the same number of columns.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// rows than `self`, then the extra rows are filled with `val`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_vertically(self, new_nrows: usize, val: N) -> MatrixMN<N, Dynamic, C>
where DefaultAllocator: Reallocator<N, R, C, Dynamic, C> {
let ncols = self.data.shape().1;
self.resize_generic(Dynamic::new(new_nrows), ncols, val)
}
/// Resizes this matrix horizontally, i.e., so that it contains `new_ncolumns` columns while keeping the same number of columns.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// columns than `self`, then the extra columns are filled with `val`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_horizontally(self, new_ncols: usize, val: N) -> MatrixMN<N, R, Dynamic>
where DefaultAllocator: Reallocator<N, R, C, R, Dynamic> {
let nrows = self.data.shape().0;
self.resize_generic(nrows, Dynamic::new(new_ncols), val)
}
/// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns.
/// ///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
@ -626,6 +707,61 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar> DMatrix<N> {
/// Resizes this matrix in-place.
///
/// 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`.
///
/// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`.
pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: N)
where DefaultAllocator: Reallocator<N, Dynamic, Dynamic, Dynamic, Dynamic> {
let placeholder = unsafe { Self::new_uninitialized(0, 0) };
let old = mem::replace(self, placeholder);
let new = old.resize(new_nrows, new_ncols, val);
let _ = mem::replace(self, new);
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, C: Dim> MatrixMN<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C> {
/// Changes the number of rows of this matrix in-place.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// rows than `self`, then the extra rows are filled with `val`.
///
/// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`).
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: N)
where DefaultAllocator: Reallocator<N, Dynamic, C, Dynamic, C> {
let placeholder = unsafe { Self::new_uninitialized_generic(Dynamic::new(0), self.data.shape().1) };
let old = mem::replace(self, placeholder);
let new = old.resize_vertically(new_nrows, val);
let _ = mem::replace(self, new);
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, R: Dim> MatrixMN<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic> {
/// Changes the number of column of this matrix in-place.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// columns than `self`, then the extra columns are filled with `val`.
///
/// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`).
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: N)
where DefaultAllocator: Reallocator<N, R, Dynamic, R, Dynamic> {
let placeholder = unsafe { Self::new_uninitialized_generic(self.data.shape().0, Dynamic::new(0)) };
let old = mem::replace(self, placeholder);
let new = old.resize_horizontally(new_ncols, val);
let _ = mem::replace(self, new);
}
}
unsafe fn compress_rows<N: Scalar>( unsafe fn compress_rows<N: Scalar>(
data: &mut [N], data: &mut [N],
nrows: usize, nrows: usize,
@ -706,6 +842,7 @@ unsafe fn extend_rows<N: Scalar>(
/// Extend the number of columns of the `Matrix` with elements from /// Extend the number of columns of the `Matrix` with elements from
/// a given iterator. /// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S> impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S>
where where
N: Scalar, N: Scalar,
@ -753,6 +890,7 @@ where
/// Extend the number of rows of the `Vector` with elements from /// Extend the number of rows of the `Vector` with elements from
/// a given iterator. /// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S> impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S>
where where
N: Scalar, N: Scalar,
@ -764,15 +902,16 @@ where
/// # Example /// # Example
/// ``` /// ```
/// # use nalgebra::DVector; /// # use nalgebra::DVector;
/// let mut vector = DVector::from_vec(3, vec![0, 1, 2]); /// let mut vector = DVector::from_vec(vec![0, 1, 2]);
/// vector.extend(vec![3, 4, 5]); /// vector.extend(vec![3, 4, 5]);
/// assert!(vector.eq(&DVector::from_vec(6, vec![0, 1, 2, 3, 4, 5]))); /// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5])));
/// ``` /// ```
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) { fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) {
self.data.extend(iter); self.data.extend(iter);
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S> impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S>
where where
N: Scalar, N: Scalar,

714
src/base/indexing.rs Normal file
View File

@ -0,0 +1,714 @@
//! Indexing
use base::{Dim, DimName, DimDiff, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1};
use base::storage::{Storage, StorageMut};
use std::ops;
// N.B.: Not a public trait!
trait DimRange<D: Dim>
{
/// The number of elements indexed by this range.
type Length: Dim;
/// The lower bound of the range, inclusive.
fn lower(&self, dimension: D) -> usize;
/// The number of elements included in the range.
fn length(&self, dimension: D) -> Self::Length;
/// Produces true if `Self` is contained within `dimension`.
fn contained_by(&self, dimension: D) -> bool;
}
impl<D: Dim> DimRange<D> for usize {
type Length = U1;
#[inline(always)]
fn lower(&self, _: D) -> usize {
*self
}
#[inline(always)]
fn length(&self, _: D) -> Self::Length {
U1
}
#[inline(always)]
fn contained_by(&self, dimension: D) -> bool {
*self < dimension.value()
}
}
#[test]
fn dimrange_usize() {
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&0, U0), false);
assert_eq!(DimRange::contained_by(&0, U1), true);
}
impl<D: Dim> DimRange<D> for ops::Range<usize> {
type Length = Dynamic;
#[inline(always)]
fn lower(&self, _: D) -> usize {
self.start
}
#[inline(always)]
fn length(&self, _: D) -> Self::Length {
Dynamic::new(self.end.saturating_sub(self.start))
}
#[inline(always)]
fn contained_by(&self, dimension: D) -> bool {
(self.start < dimension.value()) && (self.end <= dimension.value())
}
}
#[test]
fn dimrange_range_usize() {
use std::usize::MAX;
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&(0..0), U0), false);
assert_eq!(DimRange::contained_by(&(0..1), U0), false);
assert_eq!(DimRange::contained_by(&(0..1), U1), true);
assert_eq!(DimRange::contained_by(&((MAX - 1)..MAX), Dynamic::new(MAX)), true);
assert_eq!(DimRange::length(&((MAX - 1)..MAX), Dynamic::new(MAX)), Dynamic::new(1));
assert_eq!(DimRange::length(&(MAX..(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(0));
assert_eq!(DimRange::length(&(MAX..MAX), Dynamic::new(MAX)), Dynamic::new(0));
}
impl<D: Dim> DimRange<D> for ops::RangeFrom<usize> {
type Length = Dynamic;
#[inline(always)]
fn lower(&self, _: D) -> usize {
self.start
}
#[inline(always)]
fn length(&self, dimension: D) -> Self::Length {
(self.start..dimension.value()).length(dimension)
}
#[inline(always)]
fn contained_by(&self, dimension: D) -> bool {
self.start < dimension.value()
}
}
#[test]
fn dimrange_rangefrom_usize() {
use std::usize::MAX;
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&(0..), U0), false);
assert_eq!(DimRange::contained_by(&(0..), U0), false);
assert_eq!(DimRange::contained_by(&(0..), U1), true);
assert_eq!(DimRange::contained_by(&((MAX - 1)..), Dynamic::new(MAX)), true);
assert_eq!(DimRange::length(&((MAX - 1)..), Dynamic::new(MAX)), Dynamic::new(1));
assert_eq!(DimRange::length(&(MAX..), Dynamic::new(MAX)), Dynamic::new(0));
}
impl<D: Dim, T: Dim> DimRange<D> for ops::RangeFrom<T>
where D: DimSub<T>
{
type Length = DimDiff<D, T>;
#[inline(always)]
fn lower(&self, _: D) -> usize {
self.start.value()
}
#[inline(always)]
fn length(&self, dimension: D) -> Self::Length {
dimension.sub(self.start)
}
#[inline(always)]
fn contained_by(&self, _: D) -> bool {
true
}
}
#[test]
fn dimrange_rangefrom_dimname() {
use base::dimension::{U5, U4};
assert_eq!(DimRange::length(&(U1..), U5), U4);
}
impl<D: Dim> DimRange<D> for ops::RangeFull {
type Length = D;
#[inline(always)]
fn lower(&self, _: D) -> usize {
0
}
#[inline(always)]
fn length(&self, dimension: D) -> Self::Length {
dimension
}
#[inline(always)]
fn contained_by(&self, _: D) -> bool {
true
}
}
#[test]
fn dimrange_rangefull() {
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&(..), U0), true);
assert_eq!(DimRange::length(&(..), U1), U1);
}
impl<D: Dim> DimRange<D> for ops::RangeInclusive<usize> {
type Length = Dynamic;
#[inline(always)]
fn lower(&self, _: D) -> usize {
*self.start()
}
#[inline(always)]
fn length(&self, _: D) -> Self::Length {
Dynamic::new(
if self.end() < self.start() {
0
} else {
self.end().wrapping_sub(self.start().wrapping_sub(1))
})
}
#[inline(always)]
fn contained_by(&self, dimension: D) -> bool {
(*self.start() < dimension.value()) && (*self.end() < dimension.value())
}
}
#[test]
fn dimrange_rangeinclusive_usize() {
use std::usize::MAX;
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&(0..=0), U0), false);
assert_eq!(DimRange::contained_by(&(0..=0), U1), true);
assert_eq!(DimRange::contained_by(&(MAX..=MAX), Dynamic::new(MAX)), false);
assert_eq!(DimRange::contained_by(&((MAX-1)..=MAX), Dynamic::new(MAX)), false);
assert_eq!(DimRange::contained_by(&((MAX-1)..=(MAX-1)), Dynamic::new(MAX)), true);
assert_eq!(DimRange::length(&(0..=0), U1), Dynamic::new(1));
assert_eq!(DimRange::length(&((MAX - 1)..=MAX), Dynamic::new(MAX)), Dynamic::new(2));
assert_eq!(DimRange::length(&(MAX..=(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(0));
assert_eq!(DimRange::length(&(MAX..=MAX), Dynamic::new(MAX)), Dynamic::new(1));
}
impl<D: Dim> DimRange<D> for ops::RangeTo<usize>
{
type Length = Dynamic;
#[inline(always)]
fn lower(&self, _: D) -> usize {
0
}
#[inline(always)]
fn length(&self, _: D) -> Self::Length {
Dynamic::new(self.end)
}
#[inline(always)]
fn contained_by(&self, dimension: D) -> bool {
self.end <= dimension.value()
}
}
#[test]
fn dimrange_rangeto_usize() {
use std::usize::MAX;
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&(..0), U0), true);
assert_eq!(DimRange::contained_by(&(..1), U0), false);
assert_eq!(DimRange::contained_by(&(..0), U1), true);
assert_eq!(DimRange::contained_by(&(..(MAX - 1)), Dynamic::new(MAX)), true);
assert_eq!(DimRange::length(&(..(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(MAX - 1));
assert_eq!(DimRange::length(&(..MAX), Dynamic::new(MAX)), Dynamic::new(MAX));
}
impl<D: Dim> DimRange<D> for ops::RangeToInclusive<usize>
{
type Length = Dynamic;
#[inline(always)]
fn lower(&self, _: D) -> usize {
0
}
#[inline(always)]
fn length(&self, _: D) -> Self::Length {
Dynamic::new(self.end + 1)
}
#[inline(always)]
fn contained_by(&self, dimension: D) -> bool {
self.end < dimension.value()
}
}
#[test]
fn dimrange_rangetoinclusive_usize() {
use std::usize::MAX;
use base::dimension::U0;
assert_eq!(DimRange::contained_by(&(..=0), U0), false);
assert_eq!(DimRange::contained_by(&(..=1), U0), false);
assert_eq!(DimRange::contained_by(&(..=0), U1), true);
assert_eq!(DimRange::contained_by(&(..=(MAX)), Dynamic::new(MAX)), false);
assert_eq!(DimRange::contained_by(&(..=(MAX - 1)), Dynamic::new(MAX)), true);
assert_eq!(DimRange::length(&(..=(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(MAX));
}
/// A helper trait used for indexing operations.
pub trait MatrixIndex<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>>: Sized {
/// The output type returned by methods.
type Output : 'a;
/// Produces true if the given matrix is contained by this index.
#[doc(hidden)]
fn contained_by(&self, matrix: &Matrix<N, R, C, S>) -> bool;
/// Produces a shared view of the data at this location if in bounds,
/// or `None`, otherwise.
#[doc(hidden)]
#[inline(always)]
fn get(self, matrix: &'a Matrix<N, R, C, S>) -> Option<Self::Output> {
if self.contained_by(matrix) {
Some(unsafe{self.get_unchecked(matrix)})
} else {
None
}
}
/// Produces a shared view of the data at this location if in bounds
/// without any bounds checking.
#[doc(hidden)]
unsafe fn get_unchecked(self, matrix: &'a Matrix<N, R, C, S>) -> Self::Output;
/// Produces a shared view to the data at this location, or panics
/// if out of bounds.
#[doc(hidden)]
#[inline(always)]
fn index(self, matrix: &'a Matrix<N, R, C, S>) -> Self::Output {
self.get(matrix).expect("Index out of bounds.")
}
}
/// A helper trait used for indexing operations.
pub trait MatrixIndexMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>>: MatrixIndex<'a, N, R, C, S> {
/// The output type returned by methods.
type OutputMut : 'a;
/// Produces a mutable view of the data at this location, without
/// performing any bounds checking.
#[doc(hidden)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<N, R, C, S>) -> Self::OutputMut;
/// Produces a mutable view of the data at this location, if in
/// bounds.
#[doc(hidden)]
#[inline(always)]
fn get_mut(self, matrix: &'a mut Matrix<N, R, C, S>) -> Option<Self::OutputMut> {
if self.contained_by(matrix) {
Some(unsafe{self.get_unchecked_mut(matrix)})
} else {
None
}
}
/// Produces a mutable view of the data at this location, or panics
/// if out of bounds.
#[doc(hidden)]
#[inline(always)]
fn index_mut(self, matrix: &'a mut Matrix<N, R, C, S>) -> Self::OutputMut {
self.get_mut(matrix).expect("Index out of bounds.")
}
}
/// # Indexing Operations
/// ## Indices to Individual Elements
/// ### Two-Dimensional Indices
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix2::new(0, 2,
/// 1, 3);
///
/// assert_eq!(matrix.index((0, 0)), &0);
/// assert_eq!(matrix.index((1, 0)), &1);
/// assert_eq!(matrix.index((0, 1)), &2);
/// assert_eq!(matrix.index((1, 1)), &3);
/// ```
///
/// ### Linear Address Indexing
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix2::new(0, 2,
/// 1, 3);
///
/// assert_eq!(matrix.get(0), Some(&0));
/// assert_eq!(matrix.get(1), Some(&1));
/// assert_eq!(matrix.get(2), Some(&2));
/// assert_eq!(matrix.get(3), Some(&3));
/// ```
///
/// ## Indices to Individual Rows and Columns
/// ### Index to a Row
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix2::new(0, 2,
/// 1, 3);
///
/// assert!(matrix.index((0, ..))
/// .eq(&Matrix1x2::new(0, 2)));
/// ```
///
/// ### Index to a Column
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix2::new(0, 2,
/// 1, 3);
///
/// assert!(matrix.index((.., 0))
/// .eq(&Matrix2x1::new(0,
/// 1)));
/// ```
///
/// ## Indices to Parts of Individual Rows and Columns
/// ### Index to a Partial Row
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix3::new(0, 3, 6,
/// 1, 4, 7,
/// 2, 5, 8);
///
/// assert!(matrix.index((0, ..2))
/// .eq(&Matrix1x2::new(0, 3)));
/// ```
///
/// ### Index to a Partial Column
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix3::new(0, 3, 6,
/// 1, 4, 7,
/// 2, 5, 8);
///
/// assert!(matrix.index((..2, 0))
/// .eq(&Matrix2x1::new(0,
/// 1)));
///
/// assert!(matrix.index((U1.., 0))
/// .eq(&Matrix2x1::new(1,
/// 2)));
/// ```
/// ## Indices to Ranges of Rows and Columns
/// ### Index to a Range of Rows
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix3::new(0, 3, 6,
/// 1, 4, 7,
/// 2, 5, 8);
///
/// assert!(matrix.index((1..3, ..))
/// .eq(&Matrix2x3::new(1, 4, 7,
/// 2, 5, 8)));
/// ```
/// ### Index to a Range of Columns
/// ```
/// # use nalgebra::*;
/// let matrix = Matrix3::new(0, 3, 6,
/// 1, 4, 7,
/// 2, 5, 8);
///
/// assert!(matrix.index((.., 1..3))
/// .eq(&Matrix3x2::new(3, 6,
/// 4, 7,
/// 5, 8)));
/// ```
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
{
/// Produces a view of the data at the given index, or
/// `None` if the index is out of bounds.
#[inline]
pub fn get<'a, I>(&'a self, index: I) -> Option<I::Output>
where
I: MatrixIndex<'a, N, R, C, S>
{
index.get(self)
}
/// Produces a mutable view of the data at the given index, or
/// `None` if the index is out of bounds.
#[inline]
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
where
S: StorageMut<N, R, C>,
I: MatrixIndexMut<'a, N, R, C, S>
{
index.get_mut(self)
}
/// Produces a view of the data at the given index, or
/// panics if the index is out of bounds.
#[inline]
pub fn index<'a, I>(&'a self, index: I) -> I::Output
where
I: MatrixIndex<'a, N, R, C, S>
{
index.index(self)
}
/// Produces a mutable view of the data at the given index, or
/// panics if the index is out of bounds.
#[inline]
pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where
S: StorageMut<N, R, C>,
I: MatrixIndexMut<'a, N, R, C, S>
{
index.index_mut(self)
}
/// Produces a view of the data at the given index, without doing
/// any bounds checking.
#[inline]
pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::Output
where
I: MatrixIndex<'a, N, R, C, S>
{
index.get_unchecked(self)
}
/// Returns a mutable view of the data at the given index, without doing
/// any bounds checking.
#[inline]
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where
S: StorageMut<N, R, C>,
I: MatrixIndexMut<'a, N, R, C, S>
{
index.get_unchecked_mut(self)
}
}
// EXTRACT A SINGLE ELEMENT BY 1D LINEAR ADDRESS
impl<'a, N, R, C, S> MatrixIndex<'a, N, R, C, S> for usize
where
N: Scalar,
R: Dim,
C: Dim,
S: Storage<N, R, C>
{
type Output = &'a N;
#[doc(hidden)]
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<N, R, C, S>) -> bool {
*self < matrix.len()
}
#[doc(hidden)]
#[inline(always)]
unsafe fn get_unchecked(self, matrix: &'a Matrix<N, R, C, S>) -> Self::Output {
matrix.data.get_unchecked_linear(self)
}
}
impl<'a, N, R, C, S> MatrixIndexMut<'a, N, R, C, S> for usize
where
N: Scalar,
R: Dim,
C: Dim,
S: StorageMut<N, R, C>
{
type OutputMut = &'a mut N;
#[doc(hidden)]
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<N, R, C, S>) -> Self::OutputMut
where S: StorageMut<N, R, C>,
{
matrix.data.get_unchecked_linear_mut(self)
}
}
// EXTRACT A SINGLE ELEMENT BY 2D COORDINATES
impl<'a, N, R, C, S> MatrixIndex<'a, N, R, C, S> for (usize, usize)
where
N: Scalar,
R: Dim,
C: Dim,
S: Storage<N, R, C>
{
type Output = &'a N;
#[doc(hidden)]
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<N, R, C, S>) -> bool {
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
}
#[doc(hidden)]
#[inline(always)]
unsafe fn get_unchecked(self, matrix: &'a Matrix<N, R, C, S>) -> Self::Output {
let (row, col) = self;
matrix.data.get_unchecked(row, col)
}
}
impl<'a, N, R, C, S> MatrixIndexMut<'a, N, R, C, S> for (usize, usize)
where
N: Scalar,
R: Dim,
C: Dim,
S: StorageMut<N, R, C>
{
type OutputMut = &'a mut N;
#[doc(hidden)]
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<N, R, C, S>) -> Self::OutputMut
where S: StorageMut<N, R, C>,
{
let (row, col) = self;
matrix.data.get_unchecked_mut(row, col)
}
}
macro_rules! impl_index_pair {
(
$R: ident,
$C: ident,
[<$($RTyP: ident : $RTyPB: ty,)*> usize => $ROut: ty
$(where $RConstraintType: ty: $RConstraintBound: ident<$($RConstraintBoundParams: ty $( = $REqBound: ty )*),*>)*],
[<$($CTyP: ident : $CTyPB: ty,)*> usize => $COut: ty
$(where $CConstraintType: ty: $CConstraintBound: ident<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)*]
) => {};
(
$R: ident,
$C: ident,
[<$($RTyP: ident: $RTyPB: tt),*> $RIdx: ty => $ROut: ty
$(where $RConstraintType: ty: $RConstraintBound: ident $(<$($RConstraintBoundParams: ty $( = $REqBound: ty )*),*>)* )*],
[<$($CTyP: ident: $CTyPB: tt),*> $CIdx: ty => $COut: ty
$(where $CConstraintType: ty: $CConstraintBound: ident $(<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)* )*]
) =>
{
impl<'a, N, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndex<'a, N, $R, $C, S> for ($RIdx, $CIdx)
where
N: Scalar,
$R: Dim,
$C: Dim,
S: Storage<N, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{
type Output = MatrixSlice<'a, N, $ROut, $COut, S::RStride, S::CStride>;
#[doc(hidden)]
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<N, $R, $C, S>) -> bool {
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
}
#[doc(hidden)]
#[inline(always)]
unsafe fn get_unchecked(self, matrix: &'a Matrix<N, $R, $C, S>) -> Self::Output {
use base::SliceStorage;
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let data =
SliceStorage::new_unchecked(&matrix.data,
(rows.lower(nrows), cols.lower(ncols)),
(rows.length(nrows), cols.length(ncols)));
Matrix::from_data_statically_unchecked(data)
}
}
impl<'a, N, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndexMut<'a, N, $R, $C, S> for ($RIdx, $CIdx)
where
N: Scalar,
$R: Dim,
$C: Dim,
S: StorageMut<N, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{
type OutputMut = MatrixSliceMut<'a, N, $ROut, $COut, S::RStride, S::CStride>;
#[doc(hidden)]
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<N, $R, $C, S>) -> Self::OutputMut {
use base::SliceStorageMut;
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let data =
SliceStorageMut::new_unchecked(&mut matrix.data,
(rows.lower(nrows), cols.lower(ncols)),
(rows.length(nrows), cols.length(ncols)));
Matrix::from_data_statically_unchecked(data)
}
}
}
}
macro_rules! impl_index_pairs {
(index $R: ident with {} index $C: ident with {$($r: tt,)* }) => {};
(index $R: ident with {$lh : tt, $($lt : tt,)*}
index $C: ident with { $($r: tt,)* }) =>
{
$(
impl_index_pair!{$R, $C, $lh, $r}
)*
impl_index_pairs!{index $R with {$($lt,)*} index $C with {$($r,)*}}
}
}
impl_index_pairs!{
index R with {
[<> usize => U1],
[<> ops::Range<usize> => Dynamic],
[<> ops::RangeFrom<usize> => Dynamic],
[<> ops::RangeFull => R],
[<> ops::RangeInclusive<usize> => Dynamic],
[<> ops::RangeTo<usize> => Dynamic],
[<> ops::RangeToInclusive<usize> => Dynamic],
[<I: Dim> ops::RangeFrom<I>
=> DimDiff<R, I>
where R: DimSub<I>],
}
index C with {
[<> usize => U1],
[<> ops::Range<usize> => Dynamic],
[<> ops::RangeFrom<usize> => Dynamic],
[<> ops::RangeFull => C],
[<> ops::RangeInclusive<usize> => Dynamic],
[<> ops::RangeTo<usize> => Dynamic],
[<> ops::RangeToInclusive<usize> => Dynamic],
[<J: DimName> ops::RangeFrom<J>
=> DimDiff<C, J>
where C: DimSub<J>],
}
}

View File

@ -3,9 +3,9 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use base::dimension::Dim; use base::dimension::{Dim, U1};
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
use base::Scalar; use base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut};
macro_rules! iterator { macro_rules! iterator {
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
@ -96,3 +96,226 @@ macro_rules! iterator {
iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S); iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S);
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S); iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S);
/*
*
* Row iterators.
*
*/
#[derive(Clone)]
/// An iterator through the rows of a matrix.
pub struct RowIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
mat: &'a Matrix<N, R, C, S>,
curr: usize
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> RowIter<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
RowIter {
mat, curr: 0
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for RowIter<'a, N, R, C, S> {
type Item = MatrixSlice<'a, N, U1, C, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.mat.nrows() {
let res = self.mat.row(self.curr);
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.mat.nrows() - self.curr, Some(self.mat.nrows() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.mat.nrows() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for RowIter<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.mat.nrows() - self.curr
}
}
/// An iterator through the mutable rows of a matrix.
pub struct RowIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
mat: *mut Matrix<N, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> RowIterMut<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
RowIterMut {
mat,
curr: 0,
phantom: PhantomData
}
}
fn nrows(&self) -> usize {
unsafe {
(*self.mat).nrows()
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for RowIterMut<'a, N, R, C, S> {
type Item = MatrixSliceMut<'a, N, U1, C, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.nrows() {
let res = unsafe { (*self.mat).row_mut(self.curr) };
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.nrows() - self.curr, Some(self.nrows() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.nrows() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for RowIterMut<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.nrows() - self.curr
}
}
/*
*
* Column iterators.
*
*/
#[derive(Clone)]
/// An iterator through the columns of a matrix.
pub struct ColumnIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
mat: &'a Matrix<N, R, C, S>,
curr: usize
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ColumnIter<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
ColumnIter {
mat, curr: 0
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for ColumnIter<'a, N, R, C, S> {
type Item = MatrixSlice<'a, N, R, U1, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.mat.ncols() {
let res = self.mat.column(self.curr);
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.mat.ncols() - self.curr, Some(self.mat.ncols() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.mat.ncols() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for ColumnIter<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.mat.ncols() - self.curr
}
}
/// An iterator through the mutable columns of a matrix.
pub struct ColumnIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
mat: *mut Matrix<N, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ColumnIterMut<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
ColumnIterMut {
mat,
curr: 0,
phantom: PhantomData
}
}
fn ncols(&self) -> usize {
unsafe {
(*self.mat).ncols()
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for ColumnIterMut<'a, N, R, C, S> {
type Item = MatrixSliceMut<'a, N, R, U1, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.ncols() {
let res = unsafe { (*self.mat).column_mut(self.curr) };
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.ncols() - self.curr, Some(self.ncols() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.ncols() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for ColumnIterMut<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.ncols() - self.curr
}
}

View File

@ -7,6 +7,7 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::TypeId; use std::any::TypeId;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
@ -20,8 +21,8 @@ use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Real, Ring};
use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{Dim, DimAdd, DimSum, U1, U2, U3}; use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
use base::iter::{MatrixIter, MatrixIterMut}; use base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut};
use base::storage::{ use base::storage::{
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
}; };
@ -72,7 +73,7 @@ pub type MatrixCross<N, R1, C1, R2, C2> =
/// dynamically-sized column vector should be represented as a `Matrix<N, Dynamic, U1, S>` (given /// dynamically-sized column vector should be represented as a `Matrix<N, Dynamic, U1, S>` (given
/// some concrete types for `N` and a compatible data storage type `S`). /// some concrete types for `N` and a compatible data storage type `S`).
#[repr(C)] #[repr(C)]
#[derive(Hash, Clone, Copy)] #[derive(Clone, Copy)]
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> { pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
/// The data storage that contains all the matrix components and informations about its number /// The data storage that contains all the matrix components and informations about its number
/// of rows and column (if needed). /// of rows and column (if needed).
@ -246,6 +247,37 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
MatrixIter::new(&self.data) MatrixIter::new(&self.data)
} }
/// Iterate through the rows of this matrix.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, row) in a.row_iter().enumerate() {
/// assert_eq!(row, a.row(i))
/// }
/// ```
#[inline]
pub fn row_iter(&self) -> RowIter<N, R, C, S> {
RowIter::new(self)
}
/// Iterate through the columns of this matrix.
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, column) in a.column_iter().enumerate() {
/// assert_eq!(column, a.column(i))
/// }
/// ```
#[inline]
pub fn column_iter(&self) -> ColumnIter<N, R, C, S> {
ColumnIter::new(self)
}
/// Computes the row and column coordinates of the i-th element of this matrix seen as a /// Computes the row and column coordinates of the i-th element of this matrix seen as a
/// vector. /// vector.
#[inline] #[inline]
@ -263,17 +295,6 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
} }
/// Gets a reference to the element of this matrix at row `irow` and column `icol` without
/// bound-checking.
#[inline]
pub unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N {
debug_assert!(
irow < self.nrows() && icol < self.ncols(),
"Matrix index out of bounds."
);
self.data.get_unchecked(irow, icol)
}
/// Returns a pointer to the start of the matrix. /// Returns a pointer to the start of the matrix.
/// ///
/// If the matrix is not empty, this pointer is guaranteed to be aligned /// If the matrix is not empty, this pointer is guaranteed to be aligned
@ -383,7 +404,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
for j in 0..res.ncols() { for j in 0..res.ncols() {
for i in 0..res.nrows() { for i in 0..res.nrows() {
unsafe { unsafe {
*res.get_unchecked_mut(i, j) = *self.get_unchecked(i, j); *res.get_unchecked_mut((i, j)) = *self.get_unchecked((i, j));
} }
} }
} }
@ -412,7 +433,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`, /// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
/// `f` also gets passed the row and column index, i.e. `f(value, row, col)`. /// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
#[inline] #[inline]
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>( pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
&self, &self,
@ -512,6 +533,57 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res res
} }
/// Folds a function `f` on each entry of `self`.
#[inline]
pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, N) -> Acc) -> Acc {
let (nrows, ncols) = self.data.shape();
let mut res = init;
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = *self.data.get_unchecked(i, j);
res = f(res, a)
}
}
}
res
}
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
#[inline]
pub fn zip_fold<N2, R2, C2, S2, Acc>(&self, rhs: &Matrix<N2, R2, C2, S2>, init: Acc, mut f: impl FnMut(Acc, N, N2) -> Acc) -> Acc
where
N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>
{
let (nrows, ncols) = self.data.shape();
let mut res = init;
assert!(
(nrows.value(), ncols.value()) == rhs.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = *self.data.get_unchecked(i, j);
let b = *rhs.data.get_unchecked(i, j);
res = f(res, a, b)
}
}
}
res
}
/// Transposes `self` and store the result into `out`. /// Transposes `self` and store the result into `out`.
#[inline] #[inline]
pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>) pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
@ -531,7 +603,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
for i in 0..nrows { for i in 0..nrows {
for j in 0..ncols { for j in 0..ncols {
unsafe { unsafe {
*out.get_unchecked_mut(j, i) = *self.get_unchecked(i, j); *out.get_unchecked_mut((j, i)) = *self.get_unchecked((i, j));
} }
} }
} }
@ -568,14 +640,44 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
self.data.ptr_mut() self.data.ptr_mut()
} }
/// Gets a mutable reference to the i-th element of this matrix. /// Mutably iterates through this matrix rows.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, mut row) in a.row_iter_mut().enumerate() {
/// row *= (i + 1) * 10;
/// }
///
/// let expected = Matrix2x3::new(10, 20, 30,
/// 80, 100, 120);
/// assert_eq!(a, expected);
/// ```
#[inline] #[inline]
pub unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut N { pub fn row_iter_mut(&mut self) -> RowIterMut<N, R, C, S> {
debug_assert!( RowIterMut::new(self)
irow < self.nrows() && icol < self.ncols(), }
"Matrix index out of bounds."
); /// Mutably iterates through this matrix columns.
self.data.get_unchecked_mut(irow, icol) ///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, mut col) in a.column_iter_mut().enumerate() {
/// col *= (i + 1) * 10;
/// }
///
/// let expected = Matrix2x3::new(10, 40, 90,
/// 40, 100, 180);
/// assert_eq!(a, expected);
/// ```
#[inline]
pub fn column_iter_mut(&mut self) -> ColumnIterMut<N, R, C, S> {
ColumnIterMut::new(self)
} }
/// Swaps two entries without bound-checking. /// Swaps two entries without bound-checking.
@ -616,7 +718,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
for j in 0..ncols { for j in 0..ncols {
for i in 0..nrows { for i in 0..nrows {
unsafe { unsafe {
*self.get_unchecked_mut(i, j) = *slice.get_unchecked(i + j * nrows); *self.get_unchecked_mut((i, j)) = *slice.get_unchecked(i + j * nrows);
} }
} }
} }
@ -639,7 +741,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
for j in 0..self.ncols() { for j in 0..self.ncols() {
for i in 0..self.nrows() { for i in 0..self.nrows() {
unsafe { unsafe {
*self.get_unchecked_mut(i, j) = *other.get_unchecked(i, j); *self.get_unchecked_mut((i, j)) = *other.get_unchecked((i, j));
} }
} }
} }
@ -663,7 +765,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
for j in 0..ncols { for j in 0..ncols {
for i in 0..nrows { for i in 0..nrows {
unsafe { unsafe {
*self.get_unchecked_mut(i, j) = *other.get_unchecked(j, i); *self.get_unchecked_mut((i, j)) = *other.get_unchecked((j, i));
} }
} }
} }
@ -671,8 +773,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// Replaces each component of `self` by the result of a closure `f` applied on it. /// Replaces each component of `self` by the result of a closure `f` applied on it.
#[inline] #[inline]
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) {
where DefaultAllocator: Allocator<N, R, C> {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
for j in 0..ncols { for j in 0..ncols {
@ -684,6 +785,71 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
} }
} }
} }
/// Replaces each component of `self` by the result of a closure `f` applied on its components
/// joined with the components from `rhs`.
#[inline]
pub fn zip_apply<N2, R2, C2, S2>(&mut self, rhs: &Matrix<N2, R2, C2, S2>, mut f: impl FnMut(N, N2) -> N)
where N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
let (nrows, ncols) = self.shape();
assert!(
(nrows, ncols) == rhs.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
let e = self.data.get_unchecked_mut(i, j);
let rhs = rhs.get_unchecked((i, j));
*e = f(*e, *rhs)
}
}
}
}
/// Replaces each component of `self` by the result of a closure `f` applied on its components
/// joined with the components from `b` and `c`.
#[inline]
pub fn zip_zip_apply<N2, R2, C2, S2, N3, R3, C3, S3>(&mut self, b: &Matrix<N2, R2, C2, S2>, c: &Matrix<N3, R3, C3, S3>, mut f: impl FnMut(N, N2, N3) -> N)
where N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
N3: Scalar,
R3: Dim,
C3: Dim,
S3: Storage<N3, R3, C3>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
let (nrows, ncols) = self.shape();
assert!(
(nrows, ncols) == b.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
assert!(
(nrows, ncols) == c.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
let e = self.data.get_unchecked_mut(i, j);
let b = b.get_unchecked((i, j));
let c = c.get_unchecked((i, j));
*e = f(*e, *b, *c)
}
}
}
}
} }
impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> { impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
@ -760,7 +926,7 @@ impl<N: Real, R: Dim, C: Dim, S: Storage<Complex<N>, R, C>> Matrix<Complex<N>, R
for i in 0..nrows { for i in 0..nrows {
for j in 0..ncols { for j in 0..ncols {
unsafe { unsafe {
*out.get_unchecked_mut(j, i) = self.get_unchecked(i, j).conj(); *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conj();
} }
} }
} }
@ -794,8 +960,8 @@ impl<N: Real, D: Dim, S: StorageMut<Complex<N>, D, D>> Matrix<Complex<N>, D, D,
for i in 1..dim { for i in 1..dim {
for j in 0..i { for j in 0..i {
unsafe { unsafe {
let ref_ij = self.get_unchecked_mut(i, j) as *mut Complex<N>; let ref_ij = self.get_unchecked_mut((i, j)) as *mut Complex<N>;
let ref_ji = self.get_unchecked_mut(j, i) as *mut Complex<N>; let ref_ji = self.get_unchecked_mut((j, i)) as *mut Complex<N>;
let conj_ij = (*ref_ij).conj(); let conj_ij = (*ref_ij).conj();
let conj_ji = (*ref_ji).conj(); let conj_ji = (*ref_ji).conj();
*ref_ij = conj_ji; *ref_ij = conj_ji;
@ -821,7 +987,7 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
for i in 0..dim.value() { for i in 0..dim.value() {
unsafe { unsafe {
*res.vget_unchecked_mut(i) = *self.get_unchecked(i, i); *res.vget_unchecked_mut(i) = *self.get_unchecked((i, i));
} }
} }
@ -841,27 +1007,36 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
let mut res = N::zero(); let mut res = N::zero();
for i in 0..dim.value() { for i in 0..dim.value() {
res += unsafe { *self.get_unchecked(i, i) }; res += unsafe { *self.get_unchecked((i, i)) };
} }
res res
} }
} }
impl<N: Scalar + One + Zero, D: DimAdd<U1> + IsNotStaticOne, S: Storage<N, D, D>> Matrix<N, D, D, S> {
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
/// and setting the diagonal element to `1`.
#[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>, DimSum<D, U1>> {
assert!(self.is_square(), "Only square matrices can currently be transformed to homogeneous coordinates.");
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
let mut res = MatrixN::identity_generic(dim, dim);
res.generic_slice_mut::<D, D>((0, 0), self.data.shape()).copy_from(&self);
res
}
}
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> { impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its /// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
/// coordinates. /// coordinates.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>> pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>> { where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
let len = self.len(); self.push(N::zero())
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
res.generic_slice_mut((0, 0), self.data.shape())
.copy_from(self);
res[(len, 0)] = N::zero();
res
} }
/// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of /// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
@ -881,6 +1056,22 @@ impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
} }
} }
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
/// Constructs a new vector of higher dimension by appending `element` to the end of `self`.
#[inline]
pub fn push(&self, element: N) -> VectorN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
let len = self.len();
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
res.generic_slice_mut((0, 0), self.data.shape())
.copy_from(self);
res[(len, 0)] = element;
res
}
}
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S>
where where
N: Scalar + AbsDiffEq, N: Scalar + AbsDiffEq,
@ -1141,8 +1332,8 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
assert!(self.shape() == (2, 1), "2D perpendicular product "); assert!(self.shape() == (2, 1), "2D perpendicular product ");
unsafe { unsafe {
*self.get_unchecked(0, 0) * *b.get_unchecked(1, 0) *self.get_unchecked((0, 0)) * *b.get_unchecked((1, 0))
- *self.get_unchecked(1, 0) * *b.get_unchecked(0, 0) - *self.get_unchecked((1, 0)) * *b.get_unchecked((0, 0))
} }
} }
@ -1177,17 +1368,17 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
let ncols = SameShapeC::<C, C2>::from_usize(1); let ncols = SameShapeC::<C, C2>::from_usize(1);
let mut res = Matrix::new_uninitialized_generic(nrows, ncols); let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let ax = *self.get_unchecked(0, 0); let ax = *self.get_unchecked((0, 0));
let ay = *self.get_unchecked(1, 0); let ay = *self.get_unchecked((1, 0));
let az = *self.get_unchecked(2, 0); let az = *self.get_unchecked((2, 0));
let bx = *b.get_unchecked(0, 0); let bx = *b.get_unchecked((0, 0));
let by = *b.get_unchecked(1, 0); let by = *b.get_unchecked((1, 0));
let bz = *b.get_unchecked(2, 0); let bz = *b.get_unchecked((2, 0));
*res.get_unchecked_mut(0, 0) = ay * bz - az * by; *res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
*res.get_unchecked_mut(1, 0) = az * bx - ax * bz; *res.get_unchecked_mut((1, 0)) = az * bx - ax * bz;
*res.get_unchecked_mut(2, 0) = ax * by - ay * bx; *res.get_unchecked_mut((2, 0)) = ax * by - ay * bx;
res res
} }
@ -1198,17 +1389,17 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
let ncols = SameShapeC::<C, C2>::from_usize(3); let ncols = SameShapeC::<C, C2>::from_usize(3);
let mut res = Matrix::new_uninitialized_generic(nrows, ncols); let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let ax = *self.get_unchecked(0, 0); let ax = *self.get_unchecked((0, 0));
let ay = *self.get_unchecked(0, 1); let ay = *self.get_unchecked((0, 1));
let az = *self.get_unchecked(0, 2); let az = *self.get_unchecked((0, 2));
let bx = *b.get_unchecked(0, 0); let bx = *b.get_unchecked((0, 0));
let by = *b.get_unchecked(0, 1); let by = *b.get_unchecked((0, 1));
let bz = *b.get_unchecked(0, 2); let bz = *b.get_unchecked((0, 2));
*res.get_unchecked_mut(0, 0) = ay * bz - az * by; *res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
*res.get_unchecked_mut(0, 1) = az * bx - ax * bz; *res.get_unchecked_mut((0, 1)) = az * bx - ax * bz;
*res.get_unchecked_mut(0, 2) = ax * by - ay * bx; *res.get_unchecked_mut((0, 2)) = ax * by - ay * bx;
res res
} }
@ -1264,67 +1455,6 @@ impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
} }
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// The squared L2 norm of this vector.
#[inline]
pub fn norm_squared(&self) -> N {
let mut res = N::zero();
for i in 0..self.ncols() {
let col = self.column(i);
res += col.dot(&col)
}
res
}
/// The L2 norm of this matrix.
#[inline]
pub fn norm(&self) -> N {
self.norm_squared().sqrt()
}
/// A synonym for the norm of this matrix.
///
/// Aka the length.
///
/// This function is simply implemented as a call to `norm()`
#[inline]
pub fn magnitude(&self) -> N {
self.norm()
}
/// A synonym for the squared norm of this matrix.
///
/// Aka the squared length.
///
/// This function is simply implemented as a call to `norm_squared()`
#[inline]
pub fn magnitude_squared(&self) -> N {
self.norm_squared()
}
/// Returns a normalized version of this matrix.
#[inline]
pub fn normalize(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self / self.norm()
}
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
#[inline]
pub fn try_normalize(&self, min_norm: N) -> Option<MatrixMN<N, R, C>>
where DefaultAllocator: Allocator<N, R, C> {
let n = self.norm();
if n <= min_norm {
None
} else {
Some(self / n)
}
}
}
impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>> impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
Vector<N, D, S> Vector<N, D, S>
{ {
@ -1399,32 +1529,6 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
} }
} }
impl<N: Real, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// Normalizes this matrix in-place and returns its norm.
#[inline]
pub fn normalize_mut(&mut self) -> N {
let n = self.norm();
*self /= n;
n
}
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
///
/// If the normalization succeeded, returns the old normal of this matrix.
#[inline]
pub fn try_normalize_mut(&mut self, min_norm: N) -> Option<N> {
let n = self.norm();
if n <= min_norm {
None
} else {
*self /= n;
Some(n)
}
}
}
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>> impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>>
where where
N: Scalar + AbsDiffEq, N: Scalar + AbsDiffEq,
@ -1484,3 +1588,24 @@ where
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
} }
} }
impl<N, R, C, S> Hash for Matrix<N, R, C, S>
where
N: Scalar + Hash,
R: Dim,
C: Dim,
S: Storage<N, R, C>,
{
fn hash<H: Hasher>(&self, state: &mut H) {
let (nrows, ncols) = self.shape();
(nrows, ncols).hash(state);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
self.get_unchecked((i, j)).hash(state);
}
}
}
}
}

View File

@ -6,7 +6,7 @@ use num::{One, Zero};
use alga::general::{ use alga::general::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul,
ClosedNeg, Field, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice, Module, ClosedNeg, Field, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice, Module,
Multiplicative, Real, RingCommutative, Multiplicative, Real, RingCommutative,
}; };
use alga::linear::{ use alga::linear::{
@ -45,18 +45,18 @@ where
} }
} }
impl<N, R: DimName, C: DimName> Inverse<Additive> for MatrixMN<N, R, C> impl<N, R: DimName, C: DimName> TwoSidedInverse<Additive> for MatrixMN<N, R, C>
where where
N: Scalar + ClosedNeg, N: Scalar + ClosedNeg,
DefaultAllocator: Allocator<N, R, C>, DefaultAllocator: Allocator<N, R, C>,
{ {
#[inline] #[inline]
fn inverse(&self) -> MatrixMN<N, R, C> { fn two_sided_inverse(&self) -> MatrixMN<N, R, C> {
-self -self
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
*self = -self.clone() *self = -self.clone()
} }
} }

View File

@ -4,9 +4,9 @@ use std::slice;
use base::allocator::Allocator; use base::allocator::Allocator;
use base::default_allocator::DefaultAllocator; use base::default_allocator::DefaultAllocator;
use base::dimension::{Dim, DimName, Dynamic, U1}; use base::dimension::{Dim, DimName, Dynamic, U1, IsNotStaticOne};
use base::iter::MatrixIter; use base::iter::MatrixIter;
use base::storage::{Owned, Storage, StorageMut}; use base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut};
use base::{Matrix, Scalar}; use base::{Matrix, Scalar};
macro_rules! slice_storage_impl( macro_rules! slice_storage_impl(
@ -91,7 +91,8 @@ 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> Copy impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
for SliceStorage<'a, N, R, C, RStride, CStride> for SliceStorage<'a, N, R, C, RStride, CStride>
{} {
}
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
for SliceStorage<'a, N, R, C, RStride, CStride> for SliceStorage<'a, N, R, C, RStride, CStride>
@ -146,8 +147,6 @@ macro_rules! storage_impl(
} }
} }
#[inline] #[inline]
fn into_owned(self) -> Owned<N, R, C> fn into_owned(self) -> Owned<N, R, C>
where DefaultAllocator: Allocator<N, R, C> { where DefaultAllocator: Allocator<N, R, C> {
@ -199,6 +198,14 @@ unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMu
} }
} }
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage<N, R, U1> for SliceStorage<'a, N, R, U1, U1, CStride> { }
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage<N, R, U1> for SliceStorageMut<'a, N, R, U1, U1, CStride> { }
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorageMut<N, R, U1> for SliceStorageMut<'a, N, R, U1, U1, CStride> { }
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<N, R, C> for SliceStorage<'a, N, R, C, U1, R> { }
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<N, R, C> for SliceStorageMut<'a, N, R, C, U1, R> { }
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<N, R, C> for SliceStorageMut<'a, N, R, C, U1, R> { }
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> {
#[inline] #[inline]
fn assert_slice_index( fn assert_slice_index(
@ -859,3 +866,25 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
self.slice_range_mut(.., cols) self.slice_range_mut(.., cols)
} }
} }
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
for MatrixSlice<'a, N, R, C, RStride, CStride>
where
N: Scalar,
R: Dim,
C: Dim,
RStride: Dim,
CStride: Dim,
{
fn from(slice_mut: MatrixSliceMut<'a, N, R, C, RStride, CStride>) -> Self {
let data = SliceStorage {
ptr: slice_mut.data.ptr,
shape: slice_mut.data.shape,
strides: slice_mut.data.strides,
_phantoms: PhantomData,
};
unsafe { Matrix::from_data_statically_unchecked(data) }
}
}

View File

@ -18,16 +18,19 @@ mod construction;
mod construction_slice; mod construction_slice;
mod conversion; mod conversion;
mod edition; mod edition;
pub mod indexing;
mod matrix; mod matrix;
mod matrix_alga; mod matrix_alga;
mod matrix_array; mod array_storage;
mod matrix_slice; mod matrix_slice;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
mod matrix_vec; mod vec_storage;
mod properties; mod properties;
mod scalar; mod scalar;
mod swizzle; mod swizzle;
mod unit; mod unit;
mod statistics;
mod norm;
#[doc(hidden)] #[doc(hidden)]
pub mod helper; pub mod helper;
@ -35,13 +38,14 @@ pub mod helper;
pub use self::matrix::*; pub use self::matrix::*;
pub use self::scalar::*; pub use self::scalar::*;
pub use self::unit::*; pub use self::unit::*;
pub use self::norm::*;
pub use self::default_allocator::*; pub use self::default_allocator::*;
pub use self::dimension::*; pub use self::dimension::*;
pub use self::alias::*; pub use self::alias::*;
pub use self::alias_slice::*; pub use self::alias_slice::*;
pub use self::matrix_array::*; pub use self::array_storage::*;
pub use self::matrix_slice::*; pub use self::matrix_slice::*;
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub use self::matrix_vec::*; pub use self::vec_storage::*;

238
src/base/norm.rs Normal file
View File

@ -0,0 +1,238 @@
use num::Signed;
use std::cmp::PartialOrd;
use allocator::Allocator;
use ::{Real, Scalar};
use storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, Dim, MatrixMN};
use constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint};
// FIXME: this should be be a trait on alga?
/// A trait for abstract matrix norms.
///
/// This may be moved to the alga crate in the future.
pub trait Norm<N: Scalar> {
/// Apply this norm to the given matrix.
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C>;
/// Use the metric induced by this norm to compute the metric distance between the two given matrices.
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>;
}
/// Euclidean norm.
pub struct EuclideanNorm;
/// Lp norm.
pub struct LpNorm(pub i32);
/// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm.
pub struct UniformNorm;
impl<N: Real> Norm<N> for EuclideanNorm {
#[inline]
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C> {
m.norm_squared().sqrt()
}
#[inline]
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
m1.zip_fold(m2, N::zero(), |acc, a, b| {
let diff = a - b;
acc + diff * diff
}).sqrt()
}
}
impl<N: Real> Norm<N> for LpNorm {
#[inline]
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C> {
m.fold(N::zero(), |a, b| {
a + b.abs().powi(self.0)
}).powf(::convert(1.0 / (self.0 as f64)))
}
#[inline]
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
m1.zip_fold(m2, N::zero(), |acc, a, b| {
let diff = a - b;
acc + diff.abs().powi(self.0)
}).powf(::convert(1.0 / (self.0 as f64)))
}
}
impl<N: Scalar + PartialOrd + Signed> Norm<N> for UniformNorm {
#[inline]
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C> {
m.amax()
}
#[inline]
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
m1.zip_fold(m2, N::zero(), |acc, a, b| {
let val = (a - b).abs();
if val > acc {
val
} else {
acc
}
})
}
}
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// The squared L2 norm of this vector.
#[inline]
pub fn norm_squared(&self) -> N {
let mut res = N::zero();
for i in 0..self.ncols() {
let col = self.column(i);
res += col.dot(&col)
}
res
}
/// The L2 norm of this matrix.
///
/// Use `.apply_norm` to apply a custom norm.
#[inline]
pub fn norm(&self) -> N {
self.norm_squared().sqrt()
}
/// Compute the distance between `self` and `rhs` using the metric induced by the euclidean norm.
///
/// Use `.apply_metric_distance` to apply a custom norm.
#[inline]
pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>) -> N
where R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
self.apply_metric_distance(rhs, &EuclideanNorm)
}
/// Uses the given `norm` to compute the norm of `self`.
///
/// # Example
///
/// ```
/// # use nalgebra::{Vector3, UniformNorm, LpNorm, EuclideanNorm};
///
/// let v = Vector3::new(1.0, 2.0, 3.0);
/// assert_eq!(v.apply_norm(&UniformNorm), 3.0);
/// assert_eq!(v.apply_norm(&LpNorm(1)), 6.0);
/// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm());
/// ```
#[inline]
pub fn apply_norm(&self, norm: &impl Norm<N>) -> N {
norm.norm(self)
}
/// Uses the metric induced by the given `norm` to compute the metric distance between `self` and `rhs`.
///
/// # Example
///
/// ```
/// # use nalgebra::{Vector3, UniformNorm, LpNorm, EuclideanNorm};
///
/// let v1 = Vector3::new(1.0, 2.0, 3.0);
/// let v2 = Vector3::new(10.0, 20.0, 30.0);
///
/// assert_eq!(v1.apply_metric_distance(&v2, &UniformNorm), 27.0);
/// assert_eq!(v1.apply_metric_distance(&v2, &LpNorm(1)), 27.0 + 18.0 + 9.0);
/// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm());
/// ```
#[inline]
pub fn apply_metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>, norm: &impl Norm<N>) -> N
where R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
norm.metric_distance(self,rhs)
}
/// The Lp norm of this matrix.
#[inline]
pub fn lp_norm(&self, p: i32) -> N {
self.apply_norm(&LpNorm(p))
}
/// A synonym for the norm of this matrix.
///
/// Aka the length.
///
/// This function is simply implemented as a call to `norm()`
#[inline]
pub fn magnitude(&self) -> N {
self.norm()
}
/// A synonym for the squared norm of this matrix.
///
/// Aka the squared length.
///
/// This function is simply implemented as a call to `norm_squared()`
#[inline]
pub fn magnitude_squared(&self) -> N {
self.norm_squared()
}
/// Returns a normalized version of this matrix.
#[inline]
pub fn normalize(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self / self.norm()
}
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
#[inline]
pub fn try_normalize(&self, min_norm: N) -> Option<MatrixMN<N, R, C>>
where DefaultAllocator: Allocator<N, R, C> {
let n = self.norm();
if n <= min_norm {
None
} else {
Some(self / n)
}
}
}
impl<N: Real, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// Normalizes this matrix in-place and returns its norm.
#[inline]
pub fn normalize_mut(&mut self) -> N {
let n = self.norm();
*self /= n;
n
}
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
///
/// If the normalization succeeded, returns the old normal of this matrix.
#[inline]
pub fn try_normalize_mut(&mut self, min_norm: N) -> Option<N> {
let n = self.norm();
if n <= min_norm {
None
} else {
*self /= n;
Some(n)
}
}
}

View File

@ -45,7 +45,7 @@ where
"Matrix index out of bounds." "Matrix index out of bounds."
); );
unsafe { self.get_unchecked(ij.0, ij.1) } unsafe { self.get_unchecked((ij.0, ij.1)) }
} }
} }
@ -71,7 +71,7 @@ where
"Matrix index out of bounds." "Matrix index out of bounds."
); );
unsafe { self.get_unchecked_mut(ij.0, ij.1) } unsafe { self.get_unchecked_mut((ij.0, ij.1)) }
} }
} }
@ -172,8 +172,8 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
let val = self.get_unchecked(i, j).$method(*rhs.get_unchecked(i, j)); let val = self.get_unchecked((i, j)).$method(*rhs.get_unchecked((i, j)));
*out.get_unchecked_mut(i, j) = val; *out.get_unchecked_mut((i, j)) = val;
} }
} }
} }
@ -204,7 +204,7 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. rhs.ncols() { for j in 0 .. rhs.ncols() {
for i in 0 .. rhs.nrows() { for i in 0 .. rhs.nrows() {
unsafe { unsafe {
self.get_unchecked_mut(i, j).$method_assign(*rhs.get_unchecked(i, j)) self.get_unchecked_mut((i, j)).$method_assign(*rhs.get_unchecked((i, j)))
} }
} }
} }
@ -235,8 +235,8 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
let r = rhs.get_unchecked_mut(i, j); let r = rhs.get_unchecked_mut((i, j));
*r = self.get_unchecked(i, j).$method(*r) *r = self.get_unchecked((i, j)).$method(*r)
} }
} }
} }
@ -448,7 +448,7 @@ macro_rules! componentwise_scalarop_impl(
fn $method_assign(&mut self, rhs: N) { fn $method_assign(&mut self, rhs: N) {
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { self.get_unchecked_mut(i, j).$method_assign(rhs) }; unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs) };
} }
} }
} }
@ -657,7 +657,7 @@ where
for i in 0..ncols1 { for i in 0..ncols1 {
for j in 0..ncols2 { for j in 0..ncols2 {
let dot = self.column(i).dot(&rhs.column(j)); let dot = self.column(i).dot(&rhs.column(j));
unsafe { *out.get_unchecked_mut(i, j) = dot }; unsafe { *out.get_unchecked_mut((i, j)) = dot };
} }
} }
} }
@ -704,10 +704,10 @@ where
for j2 in 0..ncols2.value() { for j2 in 0..ncols2.value() {
for i1 in 0..nrows1.value() { for i1 in 0..nrows1.value() {
unsafe { unsafe {
let coeff = *self.get_unchecked(i1, j1); let coeff = *self.get_unchecked((i1, j1));
for i2 in 0..nrows2.value() { for i2 in 0..nrows2.value() {
*data_res = coeff * *rhs.get_unchecked(i2, j2); *data_res = coeff * *rhs.get_unchecked((i2, j2));
data_res = data_res.offset(1); data_res = data_res.offset(1);
} }
} }
@ -761,7 +761,7 @@ where
} }
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { 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. /// Returns the absolute value of the component with the largest absolute value.
#[inline] #[inline]
pub fn amax(&self) -> N { pub fn amax(&self) -> N {
let mut max = N::zero(); let mut max = N::zero();
@ -777,7 +777,7 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
max max
} }
/// Returns the absolute value of the coefficient with the smallest absolute value. /// Returns the absolute value of the component with the smallest absolute value.
#[inline] #[inline]
pub fn amin(&self) -> N { pub fn amin(&self) -> N {
let mut it = self.iter(); let mut it = self.iter();
@ -796,4 +796,42 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
min min
} }
/// Returns the component with the largest value.
#[inline]
pub fn max(&self) -> N {
let mut it = self.iter();
let mut max = it
.next()
.expect("max: empty matrices not supported.");
for e in it {
let ae = e;
if ae > max {
max = ae;
}
}
*max
}
/// Returns the component with the smallest value.
#[inline]
pub fn min(&self) -> N {
let mut it = self.iter();
let mut min = it
.next()
.expect("min: empty matrices not supported.");
for e in it {
let ae = e;
if ae < min {
min = ae;
}
}
*min
}
} }

309
src/base/statistics.rs Normal file
View File

@ -0,0 +1,309 @@
use ::{Real, Dim, Matrix, VectorN, RowVectorN, DefaultAllocator, U1, VectorSliceN};
use storage::Storage;
use allocator::Allocator;
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Returns a row vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix.
#[inline]
pub fn compress_rows(&self, f: impl Fn(VectorSliceN<N, R, S::RStride, S::CStride>) -> N) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
let ncols = self.data.shape().1;
let mut res = unsafe { RowVectorN::new_uninitialized_generic(U1, ncols) };
for i in 0..ncols.value() {
// FIXME: avoid bound checking of column.
unsafe { *res.get_unchecked_mut((0, i)) = f(self.column(i)); }
}
res
}
/// Returns a column vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix.
///
/// This is the same as `self.compress_rows(f).transpose()`.
#[inline]
pub fn compress_rows_tr(&self, f: impl Fn(VectorSliceN<N, R, S::RStride, S::CStride>) -> N) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
let ncols = self.data.shape().1;
let mut res = unsafe { VectorN::new_uninitialized_generic(ncols, U1) };
for i in 0..ncols.value() {
// FIXME: avoid bound checking of column.
unsafe { *res.vget_unchecked_mut(i) = f(self.column(i)); }
}
res
}
/// Returns a column vector resulting from the folding of `f` on each column of this matrix.
#[inline]
pub fn compress_columns(&self, init: VectorN<N, R>, f: impl Fn(&mut VectorN<N, R>, VectorSliceN<N, R, S::RStride, S::CStride>)) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let mut res = init;
for i in 0..self.ncols() {
f(&mut res, self.column(i))
}
res
}
}
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/*
*
* Sum computation.
*
*/
/// The sum of all the elements of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::Matrix2x3;
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.sum(), 21.0);
/// ```
#[inline]
pub fn sum(&self) -> N {
self.iter().cloned().fold(N::zero(), |a, b| a + b)
}
/// The sum of all the rows of this matrix.
///
/// Use `.row_variance_tr` if you need the result in a column vector instead.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, RowVector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_sum(), RowVector3::new(5.0, 7.0, 9.0));
/// ```
#[inline]
pub fn row_sum(&self) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
self.compress_rows(|col| col.sum())
}
/// The sum of all the rows of this matrix. The result is transposed and returned as a column vector.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_sum_tr(), Vector3::new(5.0, 7.0, 9.0));
/// ```
#[inline]
pub fn row_sum_tr(&self) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
self.compress_rows_tr(|col| col.sum())
}
/// The sum of all the columns of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector2};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.column_sum(), Vector2::new(6.0, 15.0));
/// ```
#[inline]
pub fn column_sum(&self) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let nrows = self.data.shape().0;
self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| {
out.axpy(N::one(), &col, N::one())
})
}
/*
*
* Variance computation.
*
*/
/// The variance of all the elements of this matrix.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Matrix2x3;
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_relative_eq!(m.variance(), 35.0 / 12.0, epsilon = 1.0e-8);
/// ```
#[inline]
pub fn variance(&self) -> N {
if self.len() == 0 {
N::zero()
} else {
let val = self.iter().cloned().fold((N::zero(), N::zero()), |a, b| (a.0 + b * b, a.1 + b));
let denom = N::one() / ::convert::<_, N>(self.len() as f64);
val.0 * denom - (val.1 * denom) * (val.1 * denom)
}
}
/// The variance of all the rows of this matrix.
///
/// Use `.row_variance_tr` if you need the result in a column vector instead.
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, RowVector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_variance(), RowVector3::new(2.25, 2.25, 2.25));
/// ```
#[inline]
pub fn row_variance(&self) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
self.compress_rows(|col| col.variance())
}
/// The variance of all the rows of this matrix. The result is transposed and returned as a column vector.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_variance_tr(), Vector3::new(2.25, 2.25, 2.25));
/// ```
#[inline]
pub fn row_variance_tr(&self) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
self.compress_rows_tr(|col| col.variance())
}
/// The variance of all the columns of this matrix.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix2x3, Vector2};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_relative_eq!(m.column_variance(), Vector2::new(2.0 / 3.0, 2.0 / 3.0), epsilon = 1.0e-8);
/// ```
#[inline]
pub fn column_variance(&self) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let (nrows, ncols) = self.data.shape();
let mut mean = self.column_mean();
mean.apply(|e| -(e * e));
let denom = N::one() / ::convert::<_, N>(ncols.value() as f64);
self.compress_columns(mean, |out, col| {
for i in 0..nrows.value() {
unsafe {
let val = col.vget_unchecked(i);
*out.vget_unchecked_mut(i) += denom * *val * *val
}
}
})
}
/*
*
* Mean computation.
*
*/
/// The mean of all the elements of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::Matrix2x3;
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.mean(), 3.5);
/// ```
#[inline]
pub fn mean(&self) -> N {
if self.len() == 0 {
N::zero()
} else {
self.sum() / ::convert(self.len() as f64)
}
}
/// The mean of all the rows of this matrix.
///
/// Use `.row_mean_tr` if you need the result in a column vector instead.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, RowVector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_mean(), RowVector3::new(2.5, 3.5, 4.5));
/// ```
#[inline]
pub fn row_mean(&self) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
self.compress_rows(|col| col.mean())
}
/// The mean of all the rows of this matrix. The result is transposed and returned as a column vector.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_mean_tr(), Vector3::new(2.5, 3.5, 4.5));
/// ```
#[inline]
pub fn row_mean_tr(&self) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
self.compress_rows_tr(|col| col.mean())
}
/// The mean of all the columns of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector2};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.column_mean(), Vector2::new(2.0, 5.0));
/// ```
#[inline]
pub fn column_mean(&self) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let (nrows, ncols) = self.data.shape();
let denom = N::one() / ::convert::<_, N>(ncols.value() as f64);
self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| {
out.axpy(denom, &col, N::one())
})
}
}

View File

@ -34,7 +34,7 @@ pub type CStride<N, R, C = U1> =
/// Note that `Self` must always have a number of elements compatible with the matrix length (given /// Note that `Self` must always have a number of elements compatible with the matrix length (given
/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait /// by `R` and `C` if they are known at compile-time). For example, implementors of this trait
/// 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 `VecStorage::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 = U1>: Debug + 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.

View File

@ -3,64 +3,60 @@ use storage::Storage;
use typenum::{self, Cmp, Greater}; use typenum::{self, Cmp, Greater};
macro_rules! impl_swizzle { macro_rules! impl_swizzle {
($(where $BaseDim: ident: $name: ident() -> $Result: ident[$($i: expr),*]);*) => { ($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => {
$(
impl<N: Scalar, D: DimName, S: Storage<N, D>> Vector<N, D, S>
where D::Value: Cmp<typenum::$BaseDim, Output=Greater>
{
$( $(
impl<N: Scalar, D: DimName, S: Storage<N, D>> Vector<N, D, S> {
/// Builds a new vector from components of `self`. /// Builds a new vector from components of `self`.
#[inline] #[inline]
pub fn $name(&self) -> $Result<N> pub fn $name(&self) -> $Result<N> {
where D::Value: Cmp<typenum::$BaseDim, Output=Greater> {
$Result::new($(self[$i]),*) $Result::new($(self[$i]),*)
} }
)*
} }
)* )*
} }
} }
impl_swizzle!( impl_swizzle!(
where U0: xx() -> Vector2[0, 0]; where U0: xx() -> Vector2[0, 0],
where U1: xy() -> Vector2[0, 1]; xxx() -> Vector3[0, 0, 0];
where U2: xz() -> Vector2[0, 2];
where U1: yx() -> Vector2[1, 0];
where U1: yy() -> Vector2[1, 1];
where U1: yz() -> Vector2[1, 2];
where U2: zx() -> Vector2[2, 0];
where U2: zy() -> Vector2[2, 1];
where U2: zz() -> Vector2[2, 2];
where U0: xxx() -> Vector3[0, 0, 0]; where U1: xy() -> Vector2[0, 1],
where U1: xxy() -> Vector3[0, 0, 1]; yx() -> Vector2[1, 0],
where U2: xxz() -> Vector3[0, 0, 2]; yy() -> Vector2[1, 1],
xxy() -> Vector3[0, 0, 1],
xyx() -> Vector3[0, 1, 0],
xyy() -> Vector3[0, 1, 1],
yxx() -> Vector3[1, 0, 0],
yxy() -> Vector3[1, 0, 1],
yyx() -> Vector3[1, 1, 0],
yyy() -> Vector3[1, 1, 1];
where U1: xyx() -> Vector3[0, 1, 0]; where U2: xz() -> Vector2[0, 2],
where U1: xyy() -> Vector3[0, 1, 1]; yz() -> Vector2[1, 2],
where U2: xyz() -> Vector3[0, 1, 2]; zx() -> Vector2[2, 0],
zy() -> Vector2[2, 1],
where U2: xzx() -> Vector3[0, 2, 0]; zz() -> Vector2[2, 2],
where U2: xzy() -> Vector3[0, 2, 1]; xxz() -> Vector3[0, 0, 2],
where U2: xzz() -> Vector3[0, 2, 2]; xyz() -> Vector3[0, 1, 2],
xzx() -> Vector3[0, 2, 0],
where U1: yxx() -> Vector3[1, 0, 0]; xzy() -> Vector3[0, 2, 1],
where U1: yxy() -> Vector3[1, 0, 1]; xzz() -> Vector3[0, 2, 2],
where U2: yxz() -> Vector3[1, 0, 2]; yxz() -> Vector3[1, 0, 2],
yyz() -> Vector3[1, 1, 2],
where U1: yyx() -> Vector3[1, 1, 0]; yzx() -> Vector3[1, 2, 0],
where U1: yyy() -> Vector3[1, 1, 1]; yzy() -> Vector3[1, 2, 1],
where U2: yyz() -> Vector3[1, 1, 2]; yzz() -> Vector3[1, 2, 2],
zxx() -> Vector3[2, 0, 0],
where U2: yzx() -> Vector3[1, 2, 0]; zxy() -> Vector3[2, 0, 1],
where U2: yzy() -> Vector3[1, 2, 1]; zxz() -> Vector3[2, 0, 2],
where U2: yzz() -> Vector3[1, 2, 2]; zyx() -> Vector3[2, 1, 0],
zyy() -> Vector3[2, 1, 1],
where U2: zxx() -> Vector3[2, 0, 0]; zyz() -> Vector3[2, 1, 2],
where U2: zxy() -> Vector3[2, 0, 1]; zzx() -> Vector3[2, 2, 0],
where U2: zxz() -> Vector3[2, 0, 2]; zzy() -> Vector3[2, 2, 1],
zzz() -> Vector3[2, 2, 2];
where U2: zyx() -> Vector3[2, 1, 0];
where U2: zyy() -> Vector3[2, 1, 1];
where U2: zyz() -> Vector3[2, 1, 2];
where U2: zzx() -> Vector3[2, 2, 0];
where U2: zzy() -> Vector3[2, 2, 1];
where U2: zzz() -> Vector3[2, 2, 2]
); );

View File

@ -15,7 +15,7 @@ use alga::linear::NormedSpace;
/// A wrapper that ensures the underlying algebraic entity has a unit norm. /// A wrapper that ensures the underlying algebraic entity has a unit norm.
/// ///
/// Use `.as_ref()` or `.unwrap()` to obtain the underlying value by-reference or by-move. /// Use `.as_ref()` or `.into_inner()` to obtain the underlying value by-reference or by-move.
#[repr(transparent)] #[repr(transparent)]
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
pub struct Unit<T> { pub struct Unit<T> {
@ -113,6 +113,14 @@ impl<T> Unit<T> {
/// Retrieves the underlying value. /// Retrieves the underlying value.
#[inline] #[inline]
pub fn into_inner(self) -> T {
self.value
}
/// Retrieves the underlying value.
/// Deprecated: use [Unit::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> T { pub fn unwrap(self) -> T {
self.value self.value
} }
@ -143,7 +151,7 @@ where T::Field: RelativeEq
{ {
#[inline] #[inline]
fn to_superset(&self) -> T { fn to_superset(&self) -> T {
self.clone().unwrap() self.clone().into_inner()
} }
#[inline] #[inline]

View File

@ -1,6 +1,5 @@
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
use std::ops::Deref;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
@ -24,21 +23,25 @@ use abomonation::Abomonation;
#[repr(C)] #[repr(C)]
#[derive(Eq, Debug, Clone, PartialEq)] #[derive(Eq, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct MatrixVec<N, R: Dim, C: Dim> { pub struct VecStorage<N, R: Dim, C: Dim> {
data: Vec<N>, data: Vec<N>,
nrows: R, nrows: R,
ncols: C, ncols: C,
} }
impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> { #[deprecated(note="renamed to `VecStorage`")]
/// Renamed to [VecStorage].
pub type MatrixVec<N, R, C> = VecStorage<N, R, C>;
impl<N, R: Dim, C: Dim> VecStorage<N, R, C> {
/// Creates a new dynamic matrix data storage from the given vector and shape. /// Creates a new dynamic matrix data storage from the given vector and shape.
#[inline] #[inline]
pub fn new(nrows: R, ncols: C, data: Vec<N>) -> MatrixVec<N, R, C> { pub fn new(nrows: R, ncols: C, data: Vec<N>) -> VecStorage<N, R, C> {
assert!( assert!(
nrows.value() * ncols.value() == data.len(), nrows.value() * ncols.value() == data.len(),
"Data storage buffer dimension mismatch." "Data storage buffer dimension mismatch."
); );
MatrixVec { VecStorage {
data: data, data: data,
nrows: nrows, nrows: nrows,
ncols: ncols, ncols: ncols,
@ -47,15 +50,16 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
/// The underlying data storage. /// The underlying data storage.
#[inline] #[inline]
pub fn data(&self) -> &Vec<N> { pub fn as_vec(&self) -> &Vec<N> {
&self.data &self.data
} }
/// The underlying mutable data storage. /// The underlying mutable data storage.
/// ///
/// This is unsafe because this may cause UB if the vector is modified by the user. /// This is unsafe because this may cause UB if the size of the vector is changed
/// by the user.
#[inline] #[inline]
pub unsafe fn data_mut(&mut self) -> &mut Vec<N> { pub unsafe fn as_vec_mut(&mut self) -> &mut Vec<N> {
&mut self.data &mut self.data
} }
@ -77,14 +81,18 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
self.data self.data
} }
/// The number of elements on the underlying vector.
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
} }
impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> { impl<N, R: Dim, C: Dim> Into<Vec<N>> for VecStorage<N, R, C>
type Target = Vec<N>; {
fn into(self) -> Vec<N> {
#[inline] self.data
fn deref(&self) -> &Self::Target {
&self.data
} }
} }
@ -94,7 +102,7 @@ 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 VecStorage<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
{ {
type RStride = U1; type RStride = U1;
@ -134,11 +142,11 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
#[inline] #[inline]
fn as_slice(&self) -> &[N] { fn as_slice(&self) -> &[N] {
&self[..] &self.data
} }
} }
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dynamic> unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for VecStorage<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
{ {
type RStride = U1; type RStride = U1;
@ -178,7 +186,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
#[inline] #[inline]
fn as_slice(&self) -> &[N] { fn as_slice(&self) -> &[N] {
&self[..] &self.data
} }
} }
@ -187,7 +195,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
* StorageMut, ContiguousStorage. * 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 VecStorage<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
{ {
#[inline] #[inline]
@ -201,13 +209,13 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
} }
} }
unsafe impl<N: Scalar, C: Dim> ContiguousStorage<N, Dynamic, C> for MatrixVec<N, Dynamic, C> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self> unsafe impl<N: Scalar, C: Dim> ContiguousStorage<N, Dynamic, C> for VecStorage<N, Dynamic, C> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
{} {}
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, C: Dim> ContiguousStorageMut<N, Dynamic, C> for VecStorage<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> unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for VecStorage<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
{ {
#[inline] #[inline]
@ -222,7 +230,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
} }
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for MatrixVec<N, R, C> { impl<N: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<N, R, C> {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> { unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
self.data.entomb(writer) self.data.entomb(writer)
} }
@ -236,21 +244,21 @@ impl<N: Abomonation, R: Dim, C: Dim> Abomonation for MatrixVec<N, R, C> {
} }
} }
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> ContiguousStorage<N, R, Dynamic> for VecStorage<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> unsafe impl<N: Scalar, R: DimName> ContiguousStorageMut<N, R, Dynamic> for VecStorage<N, R, Dynamic> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
{} {}
impl<N, R: Dim> Extend<N> for MatrixVec<N, R, Dynamic> impl<N, R: Dim> Extend<N> for VecStorage<N, R, Dynamic>
{ {
/// Extends the number of columns of the `MatrixVec` with elements /// Extends the number of columns of the `VecStorage` with elements
/// from the given iterator. /// from the given iterator.
/// ///
/// # Panics /// # Panics
/// This function panics if the number of elements yielded by the /// This function panics if the number of elements yielded by the
/// given iterator is not a multiple of the number of rows of the /// given iterator is not a multiple of the number of rows of the
/// `MatrixVec`. /// `VecStorage`.
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
{ {
self.data.extend(iter); self.data.extend(iter);
@ -260,7 +268,7 @@ impl<N, R: Dim> Extend<N> for MatrixVec<N, R, Dynamic>
} }
} }
impl<N, R, RV, SV> Extend<Vector<N, RV, SV>> for MatrixVec<N, R, Dynamic> impl<N, R, RV, SV> Extend<Vector<N, RV, SV>> for VecStorage<N, R, Dynamic>
where where
N: Scalar, N: Scalar,
R: Dim, R: Dim,
@ -268,13 +276,13 @@ where
SV: Storage<N, RV>, SV: Storage<N, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>, ShapeConstraint: SameNumberOfRows<R, RV>,
{ {
/// Extends the number of columns of the `MatrixVec` with vectors /// Extends the number of columns of the `VecStorage` with vectors
/// from the given iterator. /// from the given iterator.
/// ///
/// # Panics /// # Panics
/// This function panics if the number of rows of each `Vector` /// This function panics if the number of rows of each `Vector`
/// yielded by the iterator is not equal to the number of rows /// yielded by the iterator is not equal to the number of rows
/// of this `MatrixVec`. /// of this `VecStorage`.
fn extend<I: IntoIterator<Item=Vector<N, RV, SV>>>(&mut self, iter: I) fn extend<I: IntoIterator<Item=Vector<N, RV, SV>>>(&mut self, iter: I)
{ {
let nrows = self.nrows.value(); let nrows = self.nrows.value();
@ -289,9 +297,9 @@ where
} }
} }
impl<N> Extend<N> for MatrixVec<N, Dynamic, U1> impl<N> Extend<N> for VecStorage<N, Dynamic, U1>
{ {
/// Extends the number of rows of the `MatrixVec` with elements /// Extends the number of rows of the `VecStorage` with elements
/// from the given iterator. /// from the given iterator.
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
{ {

View File

@ -48,6 +48,7 @@ where
Owned<N, D, D>: Clone + Send, Owned<N, D, D>: Clone + Send,
{ {
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
use rand::Rng;
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50)); let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
Self::new(D::from_usize(dim), || N::arbitrary(g)) Self::new(D::from_usize(dim), || N::arbitrary(g))
} }

View File

@ -49,6 +49,7 @@ where
Owned<N, D, D>: Clone + Send, Owned<N, D, D>: Clone + Send,
{ {
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
use rand::Rng;
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50)); let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
Self::new(D::from_usize(dim), || N::arbitrary(g)) Self::new(D::from_usize(dim), || N::arbitrary(g))
} }

View File

@ -113,7 +113,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0); /// let tra = Translation3::new(0.0, 0.0, 3.0);
@ -167,7 +166,7 @@ where DefaultAllocator: Allocator<N, D>
/// ``` /// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
self.rotation.inverse_mut(); self.rotation.two_sided_inverse_mut();
self.translation.inverse_mut(); self.translation.inverse_mut();
self.translation.vector = self.rotation.transform_vector(&self.translation.vector); self.translation.vector = self.rotation.transform_vector(&self.translation.vector);
} }
@ -197,7 +196,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2}; /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0); /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0);
@ -220,7 +218,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2}; /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
@ -272,7 +269,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Vector2, Matrix3}; /// # use nalgebra::{Isometry2, Vector2, Matrix3};
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6); /// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::Isometry as AlgaIsometry; use alga::linear::Isometry as AlgaIsometry;
use alga::linear::{ use alga::linear::{
@ -30,18 +30,18 @@ where
} }
} }
impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Isometry<N, D, R> impl<N: Real, D: DimName, R> TwoSidedInverse<Multiplicative> for Isometry<N, D, R>
where where
R: Rotation<Point<N, D>>, R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -16,7 +16,7 @@ use base::{DefaultAllocator, Vector2, Vector3};
use geometry::{ use geometry::{
Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex, Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex,
UnitQuaternion, UnitQuaternion, Translation2, Translation3
}; };
impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R> impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R>
@ -49,7 +49,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, UnitComplex}; /// # use nalgebra::{Isometry2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::PI); /// let rot = UnitComplex::new(f32::consts::PI);
@ -130,6 +129,18 @@ impl<N: Real> Isometry<N, U2, Rotation2<N>> {
Rotation::<N, U2>::new(angle), Rotation::<N, U2>::new(angle),
) )
} }
/// Creates a new isometry from the given translation coordinates.
#[inline]
pub fn translation(x: N, y: N) -> Self {
Self::new(Vector2::new(x, y), N::zero())
}
/// Creates a new isometry from the given rotation angle.
#[inline]
pub fn rotation(angle: N) -> Self {
Self::new(Vector2::zeros(), angle)
}
} }
impl<N: Real> Isometry<N, U2, UnitComplex<N>> { impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
@ -153,6 +164,18 @@ impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
UnitComplex::from_angle(angle), UnitComplex::from_angle(angle),
) )
} }
/// Creates a new isometry from the given translation coordinates.
#[inline]
pub fn translation(x: N, y: N) -> Self {
Self::from_parts(Translation2::new(x, y), UnitComplex::identity())
}
/// Creates a new isometry from the given rotation angle.
#[inline]
pub fn rotation(angle: N) -> Self {
Self::new(Vector2::zeros(), angle)
}
} }
// 3D rotation. // 3D rotation.
@ -165,7 +188,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -191,6 +213,18 @@ macro_rules! isometry_construction_impl(
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle)) $RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
} }
/// Creates a new isometry from the given translation coordinates.
#[inline]
pub fn translation(x: N, y: N, z: N) -> Self {
Self::from_parts(Translation3::new(x, y, z), $RotId::identity())
}
/// Creates a new isometry from the given rotation angle.
#[inline]
pub fn rotation(axisangle: Vector3<N>) -> Self {
Self::new(Vector3::zeros(), axisangle)
}
/// 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
/// point `eye` and looking toward `target`. /// point `eye` and looking toward `target`.
/// ///
@ -206,7 +240,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -214,23 +247,32 @@ macro_rules! isometry_construction_impl(
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// // Isometry with its rotation part represented as a UnitQuaternion /// // Isometry with its rotation part represented as a UnitQuaternion
/// let iso = Isometry3::new_observer_frame(&eye, &target, &up); /// let iso = Isometry3::face_towards(&eye, &target, &up);
/// assert_eq!(iso * Point3::origin(), eye); /// assert_eq!(iso * Point3::origin(), eye);
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x()); /// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
/// ///
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix). /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let iso = IsometryMatrix3::new_observer_frame(&eye, &target, &up); /// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
/// assert_eq!(iso * Point3::origin(), eye); /// assert_eq!(iso * Point3::origin(), eye);
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x()); /// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame(eye: &Point3<N>, pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
up: &Vector3<N>) up: &Vector3<N>)
-> Self { -> Self {
Self::from_parts( Self::from_parts(
Translation::from(eye.coords.clone()), Translation::from(eye.coords.clone()),
$RotId::new_observer_frame(&(target - eye), up)) $RotId::face_towards(&(target - eye), up))
}
/// Deprecated: Use [Isometry::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>)
-> Self {
Self::face_towards(eye, target, up)
} }
/// Builds a right-handed look-at view matrix. /// Builds a right-handed look-at view matrix.
@ -249,7 +291,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -293,7 +334,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);

View File

@ -200,8 +200,8 @@ isometry_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: Isometry<N, D, 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.two_sided_inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.two_sided_inverse();
); );
// Isometry × R // Isometry × R

View File

@ -37,6 +37,7 @@ mod translation_alga;
mod translation_alias; mod translation_alias;
mod translation_construction; mod translation_construction;
mod translation_conversion; mod translation_conversion;
mod translation_coordinates;
mod translation_ops; mod translation_ops;
mod isometry; mod isometry;
@ -53,6 +54,8 @@ mod similarity_construction;
mod similarity_conversion; mod similarity_conversion;
mod similarity_ops; mod similarity_ops;
mod swizzle;
mod transform; mod transform;
mod transform_alga; mod transform_alga;
mod transform_alias; mod transform_alias;

View File

@ -69,7 +69,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3}; /// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// // Check this projection actually transforms the view cuboid into the double-unit cube. /// // Check this projection actually transforms the view cuboid into the double-unit cube.
@ -170,7 +169,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3, Matrix4}; /// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let inv = proj.inverse(); /// let inv = proj.inverse();
@ -271,7 +269,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3, Matrix4}; /// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let expected = Matrix4::new( /// let expected = Matrix4::new(
@ -280,9 +277,17 @@ impl<N: Real> Orthographic3<N> {
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9, /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
/// 0.0, 0.0, 0.0, 1.0 /// 0.0, 0.0, 0.0, 1.0
/// ); /// );
/// assert_eq!(proj.unwrap(), expected); /// assert_eq!(proj.into_inner(), expected);
/// ``` /// ```
#[inline] #[inline]
pub fn into_inner(self) -> Matrix4<N> {
self.matrix
}
/// Retrieves the underlying homogeneous matrix.
/// Deprecated: Use [Orthographic3::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> Matrix4<N> { pub fn unwrap(self) -> Matrix4<N> {
self.matrix self.matrix
} }
@ -291,7 +296,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6);
@ -308,7 +312,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6);
@ -325,7 +328,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6);
@ -342,7 +344,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6);
@ -359,7 +360,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6); /// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6);
@ -376,7 +376,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6);
@ -395,7 +394,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3}; /// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// ///
@ -431,7 +429,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3}; /// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// ///
@ -470,7 +467,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Vector3}; /// # use nalgebra::{Orthographic3, Vector3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// ///
@ -496,7 +492,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left(2.0); /// proj.set_left(2.0);
@ -516,7 +511,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_right(15.0); /// proj.set_right(15.0);
@ -536,7 +530,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom(8.0); /// proj.set_bottom(8.0);
@ -556,7 +549,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_top(15.0); /// proj.set_top(15.0);
@ -576,7 +568,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear(8.0); /// proj.set_znear(8.0);
@ -596,7 +587,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_zfar(15.0); /// proj.set_zfar(15.0);
@ -616,7 +606,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left_and_right(7.0, 70.0); /// proj.set_left_and_right(7.0, 70.0);
@ -642,7 +631,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom_and_top(7.0, 70.0); /// proj.set_bottom_and_top(7.0, 70.0);
@ -668,7 +656,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear_and_zfar(50.0, 5000.0); /// proj.set_znear_and_zfar(50.0, 5000.0);
@ -725,6 +712,6 @@ where Matrix4<N>: Send
impl<N: Real> From<Orthographic3<N>> for Matrix4<N> { impl<N: Real> From<Orthographic3<N>> for Matrix4<N> {
#[inline] #[inline]
fn from(orth: Orthographic3<N>) -> Self { fn from(orth: Orthographic3<N>) -> Self {
orth.unwrap() orth.into_inner()
} }
} }

View File

@ -141,6 +141,14 @@ impl<N: Real> Perspective3<N> {
/// Retrieves the underlying homogeneous matrix. /// Retrieves the underlying homogeneous matrix.
#[inline] #[inline]
pub fn into_inner(self) -> Matrix4<N> {
self.matrix
}
/// Retrieves the underlying homogeneous matrix.
/// Deprecated: Use [Perspective3::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> Matrix4<N> { pub fn unwrap(self) -> Matrix4<N> {
self.matrix self.matrix
} }
@ -279,6 +287,6 @@ impl<N: Real + Arbitrary> Arbitrary for Perspective3<N> {
impl<N: Real> From<Perspective3<N>> for Matrix4<N> { impl<N: Real> From<Perspective3<N>> for Matrix4<N> {
#[inline] #[inline]
fn from(orth: Perspective3<N>) -> Self { fn from(orth: Perspective3<N>) -> Self {
orth.unwrap() orth.into_inner()
} }
} }

View File

@ -114,7 +114,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let q_normalized = q.normalize(); /// let q_normalized = q.normalize();
@ -150,7 +149,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let inv_q = q.try_inverse(); /// let inv_q = q.try_inverse();
@ -240,7 +238,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6); /// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6);
@ -258,7 +255,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6); /// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6);
@ -345,7 +341,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0); /// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0);
/// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6) /// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6)
@ -364,7 +359,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
/// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5) /// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5)
@ -380,7 +374,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
/// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5); /// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5);
@ -410,7 +403,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6); /// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6);
@ -476,7 +468,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// ///
@ -506,7 +497,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// q.normalize_mut(); /// q.normalize_mut();
@ -672,7 +662,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -691,7 +680,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -747,7 +735,7 @@ impl<N: Real> UnitQuaternion<N> {
Unit::new_unchecked(Quaternion::from( Unit::new_unchecked(Quaternion::from(
Unit::new_unchecked(self.coords) Unit::new_unchecked(self.coords)
.slerp(&Unit::new_unchecked(other.coords), t) .slerp(&Unit::new_unchecked(other.coords), t)
.unwrap(), .into_inner(),
)) ))
} }
@ -771,7 +759,7 @@ impl<N: Real> UnitQuaternion<N> {
{ {
Unit::new_unchecked(self.coords) Unit::new_unchecked(self.coords)
.try_slerp(&Unit::new_unchecked(other.coords), t, epsilon) .try_slerp(&Unit::new_unchecked(other.coords), t, epsilon)
.map(|q| Unit::new_unchecked(Quaternion::from(q.unwrap()))) .map(|q| Unit::new_unchecked(Quaternion::from(q.into_inner())))
} }
/// Compute the conjugate of this unit quaternion in-place. /// Compute the conjugate of this unit quaternion in-place.
@ -785,7 +773,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit}; /// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let mut rot = UnitQuaternion::new(axisangle); /// let mut rot = UnitQuaternion::new(axisangle);
@ -828,7 +815,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit}; /// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = UnitQuaternion::new(axisangle); /// let rot = UnitQuaternion::new(axisangle);
@ -837,7 +823,7 @@ impl<N: Real> UnitQuaternion<N> {
#[inline] #[inline]
pub fn scaled_axis(&self) -> Vector3<N> { pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
axis.unwrap() * self.angle() axis.into_inner() * self.angle()
} else { } else {
Vector3::zero() Vector3::zero()
} }
@ -885,7 +871,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion}; /// # use nalgebra::{Vector3, UnitQuaternion};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let q = UnitQuaternion::new(axisangle); /// let q = UnitQuaternion::new(axisangle);
@ -894,7 +879,7 @@ impl<N: Real> UnitQuaternion<N> {
#[inline] #[inline]
pub fn ln(&self) -> Quaternion<N> { pub fn ln(&self) -> Quaternion<N> {
if let Some(v) = self.axis() { if let Some(v) = self.axis() {
Quaternion::from_parts(N::zero(), v.unwrap() * self.angle()) Quaternion::from_parts(N::zero(), v.into_inner() * self.angle())
} else { } else {
Quaternion::zero() Quaternion::zero()
} }
@ -908,7 +893,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit}; /// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -932,7 +916,6 @@ impl<N: Real> UnitQuaternion<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix3}; /// # use nalgebra::{UnitQuaternion, Vector3, Matrix3};
/// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
@ -990,7 +973,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitQuaternion; /// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3); /// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -1009,7 +991,6 @@ impl<N: Real> UnitQuaternion<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix4}; /// # use nalgebra::{UnitQuaternion, Vector3, Matrix4};
/// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
@ -1029,7 +1010,7 @@ impl<N: Real> UnitQuaternion<N> {
impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> { impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> {
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.into_inner();
write!( write!(
f, f,
"UnitQuaternion angle: {} axis: ({}, {}, {})", "UnitQuaternion angle: {} axis: ({}, {}, {})",

View File

@ -2,7 +2,7 @@ use num::Zero;
use alga::general::{ use alga::general::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Inverse, Module, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module,
Multiplicative, Real, Multiplicative, Real,
}; };
use alga::linear::{ use alga::linear::{
@ -42,9 +42,9 @@ impl<N: Real> AbstractMagma<Additive> for Quaternion<N> {
} }
} }
impl<N: Real> Inverse<Additive> for Quaternion<N> { impl<N: Real> TwoSidedInverse<Additive> for Quaternion<N> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
-self -self
} }
} }
@ -173,14 +173,14 @@ impl<N: Real> AbstractMagma<Multiplicative> for UnitQuaternion<N> {
} }
} }
impl<N: Real> Inverse<Multiplicative> for UnitQuaternion<N> { impl<N: Real> TwoSidedInverse<Multiplicative> for UnitQuaternion<N> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -76,7 +76,7 @@ impl<N: Real> Quaternion<N> {
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64)); let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64));
rot.unwrap() * scale rot.into_inner() * scale
} }
/// The quaternion multiplicative identity. /// The quaternion multiplicative identity.
@ -166,7 +166,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axis = Vector3::y_axis(); /// let axis = Vector3::y_axis();
@ -208,7 +207,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitQuaternion; /// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3); /// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -237,7 +235,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, UnitQuaternion, Vector3}; /// # use nalgebra::{Rotation3, UnitQuaternion, Vector3};
/// let axis = Vector3::y_axis(); /// let axis = Vector3::y_axis();
/// let angle = 0.1; /// let angle = 0.1;
@ -302,7 +299,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion}; /// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -325,7 +321,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion}; /// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -361,7 +356,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion}; /// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0)); /// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
@ -387,7 +381,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion}; /// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0)); /// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
@ -446,22 +439,31 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// let q = UnitQuaternion::new_observer_frame(&dir, &up); /// let q = UnitQuaternion::face_towards(&dir, &up);
/// assert_relative_eq!(q * Vector3::z(), dir.normalize()); /// assert_relative_eq!(q * Vector3::z(), dir.normalize());
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::from_rotation_matrix(&Rotation::<N, U3>::new_observer_frame(dir, up)) Self::from_rotation_matrix(&Rotation::<N, U3>::face_towards(dir, up))
}
/// Deprecated: Use [UnitQuaternion::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::face_towards(dir, up)
} }
/// Builds a right-handed look-at view matrix without translation. /// Builds a right-handed look-at view matrix without translation.
@ -478,7 +480,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -493,7 +494,7 @@ impl<N: Real> UnitQuaternion<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(&-dir, up).inverse() Self::face_towards(&-dir, up).inverse()
} }
/// Builds a left-handed look-at view matrix without translation. /// Builds a left-handed look-at view matrix without translation.
@ -510,7 +511,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -525,7 +525,7 @@ impl<N: Real> UnitQuaternion<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(dir, up).inverse() Self::face_towards(dir, up).inverse()
} }
/// 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.
@ -535,7 +535,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -565,7 +564,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -596,7 +594,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -625,7 +622,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -693,15 +689,16 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate rand_xorshift;
use super::*; use super::*;
use rand::{self, SeedableRng}; use rand::SeedableRng;
#[test] #[test]
fn random_unit_quats_are_unit() { fn random_unit_quats_are_unit() {
let mut rng = rand::prng::XorShiftRng::from_seed([0xAB; 16]); let mut rng = rand_xorshift::XorShiftRng::from_seed([0xAB; 16]);
for _ in 0..1000 { for _ in 0..1000 {
let x = rng.gen::<UnitQuaternion<f32>>(); let x = rng.gen::<UnitQuaternion<f32>>();
assert!(relative_eq!(x.unwrap().norm(), 1.0)) assert!(relative_eq!(x.into_inner().norm(), 1.0))
} }
} }
} }

View File

@ -228,7 +228,7 @@ impl<N: Real> From<UnitQuaternion<N>> for Matrix4<N> {
impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> { impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> {
#[inline] #[inline]
fn from(q: UnitQuaternion<N>) -> Matrix3<N> { fn from(q: UnitQuaternion<N>) -> Matrix3<N> {
q.to_rotation_matrix().unwrap() q.to_rotation_matrix().into_inner()
} }
} }

View File

@ -469,7 +469,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1) for SB: Storage<N, U3> ; (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>, self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<Vector3<N>> => U3, U4; Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap()); Unit::new_unchecked(self * rhs.into_inner());
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
@ -485,7 +485,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1) for SB: Storage<N, U3> ; (U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>, self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<Vector3<N>> => U3, U4; Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap()); Unit::new_unchecked(self * rhs.into_inner());
); );
macro_rules! scalar_op_impl( macro_rules! scalar_op_impl(

View File

@ -20,7 +20,7 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
/// represents a plane that passes through the origin. /// represents a plane that passes through the origin.
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> { pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> {
Reflection { Reflection {
axis: axis.unwrap(), axis: axis.into_inner(),
bias: bias, bias: bias,
} }
} }

View File

@ -154,7 +154,7 @@ where DefaultAllocator: Allocator<N, D, D>
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3};
/// # use std::f32; /// # use std::f32;
/// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
/// let mat = rot.unwrap(); /// let mat = rot.into_inner();
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0, /// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0, /// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0); /// 0.0, 0.0, 1.0);
@ -162,12 +162,20 @@ where DefaultAllocator: Allocator<N, D, D>
/// ///
/// ///
/// let rot = Rotation2::new(f32::consts::FRAC_PI_6); /// let rot = Rotation2::new(f32::consts::FRAC_PI_6);
/// let mat = rot.unwrap(); /// let mat = rot.into_inner();
/// let expected = Matrix2::new(0.8660254, -0.5, /// let expected = Matrix2::new(0.8660254, -0.5,
/// 0.5, 0.8660254); /// 0.5, 0.8660254);
/// assert_eq!(mat, expected); /// assert_eq!(mat, expected);
/// ``` /// ```
#[inline] #[inline]
pub fn into_inner(self) -> MatrixN<N, D> {
self.matrix
}
/// Unwraps the underlying matrix.
/// Deprecated: Use [Rotation::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> MatrixN<N, D> { pub fn unwrap(self) -> MatrixN<N, D> {
self.matrix self.matrix
} }
@ -201,6 +209,9 @@ where DefaultAllocator: Allocator<N, D, D>
D: DimNameAdd<U1>, D: DimNameAdd<U1>,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{ {
// We could use `MatrixN::to_homogeneous()` here, but that would imply
// adding the additional traits `DimAdd` and `IsNotStaticOne`. Maybe
// these things will get nicer once specialization lands in Rust.
let mut res = MatrixN::<N, DimNameSum<D, U1>>::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);
@ -246,7 +257,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let tr_rot = rot.transpose(); /// let tr_rot = rot.transpose();
@ -270,7 +280,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let inv = rot.inverse(); /// let inv = rot.inverse();
@ -294,7 +303,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
@ -322,7 +330,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::{ use alga::linear::{
self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
@ -27,16 +27,16 @@ where DefaultAllocator: Allocator<N, D, D>
} }
} }
impl<N: Real, D: DimName> Inverse<Multiplicative> for Rotation<N, D> impl<N: Real, D: DimName> TwoSidedInverse<Multiplicative> for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.transpose() self.transpose()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.transpose_mut() self.transpose_mut()
} }
} }

View File

@ -227,7 +227,7 @@ impl<N: Real> From<Rotation2<N>> for Matrix3<N> {
impl<N: Real> From<Rotation2<N>> for Matrix2<N> { impl<N: Real> From<Rotation2<N>> for Matrix2<N> {
#[inline] #[inline]
fn from(q: Rotation2<N>) -> Matrix2<N> { fn from(q: Rotation2<N>) -> Matrix2<N> {
q.unwrap() q.into_inner()
} }
} }
@ -241,6 +241,6 @@ impl<N: Real> From<Rotation3<N>> for Matrix4<N> {
impl<N: Real> From<Rotation3<N>> for Matrix3<N> { impl<N: Real> From<Rotation3<N>> for Matrix3<N> {
#[inline] #[inline]
fn from(q: Rotation3<N>) -> Matrix3<N> { fn from(q: Rotation3<N>) -> Matrix3<N> {
q.unwrap() q.into_inner()
} }
} }

View File

@ -46,9 +46,9 @@ md_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, D) for D: DimName; (D, D), (D, D) for D: DimName;
self: Rotation<N, D>, right: Rotation<N, D>, Output = Rotation<N, D>; self: Rotation<N, D>, right: Rotation<N, D>, Output = Rotation<N, D>;
[val val] => Rotation::from_matrix_unchecked(self.unwrap() * right.unwrap()); [val val] => Rotation::from_matrix_unchecked(self.into_inner() * right.into_inner());
[ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.unwrap()); [ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.into_inner());
[val ref] => Rotation::from_matrix_unchecked(self.unwrap() * right.matrix()); [val ref] => Rotation::from_matrix_unchecked(self.into_inner() * right.matrix());
[ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix()); [ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix());
); );
@ -71,9 +71,9 @@ md_impl_all!(
where DefaultAllocator: 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: Rotation<N, D1>, right: Matrix<N, R2, C2, SB>, Output = MatrixMN<N, D1, C2>; self: Rotation<N, D1>, right: Matrix<N, R2, C2, SB>, Output = MatrixMN<N, D1, C2>;
[val val] => self.unwrap() * right; [val val] => self.into_inner() * right;
[ref val] => self.matrix() * right; [ref val] => self.matrix() * right;
[val ref] => self.unwrap() * right; [val ref] => self.into_inner() * right;
[ref ref] => self.matrix() * right; [ref ref] => self.matrix() * right;
); );
@ -84,8 +84,8 @@ md_impl_all!(
where DefaultAllocator: 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: Rotation<N, D2>, Output = MatrixMN<N, R1, D2>; self: Matrix<N, R1, C1, SA>, right: Rotation<N, D2>, Output = MatrixMN<N, R1, D2>;
[val val] => self * right.unwrap(); [val val] => self * right.into_inner();
[ref val] => self * right.unwrap(); [ref val] => self * right.into_inner();
[val ref] => self * right.matrix(); [val ref] => self * right.matrix();
[ref ref] => self * right.matrix(); [ref ref] => self * right.matrix();
); );
@ -112,9 +112,9 @@ md_impl_all!(
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
where ShapeConstraint: AreMultipliable<D, D, D, U1>; where ShapeConstraint: AreMultipliable<D, D, D, U1>;
self: Rotation<N, D>, right: Point<N, D>, Output = Point<N, D>; self: Rotation<N, D>, right: Point<N, D>, Output = Point<N, D>;
[val val] => self.unwrap() * right; [val val] => self.into_inner() * right;
[ref val] => self.matrix() * right; [ref val] => self.matrix() * right;
[val ref] => self.unwrap() * right; [val ref] => self.into_inner() * right;
[ref ref] => self.matrix() * right; [ref ref] => self.matrix() * right;
); );
@ -125,9 +125,9 @@ md_impl_all!(
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
where ShapeConstraint: AreMultipliable<D, D, D, U1>; where ShapeConstraint: AreMultipliable<D, D, D, U1>;
self: Rotation<N, D>, right: Unit<Vector<N, D, S>>, Output = Unit<VectorN<N, D>>; self: Rotation<N, D>, right: Unit<Vector<N, D, S>>, Output = Unit<VectorN<N, D>>;
[val val] => Unit::new_unchecked(self.unwrap() * right.unwrap()); [val val] => Unit::new_unchecked(self.into_inner() * right.into_inner());
[ref val] => Unit::new_unchecked(self.matrix() * right.unwrap()); [ref val] => Unit::new_unchecked(self.matrix() * right.into_inner());
[val ref] => Unit::new_unchecked(self.unwrap() * right.as_ref()); [val ref] => Unit::new_unchecked(self.into_inner() * right.as_ref());
[ref ref] => Unit::new_unchecked(self.matrix() * right.as_ref()); [ref ref] => Unit::new_unchecked(self.matrix() * right.as_ref());
); );
@ -138,7 +138,7 @@ 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: Rotation<N, D>, right: Rotation<N, D>; self: Rotation<N, D>, right: Rotation<N, D>;
[val] => self.matrix_mut_unchecked().mul_assign(right.unwrap()); [val] => self.matrix_mut_unchecked().mul_assign(right.into_inner());
[ref] => self.matrix_mut_unchecked().mul_assign(right.matrix()); [ref] => self.matrix_mut_unchecked().mul_assign(right.matrix());
); );
@ -146,7 +146,7 @@ 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: Rotation<N, D>, right: Rotation<N, D>; self: Rotation<N, D>, right: Rotation<N, D>;
[val] => self.matrix_mut_unchecked().mul_assign(right.inverse().unwrap()); [val] => self.matrix_mut_unchecked().mul_assign(right.inverse().into_inner());
[ref] => self.matrix_mut_unchecked().mul_assign(right.inverse().matrix()); [ref] => self.matrix_mut_unchecked().mul_assign(right.inverse().matrix());
); );
@ -160,7 +160,7 @@ 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: MatrixMN<N, R1, C1>, right: Rotation<N, C1>; self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
[val] => self.mul_assign(right.unwrap()); [val] => self.mul_assign(right.into_inner());
[ref] => self.mul_assign(right.matrix()); [ref] => self.mul_assign(right.matrix());
); );
@ -168,6 +168,6 @@ 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: MatrixMN<N, R1, C1>, right: Rotation<N, C1>; self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
[val] => self.mul_assign(right.inverse().unwrap()); [val] => self.mul_assign(right.inverse().into_inner());
[ref] => self.mul_assign(right.inverse().matrix()); [ref] => self.mul_assign(right.inverse().matrix());
); );

View File

@ -27,7 +27,6 @@ impl<N: Real> Rotation2<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation2, Point2}; /// # use nalgebra::{Rotation2, Point2};
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2); /// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
@ -56,7 +55,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2}; /// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -79,7 +77,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2}; /// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -107,9 +104,10 @@ impl<N: Real> Rotation2<N> {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(1.78); /// let rot = Rotation2::new(1.78);
/// assert_eq!(rot.angle(), 1.78); /// assert_relative_eq!(rot.angle(), 1.78);
/// ``` /// ```
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
@ -121,7 +119,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1); /// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7); /// let rot2 = Rotation2::new(1.7);
@ -139,7 +136,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1); /// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7); /// let rot2 = Rotation2::new(1.7);
@ -158,10 +154,11 @@ impl<N: Real> Rotation2<N> {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(0.78); /// let rot = Rotation2::new(0.78);
/// let pow = rot.powf(2.0); /// let pow = rot.powf(2.0);
/// assert_eq!(pow.angle(), 2.0 * 0.78); /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ``` /// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Rotation2<N> { pub fn powf(&self, n: N) -> Rotation2<N> {
@ -213,7 +210,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3}; /// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -241,7 +237,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3}; /// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -265,7 +260,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3}; /// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axis = Vector3::y_axis(); /// let axis = Vector3::y_axis();
@ -318,7 +312,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3; /// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -359,7 +352,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3; /// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -370,12 +362,12 @@ impl<N: Real> Rotation3<N> {
pub fn euler_angles(&self) -> (N, N, N) { pub fn euler_angles(&self) -> (N, N, N) {
// Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 // http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
if self[(2, 0)].abs() != N::one() { if self[(2, 0)].abs() < N::one() {
let yaw = -self[(2, 0)].asin(); let yaw = -self[(2, 0)].asin();
let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos()); let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos());
let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos()); let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos());
(roll, yaw, pitch) (roll, yaw, pitch)
} else if self[(2, 0)] == -N::one() { } else if self[(2, 0)] <= -N::one() {
(self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero()) (self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero())
} else { } else {
( (
@ -399,17 +391,16 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// let rot = Rotation3::new_observer_frame(&dir, &up); /// let rot = Rotation3::face_towards(&dir, &up);
/// assert_relative_eq!(rot * Vector3::z(), dir.normalize()); /// assert_relative_eq!(rot * Vector3::z(), dir.normalize());
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
@ -423,6 +414,16 @@ impl<N: Real> Rotation3<N> {
)) ))
} }
/// Deprecated: Use [Rotation3::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::face_towards(dir, up)
}
/// Builds a right-handed look-at view matrix without translation. /// Builds a right-handed look-at view matrix without translation.
/// ///
/// It maps the view direction `dir` to the **negative** `z` axis. /// It maps the view direction `dir` to the **negative** `z` axis.
@ -437,7 +438,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -452,7 +452,7 @@ impl<N: Real> Rotation3<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(&dir.neg(), up).inverse() Self::face_towards(&dir.neg(), up).inverse()
} }
/// Builds a left-handed look-at view matrix without translation. /// Builds a left-handed look-at view matrix without translation.
@ -469,7 +469,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -484,7 +483,7 @@ impl<N: Real> Rotation3<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(dir, up).inverse() Self::face_towards(dir, up).inverse()
} }
/// The rotation matrix required to align `a` and `b` but with its angle. /// The rotation matrix required to align `a` and `b` but with its angle.
@ -494,7 +493,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3}; /// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -517,7 +515,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3}; /// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -562,7 +559,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Rotation3, Vector3}; /// # use nalgebra::{Unit, Rotation3, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = Rotation3::from_axis_angle(&axis, 1.78); /// let rot = Rotation3::from_axis_angle(&axis, 1.78);
@ -580,7 +576,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -607,7 +602,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = Rotation3::new(axisangle); /// let rot = Rotation3::new(axisangle);
@ -616,7 +610,7 @@ impl<N: Real> Rotation3<N> {
#[inline] #[inline]
pub fn scaled_axis(&self) -> Vector3<N> { pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
axis.unwrap() * self.angle() axis.into_inner() * self.angle()
} else { } else {
Vector::zero() Vector::zero()
} }
@ -629,7 +623,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -656,7 +649,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -674,7 +666,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -692,7 +683,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::Similarity as AlgaSimilarity; use alga::linear::Similarity as AlgaSimilarity;
use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation}; use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation};
@ -27,18 +27,18 @@ where
} }
} }
impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Similarity<N, D, R> impl<N: Real, D: DimName, R> TwoSidedInverse<Multiplicative> for Similarity<N, D, R>
where where
R: Rotation<Point<N, D>>, R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -86,7 +86,6 @@ where
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity2, Point2, UnitComplex}; /// # use nalgebra::{Similarity2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
@ -135,7 +134,6 @@ impl<N: Real> Similarity<N, U2, Rotation2<N>> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{SimilarityMatrix2, Vector2, Point2}; /// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
/// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0); /// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
@ -159,7 +157,6 @@ impl<N: Real> Similarity<N, U2, UnitComplex<N>> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity2, Vector2, Point2}; /// # use nalgebra::{Similarity2, Vector2, Point2};
/// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0); /// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
@ -187,7 +184,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -227,7 +223,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -235,22 +230,32 @@ macro_rules! similarity_construction_impl(
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// // Similarity with its rotation part represented as a UnitQuaternion /// // Similarity with its rotation part represented as a UnitQuaternion
/// let sim = Similarity3::new_observer_frame(&eye, &target, &up, 3.0); /// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0);
/// assert_eq!(sim * Point3::origin(), eye); /// assert_eq!(sim * Point3::origin(), eye);
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6); /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
/// ///
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix). /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let sim = SimilarityMatrix3::new_observer_frame(&eye, &target, &up, 3.0); /// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0);
/// assert_eq!(sim * Point3::origin(), eye); /// assert_eq!(sim * Point3::origin(), eye);
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6); /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame(eye: &Point3<N>, pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
up: &Vector3<N>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::new_observer_frame(eye, target, up), scaling) Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling)
}
/// Deprecated: Use [SimilarityMatrix3::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>,
scaling: N)
-> Self {
Self::face_towards(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.
@ -268,7 +273,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -307,7 +311,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);

View File

@ -222,8 +222,8 @@ similarity_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: Similarity<N, D, 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.two_sided_inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.two_sided_inverse();
); );
// Similarity × R // Similarity × R

65
src/geometry/swizzle.rs Normal file
View File

@ -0,0 +1,65 @@
use base::allocator::Allocator;
use base::{DefaultAllocator, DimName, Scalar};
use geometry::{Point, Point2, Point3};
use typenum::{self, Cmp, Greater};
macro_rules! impl_swizzle {
($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => {
$(
impl<N: Scalar, D: DimName> Point<N, D>
where
DefaultAllocator: Allocator<N, D>,
D::Value: Cmp<typenum::$BaseDim, Output=Greater>
{
$(
/// Builds a new point from components of `self`.
#[inline]
pub fn $name(&self) -> $Result<N> {
$Result::new($(self[$i]),*)
}
)*
}
)*
}
}
impl_swizzle!(
where U0: xx() -> Point2[0, 0],
xxx() -> Point3[0, 0, 0];
where U1: xy() -> Point2[0, 1],
yx() -> Point2[1, 0],
yy() -> Point2[1, 1],
xxy() -> Point3[0, 0, 1],
xyx() -> Point3[0, 1, 0],
xyy() -> Point3[0, 1, 1],
yxx() -> Point3[1, 0, 0],
yxy() -> Point3[1, 0, 1],
yyx() -> Point3[1, 1, 0],
yyy() -> Point3[1, 1, 1];
where U2: xz() -> Point2[0, 2],
yz() -> Point2[1, 2],
zx() -> Point2[2, 0],
zy() -> Point2[2, 1],
zz() -> Point2[2, 2],
xxz() -> Point3[0, 0, 2],
xyz() -> Point3[0, 1, 2],
xzx() -> Point3[0, 2, 0],
xzy() -> Point3[0, 2, 1],
xzz() -> Point3[0, 2, 2],
yxz() -> Point3[1, 0, 2],
yyz() -> Point3[1, 1, 2],
yzx() -> Point3[1, 2, 0],
yzy() -> Point3[1, 2, 1],
yzz() -> Point3[1, 2, 2],
zxx() -> Point3[2, 0, 0],
zxy() -> Point3[2, 0, 1],
zxz() -> Point3[2, 0, 2],
zyx() -> Point3[2, 1, 0],
zyy() -> Point3[2, 1, 1],
zyz() -> Point3[2, 1, 2],
zzx() -> Point3[2, 2, 0],
zzy() -> Point3[2, 2, 1],
zzz() -> Point3[2, 2, 2];
);

View File

@ -248,9 +248,17 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// 3.0, 4.0, 0.0, /// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0); /// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m); /// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.unwrap(), m); /// assert_eq!(t.into_inner(), m);
/// ``` /// ```
#[inline] #[inline]
pub fn into_inner(self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix
}
/// Retrieves the underlying matrix.
/// Deprecated: Use [Transform::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> { pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix self.matrix
} }
@ -329,7 +337,7 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// 3.0, 4.0, 0.0, /// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0); /// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m); /// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.unwrap(), m); /// assert_eq!(t.into_inner(), m);
/// ``` /// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> { pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
@ -342,7 +350,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Transform2}; /// # use nalgebra::{Matrix3, Transform2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,
@ -375,7 +382,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Projective2}; /// # use nalgebra::{Matrix3, Projective2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,
@ -399,7 +405,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Transform2}; /// # use nalgebra::{Matrix3, Transform2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,
@ -429,7 +434,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Projective2}; /// # use nalgebra::{Matrix3, Projective2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::{ProjectiveTransformation, Transformation}; use alga::linear::{ProjectiveTransformation, Transformation};
@ -26,18 +26,18 @@ where
} }
} }
impl<N: Real, D: DimNameAdd<U1>, C> Inverse<Multiplicative> for Transform<N, D, C> impl<N: Real, D: DimNameAdd<U1>, C> TwoSidedInverse<Multiplicative> for Transform<N, D, C>
where where
C: SubTCategoryOf<TProjective>, C: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.clone().inverse() self.clone().inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }
@ -116,12 +116,12 @@ where
{ {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self.inverse() * pt self.two_sided_inverse() * pt
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self.inverse() * v self.two_sided_inverse() * v
} }
} }

View File

@ -143,7 +143,7 @@ md_impl_all!(
if C::has_normalizer() { if C::has_normalizer() {
let normalizer = self.matrix().fixed_slice::<U1, D>(D::dim(), 0); let normalizer = self.matrix().fixed_slice::<U1, D>(D::dim(), 0);
let n = normalizer.tr_dot(&rhs.coords) + unsafe { *self.matrix().get_unchecked(D::dim(), D::dim()) }; let n = normalizer.tr_dot(&rhs.coords) + unsafe { *self.matrix().get_unchecked((D::dim(), D::dim())) };
if !n.is_zero() { if !n.is_zero() {
return (transform * rhs + translation) / n; return (transform * rhs + translation) / n;
@ -159,9 +159,9 @@ md_impl_all!(
Mul, mul where N: Real; 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: Transform<N, D, CA>, rhs: Transform<N, D, CB>, Output = Transform<N, D, 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.into_inner() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.matrix()); [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.matrix());
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.matrix()); [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.matrix());
); );
@ -170,9 +170,9 @@ md_impl_all!(
Mul, mul where N: Real; 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>;
self: Transform<N, D, C>, rhs: Rotation<N, D>, Output = Transform<N, D, C::Representative>; self: Transform<N, D, C>, rhs: Rotation<N, D>, 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.into_inner() * 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.into_inner() * 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());
); );
@ -181,8 +181,8 @@ md_impl_all!(
Mul, mul where N: Real; 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>;
self: Rotation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>; self: Rotation<N, D>, 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.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
); );
@ -192,9 +192,9 @@ 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>;
self: Transform<N, U3, C>, rhs: UnitQuaternion<N>, Output = Transform<N, U3, C::Representative>; self: Transform<N, U3, C>, rhs: UnitQuaternion<N>, Output = Transform<N, U3, C::Representative>;
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * 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.into_inner() * 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());
); );
@ -203,8 +203,8 @@ 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>;
self: UnitQuaternion<N>, rhs: Transform<N, U3, C>, Output = Transform<N, U3, C::Representative>; self: UnitQuaternion<N>, rhs: Transform<N, U3, C>, Output = Transform<N, U3, 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.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
); );
@ -215,9 +215,9 @@ md_impl_all!(
(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<MatrixN<N, DimNameSum<D, U1>> >; for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, 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.to_homogeneous()); [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * 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.into_inner() * 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());
); );
@ -227,8 +227,8 @@ md_impl_all!(
(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<MatrixN<N, DimNameSum<D, U1>> >; for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, 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.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
); );
@ -239,9 +239,9 @@ md_impl_all!(
(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<MatrixN<N, DimNameSum<D, U1>> >; for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, 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.into_inner() * 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.into_inner() * 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());
); );
@ -251,8 +251,8 @@ md_impl_all!(
(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<MatrixN<N, DimNameSum<D, U1>> >; for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, 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.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
); );
@ -270,9 +270,9 @@ 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>;
self: Transform<N, D, C>, rhs: Translation<N, D>, Output = Transform<N, D, C::Representative>; self: Transform<N, D, C>, rhs: Translation<N, D>, 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.into_inner() * 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.into_inner() * 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());
); );
@ -282,8 +282,8 @@ md_impl_all!(
(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>;
self: Translation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>; self: Translation<N, D>, 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.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
); );
@ -350,9 +350,9 @@ md_impl_all!(
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> > // 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: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, 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.into_inner() * 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.into_inner() * 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());
// ); // );
@ -363,8 +363,8 @@ md_impl_all!(
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> > // 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: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, 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.into_inner());
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); // [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); // [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
// ); // );
@ -377,9 +377,9 @@ md_impl_all!(
// 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: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, 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.into_inner() * 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.into_inner() * 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());
// ); // );
@ -391,8 +391,8 @@ md_impl_all!(
// 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: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, 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.into_inner());
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap()); // [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); // [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); // [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
// ); // );
@ -425,7 +425,7 @@ md_assign_impl_all!(
MulAssign, mul_assign where N: Real; 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: Transform<N, D, CA>, rhs: Transform<N, D, CB>; self: Transform<N, D, CA>, rhs: Transform<N, D, CB>;
[val] => *self.matrix_mut_unchecked() *= rhs.unwrap(); [val] => *self.matrix_mut_unchecked() *= rhs.into_inner();
[ref] => *self.matrix_mut_unchecked() *= rhs.matrix(); [ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
); );

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::Translation as AlgaTranslation; use alga::linear::Translation as AlgaTranslation;
use alga::linear::{ use alga::linear::{
@ -28,16 +28,16 @@ where DefaultAllocator: Allocator<N, D>
} }
} }
impl<N: Real, D: DimName> Inverse<Multiplicative> for Translation<N, D> impl<N: Real, D: DimName> TwoSidedInverse<Multiplicative> for Translation<N, D>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -0,0 +1,44 @@
use std::mem;
use std::ops::{Deref, DerefMut};
use base::allocator::Allocator;
use base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
use base::dimension::{U1, U2, U3, U4, U5, U6};
use base::{DefaultAllocator, Scalar};
use geometry::Translation;
/*
*
* Give coordinates to Translation{1 .. 6}
*
*/
macro_rules! deref_impl(
($D: ty, $Target: ident $(, $comps: ident)*) => {
impl<N: Scalar> Deref for Translation<N, $D>
where DefaultAllocator: Allocator<N, $D> {
type Target = $Target<N>;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) }
}
}
impl<N: Scalar> DerefMut for Translation<N, $D>
where DefaultAllocator: Allocator<N, $D> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) }
}
}
}
);
deref_impl!(U1, X, x);
deref_impl!(U2, XY, x, y);
deref_impl!(U3, XYZ, x, y, z);
deref_impl!(U4, XYZW, x, y, z, w);
deref_impl!(U5, XYZWA, x, y, z, w, a);
deref_impl!(U6, XYZWAB, x, y, z, w, a, b);

View File

@ -85,7 +85,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # extern crate num_complex; /// # extern crate num_complex;
/// # extern crate nalgebra;
/// # use num_complex::Complex; /// # use num_complex::Complex;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let angle = 1.78f32; /// let angle = 1.78f32;
@ -117,7 +116,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(1.2); /// let rot = UnitComplex::new(1.2);
/// let inv = rot.inverse(); /// let inv = rot.inverse();
@ -134,7 +132,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot1 = UnitComplex::new(0.1); /// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7); /// let rot2 = UnitComplex::new(1.7);
@ -153,7 +150,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot1 = UnitComplex::new(0.1); /// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7); /// let rot2 = UnitComplex::new(1.7);
@ -172,7 +168,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let angle = 1.7; /// let angle = 1.7;
/// let rot = UnitComplex::new(angle); /// let rot = UnitComplex::new(angle);
@ -192,7 +187,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let angle = 1.7; /// let angle = 1.7;
/// let mut rot = UnitComplex::new(angle); /// let mut rot = UnitComplex::new(angle);
@ -212,10 +206,11 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(0.78); /// let rot = UnitComplex::new(0.78);
/// let pow = rot.powf(2.0); /// let pow = rot.powf(2.0);
/// assert_eq!(pow.angle(), 2.0 * 0.78); /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ``` /// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Self { pub fn powf(&self, n: N) -> Self {
@ -320,6 +315,6 @@ impl<N: Real> From<UnitComplex<N>> for Matrix3<N> {
impl<N: Real> From<UnitComplex<N>> for Matrix2<N> { impl<N: Real> From<UnitComplex<N>> for Matrix2<N> {
#[inline] #[inline]
fn from(q: UnitComplex<N>) -> Matrix2<N> { fn from(q: UnitComplex<N>) -> Matrix2<N> {
q.to_rotation_matrix().unwrap() q.to_rotation_matrix().into_inner()
} }
} }

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::{ use alga::linear::{
AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
@ -31,14 +31,14 @@ impl<N: Real> AbstractMagma<Multiplicative> for UnitComplex<N> {
} }
} }
impl<N: Real> Inverse<Multiplicative> for UnitComplex<N> { impl<N: Real> TwoSidedInverse<Multiplicative> for UnitComplex<N> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -7,10 +7,9 @@ use rand::distributions::{Distribution, OpenClosed01, Standard};
use rand::Rng; use rand::Rng;
use alga::general::Real; use alga::general::Real;
use base::allocator::Allocator;
use base::dimension::{U1, U2}; use base::dimension::{U1, U2};
use base::storage::Storage; use base::storage::Storage;
use base::{DefaultAllocator, Unit, Vector}; use base::{Unit, Vector};
use geometry::{Rotation2, UnitComplex}; use geometry::{Rotation2, UnitComplex};
impl<N: Real> UnitComplex<N> { impl<N: Real> UnitComplex<N> {
@ -36,7 +35,6 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitComplex, Point2}; /// # use nalgebra::{UnitComplex, Point2};
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
@ -57,7 +55,6 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitComplex, Point2}; /// # use nalgebra::{UnitComplex, Point2};
/// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2); /// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
@ -79,7 +76,6 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitComplex, Vector2, Point2}; /// # use nalgebra::{UnitComplex, Vector2, Point2};
/// let angle = f32::consts::FRAC_PI_2; /// let angle = f32::consts::FRAC_PI_2;
@ -139,7 +135,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, UnitComplex}; /// # use nalgebra::{Vector2, UnitComplex};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -162,7 +157,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, UnitComplex}; /// # use nalgebra::{Vector2, UnitComplex};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -198,7 +192,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector2, UnitComplex}; /// # use nalgebra::{Unit, Vector2, UnitComplex};
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0)); /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0)); /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
@ -224,7 +217,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector2, UnitComplex}; /// # use nalgebra::{Unit, Vector2, UnitComplex};
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0)); /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0)); /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));

View File

@ -50,7 +50,7 @@ impl<N: Real> Mul<UnitComplex<N>> for UnitComplex<N> {
#[inline] #[inline]
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.unwrap() * rhs.unwrap()) Unit::new_unchecked(self.into_inner() * rhs.into_inner())
} }
} }
@ -59,7 +59,7 @@ impl<'a, N: Real> Mul<UnitComplex<N>> for &'a UnitComplex<N> {
#[inline] #[inline]
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.complex() * rhs.unwrap()) Unit::new_unchecked(self.complex() * rhs.into_inner())
} }
} }
@ -68,7 +68,7 @@ impl<'b, N: Real> Mul<&'b UnitComplex<N>> for UnitComplex<N> {
#[inline] #[inline]
fn mul(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.unwrap() * rhs.complex()) Unit::new_unchecked(self.into_inner() * rhs.complex())
} }
} }
@ -87,7 +87,7 @@ impl<N: Real> Div<UnitComplex<N>> for UnitComplex<N> {
#[inline] #[inline]
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.unwrap() * rhs.conjugate().unwrap()) Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner())
} }
} }
@ -96,7 +96,7 @@ impl<'a, N: Real> Div<UnitComplex<N>> for &'a UnitComplex<N> {
#[inline] #[inline]
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.complex() * rhs.conjugate().unwrap()) Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner())
} }
} }
@ -105,7 +105,7 @@ impl<'b, N: Real> Div<&'b UnitComplex<N>> for UnitComplex<N> {
#[inline] #[inline]
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.unwrap() * rhs.conjugate().unwrap()) Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner())
} }
} }
@ -114,7 +114,7 @@ impl<'a, 'b, N: Real> Div<&'b UnitComplex<N>> for &'a UnitComplex<N> {
#[inline] #[inline]
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
Unit::new_unchecked(self.complex() * rhs.conjugate().unwrap()) Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner())
} }
} }
@ -425,11 +425,11 @@ impl<N: Real> UnitComplex<N> {
for j in 0..rhs.ncols() { for j in 0..rhs.ncols() {
unsafe { unsafe {
let a = *rhs.get_unchecked(0, j); let a = *rhs.get_unchecked((0, j));
let b = *rhs.get_unchecked(1, j); let b = *rhs.get_unchecked((1, j));
*rhs.get_unchecked_mut(0, j) = r * a - i * b; *rhs.get_unchecked_mut((0, j)) = r * a - i * b;
*rhs.get_unchecked_mut(1, j) = i * a + r * b; *rhs.get_unchecked_mut((1, j)) = i * a + r * b;
} }
} }
} }
@ -452,11 +452,11 @@ impl<N: Real> UnitComplex<N> {
// FIXME: can we optimize that to iterate on one column at a time ? // FIXME: can we optimize that to iterate on one column at a time ?
for j in 0..lhs.nrows() { for j in 0..lhs.nrows() {
unsafe { unsafe {
let a = *lhs.get_unchecked(j, 0); let a = *lhs.get_unchecked((j, 0));
let b = *lhs.get_unchecked(j, 1); let b = *lhs.get_unchecked((j, 1));
*lhs.get_unchecked_mut(j, 0) = r * a + i * b; *lhs.get_unchecked_mut((j, 0)) = r * a + i * b;
*lhs.get_unchecked_mut(j, 1) = -i * a + r * b; *lhs.get_unchecked_mut((j, 1)) = -i * a + r * b;
} }
} }
} }

16
src/io/matrix_market.pest Normal file
View File

@ -0,0 +1,16 @@
WHITESPACE = _{ " " }
Comments = _{ "%" ~ (!NEWLINE ~ ANY)* }
Header = { "%%" ~ (!NEWLINE ~ ANY)* }
Shape = { Dimension ~ Dimension ~ Dimension }
Document = {
SOI ~
NEWLINE* ~
Header ~
(NEWLINE ~ Comments)* ~
(NEWLINE ~ Shape) ~
(NEWLINE ~ Entry?)*
}
Dimension = @{ ASCII_DIGIT+ }
Value = @{ ("+" | "-")? ~ NUMBER+ ~ ("." ~ NUMBER+)? ~ ("e" ~ ("+" | "-")? ~ NUMBER+)? }
Entry = { Dimension ~ Dimension ~ Value }

53
src/io/matrix_market.rs Normal file
View File

@ -0,0 +1,53 @@
use std::fs;
use std::path::Path;
use pest::Parser;
use sparse::CsMatrix;
use Real;
#[derive(Parser)]
#[grammar = "io/matrix_market.pest"]
struct MatrixMarketParser;
// FIXME: return an Error instead of an Option.
/// Parses a Matrix Market file at the given path, and returns the corresponding sparse matrix.
pub fn cs_matrix_from_matrix_market<N: Real, P: AsRef<Path>>(path: P) -> Option<CsMatrix<N>> {
let file = fs::read_to_string(path).ok()?;
cs_matrix_from_matrix_market_str(&file)
}
// FIXME: return an Error instead of an Option.
/// Parses a Matrix Market file described by the given string, and returns the corresponding sparse matrix.
pub fn cs_matrix_from_matrix_market_str<N: Real>(data: &str) -> Option<CsMatrix<N>> {
let file = MatrixMarketParser::parse(Rule::Document, data)
.unwrap()
.next()?;
let mut shape = (0, 0, 0);
let mut rows: Vec<usize> = Vec::new();
let mut cols: Vec<usize> = Vec::new();
let mut data: Vec<N> = Vec::new();
for line in file.into_inner() {
match line.as_rule() {
Rule::Header => {}
Rule::Shape => {
let mut inner = line.into_inner();
shape.0 = inner.next()?.as_str().parse::<usize>().ok()?;
shape.1 = inner.next()?.as_str().parse::<usize>().ok()?;
shape.2 = inner.next()?.as_str().parse::<usize>().ok()?;
}
Rule::Entry => {
let mut inner = line.into_inner();
// NOTE: indices are 1-based.
rows.push(inner.next()?.as_str().parse::<usize>().ok()? - 1);
cols.push(inner.next()?.as_str().parse::<usize>().ok()? - 1);
data.push(::convert(inner.next()?.as_str().parse::<f64>().ok()?));
}
_ => return None, // FIXME: return an Err instead.
}
}
Some(CsMatrix::from_triplet(
shape.0, shape.1, &rows, &cols, &data,
))
}

5
src/io/mod.rs Normal file
View File

@ -0,0 +1,5 @@
//! Parsers for various matrix formats.
pub use self::matrix_market::{cs_matrix_from_matrix_market, cs_matrix_from_matrix_market_str};
mod matrix_market;

View File

@ -81,10 +81,12 @@ an optimized set of tools for computer graphics and physics. Those features incl
#![deny(non_upper_case_globals)] #![deny(non_upper_case_globals)]
#![deny(unused_qualifications)] #![deny(unused_qualifications)]
#![deny(unused_results)] #![deny(unused_results)]
#![deny(missing_docs)] #![warn(missing_docs)] // FIXME: deny this
#![warn(incoherent_fundamental_impls)] #![warn(incoherent_fundamental_impls)]
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico", #![doc(
html_root_url = "http://nalgebra.org/rustdoc")] html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc"
)]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
@ -121,11 +123,21 @@ extern crate alloc;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
extern crate core as std; extern crate core as std;
#[cfg(feature = "io")]
extern crate pest;
#[macro_use]
#[cfg(feature = "io")]
extern crate pest_derive;
pub mod base; pub mod base;
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
pub mod debug; pub mod debug;
pub mod geometry; pub mod geometry;
#[cfg(feature = "io")]
pub mod io;
pub mod linalg; pub mod linalg;
#[cfg(feature = "sparse")]
pub mod sparse;
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[deprecated( #[deprecated(
@ -135,11 +147,13 @@ pub use base as core;
pub use base::*; pub use base::*;
pub use geometry::*; pub use geometry::*;
pub use linalg::*; pub use linalg::*;
#[cfg(feature = "sparse")]
pub use sparse::*;
use std::cmp::{self, Ordering, PartialOrd}; use std::cmp::{self, Ordering, PartialOrd};
use alga::general::{ use alga::general::{
Additive, AdditiveGroup, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice, Additive, AdditiveGroup, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice,
Multiplicative, SupersetOf, Multiplicative, SupersetOf,
}; };
use alga::linear::SquareMatrix as AlgaSquareMatrix; use alga::linear::SquareMatrix as AlgaSquareMatrix;
@ -189,6 +203,12 @@ pub fn zero<T: Identity<Additive>>() -> T {
/// ///
/// * [`one`](fn.one.html) /// * [`one`](fn.one.html)
/// * [`zero`](fn.zero.html) /// * [`zero`](fn.zero.html)
///
/// # Deprecated
/// Use [Point::origin] instead.
///
/// Or, use [EuclideanSpace::origin](https://docs.rs/alga/0.7.2/alga/linear/trait.EuclideanSpace.html#tymethod.origin).
#[deprecated(note = "use `Point::origin` instead")]
#[inline] #[inline]
pub fn origin<P: EuclideanSpace>() -> P { pub fn origin<P: EuclideanSpace>() -> P {
P::origin() P::origin()
@ -275,6 +295,9 @@ pub fn min<T: Ord>(a: T, b: T) -> T {
} }
/// The absolute value of `a`. /// The absolute value of `a`.
///
/// Deprecated: Use [Matrix::abs] or [Real::abs] instead.
#[deprecated(note = "use `Matrix::abs` or `Real::abs` instead")]
#[inline] #[inline]
pub fn abs<T: Signed>(a: &T) -> T { pub fn abs<T: Signed>(a: &T) -> T {
a.abs() a.abs()
@ -404,8 +427,8 @@ pub fn try_inverse<M: AlgaSquareMatrix>(m: &M) -> Option<M> {
/// ///
/// * [`try_inverse`](fn.try_inverse.html) /// * [`try_inverse`](fn.try_inverse.html)
#[inline] #[inline]
pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M { pub fn inverse<M: TwoSidedInverse<Multiplicative>>(m: &M) -> M {
m.inverse() m.two_sided_inverse()
} }
/* /*
@ -413,12 +436,26 @@ pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
*/ */
/// Computes the dot product of two vectors. /// Computes the dot product of two vectors.
///
/// ## Deprecated
/// Use these methods instead:
/// - [Matrix::dot]
/// - [Quaternion::dot]
///
/// Or, use [FiniteDimVectorSpace::dot](https://docs.rs/alga/0.7.2/alga/linear/trait.FiniteDimVectorSpace.html#tymethod.dot).
#[deprecated(note = "use `Matrix::dot` or `Quaternion::dot` instead")]
#[inline] #[inline]
pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field { pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field {
a.dot(b) a.dot(b)
} }
/// Computes the smallest angle between two vectors. /// Computes the smallest angle between two vectors.
///
/// ## Deprecated
/// Use [Matrix::angle] instead.
///
/// Or, use [InnerSpace::angle](https://docs.rs/alga/0.7.2/alga/linear/trait.InnerSpace.html#method.angle).
#[deprecated(note = "use `Matrix::angle` instead")]
#[inline] #[inline]
pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real { pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
a.angle(b) a.angle(b)
@ -435,6 +472,14 @@ pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
/// * [`magnitude`](fn.magnitude.html) /// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude_squared`](fn.magnitude_squared.html) /// * [`magnitude_squared`](fn.magnitude_squared.html)
/// * [`norm_squared`](fn.norm_squared.html) /// * [`norm_squared`](fn.norm_squared.html)
///
/// # Deprecated
/// Use these methods instead:
/// * [Matrix::norm]
/// * [Quaternion::norm]
///
/// Or, use [NormedSpace::norm](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm).
#[deprecated(note = "use `Matrix::norm` or `Quaternion::norm` instead")]
#[inline] #[inline]
pub fn norm<V: NormedSpace>(v: &V) -> V::Field { pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
v.norm() v.norm()
@ -447,6 +492,14 @@ pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
/// * [`magnitude`](fn.magnitude.html) /// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude_squared`](fn.magnitude_squared.html) /// * [`magnitude_squared`](fn.magnitude_squared.html)
/// * [`norm`](fn.norm.html) /// * [`norm`](fn.norm.html)
///
/// # Deprecated
/// Use these methods instead:
/// * [Matrix::norm_squared]
/// * [Quaternion::norm_squared]
///
/// Or, use [NormedSpace::norm_squared](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm_squared).
#[deprecated(note = "use `Matrix::norm_squared` or `Quaternion::norm_squared` instead")]
#[inline] #[inline]
pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field { pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
v.norm_squared() v.norm_squared()
@ -459,6 +512,14 @@ pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
/// * [`magnitude_squared`](fn.magnitude_squared.html) /// * [`magnitude_squared`](fn.magnitude_squared.html)
/// * [`norm`](fn.norm.html) /// * [`norm`](fn.norm.html)
/// * [`norm_squared`](fn.norm_squared.html) /// * [`norm_squared`](fn.norm_squared.html)
///
/// # Deprecated
/// Use these methods instead:
/// * [Matrix::magnitude]
/// * [Quaternion::magnitude]
///
/// Or, use [NormedSpace::norm](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm).
#[deprecated(note = "use `Matrix::magnitude` or `Quaternion::magnitude` instead")]
#[inline] #[inline]
pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field { pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
v.norm() v.norm()
@ -472,18 +533,42 @@ pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
/// * [`magnitude`](fn.magnitude.html) /// * [`magnitude`](fn.magnitude.html)
/// * [`norm`](fn.norm.html) /// * [`norm`](fn.norm.html)
/// * [`norm_squared`](fn.norm_squared.html) /// * [`norm_squared`](fn.norm_squared.html)
///
/// # Deprecated
/// Use these methods instead:
/// * [Matrix::magnitude_squared]
/// * [Quaternion::magnitude_squared]
///
/// Or, use [NormedSpace::norm_squared](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm_squared).
#[deprecated(note = "use `Matrix::magnitude_squared` or `Quaternion::magnitude_squared` instead")]
#[inline] #[inline]
pub fn magnitude_squared<V: NormedSpace>(v: &V) -> V::Field { pub fn magnitude_squared<V: NormedSpace>(v: &V) -> V::Field {
v.norm_squared() v.norm_squared()
} }
/// Computes the normalized version of the vector `v`. /// Computes the normalized version of the vector `v`.
///
/// # Deprecated
/// Use these methods instead:
/// * [Matrix::normalize]
/// * [Quaternion::normalize]
///
/// Or, use [NormedSpace::normalize](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.normalize).
#[deprecated(note = "use `Matrix::normalize` or `Quaternion::normalize` instead")]
#[inline] #[inline]
pub fn normalize<V: NormedSpace>(v: &V) -> V { pub fn normalize<V: NormedSpace>(v: &V) -> V {
v.normalize() v.normalize()
} }
/// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`. /// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`.
///
/// # Deprecated
/// Use these methods instead:
/// * [Matrix::try_normalize]
/// * [Quaternion::try_normalize]
///
/// Or, use [NormedSpace::try_normalize](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.try_normalize).
#[deprecated(note = "use `Matrix::try_normalize` or `Quaternion::try_normalize` instead")]
#[inline] #[inline]
pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> { pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> {
v.try_normalize(min_norm) v.try_normalize(min_norm)

View File

@ -52,7 +52,7 @@ where DefaultAllocator: Allocator<N, D, D>
for j in 0..n { for j in 0..n {
for k in 0..j { for k in 0..j {
let factor = unsafe { -*matrix.get_unchecked(j, k) }; let factor = unsafe { -*matrix.get_unchecked((j, k)) };
let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k); let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k);
let mut col_j = col_j.rows_range_mut(j..); let mut col_j = col_j.rows_range_mut(j..);
@ -61,11 +61,11 @@ where DefaultAllocator: Allocator<N, D, D>
col_j.axpy(factor, &col_k, N::one()); col_j.axpy(factor, &col_k, N::one());
} }
let diag = unsafe { *matrix.get_unchecked(j, j) }; let diag = unsafe { *matrix.get_unchecked((j, j)) };
if diag > N::zero() { if diag > N::zero() {
let denom = diag.sqrt(); let denom = diag.sqrt();
unsafe { unsafe {
*matrix.get_unchecked_mut(j, j) = denom; *matrix.get_unchecked_mut((j, j)) = denom;
} }
let mut col = matrix.slice_range_mut(j + 1.., j); let mut col = matrix.slice_range_mut(j + 1.., j);

View File

@ -23,27 +23,27 @@ impl<N: Real, D: DimMin<D, Output = D>, S: Storage<N, D, D>> SquareMatrix<N, D,
unsafe { unsafe {
match dim { match dim {
0 => N::one(), 0 => N::one(),
1 => *self.get_unchecked(0, 0), 1 => *self.get_unchecked((0, 0)),
2 => { 2 => {
let m11 = *self.get_unchecked(0, 0); let m11 = *self.get_unchecked((0, 0));
let m12 = *self.get_unchecked(0, 1); let m12 = *self.get_unchecked((0, 1));
let m21 = *self.get_unchecked(1, 0); let m21 = *self.get_unchecked((1, 0));
let m22 = *self.get_unchecked(1, 1); let m22 = *self.get_unchecked((1, 1));
m11 * m22 - m21 * m12 m11 * m22 - m21 * m12
} }
3 => { 3 => {
let m11 = *self.get_unchecked(0, 0); let m11 = *self.get_unchecked((0, 0));
let m12 = *self.get_unchecked(0, 1); let m12 = *self.get_unchecked((0, 1));
let m13 = *self.get_unchecked(0, 2); let m13 = *self.get_unchecked((0, 2));
let m21 = *self.get_unchecked(1, 0); let m21 = *self.get_unchecked((1, 0));
let m22 = *self.get_unchecked(1, 1); let m22 = *self.get_unchecked((1, 1));
let m23 = *self.get_unchecked(1, 2); let m23 = *self.get_unchecked((1, 2));
let m31 = *self.get_unchecked(2, 0); let m31 = *self.get_unchecked((2, 0));
let m32 = *self.get_unchecked(2, 1); let m32 = *self.get_unchecked((2, 1));
let m33 = *self.get_unchecked(2, 2); let m33 = *self.get_unchecked((2, 2));
let minor_m12_m23 = m22 * m33 - m32 * m23; let minor_m12_m23 = m22 * m33 - m32 * m23;
let minor_m11_m23 = m21 * m33 - m31 * m23; let minor_m11_m23 = m21 * m33 - m31 * m23;

View File

@ -251,7 +251,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
let mut res = self.lu[(dim - 1, dim - 1)]; let mut res = self.lu[(dim - 1, dim - 1)];
if !res.is_zero() { if !res.is_zero() {
for i in 0..dim - 1 { for i in 0..dim - 1 {
res *= unsafe { *self.lu.get_unchecked(i, i) }; res *= unsafe { *self.lu.get_unchecked((i, i)) };
} }
res * self.p.determinant() * self.q.determinant() res * self.p.determinant() * self.q.determinant()

View File

@ -35,46 +35,46 @@ impl<N: Real, D: Dim, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
match dim { match dim {
0 => true, 0 => true,
1 => { 1 => {
let determinant = self.get_unchecked(0, 0).clone(); let determinant = self.get_unchecked((0, 0)).clone();
if determinant == N::zero() { if determinant == N::zero() {
false false
} else { } else {
*self.get_unchecked_mut(0, 0) = N::one() / determinant; *self.get_unchecked_mut((0, 0)) = N::one() / determinant;
true true
} }
} }
2 => { 2 => {
let m11 = *self.get_unchecked(0, 0); let m11 = *self.get_unchecked((0, 0));
let m12 = *self.get_unchecked(0, 1); let m12 = *self.get_unchecked((0, 1));
let m21 = *self.get_unchecked(1, 0); let m21 = *self.get_unchecked((1, 0));
let m22 = *self.get_unchecked(1, 1); let m22 = *self.get_unchecked((1, 1));
let determinant = m11 * m22 - m21 * m12; let determinant = m11 * m22 - m21 * m12;
if determinant == N::zero() { if determinant == N::zero() {
false false
} else { } else {
*self.get_unchecked_mut(0, 0) = m22 / determinant; *self.get_unchecked_mut((0, 0)) = m22 / determinant;
*self.get_unchecked_mut(0, 1) = -m12 / determinant; *self.get_unchecked_mut((0, 1)) = -m12 / determinant;
*self.get_unchecked_mut(1, 0) = -m21 / determinant; *self.get_unchecked_mut((1, 0)) = -m21 / determinant;
*self.get_unchecked_mut(1, 1) = m11 / determinant; *self.get_unchecked_mut((1, 1)) = m11 / determinant;
true true
} }
} }
3 => { 3 => {
let m11 = *self.get_unchecked(0, 0); let m11 = *self.get_unchecked((0, 0));
let m12 = *self.get_unchecked(0, 1); let m12 = *self.get_unchecked((0, 1));
let m13 = *self.get_unchecked(0, 2); let m13 = *self.get_unchecked((0, 2));
let m21 = *self.get_unchecked(1, 0); let m21 = *self.get_unchecked((1, 0));
let m22 = *self.get_unchecked(1, 1); let m22 = *self.get_unchecked((1, 1));
let m23 = *self.get_unchecked(1, 2); let m23 = *self.get_unchecked((1, 2));
let m31 = *self.get_unchecked(2, 0); let m31 = *self.get_unchecked((2, 0));
let m32 = *self.get_unchecked(2, 1); let m32 = *self.get_unchecked((2, 1));
let m33 = *self.get_unchecked(2, 2); let m33 = *self.get_unchecked((2, 2));
let minor_m12_m23 = m22 * m33 - m32 * m23; let minor_m12_m23 = m22 * m33 - m32 * m23;
let minor_m11_m23 = m21 * m33 - m31 * m23; let minor_m11_m23 = m21 * m33 - m31 * m23;
@ -86,17 +86,17 @@ impl<N: Real, D: Dim, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
if determinant == N::zero() { if determinant == N::zero() {
false false
} else { } else {
*self.get_unchecked_mut(0, 0) = minor_m12_m23 / determinant; *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, 1)) = (m13 * m32 - m33 * m12) / determinant;
*self.get_unchecked_mut(0, 2) = (m12 * m23 - m22 * m13) / 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, 0)) = -minor_m11_m23 / determinant;
*self.get_unchecked_mut(1, 1) = (m11 * m33 - m31 * m13) / 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((1, 2)) = (m13 * m21 - m23 * m11) / determinant;
*self.get_unchecked_mut(2, 0) = minor_m11_m22 / 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, 1)) = (m12 * m31 - m32 * m11) / determinant;
*self.get_unchecked_mut(2, 2) = (m11 * m22 - m21 * m12) / determinant; *self.get_unchecked_mut((2, 2)) = (m11 * m22 - m21 * m12) / determinant;
true true
} }

View File

@ -290,7 +290,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
let mut res = N::one(); let mut res = N::one();
for i in 0..dim { for i in 0..dim {
res *= unsafe { *self.lu.get_unchecked(i, i) }; res *= unsafe { *self.lu.get_unchecked((i, i)) };
} }
res * self.p.determinant() res * self.p.determinant()

View File

@ -412,7 +412,7 @@ where
rot.rotate_rows(&mut m); rot.rotate_rows(&mut m);
if compute_q { if compute_q {
let c = rot.unwrap(); let c = rot.into_inner();
// XXX: we have to build the matrix manually because // XXX: we have to build the matrix manually because
// rot.to_rotation_matrix().unwrap() causes an ICE. // rot.to_rotation_matrix().unwrap() causes an ICE.
q = Some(MatrixN::from_column_slice_generic( q = Some(MatrixN::from_column_slice_generic(

View File

@ -79,7 +79,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
let coeff; let coeff;
unsafe { unsafe {
let diag = *self.get_unchecked(i, i); let diag = *self.get_unchecked((i, i));
if diag.is_zero() { if diag.is_zero() {
return false; return false;
@ -161,7 +161,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
let coeff; let coeff;
unsafe { unsafe {
let diag = *self.get_unchecked(i, i); let diag = *self.get_unchecked((i, i));
if diag.is_zero() { if diag.is_zero() {
return false; return false;
@ -258,7 +258,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
unsafe { unsafe {
let b_i = b.vget_unchecked_mut(i); let b_i = b.vget_unchecked_mut(i);
let diag = *self.get_unchecked(i, i); let diag = *self.get_unchecked((i, i));
if diag.is_zero() { if diag.is_zero() {
return false; return false;
@ -304,7 +304,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
unsafe { unsafe {
let b_i = b.vget_unchecked_mut(i); let b_i = b.vget_unchecked_mut(i);
let diag = *self.get_unchecked(i, i); let diag = *self.get_unchecked((i, i));
if diag.is_zero() { if diag.is_zero() {
return false; return false;

View File

@ -484,33 +484,37 @@ where
/// Rebuild the original matrix. /// Rebuild the original matrix.
/// ///
/// This is useful if some of the singular values have been manually modified. Panics if the /// This is useful if some of the singular values have been manually modified.
/// right- and left- singular vectors have not been computed at construction-time. /// Returns `Err` if the right- and left- singular vectors have not been
pub fn recompose(self) -> MatrixMN<N, R, C> { /// computed at construction-time.
let mut u = self.u.expect("SVD recomposition: U has not been computed."); pub fn recompose(self) -> Result<MatrixMN<N, R, C>, &'static str> {
let v_t = self match (self.u, self.v_t) {
.v_t (Some(mut u), Some(v_t)) => {
.expect("SVD recomposition: V^t has not been computed.");
for i in 0..self.singular_values.len() { for i in 0..self.singular_values.len() {
let val = self.singular_values[i]; let val = self.singular_values[i];
u.column_mut(i).mul_assign(val); u.column_mut(i).mul_assign(val);
} }
Ok(u * v_t)
u * v_t }
(None, None) => Err("SVD recomposition: U and V^t have not been computed."),
(None, _) => Err("SVD recomposition: U has not been computed."),
(_, None) => Err("SVD recomposition: V^t has not been computed.")
}
} }
/// Computes the pseudo-inverse of the decomposed matrix. /// Computes the pseudo-inverse of the decomposed matrix.
/// ///
/// Any singular value smaller than `eps` is assumed to be zero. /// Any singular value smaller than `eps` is assumed to be zero.
/// Panics if the right- and left- singular vectors have not been computed at /// Returns `Err` if the right- and left- singular vectors have not
/// construction-time. /// been computed at construction-time.
pub fn pseudo_inverse(mut self, eps: N) -> MatrixMN<N, C, R> pub fn pseudo_inverse(mut self, eps: N) -> Result<MatrixMN<N, C, R>, &'static str>
where DefaultAllocator: Allocator<N, C, R> { where
assert!( DefaultAllocator: Allocator<N, C, R>,
eps >= N::zero(), {
"SVD pseudo inverse: the epsilon must be non-negative." if eps < N::zero() {
); Err("SVD pseudo inverse: the epsilon must be non-negative.")
}
else {
for i in 0..self.singular_values.len() { for i in 0..self.singular_values.len() {
let val = self.singular_values[i]; let val = self.singular_values[i];
@ -521,37 +525,31 @@ where
} }
} }
self.recompose().transpose() self.recompose().map(|m| m.transpose())
}
} }
/// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown. /// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown.
/// ///
/// Any singular value smaller than `eps` is assumed to be zero. /// Any singular value smaller than `eps` is assumed to be zero.
/// Returns `None` if the singular vectors `U` and `V` have not been computed. /// Returns `Err` if the singular vectors `U` and `V` have not been computed.
// FIXME: make this more generic wrt the storage types and the dimensions for `b`. // FIXME: make this more generic wrt the storage types and the dimensions for `b`.
pub fn solve<R2: Dim, C2: Dim, S2>( pub fn solve<R2: Dim, C2: Dim, S2>(
&self, &self,
b: &Matrix<N, R2, C2, S2>, b: &Matrix<N, R2, C2, S2>,
eps: N, eps: N,
) -> MatrixMN<N, C, C2> ) -> Result<MatrixMN<N, C, C2>, &'static str>
where where
S2: Storage<N, R2, C2>, S2: Storage<N, R2, C2>,
DefaultAllocator: Allocator<N, C, C2> + Allocator<N, DimMinimum<R, C>, C2>, DefaultAllocator: Allocator<N, C, C2> + Allocator<N, DimMinimum<R, C>, C2>,
ShapeConstraint: SameNumberOfRows<R, R2>, ShapeConstraint: SameNumberOfRows<R, R2>,
{ {
assert!( if eps < N::zero() {
eps >= N::zero(), Err("SVD solve: the epsilon must be non-negative.")
"SVD solve: the epsilon must be non-negative." }
); else {
let u = self match (&self.u, &self.v_t) {
.u (Some(u), Some(v_t)) => {
.as_ref()
.expect("SVD solve: U has not been computed.");
let v_t = self
.v_t
.as_ref()
.expect("SVD solve: V^t has not been computed.");
let mut ut_b = u.tr_mul(b); let mut ut_b = u.tr_mul(b);
for j in 0..ut_b.ncols() { for j in 0..ut_b.ncols() {
@ -567,7 +565,13 @@ where
} }
} }
v_t.tr_mul(&ut_b) Ok(v_t.tr_mul(&ut_b))
}
(None, None) => Err("SVD solve: U and V^t have not been computed."),
(None, _) => Err("SVD solve: U has not been computed."),
(_, None) => Err("SVD solve: V^t has not been computed.")
}
}
} }
} }
@ -624,8 +628,10 @@ where
/// Computes the pseudo-inverse of this matrix. /// Computes the pseudo-inverse of this matrix.
/// ///
/// All singular values below `eps` are considered equal to 0. /// All singular values below `eps` are considered equal to 0.
pub fn pseudo_inverse(self, eps: N) -> MatrixMN<N, C, R> pub fn pseudo_inverse(self, eps: N) -> Result<MatrixMN<N, C, R>, &'static str>
where DefaultAllocator: Allocator<N, C, R> { where
DefaultAllocator: Allocator<N, C, R>,
{
SVD::new(self.clone_owned(), true, true).pseudo_inverse(eps) SVD::new(self.clone_owned(), true, true).pseudo_inverse(eps)
} }
} }

517
src/sparse/cs_matrix.rs Normal file
View File

@ -0,0 +1,517 @@
use alga::general::ClosedAdd;
use num::Zero;
use std::iter;
use std::marker::PhantomData;
use std::ops::Range;
use std::slice;
use allocator::Allocator;
use sparse::cs_utils;
use {
DefaultAllocator, Dim, Dynamic, Scalar, Vector, VectorN, U1
};
pub struct ColumnEntries<'a, N> {
curr: usize,
i: &'a [usize],
v: &'a [N],
}
impl<'a, N> ColumnEntries<'a, N> {
#[inline]
pub fn new(i: &'a [usize], v: &'a [N]) -> Self {
assert_eq!(i.len(), v.len());
ColumnEntries { curr: 0, i, v }
}
}
impl<'a, N: Copy> Iterator for ColumnEntries<'a, N> {
type Item = (usize, N);
#[inline]
fn next(&mut self) -> Option<(usize, N)> {
if self.curr >= self.i.len() {
None
} else {
let res = Some((unsafe { *self.i.get_unchecked(self.curr) }, unsafe {
*self.v.get_unchecked(self.curr)
}));
self.curr += 1;
res
}
}
}
// FIXME: this structure exists for now only because impl trait
// cannot be used for trait method return types.
/// Trait for iterable compressed-column matrix storage.
pub trait CsStorageIter<'a, N, R, C = U1> {
/// Iterator through all the rows of a specific columns.
///
/// The elements are given as a tuple (row_index, value).
type ColumnEntries: Iterator<Item = (usize, N)>;
/// Iterator through the row indices of a specific column.
type ColumnRowIndices: Iterator<Item = usize>;
/// Iterates through all the row indices of the j-th column.
fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices;
#[inline(always)]
/// Iterates through all the entries of the j-th column.
fn column_entries(&'a self, j: usize) -> Self::ColumnEntries;
}
/// Trait for mutably iterable compressed-column sparse matrix storage.
pub trait CsStorageIterMut<'a, N: 'a, R, C = U1> {
/// Mutable iterator through all the values of the sparse matrix.
type ValuesMut: Iterator<Item = &'a mut N>;
/// Mutable iterator through all the rows of a specific columns.
///
/// The elements are given as a tuple (row_index, value).
type ColumnEntriesMut: Iterator<Item = (usize, &'a mut N)>;
/// A mutable iterator through the values buffer of the sparse matrix.
fn values_mut(&'a mut self) -> Self::ValuesMut;
/// Iterates mutably through all the entries of the j-th column.
fn column_entries_mut(&'a mut self, j: usize) -> Self::ColumnEntriesMut;
}
/// Trait for compressed column sparse matrix storage.
pub trait CsStorage<N, R, C = U1>: for<'a> CsStorageIter<'a, N, R, C> {
/// The shape of the stored matrix.
fn shape(&self) -> (R, C);
/// Retrieve the i-th row index of the underlying row index buffer.
///
/// No bound-checking is performed.
unsafe fn row_index_unchecked(&self, i: usize) -> usize;
/// The i-th value on the contiguous value buffer of this storage.
///
/// No bound-checking is performed.
unsafe fn get_value_unchecked(&self, i: usize) -> &N;
/// The i-th value on the contiguous value buffer of this storage.
fn get_value(&self, i: usize) -> &N;
/// Retrieve the i-th row index of the underlying row index buffer.
fn row_index(&self, i: usize) -> usize;
/// The value indices for the `i`-th column.
fn column_range(&self, i: usize) -> Range<usize>;
/// The size of the value buffer (i.e. the entries known as possibly being non-zero).
fn len(&self) -> usize;
}
/// Trait for compressed column sparse matrix mutable storage.
pub trait CsStorageMut<N, R, C = U1>:
CsStorage<N, R, C> + for<'a> CsStorageIterMut<'a, N, R, C>
{
}
/// A storage of column-compressed sparse matrix based on a Vec.
#[derive(Clone, Debug, PartialEq)]
pub struct CsVecStorage<N: Scalar, R: Dim, C: Dim>
where DefaultAllocator: Allocator<usize, C>
{
pub(crate) shape: (R, C),
pub(crate) p: VectorN<usize, C>,
pub(crate) i: Vec<usize>,
pub(crate) vals: Vec<N>,
}
impl<N: Scalar, R: Dim, C: Dim> CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
/// The value buffer of this storage.
pub fn values(&self) -> &[N] {
&self.vals
}
/// The column shifts buffer.
pub fn p(&self) -> &[usize] {
self.p.as_slice()
}
/// The row index buffers.
pub fn i(&self) -> &[usize] {
&self.i
}
}
impl<N: Scalar, R: Dim, C: Dim> CsVecStorage<N, R, C> where DefaultAllocator: Allocator<usize, C> {}
impl<'a, N: Scalar, R: Dim, C: Dim> CsStorageIter<'a, N, R, C> for CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
type ColumnEntries = ColumnEntries<'a, N>;
type ColumnRowIndices = iter::Cloned<slice::Iter<'a, usize>>;
#[inline]
fn column_entries(&'a self, j: usize) -> Self::ColumnEntries {
let rng = self.column_range(j);
ColumnEntries::new(&self.i[rng.clone()], &self.vals[rng])
}
#[inline]
fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices {
let rng = self.column_range(j);
self.i[rng.clone()].iter().cloned()
}
}
impl<N: Scalar, R: Dim, C: Dim> CsStorage<N, R, C> for CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
#[inline]
fn shape(&self) -> (R, C) {
self.shape
}
#[inline]
fn len(&self) -> usize {
self.vals.len()
}
#[inline]
fn row_index(&self, i: usize) -> usize {
self.i[i]
}
#[inline]
unsafe fn row_index_unchecked(&self, i: usize) -> usize {
*self.i.get_unchecked(i)
}
#[inline]
unsafe fn get_value_unchecked(&self, i: usize) -> &N {
self.vals.get_unchecked(i)
}
#[inline]
fn get_value(&self, i: usize) -> &N {
&self.vals[i]
}
#[inline]
fn column_range(&self, j: usize) -> Range<usize> {
let end = if j + 1 == self.p.len() {
self.len()
} else {
self.p[j + 1]
};
self.p[j]..end
}
}
impl<'a, N: Scalar, R: Dim, C: Dim> CsStorageIterMut<'a, N, R, C> for CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
type ValuesMut = slice::IterMut<'a, N>;
type ColumnEntriesMut = iter::Zip<iter::Cloned<slice::Iter<'a, usize>>, slice::IterMut<'a, N>>;
#[inline]
fn values_mut(&'a mut self) -> Self::ValuesMut {
self.vals.iter_mut()
}
#[inline]
fn column_entries_mut(&'a mut self, j: usize) -> Self::ColumnEntriesMut {
let rng = self.column_range(j);
self.i[rng.clone()]
.iter()
.cloned()
.zip(self.vals[rng].iter_mut())
}
}
impl<N: Scalar, R: Dim, C: Dim> CsStorageMut<N, R, C> for CsVecStorage<N, R, C> where DefaultAllocator: Allocator<usize, C>
{}
/*
pub struct CsSliceStorage<'a, N: Scalar, R: Dim, C: DimAdd<U1>> {
shape: (R, C),
p: VectorSlice<usize, DimSum<C, U1>>,
i: VectorSlice<usize, Dynamic>,
vals: VectorSlice<N, Dynamic>,
}*/
/// A compressed sparse column matrix.
#[derive(Clone, Debug, PartialEq)]
pub struct CsMatrix<
N: Scalar,
R: Dim = Dynamic,
C: Dim = Dynamic,
S: CsStorage<N, R, C> = CsVecStorage<N, R, C>,
> {
pub(crate) data: S,
_phantoms: PhantomData<(N, R, C)>,
}
/// A column compressed sparse vector.
pub type CsVector<N, R = Dynamic, S = CsVecStorage<N, R, U1>> = CsMatrix<N, R, U1, S>;
impl<N: Scalar, R: Dim, C: Dim> CsMatrix<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
/// Creates a new compressed sparse column matrix with the specified dimension and
/// `nvals` possible non-zero values.
pub fn new_uninitialized_generic(nrows: R, ncols: C, nvals: usize) -> Self {
let mut i = Vec::with_capacity(nvals);
unsafe {
i.set_len(nvals);
}
i.shrink_to_fit();
let mut vals = Vec::with_capacity(nvals);
unsafe {
vals.set_len(nvals);
}
vals.shrink_to_fit();
CsMatrix {
data: CsVecStorage {
shape: (nrows, ncols),
p: VectorN::zeros_generic(ncols, U1),
i,
vals,
},
_phantoms: PhantomData,
}
}
/*
pub(crate) fn from_parts_generic(
nrows: R,
ncols: C,
p: VectorN<usize, C>,
i: Vec<usize>,
vals: Vec<N>,
) -> Self
where
N: Zero + ClosedAdd,
DefaultAllocator: Allocator<N, R>,
{
assert_eq!(ncols.value(), p.len(), "Invalid inptr size.");
assert_eq!(i.len(), vals.len(), "Invalid value size.");
// Check p.
for ptr in &p {
assert!(*ptr < i.len(), "Invalid inptr value.");
}
for ptr in p.as_slice().windows(2) {
assert!(ptr[0] <= ptr[1], "Invalid inptr ordering.");
}
// Check i.
for i in &i {
assert!(*i < nrows.value(), "Invalid row ptr value.")
}
let mut res = CsMatrix {
data: CsVecStorage {
shape: (nrows, ncols),
p,
i,
vals,
},
_phantoms: PhantomData,
};
// Sort and remove duplicates.
res.sort();
res.dedup();
res
}*/
}
/*
impl<N: Scalar + Zero + ClosedAdd> CsMatrix<N> {
pub(crate) fn from_parts(
nrows: usize,
ncols: usize,
p: Vec<usize>,
i: Vec<usize>,
vals: Vec<N>,
) -> Self
{
let nrows = Dynamic::new(nrows);
let ncols = Dynamic::new(ncols);
let p = DVector::from_data(VecStorage::new(ncols, U1, p));
Self::from_parts_generic(nrows, ncols, p, i, vals)
}
}
*/
impl<N: Scalar, R: Dim, C: Dim, S: CsStorage<N, R, C>> CsMatrix<N, R, C, S> {
pub(crate) fn from_data(data: S) -> Self {
CsMatrix {
data,
_phantoms: PhantomData,
}
}
/// The size of the data buffer.
pub fn len(&self) -> usize {
self.data.len()
}
/// The number of rows of this matrix.
pub fn nrows(&self) -> usize {
self.data.shape().0.value()
}
/// The number of rows of this matrix.
pub fn ncols(&self) -> usize {
self.data.shape().1.value()
}
/// The shape of this matrix.
pub fn shape(&self) -> (usize, usize) {
let (nrows, ncols) = self.data.shape();
(nrows.value(), ncols.value())
}
/// Whether this matrix is square or not.
pub fn is_square(&self) -> bool {
let (nrows, ncols) = self.data.shape();
nrows.value() == ncols.value()
}
/// Should always return `true`.
///
/// This method is generally used for debugging and should typically not be called in user code.
/// This checks that the row inner indices of this matrix are sorted. It takes `O(n)` time,
/// where n` is `self.len()`.
/// All operations of CSC matrices on nalgebra assume, and will return, sorted indices.
/// If at any time this `is_sorted` method returns `false`, then, something went wrong
/// and an issue should be open on the nalgebra repository with details on how to reproduce
/// this.
pub fn is_sorted(&self) -> bool {
for j in 0..self.ncols() {
let mut curr = None;
for idx in self.data.column_row_indices(j) {
if let Some(curr) = curr {
if idx <= curr {
return false;
}
}
curr = Some(idx);
}
}
true
}
/// Computes the transpose of this sparse matrix.
pub fn transpose(&self) -> CsMatrix<N, C, R>
where DefaultAllocator: Allocator<usize, R> {
let (nrows, ncols) = self.data.shape();
let nvals = self.len();
let mut res = CsMatrix::new_uninitialized_generic(ncols, nrows, nvals);
let mut workspace = Vector::zeros_generic(nrows, U1);
// Compute p.
for i in 0..nvals {
let row_id = self.data.row_index(i);
workspace[row_id] += 1;
}
let _ = cs_utils::cumsum(&mut workspace, &mut res.data.p);
// Fill the result.
for j in 0..ncols.value() {
for (row_id, value) in self.data.column_entries(j) {
let shift = workspace[row_id];
res.data.vals[shift] = value;
res.data.i[shift] = j;
workspace[row_id] += 1;
}
}
res
}
}
impl<N: Scalar, R: Dim, C: Dim, S: CsStorageMut<N, R, C>> CsMatrix<N, R, C, S> {
/// Iterator through all the mutable values of this sparse matrix.
#[inline]
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut N> {
self.data.values_mut()
}
}
impl<N: Scalar, R: Dim, C: Dim> CsMatrix<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
pub(crate) fn sort(&mut self)
where DefaultAllocator: Allocator<N, R> {
// Size = R
let nrows = self.data.shape().0;
let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows, U1) };
self.sort_with_workspace(workspace.as_mut_slice());
}
pub(crate) fn sort_with_workspace(&mut self, workspace: &mut [N]) {
assert!(
workspace.len() >= self.nrows(),
"Workspace must be able to hold at least self.nrows() elements."
);
for j in 0..self.ncols() {
// Scatter the row in the workspace.
for (irow, val) in self.data.column_entries(j) {
workspace[irow] = val;
}
// Sort the index vector.
let range = self.data.column_range(j);
self.data.i[range.clone()].sort();
// Permute the values too.
for (i, irow) in range.clone().zip(self.data.i[range].iter().cloned()) {
self.data.vals[i] = workspace[irow];
}
}
}
// Remove dupliate entries on a sorted CsMatrix.
pub(crate) fn dedup(&mut self)
where N: Zero + ClosedAdd {
let mut curr_i = 0;
for j in 0..self.ncols() {
let range = self.data.column_range(j);
self.data.p[j] = curr_i;
if range.start != range.end {
let mut value = N::zero();
let mut irow = self.data.i[range.start];
for idx in range {
let curr_irow = self.data.i[idx];
if curr_irow == irow {
value += self.data.vals[idx];
} else {
self.data.i[curr_i] = irow;
self.data.vals[curr_i] = value;
value = self.data.vals[idx];
irow = curr_irow;
curr_i += 1;
}
}
// Handle the last entry.
self.data.i[curr_i] = irow;
self.data.vals[curr_i] = value;
curr_i += 1;
}
}
self.data.i.truncate(curr_i);
self.data.i.shrink_to_fit();
self.data.vals.truncate(curr_i);
self.data.vals.shrink_to_fit();
}
}

View File

@ -0,0 +1,408 @@
use std::iter;
use std::mem;
use allocator::Allocator;
use sparse::{CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsVecStorage};
use {DefaultAllocator, Dim, Real, VectorN, U1};
/// The cholesky decomposition of a column compressed sparse matrix.
pub struct CsCholesky<N: Real, D: Dim>
where DefaultAllocator: Allocator<usize, D> + Allocator<N, D>
{
// Non-zero pattern of the original matrix upper-triangular part.
// Unlike the original matrix, the `original_p` array does contain the last sentinel value
// equal to `original_i.len()` at the end.
original_p: Vec<usize>,
original_i: Vec<usize>,
// Decomposition result.
l: CsMatrix<N, D, D>,
// Used only for the pattern.
// FIXME: store only the nonzero pattern instead.
u: CsMatrix<N, D, D>,
ok: bool,
// Workspaces.
work_x: VectorN<N, D>,
work_c: VectorN<usize, D>,
}
impl<N: Real, D: Dim> CsCholesky<N, D>
where DefaultAllocator: Allocator<usize, D> + Allocator<N, D>
{
/// Computes the cholesky decomposition of the sparse matrix `m`.
pub fn new(m: &CsMatrix<N, D, D>) -> Self {
let mut me = Self::new_symbolic(m);
let _ = me.decompose_left_looking(&m.data.vals);
me
}
/// Perform symbolic analysis for the given matrix.
///
/// This does not access the numerical values of `m`.
pub fn new_symbolic(m: &CsMatrix<N, D, D>) -> Self {
assert!(
m.is_square(),
"The matrix `m` must be square to compute its elimination tree."
);
let (l, u) = Self::nonzero_pattern(m);
// Workspaces.
let work_x = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) };
let work_c = unsafe { VectorN::new_uninitialized_generic(m.data.shape().1, U1) };
let mut original_p = m.data.p.as_slice().to_vec();
original_p.push(m.data.i.len());
CsCholesky {
original_p,
original_i: m.data.i.clone(),
l,
u,
ok: false,
work_x,
work_c,
}
}
/// The lower-triangular matrix of the cholesky decomposition.
pub fn l(&self) -> Option<&CsMatrix<N, D, D>> {
if self.ok {
Some(&self.l)
} else {
None
}
}
/// Extracts the lower-triangular matrix of the cholesky decomposition.
pub fn unwrap_l(self) -> Option<CsMatrix<N, D, D>> {
if self.ok {
Some(self.l)
} else {
None
}
}
/// Perform a numerical left-looking cholesky decomposition of a matrix with the same structure as the
/// one used to initialize `self`, but with different non-zero values provided by `values`.
pub fn decompose_left_looking(&mut self, values: &[N]) -> bool {
assert!(
values.len() >= self.original_i.len(),
"The set of values is too small."
);
let n = self.l.nrows();
// Reset `work_c` to the column pointers of `l`.
self.work_c.copy_from(&self.l.data.p);
unsafe {
for k in 0..n {
// Scatter the k-th column of the original matrix with the values provided.
let range_k =
*self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1);
*self.work_x.vget_unchecked_mut(k) = N::zero();
for p in range_k.clone() {
let irow = *self.original_i.get_unchecked(p);
if irow >= k {
*self.work_x.vget_unchecked_mut(irow) = *values.get_unchecked(p);
}
}
for j in self.u.data.column_row_indices(k) {
let factor = -*self
.l
.data
.vals
.get_unchecked(*self.work_c.vget_unchecked(j));
*self.work_c.vget_unchecked_mut(j) += 1;
if j < k {
for (z, val) in self.l.data.column_entries(j) {
if z >= k {
*self.work_x.vget_unchecked_mut(z) += val * factor;
}
}
}
}
let diag = *self.work_x.vget_unchecked(k);
if diag > N::zero() {
let denom = diag.sqrt();
*self
.l
.data
.vals
.get_unchecked_mut(*self.l.data.p.vget_unchecked(k)) = denom;
for (p, val) in self.l.data.column_entries_mut(k) {
*val = *self.work_x.vget_unchecked(p) / denom;
*self.work_x.vget_unchecked_mut(p) = N::zero();
}
} else {
self.ok = false;
return false;
}
}
}
self.ok = true;
true
}
/// Perform a numerical up-looking cholesky decomposition of a matrix with the same structure as the
/// one used to initialize `self`, but with different non-zero values provided by `values`.
pub fn decompose_up_looking(&mut self, values: &[N]) -> bool {
assert!(
values.len() >= self.original_i.len(),
"The set of values is too small."
);
// Reset `work_c` to the column pointers of `l`.
self.work_c.copy_from(&self.l.data.p);
// Perform the decomposition.
for k in 0..self.l.nrows() {
unsafe {
// Scatter the k-th column of the original matrix with the values provided.
let column_range =
*self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1);
*self.work_x.vget_unchecked_mut(k) = N::zero();
for p in column_range.clone() {
let irow = *self.original_i.get_unchecked(p);
if irow <= k {
*self.work_x.vget_unchecked_mut(irow) = *values.get_unchecked(p);
}
}
let mut diag = *self.work_x.vget_unchecked(k);
*self.work_x.vget_unchecked_mut(k) = N::zero();
// Triangular solve.
for irow in self.u.data.column_row_indices(k) {
if irow >= k {
continue;
}
let lki = *self.work_x.vget_unchecked(irow)
/ *self
.l
.data
.vals
.get_unchecked(*self.l.data.p.vget_unchecked(irow));
*self.work_x.vget_unchecked_mut(irow) = N::zero();
for p in
*self.l.data.p.vget_unchecked(irow) + 1..*self.work_c.vget_unchecked(irow)
{
*self
.work_x
.vget_unchecked_mut(*self.l.data.i.get_unchecked(p)) -=
*self.l.data.vals.get_unchecked(p) * lki;
}
diag -= lki * lki;
let p = *self.work_c.vget_unchecked(irow);
*self.work_c.vget_unchecked_mut(irow) += 1;
*self.l.data.i.get_unchecked_mut(p) = k;
*self.l.data.vals.get_unchecked_mut(p) = lki;
}
if diag <= N::zero() {
self.ok = false;
return false;
}
// Deal with the diagonal element.
let p = *self.work_c.vget_unchecked(k);
*self.work_c.vget_unchecked_mut(k) += 1;
*self.l.data.i.get_unchecked_mut(p) = k;
*self.l.data.vals.get_unchecked_mut(p) = diag.sqrt();
}
}
self.ok = true;
true
}
fn elimination_tree<S: CsStorage<N, D, D>>(m: &CsMatrix<N, D, D, S>) -> Vec<usize> {
let nrows = m.nrows();
let mut forest: Vec<_> = iter::repeat(usize::max_value()).take(nrows).collect();
let mut ancestor: Vec<_> = iter::repeat(usize::max_value()).take(nrows).collect();
for k in 0..nrows {
for irow in m.data.column_row_indices(k) {
let mut i = irow;
while i < k {
let i_ancestor = ancestor[i];
ancestor[i] = k;
if i_ancestor == usize::max_value() {
forest[i] = k;
break;
}
i = i_ancestor;
}
}
}
forest
}
fn reach<S: CsStorage<N, D, D>>(
m: &CsMatrix<N, D, D, S>,
j: usize,
max_j: usize,
tree: &[usize],
marks: &mut Vec<bool>,
out: &mut Vec<usize>,
)
{
marks.clear();
marks.resize(tree.len(), false);
// FIXME: avoid all those allocations.
let mut tmp = Vec::new();
let mut res = Vec::new();
for irow in m.data.column_row_indices(j) {
let mut curr = irow;
while curr != usize::max_value() && curr <= max_j && !marks[curr] {
marks[curr] = true;
tmp.push(curr);
curr = tree[curr];
}
tmp.append(&mut res);
mem::swap(&mut tmp, &mut res);
}
out.append(&mut res);
}
fn nonzero_pattern<S: CsStorage<N, D, D>>(
m: &CsMatrix<N, D, D, S>,
) -> (CsMatrix<N, D, D>, CsMatrix<N, D, D>) {
let etree = Self::elimination_tree(m);
let (nrows, ncols) = m.data.shape();
let mut rows = Vec::with_capacity(m.len());
let mut cols = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) };
let mut marks = Vec::new();
// NOTE: the following will actually compute the non-zero pattern of
// the transpose of l.
for i in 0..nrows.value() {
cols[i] = rows.len();
Self::reach(m, i, i, &etree, &mut marks, &mut rows);
}
let mut vals = Vec::with_capacity(rows.len());
unsafe {
vals.set_len(rows.len());
}
vals.shrink_to_fit();
let data = CsVecStorage {
shape: (nrows, ncols),
p: cols,
i: rows,
vals,
};
let u = CsMatrix::from_data(data);
// XXX: avoid this transpose.
let l = u.transpose();
(l, u)
}
/*
*
* NOTE: All the following methods are untested and currently unused.
*
*
fn column_counts<S: CsStorage<N, D, D>>(
m: &CsMatrix<N, D, D, S>,
tree: &[usize],
) -> Vec<usize> {
let len = m.data.shape().0.value();
let mut counts: Vec<_> = iter::repeat(0).take(len).collect();
let mut reach = Vec::new();
let mut marks = Vec::new();
for i in 0..len {
Self::reach(m, i, i, tree, &mut marks, &mut reach);
for j in reach.drain(..) {
counts[j] += 1;
}
}
counts
}
fn tree_postorder(tree: &[usize]) -> Vec<usize> {
// FIXME: avoid all those allocations?
let mut first_child: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect();
let mut other_children: Vec<_> =
iter::repeat(usize::max_value()).take(tree.len()).collect();
// Build the children list from the parent list.
// The set of children of the node `i` is given by the linked list
// starting at `first_child[i]`. The nodes of this list are then:
// { first_child[i], other_children[first_child[i]], other_children[other_children[first_child[i]], ... }
for (i, parent) in tree.iter().enumerate() {
if *parent != usize::max_value() {
let brother = first_child[*parent];
first_child[*parent] = i;
other_children[i] = brother;
}
}
let mut stack = Vec::with_capacity(tree.len());
let mut postorder = Vec::with_capacity(tree.len());
for (i, node) in tree.iter().enumerate() {
if *node == usize::max_value() {
Self::dfs(
i,
&mut first_child,
&other_children,
&mut stack,
&mut postorder,
)
}
}
postorder
}
fn dfs(
i: usize,
first_child: &mut [usize],
other_children: &[usize],
stack: &mut Vec<usize>,
result: &mut Vec<usize>,
) {
stack.clear();
stack.push(i);
while let Some(n) = stack.pop() {
let child = first_child[n];
if child == usize::max_value() {
// No children left.
result.push(n);
} else {
stack.push(n);
stack.push(child);
first_child[n] = other_children[child];
}
}
}
*/
}

View File

@ -0,0 +1,114 @@
use alga::general::ClosedAdd;
use num::Zero;
use allocator::Allocator;
use sparse::cs_utils;
use sparse::{CsMatrix, CsStorage};
use storage::Storage;
use {DefaultAllocator, Dim, Dynamic, Matrix, MatrixMN, Scalar};
impl<'a, N: Scalar + Zero + ClosedAdd> CsMatrix<N> {
/// Creates a column-compressed sparse matrix from a sparse matrix in triplet form.
pub fn from_triplet(
nrows: usize,
ncols: usize,
irows: &[usize],
icols: &[usize],
vals: &[N],
) -> Self
{
Self::from_triplet_generic(Dynamic::new(nrows), Dynamic::new(ncols), irows, icols, vals)
}
}
impl<'a, N: Scalar + Zero + ClosedAdd, R: Dim, C: Dim> CsMatrix<N, R, C>
where DefaultAllocator: Allocator<usize, C> + Allocator<N, R>
{
/// Creates a column-compressed sparse matrix from a sparse matrix in triplet form.
pub fn from_triplet_generic(
nrows: R,
ncols: C,
irows: &[usize],
icols: &[usize],
vals: &[N],
) -> Self
{
assert!(vals.len() == irows.len());
assert!(vals.len() == icols.len());
let mut res = CsMatrix::new_uninitialized_generic(nrows, ncols, vals.len());
let mut workspace = res.data.p.clone();
// Column count.
for j in icols.iter().cloned() {
workspace[j] += 1;
}
let _ = cs_utils::cumsum(&mut workspace, &mut res.data.p);
// Fill i and vals.
for ((i, j), val) in irows
.iter()
.cloned()
.zip(icols.iter().cloned())
.zip(vals.iter().cloned())
{
let offset = workspace[j];
res.data.i[offset] = i;
res.data.vals[offset] = val;
workspace[j] = offset + 1;
}
// Sort the result.
res.sort();
res.dedup();
res
}
}
impl<'a, N: Scalar + Zero, R: Dim, C: Dim, S> From<CsMatrix<N, R, C, S>> for MatrixMN<N, R, C>
where
S: CsStorage<N, R, C>,
DefaultAllocator: Allocator<N, R, C>,
{
fn from(m: CsMatrix<N, R, C, S>) -> Self {
let (nrows, ncols) = m.data.shape();
let mut res = MatrixMN::zeros_generic(nrows, ncols);
for j in 0..ncols.value() {
for (i, val) in m.data.column_entries(j) {
res[(i, j)] = val;
}
}
res
}
}
impl<'a, N: Scalar + Zero, R: Dim, C: Dim, S> From<Matrix<N, R, C, S>> for CsMatrix<N, R, C>
where
S: Storage<N, R, C>,
DefaultAllocator: Allocator<N, R, C> + Allocator<usize, C>,
{
fn from(m: Matrix<N, R, C, S>) -> Self {
let (nrows, ncols) = m.data.shape();
let len = m.iter().filter(|e| !e.is_zero()).count();
let mut res = CsMatrix::new_uninitialized_generic(nrows, ncols, len);
let mut nz = 0;
for j in 0..ncols.value() {
let column = m.column(j);
res.data.p[j] = nz;
for i in 0..nrows.value() {
if !column[i].is_zero() {
res.data.i[nz] = i;
res.data.vals[nz] = column[i];
nz += 1;
}
}
}
res
}
}

304
src/sparse/cs_matrix_ops.rs Normal file
View File

@ -0,0 +1,304 @@
use alga::general::{ClosedAdd, ClosedMul};
use num::{One, Zero};
use std::ops::{Add, Mul};
use allocator::Allocator;
use constraint::{AreMultipliable, DimEq, ShapeConstraint};
use sparse::{CsMatrix, CsStorage, CsStorageMut, CsVector};
use storage::StorageMut;
use {DefaultAllocator, Dim, Scalar, Vector, VectorN, U1};
impl<N: Scalar, R: Dim, C: Dim, S: CsStorage<N, R, C>> CsMatrix<N, R, C, S> {
fn scatter<R2: Dim, C2: Dim>(
&self,
j: usize,
beta: N,
timestamps: &mut [usize],
timestamp: usize,
workspace: &mut [N],
mut nz: usize,
res: &mut CsMatrix<N, R2, C2>,
) -> usize
where
N: ClosedAdd + ClosedMul,
DefaultAllocator: Allocator<usize, C2>,
{
for (i, val) in self.data.column_entries(j) {
if timestamps[i] < timestamp {
timestamps[i] = timestamp;
res.data.i[nz] = i;
nz += 1;
workspace[i] = val * beta;
} else {
workspace[i] += val * beta;
}
}
nz
}
}
/*
impl<N: Scalar, R, S> CsVector<N, R, S> {
pub fn axpy(&mut self, alpha: N, x: CsVector<N, R, S>, beta: N) {
// First, compute the number of non-zero entries.
let mut nnzero = 0;
// Allocate a size large enough.
self.data.set_column_len(0, nnzero);
// Fill with the axpy.
let mut i = self.len();
let mut j = x.len();
let mut k = nnzero - 1;
let mut rid1 = self.data.row_index(0, i - 1);
let mut rid2 = x.data.row_index(0, j - 1);
while k > 0 {
if rid1 == rid2 {
self.data.set_row_index(0, k, rid1);
self[k] = alpha * x[j] + beta * self[k];
i -= 1;
j -= 1;
} else if rid1 < rid2 {
self.data.set_row_index(0, k, rid1);
self[k] = beta * self[i];
i -= 1;
} else {
self.data.set_row_index(0, k, rid2);
self[k] = alpha * x[j];
j -= 1;
}
k -= 1;
}
}
}
*/
impl<N: Scalar + Zero + ClosedAdd + ClosedMul, D: Dim, S: StorageMut<N, D>> Vector<N, D, S> {
/// Perform a sparse axpy operation: `self = alpha * x + beta * self` operation.
pub fn axpy_cs<D2: Dim, S2>(&mut self, alpha: N, x: &CsVector<N, D2, S2>, beta: N)
where
S2: CsStorage<N, D2>,
ShapeConstraint: DimEq<D, D2>,
{
if beta.is_zero() {
for i in 0..x.len() {
unsafe {
let k = x.data.row_index_unchecked(i);
let y = self.vget_unchecked_mut(k);
*y = alpha * *x.data.get_value_unchecked(i);
}
}
} else {
// Needed to be sure even components not present on `x` are multiplied.
*self *= beta;
for i in 0..x.len() {
unsafe {
let k = x.data.row_index_unchecked(i);
let y = self.vget_unchecked_mut(k);
*y += alpha * *x.data.get_value_unchecked(i);
}
}
}
}
/*
pub fn gemv_sparse<R2: Dim, C2: Dim, S2>(&mut self, alpha: N, a: &CsMatrix<N, R2, C2, S2>, x: &DVector<N>, beta: N)
where
S2: CsStorage<N, R2, C2> {
let col2 = a.column(0);
let val = unsafe { *x.vget_unchecked(0) };
self.axpy_sparse(alpha * val, &col2, beta);
for j in 1..ncols2 {
let col2 = a.column(j);
let val = unsafe { *x.vget_unchecked(j) };
self.axpy_sparse(alpha * val, &col2, N::one());
}
}
*/
}
impl<'a, 'b, N, R1, R2, C1, C2, S1, S2> Mul<&'b CsMatrix<N, R2, C2, S2>>
for &'a CsMatrix<N, R1, C1, S1>
where
N: Scalar + ClosedAdd + ClosedMul + Zero,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
S1: CsStorage<N, R1, C1>,
S2: CsStorage<N, R2, C2>,
ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
DefaultAllocator: Allocator<usize, C2> + Allocator<usize, R1> + Allocator<N, R1>,
{
type Output = CsMatrix<N, R1, C2>;
fn mul(self, rhs: &'b CsMatrix<N, R2, C2, S2>) -> CsMatrix<N, R1, C2> {
let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape();
assert_eq!(
ncols1.value(),
nrows2.value(),
"Mismatched dimensions for matrix multiplication."
);
let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
let mut workspace = VectorN::<N, R1>::zeros_generic(nrows1, U1);
let mut nz = 0;
for j in 0..ncols2.value() {
res.data.p[j] = nz;
let new_size_bound = nz + nrows1.value();
res.data.i.resize(new_size_bound, 0);
res.data.vals.resize(new_size_bound, N::zero());
for (i, beta) in rhs.data.column_entries(j) {
for (k, val) in self.data.column_entries(i) {
workspace[k] += val * beta;
}
}
for (i, val) in workspace.as_mut_slice().iter_mut().enumerate() {
if !val.is_zero() {
res.data.i[nz] = i;
res.data.vals[nz] = *val;
*val = N::zero();
nz += 1;
}
}
}
// NOTE: the following has a lower complexity, but is slower in many cases, likely because
// of branching inside of the inner loop.
//
// let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
// let mut timestamps = VectorN::zeros_generic(nrows1, U1);
// let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows1, U1) };
// let mut nz = 0;
//
// for j in 0..ncols2.value() {
// res.data.p[j] = nz;
// let new_size_bound = nz + nrows1.value();
// res.data.i.resize(new_size_bound, 0);
// res.data.vals.resize(new_size_bound, N::zero());
//
// for (i, val) in rhs.data.column_entries(j) {
// nz = self.scatter(
// i,
// val,
// timestamps.as_mut_slice(),
// j + 1,
// workspace.as_mut_slice(),
// nz,
// &mut res,
// );
// }
//
// // Keep the output sorted.
// let range = res.data.p[j]..nz;
// res.data.i[range.clone()].sort();
//
// for p in range {
// res.data.vals[p] = workspace[res.data.i[p]]
// }
// }
res.data.i.truncate(nz);
res.data.i.shrink_to_fit();
res.data.vals.truncate(nz);
res.data.vals.shrink_to_fit();
res
}
}
impl<'a, 'b, N, R1, R2, C1, C2, S1, S2> Add<&'b CsMatrix<N, R2, C2, S2>>
for &'a CsMatrix<N, R1, C1, S1>
where
N: Scalar + ClosedAdd + ClosedMul + One,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
S1: CsStorage<N, R1, C1>,
S2: CsStorage<N, R2, C2>,
ShapeConstraint: DimEq<R1, R2> + DimEq<C1, C2>,
DefaultAllocator: Allocator<usize, C2> + Allocator<usize, R1> + Allocator<N, R1>,
{
type Output = CsMatrix<N, R1, C2>;
fn add(self, rhs: &'b CsMatrix<N, R2, C2, S2>) -> CsMatrix<N, R1, C2> {
let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape();
assert_eq!(
(nrows1.value(), ncols1.value()),
(nrows2.value(), ncols2.value()),
"Mismatched dimensions for matrix sum."
);
let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
let mut timestamps = VectorN::zeros_generic(nrows1, U1);
let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows1, U1) };
let mut nz = 0;
for j in 0..ncols2.value() {
res.data.p[j] = nz;
nz = self.scatter(
j,
N::one(),
timestamps.as_mut_slice(),
j + 1,
workspace.as_mut_slice(),
nz,
&mut res,
);
nz = rhs.scatter(
j,
N::one(),
timestamps.as_mut_slice(),
j + 1,
workspace.as_mut_slice(),
nz,
&mut res,
);
// Keep the output sorted.
let range = res.data.p[j]..nz;
res.data.i[range.clone()].sort();
for p in range {
res.data.vals[p] = workspace[res.data.i[p]]
}
}
res.data.i.truncate(nz);
res.data.i.shrink_to_fit();
res.data.vals.truncate(nz);
res.data.vals.shrink_to_fit();
res
}
}
impl<'a, 'b, N, R, C, S> Mul<N> for CsMatrix<N, R, C, S>
where
N: Scalar + ClosedAdd + ClosedMul + Zero,
R: Dim,
C: Dim,
S: CsStorageMut<N, R, C>,
{
type Output = Self;
fn mul(mut self, rhs: N) -> Self {
for e in self.values_mut() {
*e *= rhs
}
self
}
}

View File

@ -0,0 +1,283 @@
use allocator::Allocator;
use constraint::{SameNumberOfRows, ShapeConstraint};
use sparse::{CsMatrix, CsStorage, CsVector};
use storage::{Storage, StorageMut};
use {DefaultAllocator, Dim, Matrix, MatrixMN, Real, VectorN, U1};
impl<N: Real, D: Dim, S: CsStorage<N, D, D>> CsMatrix<N, D, D, S> {
/// Solve a lower-triangular system with a dense right-hand-side.
pub fn solve_lower_triangular<R2: Dim, C2: Dim, S2>(
&self,
b: &Matrix<N, R2, C2, S2>,
) -> Option<MatrixMN<N, R2, C2>>
where
S2: Storage<N, R2, C2>,
DefaultAllocator: Allocator<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let mut b = b.clone_owned();
if self.solve_lower_triangular_mut(&mut b) {
Some(b)
} else {
None
}
}
/// Solve a lower-triangular system with `self` transposed and a dense right-hand-side.
pub fn tr_solve_lower_triangular<R2: Dim, C2: Dim, S2>(
&self,
b: &Matrix<N, R2, C2, S2>,
) -> Option<MatrixMN<N, R2, C2>>
where
S2: Storage<N, R2, C2>,
DefaultAllocator: Allocator<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let mut b = b.clone_owned();
if self.tr_solve_lower_triangular_mut(&mut b) {
Some(b)
} else {
None
}
}
/// Solve in-place a lower-triangular system with a dense right-hand-side.
pub fn solve_lower_triangular_mut<R2: Dim, C2: Dim, S2>(
&self,
b: &mut Matrix<N, R2, C2, S2>,
) -> bool
where
S2: StorageMut<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let (nrows, ncols) = self.data.shape();
assert_eq!(nrows.value(), ncols.value(), "The matrix must be square.");
assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions.");
for j2 in 0..b.ncols() {
let mut b = b.column_mut(j2);
for j in 0..ncols.value() {
let mut column = self.data.column_entries(j);
let mut diag_found = false;
while let Some((i, val)) = column.next() {
if i == j {
if val.is_zero() {
return false;
}
b[j] /= val;
diag_found = true;
break;
}
}
if !diag_found {
return false;
}
for (i, val) in column {
b[i] -= b[j] * val;
}
}
}
true
}
/// Solve a lower-triangular system with `self` transposed and a dense right-hand-side.
pub fn tr_solve_lower_triangular_mut<R2: Dim, C2: Dim, S2>(
&self,
b: &mut Matrix<N, R2, C2, S2>,
) -> bool
where
S2: StorageMut<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let (nrows, ncols) = self.data.shape();
assert_eq!(nrows.value(), ncols.value(), "The matrix must be square.");
assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions.");
for j2 in 0..b.ncols() {
let mut b = b.column_mut(j2);
for j in (0..ncols.value()).rev() {
let mut column = self.data.column_entries(j);
let mut diag = None;
while let Some((i, val)) = column.next() {
if i == j {
if val.is_zero() {
return false;
}
diag = Some(val);
break;
}
}
if let Some(diag) = diag {
for (i, val) in column {
b[j] -= val * b[i];
}
b[j] /= diag;
} else {
return false;
}
}
}
true
}
/// Solve a lower-triangular system with a sparse right-hand-side.
pub fn solve_lower_triangular_cs<D2: Dim, S2>(
&self,
b: &CsVector<N, D2, S2>,
) -> Option<CsVector<N, D2>>
where
S2: CsStorage<N, D2>,
DefaultAllocator: Allocator<bool, D> + Allocator<N, D2> + Allocator<usize, D2>,
ShapeConstraint: SameNumberOfRows<D, D2>,
{
let mut reach = Vec::new();
// We don't compute a postordered reach here because it will be sorted after anyway.
self.lower_triangular_reach(b, &mut reach);
// We sort the reach so the result matrix has sorted indices.
reach.sort();
let mut workspace = unsafe { VectorN::new_uninitialized_generic(b.data.shape().0, U1) };
for i in reach.iter().cloned() {
workspace[i] = N::zero();
}
for (i, val) in b.data.column_entries(0) {
workspace[i] = val;
}
for j in reach.iter().cloned() {
let mut column = self.data.column_entries(j);
let mut diag_found = false;
while let Some((i, val)) = column.next() {
if i == j {
if val.is_zero() {
break;
}
workspace[j] /= val;
diag_found = true;
break;
}
}
if !diag_found {
return None;
}
for (i, val) in column {
workspace[i] -= workspace[j] * val;
}
}
// Copy the result into a sparse vector.
let mut result = CsVector::new_uninitialized_generic(b.data.shape().0, U1, reach.len());
for (i, val) in reach.iter().zip(result.data.vals.iter_mut()) {
*val = workspace[*i];
}
result.data.i = reach;
Some(result)
}
/*
// Computes the reachable, post-ordered, nodes from `b`.
fn lower_triangular_reach_postordered<D2: Dim, S2>(
&self,
b: &CsVector<N, D2, S2>,
xi: &mut Vec<usize>,
) where
S2: CsStorage<N, D2>,
DefaultAllocator: Allocator<bool, D>,
{
let mut visited = VectorN::repeat_generic(self.data.shape().1, U1, false);
let mut stack = Vec::new();
for i in b.data.column_range(0) {
let row_index = b.data.row_index(i);
if !visited[row_index] {
let rng = self.data.column_range(row_index);
stack.push((row_index, rng));
self.lower_triangular_dfs(visited.as_mut_slice(), &mut stack, xi);
}
}
}
fn lower_triangular_dfs(
&self,
visited: &mut [bool],
stack: &mut Vec<(usize, Range<usize>)>,
xi: &mut Vec<usize>,
)
{
'recursion: while let Some((j, rng)) = stack.pop() {
visited[j] = true;
for i in rng.clone() {
let row_id = self.data.row_index(i);
if row_id > j && !visited[row_id] {
stack.push((j, (i + 1)..rng.end));
stack.push((row_id, self.data.column_range(row_id)));
continue 'recursion;
}
}
xi.push(j)
}
}
*/
// Computes the nodes reachable from `b` in an arbitrary order.
fn lower_triangular_reach<D2: Dim, S2>(&self, b: &CsVector<N, D2, S2>, xi: &mut Vec<usize>)
where
S2: CsStorage<N, D2>,
DefaultAllocator: Allocator<bool, D>,
{
let mut visited = VectorN::repeat_generic(self.data.shape().1, U1, false);
let mut stack = Vec::new();
for irow in b.data.column_row_indices(0) {
self.lower_triangular_bfs(irow, visited.as_mut_slice(), &mut stack, xi);
}
}
fn lower_triangular_bfs(
&self,
start: usize,
visited: &mut [bool],
stack: &mut Vec<usize>,
xi: &mut Vec<usize>,
)
{
if !visited[start] {
stack.clear();
stack.push(start);
xi.push(start);
visited[start] = true;
while let Some(j) = stack.pop() {
for irow in self.data.column_row_indices(j) {
if irow > j && !visited[irow] {
stack.push(irow);
xi.push(irow);
visited[irow] = true;
}
}
}
}
}
}

16
src/sparse/cs_utils.rs Normal file
View File

@ -0,0 +1,16 @@
use allocator::Allocator;
use {DefaultAllocator, Dim, VectorN};
pub fn cumsum<D: Dim>(a: &mut VectorN<usize, D>, b: &mut VectorN<usize, D>) -> usize
where DefaultAllocator: Allocator<usize, D> {
assert!(a.len() == b.len());
let mut sum = 0;
for i in 0..a.len() {
b[i] = sum;
sum += a[i];
a[i] = b[i];
}
sum
}

13
src/sparse/mod.rs Normal file
View File

@ -0,0 +1,13 @@
//! Sparse matrices.
pub use self::cs_matrix::{
CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsStorageMut, CsVecStorage, CsVector,
};
pub use self::cs_matrix_cholesky::CsCholesky;
mod cs_matrix;
mod cs_matrix_cholesky;
mod cs_matrix_conversion;
mod cs_matrix_ops;
mod cs_matrix_solve;
pub(crate) mod cs_utils;

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