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
### 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 `.dot` to quaternions.
* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them.
@ -25,13 +26,34 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* 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`
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
* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The
only restriction now ith that they must not be equal (in which case the projection would be singular).
* 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
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]
All dependencies have been updated to their latest versions.

View File

@ -1,6 +1,6 @@
[package]
name = "nalgebra"
version = "0.16.10"
version = "0.16.13"
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
@ -23,26 +23,31 @@ stdweb = [ "rand/stdweb" ]
arbitrary = [ "quickcheck" ]
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
abomonation-serialize = [ "abomonation" ]
sparse = [ ]
debug = [ ]
alloc = [ ]
io = [ "pest", "pest_derive" ]
[dependencies]
typenum = "1.10"
generic-array = "0.11"
rand = { version = "0.5", default-features = false }
generic-array = "0.12"
rand = { version = "0.6", default-features = false }
num-traits = { version = "0.2", default-features = false }
num-complex = { version = "0.2", default-features = false }
approx = { version = "0.3", default-features = false }
alga = { version = "0.7", default-features = false }
matrixmultiply = { version = "0.1", optional = true }
alga = { version = "0.8", default-features = false }
matrixmultiply = { version = "0.2", optional = true }
serde = { 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 }
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]
serde_json = "1.0"
rand_xorshift = "0.1"
[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) => {
#[bench]
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 b = rng.gen::<$t2>();
@ -19,7 +20,8 @@ macro_rules! bench_binop_ref(
($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
#[bench]
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 b = rng.gen::<$t2>();
@ -34,7 +36,8 @@ macro_rules! bench_binop_fn(
($name: ident, $t1: ty, $t2: ty, $binop: path) => {
#[bench]
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 b = rng.gen::<$t2>();
@ -51,7 +54,8 @@ macro_rules! bench_unop_na(
fn $name(bh: &mut Bencher) {
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 mut i = 0;
@ -73,7 +77,8 @@ macro_rules! bench_unop(
fn $name(bh: &mut Bencher) {
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 i = 0;
@ -95,7 +100,8 @@ macro_rules! bench_construction(
fn $name(bh: &mut Bencher) {
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 mut i = 0;

View File

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

View File

@ -14,6 +14,7 @@ mod geometry;
mod linalg;
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())
}

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 "abomonation-serialize";
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
cargo build -p nalgebra-lapack;
fi

View File

@ -51,8 +51,8 @@ fn main() {
// Components listed column-by-column.
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
]
.iter()
.cloned(),
.iter()
.cloned(),
);
assert_eq!(dm, dm1);

View File

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

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "nalgebra-glm"
version = "0.2.0"
version = "0.2.1"
authors = ["sebcrozet <developer@crozet.re>"]
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" ]
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]
num-traits = { version = "0.2", default-features = false }
approx = { version = "0.3", default-features = false }
alga = "0.7"
nalgebra = { path = "..", version = "^0.16.4" }
alga = { version = "0.8", default-features = false }
nalgebra = { path = "..", version = "^0.16.13", default-features = false }

View File

@ -1,5 +1,5 @@
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> {
// unimplemented!()
@ -53,119 +53,644 @@ use na::{Orthographic3, Perspective3, Real};
// 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> {
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> {
// unimplemented!()
//}
//
//pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// 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 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<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)
}
/// 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
/// 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> {
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> {
// 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:
///
@ -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:
///

View File

@ -1,6 +1,16 @@
//! (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::{
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> {
Unit::new_normalize(*x)
.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`.
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> {

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.
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.
pub fn quat_axis<N: Real>(x: &Qua<N>) -> TVec3<N> {
if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() {
a.unwrap()
a.into_inner()
} else {
TVec3::zeros()
}

View File

@ -15,4 +15,4 @@
//pub fn uround<N: Scalar, D: Dimension>(x: &TVec<N, D>) -> TVec<u32, D>
// where DefaultAllocator: Alloc<N, D> {
// unimplemented!()
//}
//}

View File

@ -288,4 +288,4 @@ pub fn unpackUnorm4x16(p: u64) -> Vec4 {
pub fn unpackUnorm4x4(p: u16) -> Vec4 {
unimplemented!()
}
}

View File

@ -5,7 +5,7 @@ use aliases::{Qua, TMat4, TVec, TVec3};
/// Euler angles of the quaternion `q` as (pitch, yaw, roll).
pub fn quat_euler_angles<N: Real>(x: &Qua<N>) -> TVec3<N> {
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)
}
@ -34,19 +34,25 @@ pub fn quat_cast<N: Real>(x: &Qua<N>) -> TMat4<N> {
::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> {
quat_look_at_rh(direction, up)
}
/// 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> {
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).
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.

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> {
Unit::new_unchecked(*x)
.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> {
@ -40,7 +40,7 @@ pub fn quat_magnitude2<N: Real>(q: &Qua<N>) -> N {
/// The quaternion representing the identity rotation.
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.
@ -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> {
UnitQuaternion::rotation_between(orig, dest)
.unwrap_or_else(UnitQuaternion::identity)
.unwrap()
.into_inner()
}
/// The spherical linear interpolation between two quaternions.
pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
Unit::new_normalize(*x)
.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> {
@ -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> {
UnitQuaternion::new_unchecked(*x)
.to_rotation_matrix()
.unwrap()
.into_inner()
}
/// 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.
pub fn mat3_to_quat<N: Real>(x: &TMat3<N>) -> Qua<N> {
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.

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.
/// * `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> {
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> {
Unit::new_unchecked(*x)
.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)).
*/
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate num_traits as num;
#[macro_use]
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,
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,
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, 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,
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, 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,
perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, perspective_rh,
perspective_rh_no, perspective_rh_zo, perspective_zo, ortho_lh, ortho_lh_no, ortho_lh_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::{
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 = ".." }
num-traits = "0.2"
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_derive = { version = "1.0", optional = true }
lapack = { version = "0.16", default-features = false }
@ -34,6 +34,6 @@ lapack-src = { version = "0.2", default-features = false }
[dev-dependencies]
nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] }
quickcheck = "0.6"
quickcheck = "0.8"
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.
for i in 0..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_results)]
#![deny(missing_docs)]
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc")]
#![doc(
html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc"
)]
extern crate alga;
extern crate lapack;

View File

@ -1,3 +1,3 @@
unstable_features = true
indent_style = "Block"
where_single_line = true
where_single_line = true

View File

@ -2,7 +2,7 @@
use base::dimension::Dynamic;
use base::dimension::{U1, U2, U3, U4, U5, U6};
#[cfg(any(feature = "std", feature = "alloc"))]
use base::matrix_vec::MatrixVec;
use base::vec_storage::VecStorage;
use base::storage::Owned;
use base::Matrix;
@ -119,7 +119,7 @@ pub type Matrix6x5<N> = MatrixMN<N, U6, U5>;
*/
/// A dynamically sized column vector.
#[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.
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.
#[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.
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>;
/// A column vector slice with `D` rows.
pub type VectorSliceN<'a, N, D, Stride = U1> =
Matrix<N, D, U1, SliceStorage<'a, N, D, U1, Stride, D>>;
pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> =
Matrix<N, D, U1, SliceStorage<'a, N, D, U1, RStride, CStride>>;
/// 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.
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.
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.
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.
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.
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.
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>;
/// A mutable column vector slice with `D` rows.
pub type VectorSliceMutN<'a, N, D, Stride = U1> =
Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, Stride, D>>;
pub type VectorSliceMutN<'a, N, D, RStride = U1, CStride = D> =
Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, RStride, CStride>>;
/// 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.
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.
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.
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.
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.
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.
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.
#[repr(C)]
pub struct MatrixArray<N, R, C>
pub struct ArrayStorage<N, R, C>
where
R: DimName,
C: DimName,
@ -44,7 +44,11 @@ where
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
N: Hash,
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
R: 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
R: 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
N: Debug,
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
N: Copy,
R: DimName,
@ -109,7 +113,7 @@ where
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
N: Clone,
R: DimName,
@ -119,13 +123,13 @@ where
{
#[inline]
fn clone(&self) -> Self {
MatrixArray {
ArrayStorage {
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
N: Eq,
R: DimName,
@ -134,7 +138,7 @@ where
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
N: PartialEq,
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
N: Scalar,
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
N: Scalar,
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
N: Scalar,
R: DimName,
@ -230,7 +234,7 @@ where
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
N: Scalar,
R: DimName,
@ -247,7 +251,7 @@ where
*/
// XXX: open an issue for GenericArray so that it implements serde traits?
#[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
N: Scalar + Serialize,
R: DimName,
@ -268,7 +272,7 @@ where
}
#[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
N: Scalar + Deserialize<'a>,
R: DimName,
@ -278,18 +282,18 @@ where
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
deserializer.deserialize_seq(MatrixArrayVisitor::new())
deserializer.deserialize_seq(ArrayStorageVisitor::new())
}
}
#[cfg(feature = "serde-serialize")]
/// A visitor that produces a matrix array.
struct MatrixArrayVisitor<N, R, C> {
struct ArrayStorageVisitor<N, R, C> {
marker: PhantomData<(N, R, C)>,
}
#[cfg(feature = "serde-serialize")]
impl<N, R, C> MatrixArrayVisitor<N, R, C>
impl<N, R, C> ArrayStorageVisitor<N, R, C>
where
N: Scalar,
R: DimName,
@ -299,14 +303,14 @@ where
{
/// Construct a new sequence visitor.
pub fn new() -> Self {
MatrixArrayVisitor {
ArrayStorageVisitor {
marker: PhantomData,
}
}
}
#[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
N: Scalar + Deserialize<'a>,
R: DimName,
@ -314,20 +318,20 @@ where
R::Value: Mul<C::Value>,
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 {
formatter.write_str("a matrix array")
}
#[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> {
let mut out: Self::Value = unsafe { mem::uninitialized() };
let mut curr = 0;
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;
}
@ -340,7 +344,7 @@ where
}
#[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
R: 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::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector};
impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index of the vector component with the largest value.
impl<N: Scalar + PartialOrd, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index and value of the vector component with the largest value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.imax(), 2);
/// assert_eq!(vec.argmax(), (2, 13));
/// ```
#[inline]
pub fn imax(&self) -> usize {
pub fn argmax(&self) -> (usize, N) {
assert!(!self.is_empty(), "The input vector must not be empty.");
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.
@ -52,7 +66,8 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// assert_eq!(vec.iamax(), 1);
/// ```
#[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.");
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
}
/// 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.
///
/// # Examples:
@ -81,21 +124,7 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// ```
#[inline]
pub fn imin(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty.");
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
self.argmin().0
}
/// 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);
/// ```
#[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.");
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;
for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i).abs() };
if val < the_max {
the_max = val;
if val < the_min {
the_min = val;
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) {
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);
for j in 0..self.ncols() {
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 {
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.
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe {
let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0);
let b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0);
let a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0));
let b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
return a + b;
}
}
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe {
let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0);
let b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0);
let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0);
let a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0));
let b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0));
return a + b + c;
}
}
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe {
let mut a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0);
let mut b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0);
let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0);
let d = *self.get_unchecked(3, 0) * *rhs.get_unchecked(3, 0);
let mut a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0));
let mut b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0));
let d = *self.get_unchecked((3, 0)) * *rhs.get_unchecked((3, 0));
a += c;
b += d;
@ -257,14 +287,14 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
acc7 = N::zero();
while self.nrows() - i >= 8 {
acc0 += unsafe { *self.get_unchecked(i + 0, j) * *rhs.get_unchecked(i + 0, j) };
acc1 += unsafe { *self.get_unchecked(i + 1, j) * *rhs.get_unchecked(i + 1, j) };
acc2 += unsafe { *self.get_unchecked(i + 2, j) * *rhs.get_unchecked(i + 2, j) };
acc3 += unsafe { *self.get_unchecked(i + 3, j) * *rhs.get_unchecked(i + 3, j) };
acc4 += unsafe { *self.get_unchecked(i + 4, j) * *rhs.get_unchecked(i + 4, j) };
acc5 += unsafe { *self.get_unchecked(i + 5, j) * *rhs.get_unchecked(i + 5, j) };
acc6 += unsafe { *self.get_unchecked(i + 6, j) * *rhs.get_unchecked(i + 6, j) };
acc7 += unsafe { *self.get_unchecked(i + 7, j) * *rhs.get_unchecked(i + 7, j) };
acc0 += unsafe { *self.get_unchecked((i + 0, j)) * *rhs.get_unchecked((i + 0, j)) };
acc1 += unsafe { *self.get_unchecked((i + 1, j)) * *rhs.get_unchecked((i + 1, j)) };
acc2 += unsafe { *self.get_unchecked((i + 2, j)) * *rhs.get_unchecked((i + 2, j)) };
acc3 += unsafe { *self.get_unchecked((i + 3, j)) * *rhs.get_unchecked((i + 3, j)) };
acc4 += unsafe { *self.get_unchecked((i + 4, j)) * *rhs.get_unchecked((i + 4, j)) };
acc5 += unsafe { *self.get_unchecked((i + 5, j)) * *rhs.get_unchecked((i + 5, j)) };
acc6 += unsafe { *self.get_unchecked((i + 6, j)) * *rhs.get_unchecked((i + 6, j)) };
acc7 += unsafe { *self.get_unchecked((i + 7, j)) * *rhs.get_unchecked((i + 7, j)) };
i += 8;
}
@ -274,7 +304,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
res += acc3 + acc7;
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 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;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity();
/// 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;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix3x2::new(1.0, 4.0,
@ -879,7 +907,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{DMatrix, DVector};
/// // 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
@ -934,7 +961,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
/// let mut mat = Matrix2::identity();
/// 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;
/// # extern crate nalgebra;
/// # use nalgebra::{DMatrix, DVector};
/// // 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
@ -1026,7 +1051,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
/// let mut mat = Matrix2::identity();
/// 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.
#[inline]
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.
#[inline]
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
@ -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
/// `eye`.
#[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 {
IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous()
Matrix4::face_towards(eye, target, up)
}
/// 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 normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
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() {
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 std::ops::{Add, Mul};
@ -61,7 +61,7 @@ macro_rules! component_binop_impl(
for j in 0 .. res.ncols() {
for i in 0 .. res.nrows() {
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 i in 0 .. self.nrows() {
unsafe {
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
*self.get_unchecked_mut(i, j) = res;
let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
*self.get_unchecked_mut((i, j)) = res;
}
}
}
@ -99,8 +99,8 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
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;
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;
}
}
}
@ -121,7 +121,7 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
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 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 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);
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
@ -152,7 +152,7 @@ where DefaultAllocator: Allocator<N, R, C>
);
for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut(i, i) = *elt }
unsafe { *res.get_unchecked_mut((i, i)) = *elt }
}
res
@ -270,7 +270,7 @@ where DefaultAllocator: Allocator<N, R, C>
/// let vec_ptr = vec.as_ptr();
///
/// 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.
/// 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));
/// // 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 &&
/// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 &&
@ -313,7 +313,7 @@ where
for i in 0..diag.len() {
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)
}
/// 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
/// component coordinates.
///
@ -612,32 +555,6 @@ macro_rules! impl_constructors(
) -> Self {
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)*>
@ -676,6 +593,125 @@ impl_constructors!(Dynamic, Dynamic;
Dynamic::new(nrows), Dynamic::new(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.
@ -791,7 +827,7 @@ macro_rules! componentwise_constructors_impl(
pub fn new($($args: N),*) -> Self {
unsafe {
let mut res = Self::new_uninitialized();
$( *res.get_unchecked_mut($irow, $icol) = $args; )*
$( *res.get_unchecked_mut(($irow, $icol)) = $args; )*
res
}

View File

@ -12,13 +12,15 @@ use typenum::Prod;
use base::allocator::{Allocator, SameShapeAllocator};
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
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::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))]
use base::MatrixVec;
use base::{DefaultAllocator, Matrix, MatrixArray, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
use base::VecStorage;
use base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
// 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>
@ -42,7 +44,7 @@ where
let mut res = unsafe { MatrixMN::<N2, R2, C2>::new_uninitialized_generic(nrows2, ncols2) };
for i in 0..nrows {
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);
for i in 0..nrows2 {
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>>
for Matrix<N, R, C, MatrixArray<N, R, C>>
for Matrix<N, R, C, ArrayStorage<N, R, C>>
where
N: Scalar,
R: DimName,
@ -353,7 +355,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
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
N: Scalar,
C: Dim,
@ -367,7 +369,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
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
N: Scalar,
R: DimName,
@ -380,7 +382,7 @@ where
}
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
N: Scalar,
R: DimName,
@ -397,7 +399,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
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
N: Scalar,
C: Dim,
@ -411,7 +413,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
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
N: Scalar,
R: DimName,

View File

@ -18,9 +18,9 @@ use base::allocator::{Allocator, Reallocator};
#[cfg(any(feature = "alloc", feature = "std"))]
use base::dimension::Dynamic;
use base::dimension::{Dim, DimName};
use base::matrix_array::MatrixArray;
use base::array_storage::ArrayStorage;
#[cfg(any(feature = "std", feature = "alloc"))]
use base::matrix_vec::MatrixVec;
use base::vec_storage::VecStorage;
use base::storage::{Storage, StorageMut};
use base::Scalar;
@ -29,7 +29,7 @@ use base::Scalar;
* 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.
pub struct DefaultAllocator;
@ -42,7 +42,7 @@ where
R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>,
{
type Buffer = MatrixArray<N, R, C>;
type Buffer = ArrayStorage<N, R, C>;
#[inline]
unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
@ -77,7 +77,7 @@ where
// Dynamic - Dynamic
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
type Buffer = MatrixVec<N, Dynamic, C>;
type Buffer = VecStorage<N, Dynamic, C>;
#[inline]
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.set_len(length);
MatrixVec::new(nrows, ncols, res)
VecStorage::new(nrows, ncols, res)
}
#[inline]
@ -101,14 +101,14 @@ impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
assert!(res.len() == nrows.value() * ncols.value(),
"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
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
type Buffer = MatrixVec<N, R, Dynamic>;
type Buffer = VecStorage<N, R, Dynamic>;
#[inline]
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.set_len(length);
MatrixVec::new(nrows, ncols, res)
VecStorage::new(nrows, ncols, res)
}
#[inline]
@ -132,7 +132,7 @@ impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
assert!(res.len() == nrows.value() * ncols.value(),
"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,
cto: CTo,
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);
@ -185,8 +185,8 @@ where
unsafe fn reallocate_copy(
rto: Dynamic,
cto: CTo,
buf: MatrixArray<N, RFrom, CFrom>,
) -> MatrixVec<N, Dynamic, CTo>
buf: ArrayStorage<N, RFrom, CFrom>,
) -> VecStorage<N, Dynamic, CTo>
{
let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto);
@ -214,8 +214,8 @@ where
unsafe fn reallocate_copy(
rto: RTo,
cto: Dynamic,
buf: MatrixArray<N, RFrom, CFrom>,
) -> MatrixVec<N, RTo, Dynamic>
buf: ArrayStorage<N, RFrom, CFrom>,
) -> VecStorage<N, RTo, Dynamic>
{
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(
rto: Dynamic,
cto: CTo,
buf: MatrixVec<N, Dynamic, CFrom>,
) -> MatrixVec<N, Dynamic, CTo>
buf: VecStorage<N, Dynamic, CFrom>,
) -> VecStorage<N, Dynamic, CTo>
{
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(
rto: RTo,
cto: Dynamic,
buf: MatrixVec<N, Dynamic, CFrom>,
) -> MatrixVec<N, RTo, Dynamic>
buf: VecStorage<N, Dynamic, CFrom>,
) -> VecStorage<N, RTo, Dynamic>
{
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(
rto: Dynamic,
cto: CTo,
buf: MatrixVec<N, RFrom, Dynamic>,
) -> MatrixVec<N, Dynamic, CTo>
buf: VecStorage<N, RFrom, Dynamic>,
) -> VecStorage<N, Dynamic, CTo>
{
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(
rto: RTo,
cto: Dynamic,
buf: MatrixVec<N, RFrom, Dynamic>,
) -> MatrixVec<N, RTo, Dynamic>
buf: VecStorage<N, RFrom, Dynamic>,
) -> VecStorage<N, RTo, Dynamic>
{
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;
DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff;
DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot;
DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameNimimum, Minimum;
DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum;
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
);
@ -364,7 +364,8 @@ impl<
G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
> IsNotStaticOne
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
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
for UInt<U, B>
{}
{
}

View File

@ -1,12 +1,18 @@
use num::{One, Zero};
use std::cmp;
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::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
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};
#[cfg(any(feature = "std", feature = "alloc"))]
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
}
/// Extracts the upper triangular part of this matrix (including the diagonal).
/// Extracts the lower triangular part of this matrix (including the diagonal).
#[inline]
pub fn lower_triangle(&self) -> MatrixMN<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
}
/// 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> {
@ -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);
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) {
assert!(i < self.nrows(), "Row index out of bounds.");
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) {
assert!(j < self.ncols(), "Row index out of bounds.");
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.");
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) {
for j in 0..self.ncols() {
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 ?
// (necessary for rectangular matrices)
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 i in j + 1..dim {
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 i in 0..j {
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).
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic>
where
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).
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C>
where
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.
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic>
where
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.
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C>
where
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)
}
/// 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.
///
/// 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>(
data: &mut [N],
nrows: usize,
@ -706,6 +842,7 @@ unsafe fn extend_rows<N: Scalar>(
/// Extend the number of columns of the `Matrix` with elements from
/// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S>
where
N: Scalar,
@ -753,6 +890,7 @@ where
/// Extend the number of rows of the `Vector` with elements from
/// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S>
where
N: Scalar,
@ -764,15 +902,16 @@ where
/// # Example
/// ```
/// # 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]);
/// 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) {
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>
where
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::mem;
use base::dimension::Dim;
use base::dimension::{Dim, U1};
use base::storage::{Storage, StorageMut};
use base::Scalar;
use base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut};
macro_rules! iterator {
(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 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::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
@ -20,8 +21,8 @@ use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Real, Ring};
use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{Dim, DimAdd, DimSum, U1, U2, U3};
use base::iter::{MatrixIter, MatrixIterMut};
use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
use base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut};
use base::storage::{
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
/// some concrete types for `N` and a compatible data storage type `S`).
#[repr(C)]
#[derive(Hash, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
/// The data storage that contains all the matrix components and informations about its number
/// 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)
}
/// 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
/// vector.
#[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.
///
/// 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 i in 0..res.nrows() {
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`,
/// `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]
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
&self,
@ -512,6 +533,57 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
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`.
#[inline]
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 j in 0..ncols {
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()
}
/// 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]
pub unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut N {
debug_assert!(
irow < self.nrows() && icol < self.ncols(),
"Matrix index out of bounds."
);
self.data.get_unchecked_mut(irow, icol)
pub fn row_iter_mut(&mut self) -> RowIterMut<N, R, C, S> {
RowIterMut::new(self)
}
/// Mutably iterates through this matrix columns.
///
/// # 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.
@ -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 i in 0..nrows {
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 i in 0..self.nrows() {
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 i in 0..nrows {
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.
#[inline]
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F)
where DefaultAllocator: Allocator<N, R, C> {
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) {
let (nrows, ncols) = self.shape();
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> {
@ -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 j in 0..ncols {
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 j in 0..i {
unsafe {
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_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 conj_ij = (*ref_ij).conj();
let conj_ji = (*ref_ji).conj();
*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() {
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();
for i in 0..dim.value() {
res += unsafe { *self.get_unchecked(i, i) };
res += unsafe { *self.get_unchecked((i, i)) };
}
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> {
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
/// coordinates.
#[inline]
pub fn to_homogeneous(&self) -> 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)] = N::zero();
res
self.push(N::zero())
}
/// 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>
where
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 ");
unsafe {
*self.get_unchecked(0, 0) * *b.get_unchecked(1, 0)
- *self.get_unchecked(1, 0) * *b.get_unchecked(0, 0)
*self.get_unchecked((0, 0)) * *b.get_unchecked((1, 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 mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let ax = *self.get_unchecked(0, 0);
let ay = *self.get_unchecked(1, 0);
let az = *self.get_unchecked(2, 0);
let ax = *self.get_unchecked((0, 0));
let ay = *self.get_unchecked((1, 0));
let az = *self.get_unchecked((2, 0));
let bx = *b.get_unchecked(0, 0);
let by = *b.get_unchecked(1, 0);
let bz = *b.get_unchecked(2, 0);
let bx = *b.get_unchecked((0, 0));
let by = *b.get_unchecked((1, 0));
let bz = *b.get_unchecked((2, 0));
*res.get_unchecked_mut(0, 0) = ay * bz - az * by;
*res.get_unchecked_mut(1, 0) = az * bx - ax * bz;
*res.get_unchecked_mut(2, 0) = ax * by - ay * bx;
*res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
*res.get_unchecked_mut((1, 0)) = az * bx - ax * bz;
*res.get_unchecked_mut((2, 0)) = ax * by - ay * bx;
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 mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let ax = *self.get_unchecked(0, 0);
let ay = *self.get_unchecked(0, 1);
let az = *self.get_unchecked(0, 2);
let ax = *self.get_unchecked((0, 0));
let ay = *self.get_unchecked((0, 1));
let az = *self.get_unchecked((0, 2));
let bx = *b.get_unchecked(0, 0);
let by = *b.get_unchecked(0, 1);
let bz = *b.get_unchecked(0, 2);
let bx = *b.get_unchecked((0, 0));
let by = *b.get_unchecked((0, 1));
let bz = *b.get_unchecked((0, 2));
*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, 2) = ax * by - ay * bx;
*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, 2)) = ax * by - ay * bx;
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>>
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>>
where
N: Scalar + AbsDiffEq,
@ -1484,3 +1588,24 @@ where
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::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
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,
};
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
N: Scalar + ClosedNeg,
DefaultAllocator: Allocator<N, R, C>,
{
#[inline]
fn inverse(&self) -> MatrixMN<N, R, C> {
fn two_sided_inverse(&self) -> MatrixMN<N, R, C> {
-self
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
*self = -self.clone()
}
}

View File

@ -4,9 +4,9 @@ use std::slice;
use base::allocator::Allocator;
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::storage::{Owned, Storage, StorageMut};
use base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut};
use base::{Matrix, Scalar};
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
for SliceStorage<'a, N, R, C, RStride, CStride>
{}
{
}
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
for SliceStorage<'a, N, R, C, RStride, CStride>
@ -146,8 +147,6 @@ macro_rules! storage_impl(
}
}
#[inline]
fn into_owned(self) -> Owned<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> {
#[inline]
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)
}
}
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 conversion;
mod edition;
pub mod indexing;
mod matrix;
mod matrix_alga;
mod matrix_array;
mod array_storage;
mod matrix_slice;
#[cfg(any(feature = "std", feature = "alloc"))]
mod matrix_vec;
mod vec_storage;
mod properties;
mod scalar;
mod swizzle;
mod unit;
mod statistics;
mod norm;
#[doc(hidden)]
pub mod helper;
@ -35,13 +38,14 @@ pub mod helper;
pub use self::matrix::*;
pub use self::scalar::*;
pub use self::unit::*;
pub use self::norm::*;
pub use self::default_allocator::*;
pub use self::dimension::*;
pub use self::alias::*;
pub use self::alias_slice::*;
pub use self::matrix_array::*;
pub use self::array_storage::*;
pub use self::matrix_slice::*;
#[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."
);
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."
);
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 i in 0 .. self.nrows() {
unsafe {
let val = self.get_unchecked(i, j).$method(*rhs.get_unchecked(i, j));
*out.get_unchecked_mut(i, j) = val;
let val = self.get_unchecked((i, j)).$method(*rhs.get_unchecked((i, j)));
*out.get_unchecked_mut((i, j)) = val;
}
}
}
@ -204,7 +204,7 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. rhs.ncols() {
for i in 0 .. rhs.nrows() {
unsafe {
self.get_unchecked_mut(i, j).$method_assign(*rhs.get_unchecked(i, j))
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 i in 0 .. self.nrows() {
unsafe {
let r = rhs.get_unchecked_mut(i, j);
*r = self.get_unchecked(i, j).$method(*r)
let r = rhs.get_unchecked_mut((i, j));
*r = self.get_unchecked((i, j)).$method(*r)
}
}
}
@ -448,7 +448,7 @@ macro_rules! componentwise_scalarop_impl(
fn $method_assign(&mut self, rhs: N) {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe { self.get_unchecked_mut(i, j).$method_assign(rhs) };
unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs) };
}
}
}
@ -657,7 +657,7 @@ where
for i in 0..ncols1 {
for j in 0..ncols2 {
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 i1 in 0..nrows1.value() {
unsafe {
let coeff = *self.get_unchecked(i1, j1);
let coeff = *self.get_unchecked((i1, j1));
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);
}
}
@ -761,7 +761,7 @@ where
}
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]
pub fn amax(&self) -> N {
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
}
/// 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]
pub fn amin(&self) -> N {
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
}
/// 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
/// 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
/// (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.
pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
/// The static stride of this storage's rows.

View File

@ -3,64 +3,60 @@ use storage::Storage;
use typenum::{self, Cmp, Greater};
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> {
/// Builds a new vector from components of `self`.
#[inline]
pub fn $name(&self) -> $Result<N>
where D::Value: Cmp<typenum::$BaseDim, Output=Greater> {
$Result::new($(self[$i]),*)
}
impl<N: Scalar, D: DimName, S: Storage<N, D>> Vector<N, D, S>
where D::Value: Cmp<typenum::$BaseDim, Output=Greater>
{
$(
/// Builds a new vector from components of `self`.
#[inline]
pub fn $name(&self) -> $Result<N> {
$Result::new($(self[$i]),*)
}
)*
}
)*
}
}
impl_swizzle!(
where U0: xx() -> Vector2[0, 0];
where U1: xy() -> Vector2[0, 1];
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: xx() -> Vector2[0, 0],
xxx() -> Vector3[0, 0, 0];
where U0: xxx() -> Vector3[0, 0, 0];
where U1: xxy() -> Vector3[0, 0, 1];
where U2: xxz() -> Vector3[0, 0, 2];
where U1: xy() -> Vector2[0, 1],
yx() -> Vector2[1, 0],
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 U1: xyy() -> Vector3[0, 1, 1];
where U2: xyz() -> Vector3[0, 1, 2];
where U2: xzx() -> Vector3[0, 2, 0];
where U2: xzy() -> Vector3[0, 2, 1];
where U2: xzz() -> Vector3[0, 2, 2];
where U1: yxx() -> Vector3[1, 0, 0];
where U1: yxy() -> Vector3[1, 0, 1];
where U2: yxz() -> Vector3[1, 0, 2];
where U1: yyx() -> Vector3[1, 1, 0];
where U1: yyy() -> Vector3[1, 1, 1];
where U2: yyz() -> Vector3[1, 1, 2];
where U2: yzx() -> Vector3[1, 2, 0];
where U2: yzy() -> Vector3[1, 2, 1];
where U2: yzz() -> Vector3[1, 2, 2];
where U2: zxx() -> Vector3[2, 0, 0];
where U2: zxy() -> Vector3[2, 0, 1];
where U2: zxz() -> Vector3[2, 0, 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]
where U2: xz() -> Vector2[0, 2],
yz() -> Vector2[1, 2],
zx() -> Vector2[2, 0],
zy() -> Vector2[2, 1],
zz() -> Vector2[2, 2],
xxz() -> Vector3[0, 0, 2],
xyz() -> Vector3[0, 1, 2],
xzx() -> Vector3[0, 2, 0],
xzy() -> Vector3[0, 2, 1],
xzz() -> Vector3[0, 2, 2],
yxz() -> Vector3[1, 0, 2],
yyz() -> Vector3[1, 1, 2],
yzx() -> Vector3[1, 2, 0],
yzy() -> Vector3[1, 2, 1],
yzz() -> Vector3[1, 2, 2],
zxx() -> Vector3[2, 0, 0],
zxy() -> Vector3[2, 0, 1],
zxz() -> Vector3[2, 0, 2],
zyx() -> Vector3[2, 1, 0],
zyy() -> Vector3[2, 1, 1],
zyz() -> Vector3[2, 1, 2],
zzx() -> Vector3[2, 2, 0],
zzy() -> Vector3[2, 2, 1],
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.
///
/// 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)]
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
pub struct Unit<T> {
@ -113,6 +113,14 @@ impl<T> Unit<T> {
/// Retrieves the underlying value.
#[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 {
self.value
}
@ -143,7 +151,7 @@ where T::Field: RelativeEq
{
#[inline]
fn to_superset(&self) -> T {
self.clone().unwrap()
self.clone().into_inner()
}
#[inline]

View File

@ -1,6 +1,5 @@
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
use std::ops::Deref;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec;
@ -24,21 +23,25 @@ use abomonation::Abomonation;
#[repr(C)]
#[derive(Eq, Debug, Clone, PartialEq)]
#[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>,
nrows: R,
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.
#[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!(
nrows.value() * ncols.value() == data.len(),
"Data storage buffer dimension mismatch."
);
MatrixVec {
VecStorage {
data: data,
nrows: nrows,
ncols: ncols,
@ -47,15 +50,16 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
/// The underlying data storage.
#[inline]
pub fn data(&self) -> &Vec<N> {
pub fn as_vec(&self) -> &Vec<N> {
&self.data
}
/// 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]
pub unsafe fn data_mut(&mut self) -> &mut Vec<N> {
pub unsafe fn as_vec_mut(&mut self) -> &mut Vec<N> {
&mut self.data
}
@ -77,14 +81,18 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
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> {
type Target = Vec<N>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
impl<N, R: Dim, C: Dim> Into<Vec<N>> for VecStorage<N, R, C>
{
fn into(self) -> Vec<N> {
self.data
}
}
@ -94,7 +102,7 @@ impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
* 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>
{
type RStride = U1;
@ -134,11 +142,11 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
#[inline]
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>
{
type RStride = U1;
@ -178,7 +186,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
&self.data
}
}
@ -187,7 +195,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
* 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>
{
#[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>
{
#[inline]
@ -222,7 +230,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
}
#[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<()> {
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.
///
/// # Panics
/// This function panics if the number of elements yielded by 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)
{
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
N: Scalar,
R: Dim,
@ -268,13 +276,13 @@ where
SV: Storage<N, 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.
///
/// # Panics
/// This function panics if the number of rows of each `Vector`
/// 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)
{
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.
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
{

View File

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

View File

@ -49,6 +49,7 @@ where
Owned<N, D, D>: Clone + Send,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
use rand::Rng;
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
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;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
@ -167,7 +166,7 @@ where DefaultAllocator: Allocator<N, D>
/// ```
#[inline]
pub fn inverse_mut(&mut self) {
self.rotation.inverse_mut();
self.rotation.two_sided_inverse_mut();
self.translation.inverse_mut();
self.translation.vector = self.rotation.transform_vector(&self.translation.vector);
}
@ -197,7 +196,6 @@ where DefaultAllocator: Allocator<N, D>
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
/// 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;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// 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;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Vector2, Matrix3};
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);

View File

@ -1,6 +1,6 @@
use alga::general::{
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::{
@ -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
R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D>,
{
#[inline]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.inverse()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
self.inverse_mut()
}
}

View File

@ -16,7 +16,7 @@ use base::{DefaultAllocator, Vector2, Vector3};
use geometry::{
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>
@ -49,7 +49,6 @@ where DefaultAllocator: Allocator<N, D>
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::PI);
@ -130,6 +129,18 @@ impl<N: Real> Isometry<N, U2, Rotation2<N>> {
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>> {
@ -153,6 +164,18 @@ impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
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.
@ -165,7 +188,6 @@ macro_rules! isometry_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -191,6 +213,18 @@ macro_rules! isometry_construction_impl(
$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
/// point `eye` and looking toward `target`.
///
@ -206,7 +240,6 @@ macro_rules! isometry_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
@ -214,23 +247,32 @@ macro_rules! isometry_construction_impl(
/// let up = Vector3::y();
///
/// // 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_relative_eq!(iso * Vector3::z(), Vector3::x());
///
/// // 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_relative_eq!(iso * Vector3::z(), Vector3::x());
/// ```
#[inline]
pub fn new_observer_frame(eye: &Point3<N>,
pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>)
-> Self {
Self::from_parts(
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.
@ -249,7 +291,6 @@ macro_rules! isometry_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
@ -293,7 +334,6 @@ macro_rules! isometry_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);

View File

@ -200,8 +200,8 @@ isometry_binop_assign_impl_all!(
DivAssign, div_assign;
self: Isometry<N, D, R>, rhs: R;
// FIXME: don't invert explicitly?
[val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse();
[val] => *self *= rhs.two_sided_inverse();
[ref] => *self *= rhs.two_sided_inverse();
);
// Isometry × R

View File

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

View File

@ -69,7 +69,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3};
/// 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.
@ -170,7 +169,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let inv = proj.inverse();
@ -271,7 +269,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// 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, 0.0, 1.0
/// );
/// assert_eq!(proj.unwrap(), expected);
/// assert_eq!(proj.into_inner(), expected);
/// ```
#[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> {
self.matrix
}
@ -291,7 +296,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -308,7 +312,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -325,7 +328,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -342,7 +344,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -359,7 +360,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -376,7 +376,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -395,7 +394,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3};
/// 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
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3};
/// 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
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Vector3};
/// 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;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left(2.0);
@ -516,7 +511,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_right(15.0);
@ -536,7 +530,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom(8.0);
@ -556,7 +549,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_top(15.0);
@ -576,7 +568,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear(8.0);
@ -596,7 +587,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_zfar(15.0);
@ -616,7 +606,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -642,7 +631,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -668,7 +656,6 @@ impl<N: Real> Orthographic3<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3;
/// 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);
@ -725,6 +712,6 @@ where Matrix4<N>: Send
impl<N: Real> From<Orthographic3<N>> for Matrix4<N> {
#[inline]
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.
#[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> {
self.matrix
}
@ -279,6 +287,6 @@ impl<N: Real + Arbitrary> Arbitrary for Perspective3<N> {
impl<N: Real> From<Perspective3<N>> for Matrix4<N> {
#[inline]
fn from(orth: Perspective3<N>) -> Self {
orth.unwrap()
orth.into_inner()
}
}

View File

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

View File

@ -2,7 +2,7 @@ use num::Zero;
use alga::general::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Inverse, Module,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module,
Multiplicative, Real,
};
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]
fn inverse(&self) -> Self {
fn two_sided_inverse(&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]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.inverse()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
self.inverse_mut()
}
}

View File

@ -76,7 +76,7 @@ impl<N: Real> Quaternion<N> {
where SB: Storage<N, U3> {
let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64));
rot.unwrap() * scale
rot.into_inner() * scale
}
/// The quaternion multiplicative identity.
@ -166,7 +166,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axis = Vector3::y_axis();
@ -208,7 +207,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
@ -237,7 +235,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, UnitQuaternion, Vector3};
/// let axis = Vector3::y_axis();
/// let angle = 0.1;
@ -302,7 +299,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
@ -325,7 +321,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
@ -361,7 +356,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// 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));
@ -387,7 +381,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// 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));
@ -446,22 +439,31 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// 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());
/// ```
#[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
SB: 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.
@ -478,7 +480,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -493,7 +494,7 @@ impl<N: Real> UnitQuaternion<N> {
SB: 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.
@ -510,7 +511,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -525,7 +525,7 @@ impl<N: Real> UnitQuaternion<N> {
SB: 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.
@ -535,7 +535,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -565,7 +564,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -596,7 +594,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -625,7 +622,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -693,15 +689,16 @@ where
#[cfg(test)]
mod tests {
extern crate rand_xorshift;
use super::*;
use rand::{self, SeedableRng};
use rand::SeedableRng;
#[test]
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 {
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> {
#[inline]
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> ;
self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap());
Unit::new_unchecked(self * rhs.into_inner());
'a);
quaternion_op_impl!(
@ -485,7 +485,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap());
Unit::new_unchecked(self * rhs.into_inner());
);
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.
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> {
Reflection {
axis: axis.unwrap(),
axis: axis.into_inner(),
bias: bias,
}
}

View File

@ -154,7 +154,7 @@ where DefaultAllocator: Allocator<N, D, D>
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3};
/// # use std::f32;
/// 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,
/// 0.5, 0.8660254, 0.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 mat = rot.unwrap();
/// let mat = rot.into_inner();
/// let expected = Matrix2::new(0.8660254, -0.5,
/// 0.5, 0.8660254);
/// assert_eq!(mat, expected);
/// ```
#[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> {
self.matrix
}
@ -201,6 +209,9 @@ where DefaultAllocator: Allocator<N, D, D>
D: DimNameAdd<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();
res.fixed_slice_mut::<D, D>(0, 0).copy_from(&self.matrix);
@ -246,7 +257,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let tr_rot = rot.transpose();
@ -270,7 +280,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let inv = rot.inverse();
@ -294,7 +303,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// 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));
@ -322,7 +330,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// 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));

View File

@ -1,6 +1,6 @@
use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real,
AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
};
use alga::linear::{
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>
{
#[inline]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.transpose()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
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> {
#[inline]
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> {
#[inline]
fn from(q: Rotation3<N>) -> Matrix3<N> {
q.unwrap()
q.into_inner()
}
}

View File

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

View File

@ -27,7 +27,6 @@ impl<N: Real> Rotation2<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation2, Point2};
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
@ -56,7 +55,6 @@ impl<N: Real> Rotation2<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
@ -79,7 +77,6 @@ impl<N: Real> Rotation2<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
@ -107,9 +104,10 @@ impl<N: Real> Rotation2<N> {
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(1.78);
/// assert_eq!(rot.angle(), 1.78);
/// assert_relative_eq!(rot.angle(), 1.78);
/// ```
#[inline]
pub fn angle(&self) -> N {
@ -121,7 +119,6 @@ impl<N: Real> Rotation2<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7);
@ -139,7 +136,6 @@ impl<N: Real> Rotation2<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7);
@ -158,10 +154,11 @@ impl<N: Real> Rotation2<N> {
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(0.78);
/// let pow = rot.powf(2.0);
/// assert_eq!(pow.angle(), 2.0 * 0.78);
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ```
#[inline]
pub fn powf(&self, n: N) -> Rotation2<N> {
@ -213,7 +210,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -241,7 +237,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -265,7 +260,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axis = Vector3::y_axis();
@ -318,7 +312,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
@ -359,7 +352,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
@ -370,12 +362,12 @@ impl<N: Real> Rotation3<N> {
pub fn euler_angles(&self) -> (N, N, N) {
// 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
if self[(2, 0)].abs() != N::one() {
if self[(2, 0)].abs() < N::one() {
let yaw = -self[(2, 0)].asin();
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());
(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())
} else {
(
@ -399,17 +391,16 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// 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());
/// ```
#[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
SB: 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.
///
/// It maps the view direction `dir` to the **negative** `z` axis.
@ -437,7 +438,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -452,7 +452,7 @@ impl<N: Real> Rotation3<N> {
SB: 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.
@ -469,7 +469,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -484,7 +483,7 @@ impl<N: Real> Rotation3<N> {
SB: 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.
@ -494,7 +493,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
@ -517,7 +515,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
@ -562,7 +559,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Rotation3, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = Rotation3::from_axis_angle(&axis, 1.78);
@ -580,7 +576,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
@ -607,7 +602,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = Rotation3::new(axisangle);
@ -616,7 +610,7 @@ impl<N: Real> Rotation3<N> {
#[inline]
pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() {
axis.unwrap() * self.angle()
axis.into_inner() * self.angle()
} else {
Vector::zero()
}
@ -629,7 +623,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
@ -656,7 +649,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -674,7 +666,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -692,7 +683,6 @@ impl<N: Real> Rotation3<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;

View File

@ -1,6 +1,6 @@
use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Identity, Inverse, Multiplicative, Real,
AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
};
use alga::linear::Similarity as AlgaSimilarity;
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
R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D>,
{
#[inline]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.inverse()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
self.inverse_mut()
}
}

View File

@ -86,7 +86,6 @@ where
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Similarity2, Point2, UnitComplex};
/// 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;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
/// 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;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Similarity2, Vector2, Point2};
/// 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;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -227,7 +223,6 @@ macro_rules! similarity_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
@ -235,22 +230,32 @@ macro_rules! similarity_construction_impl(
/// let up = Vector3::y();
///
/// // 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_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).
/// 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_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
/// ```
#[inline]
pub fn new_observer_frame(eye: &Point3<N>,
pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>,
scaling: N)
-> 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.
@ -268,7 +273,6 @@ macro_rules! similarity_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
@ -307,7 +311,6 @@ macro_rules! similarity_construction_impl(
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);

View File

@ -222,8 +222,8 @@ similarity_binop_assign_impl_all!(
DivAssign, div_assign;
self: Similarity<N, D, R>, rhs: R;
// FIXME: don't invert explicitly?
[val] => *self *= rhs.inverse();
[ref] => *self *= rhs.inverse();
[val] => *self *= rhs.two_sided_inverse();
[ref] => *self *= rhs.two_sided_inverse();
);
// 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,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.unwrap(), m);
/// assert_eq!(t.into_inner(), m);
/// ```
#[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>> {
self.matrix
}
@ -329,7 +337,7 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.unwrap(), m);
/// assert_eq!(t.into_inner(), m);
/// ```
#[inline]
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
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Transform2};
///
/// 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
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Projective2};
///
/// 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
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Transform2};
///
/// 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
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Projective2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,

View File

@ -1,6 +1,6 @@
use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Identity, Inverse, Multiplicative, Real,
AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
};
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
C: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{
#[inline]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.clone().inverse()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
self.inverse_mut()
}
}
@ -116,12 +116,12 @@ where
{
#[inline]
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self.inverse() * pt
self.two_sided_inverse() * pt
}
#[inline]
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() {
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() {
return (transform * rhs + translation) / n;
@ -159,9 +159,9 @@ md_impl_all!(
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;
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());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.unwrap());
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.matrix());
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.into_inner());
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.into_inner());
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * 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;
(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>;
[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());
[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());
);
@ -181,8 +181,8 @@ md_impl_all!(
Mul, mul where N: Real;
(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>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[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());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
);
@ -192,9 +192,9 @@ md_impl_all!(
Mul, mul where N: Real;
(U4, U4), (U4, U1) for C: TCategoryMul<TAffine>;
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());
[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());
);
@ -203,8 +203,8 @@ md_impl_all!(
Mul, mul where N: Real;
(U4, U1), (U4, U4) for C: TCategoryMul<TAffine>;
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());
[ref 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.into_inner());
[val 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)
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>;
[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());
[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());
);
@ -227,8 +227,8 @@ md_impl_all!(
(D, U1), (DimNameSum<D, U1>, 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>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[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());
[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)
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>;
[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());
[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());
);
@ -251,8 +251,8 @@ md_impl_all!(
(D, U1), (DimNameSum<D, U1>, 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>;
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
[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());
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
);
@ -270,9 +270,9 @@ md_impl_all!(
Mul, mul where N: Real;
(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>;
[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());
[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());
);
@ -282,8 +282,8 @@ md_impl_all!(
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
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());
[ref 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.into_inner());
[val 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>> >
// 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>;
// [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());
// [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());
// );
@ -363,8 +363,8 @@ md_impl_all!(
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
// self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
// [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());
// [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, DimNameSum<D, U1>, DimNameSum<D, U1> >;
// 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());
// [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());
// );
@ -391,8 +391,8 @@ md_impl_all!(
// where SA::Alloc: Allocator<N, D, D >
// 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>;
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
// [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());
// [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;
(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>;
[val] => *self.matrix_mut_unchecked() *= rhs.unwrap();
[val] => *self.matrix_mut_unchecked() *= rhs.into_inner();
[ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
);

View File

@ -1,6 +1,6 @@
use alga::general::{
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::{
@ -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>
{
#[inline]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.inverse()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
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
/// ```
/// # extern crate num_complex;
/// # extern crate nalgebra;
/// # use num_complex::Complex;
/// # use nalgebra::UnitComplex;
/// let angle = 1.78f32;
@ -117,7 +116,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(1.2);
/// let inv = rot.inverse();
@ -134,7 +132,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex;
/// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7);
@ -153,7 +150,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex;
/// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7);
@ -172,7 +168,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex;
/// let angle = 1.7;
/// let rot = UnitComplex::new(angle);
@ -192,7 +187,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex;
/// let angle = 1.7;
/// let mut rot = UnitComplex::new(angle);
@ -212,10 +206,11 @@ impl<N: Real> UnitComplex<N> {
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(0.78);
/// let pow = rot.powf(2.0);
/// assert_eq!(pow.angle(), 2.0 * 0.78);
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ```
#[inline]
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> {
#[inline]
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::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real,
AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
};
use alga::linear::{
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]
fn inverse(&self) -> Self {
fn two_sided_inverse(&self) -> Self {
self.inverse()
}
#[inline]
fn inverse_mut(&mut self) {
fn two_sided_inverse_mut(&mut self) {
self.inverse_mut()
}
}

View File

@ -7,10 +7,9 @@ use rand::distributions::{Distribution, OpenClosed01, Standard};
use rand::Rng;
use alga::general::Real;
use base::allocator::Allocator;
use base::dimension::{U1, U2};
use base::storage::Storage;
use base::{DefaultAllocator, Unit, Vector};
use base::{Unit, Vector};
use geometry::{Rotation2, UnitComplex};
impl<N: Real> UnitComplex<N> {
@ -36,7 +35,6 @@ impl<N: Real> UnitComplex<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitComplex, Point2};
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
@ -57,7 +55,6 @@ impl<N: Real> UnitComplex<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitComplex, Point2};
/// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
@ -79,7 +76,6 @@ impl<N: Real> UnitComplex<N> {
///
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32;
/// # use nalgebra::{UnitComplex, Vector2, Point2};
/// let angle = f32::consts::FRAC_PI_2;
@ -139,7 +135,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, UnitComplex};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
@ -162,7 +157,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, UnitComplex};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
@ -198,7 +192,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector2, UnitComplex};
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
@ -224,7 +217,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector2, UnitComplex};
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.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]
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]
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]
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]
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]
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]
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]
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() {
unsafe {
let a = *rhs.get_unchecked(0, j);
let b = *rhs.get_unchecked(1, j);
let a = *rhs.get_unchecked((0, j));
let b = *rhs.get_unchecked((1, j));
*rhs.get_unchecked_mut(0, j) = r * a - i * b;
*rhs.get_unchecked_mut(1, j) = i * a + r * b;
*rhs.get_unchecked_mut((0, j)) = r * a - i * 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 ?
for j in 0..lhs.nrows() {
unsafe {
let a = *lhs.get_unchecked(j, 0);
let b = *lhs.get_unchecked(j, 1);
let a = *lhs.get_unchecked((j, 0));
let b = *lhs.get_unchecked((j, 1));
*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, 0)) = r * a + i * 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(unused_qualifications)]
#![deny(unused_results)]
#![deny(missing_docs)]
#![warn(missing_docs)] // FIXME: deny this
#![warn(incoherent_fundamental_impls)]
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc")]
#![doc(
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(all(feature = "alloc", not(feature = "std")), feature(alloc))]
@ -121,11 +123,21 @@ extern crate alloc;
#[cfg(not(feature = "std"))]
extern crate core as std;
#[cfg(feature = "io")]
extern crate pest;
#[macro_use]
#[cfg(feature = "io")]
extern crate pest_derive;
pub mod base;
#[cfg(feature = "debug")]
pub mod debug;
pub mod geometry;
#[cfg(feature = "io")]
pub mod io;
pub mod linalg;
#[cfg(feature = "sparse")]
pub mod sparse;
#[cfg(feature = "std")]
#[deprecated(
@ -135,11 +147,13 @@ pub use base as core;
pub use base::*;
pub use geometry::*;
pub use linalg::*;
#[cfg(feature = "sparse")]
pub use sparse::*;
use std::cmp::{self, Ordering, PartialOrd};
use alga::general::{
Additive, AdditiveGroup, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice,
Additive, AdditiveGroup, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice,
Multiplicative, SupersetOf,
};
use alga::linear::SquareMatrix as AlgaSquareMatrix;
@ -189,6 +203,12 @@ pub fn zero<T: Identity<Additive>>() -> T {
///
/// * [`one`](fn.one.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]
pub fn origin<P: EuclideanSpace>() -> P {
P::origin()
@ -275,6 +295,9 @@ pub fn min<T: Ord>(a: T, b: T) -> T {
}
/// The absolute value of `a`.
///
/// Deprecated: Use [Matrix::abs] or [Real::abs] instead.
#[deprecated(note = "use `Matrix::abs` or `Real::abs` instead")]
#[inline]
pub fn abs<T: Signed>(a: &T) -> T {
a.abs()
@ -404,8 +427,8 @@ pub fn try_inverse<M: AlgaSquareMatrix>(m: &M) -> Option<M> {
///
/// * [`try_inverse`](fn.try_inverse.html)
#[inline]
pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
m.inverse()
pub fn inverse<M: TwoSidedInverse<Multiplicative>>(m: &M) -> M {
m.two_sided_inverse()
}
/*
@ -413,12 +436,26 @@ pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
*/
/// 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]
pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field {
a.dot(b)
}
/// 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]
pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
a.angle(b)
@ -435,6 +472,14 @@ pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
/// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude_squared`](fn.magnitude_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]
pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
v.norm()
@ -447,6 +492,14 @@ pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
/// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude_squared`](fn.magnitude_squared.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]
pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
v.norm_squared()
@ -459,6 +512,14 @@ pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
/// * [`magnitude_squared`](fn.magnitude_squared.html)
/// * [`norm`](fn.norm.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]
pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
v.norm()
@ -472,18 +533,42 @@ pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
/// * [`magnitude`](fn.magnitude.html)
/// * [`norm`](fn.norm.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]
pub fn magnitude_squared<V: NormedSpace>(v: &V) -> V::Field {
v.norm_squared()
}
/// 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]
pub fn normalize<V: NormedSpace>(v: &V) -> V {
v.normalize()
}
/// 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]
pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> {
v.try_normalize(min_norm)

View File

@ -52,7 +52,7 @@ where DefaultAllocator: Allocator<N, D, D>
for j in 0..n {
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_j.rows_range_mut(j..);
@ -61,11 +61,11 @@ where DefaultAllocator: Allocator<N, D, D>
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() {
let denom = diag.sqrt();
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);

View File

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

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)];
if !res.is_zero() {
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()

View File

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

View File

@ -290,7 +290,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
let mut res = N::one();
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()

View File

@ -412,7 +412,7 @@ where
rot.rotate_rows(&mut m);
if compute_q {
let c = rot.unwrap();
let c = rot.into_inner();
// XXX: we have to build the matrix manually because
// rot.to_rotation_matrix().unwrap() causes an ICE.
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;
unsafe {
let diag = *self.get_unchecked(i, i);
let diag = *self.get_unchecked((i, i));
if diag.is_zero() {
return false;
@ -161,7 +161,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
let coeff;
unsafe {
let diag = *self.get_unchecked(i, i);
let diag = *self.get_unchecked((i, i));
if diag.is_zero() {
return false;
@ -258,7 +258,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
unsafe {
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() {
return false;
@ -304,7 +304,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
unsafe {
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() {
return false;

View File

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

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