Merge branch 'master' into as_ptr
This commit is contained in:
commit
cc7bab9755
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -7,7 +7,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
## [0.17.0] - WIP
|
## [0.17.0] - WIP
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* Add swizzling up to dimension 3. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.w)`.
|
* Add swizzling up to dimension 3 for vectors. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.y)`.
|
||||||
|
* Add swizzling up to dimension 3 for points. For example, you can do `p.zxy()` as an equivalent to `Point3::new(p.z, p.x, p.y)`.
|
||||||
* Add `.copy_from_slice` to copy matrix components from a slice in column-major order.
|
* Add `.copy_from_slice` to copy matrix components from a slice in column-major order.
|
||||||
* Add `.dot` to quaternions.
|
* Add `.dot` to quaternions.
|
||||||
* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them.
|
* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them.
|
||||||
|
@ -25,6 +26,16 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
* Add impl `From<Vector>` for `Translation`.
|
* Add impl `From<Vector>` for `Translation`.
|
||||||
* Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec`
|
* Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec`
|
||||||
as-is for its storage).
|
as-is for its storage).
|
||||||
|
* Add `.to_homogeneous` to square matrices (and with dimensions higher than 1x1). This will increase their number of row
|
||||||
|
and columns by 1. The new column and row are filled with 0, except for the diagonal element which is set to 1.
|
||||||
|
* Implement `Extend<Vec>` for matrices with a dynamic storage. The provided `Vec` is assumed to represent a column-major
|
||||||
|
matrix with the same number of rows as the one being extended. This will effectively append new columns on the right of
|
||||||
|
the matrix being extended.
|
||||||
|
* Implement `Extend<Vec>` for vectors with a dynamic storage. This will concatenate the vector with the given `Vec`.
|
||||||
|
* Implement `Extend<Matrix<...>>` for matrices with dynamic storage. This will concatenate the columns of both matrices.
|
||||||
|
* Implement `Into<Vec>` for the `MatrixVec` storage.
|
||||||
|
* Implement `Hash` for all matrices.
|
||||||
|
* Add a `.len()` method to retrieve the size of a `MatrixVec`.
|
||||||
|
|
||||||
### Modified
|
### Modified
|
||||||
* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The
|
* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The
|
||||||
|
@ -32,6 +43,17 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
* The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead.
|
* The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead.
|
||||||
* The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not have to
|
* The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not have to
|
||||||
explicitly import the `Transform` trait from the alga crate.
|
explicitly import the `Transform` trait from the alga crate.
|
||||||
|
* Renamed the matrix storage types: `MatrixArray` -> `ArrayStorage` and `MatrixVec` -> `VecStorage`.
|
||||||
|
* Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type.
|
||||||
|
This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`.
|
||||||
|
* Deprecate several functions at the root of the crate (replaced by methods).
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* Remove the `Deref` impl for `MatrixVec` as it could cause hard-to-understand compilation errors.
|
||||||
|
|
||||||
|
### nalgebra-glm
|
||||||
|
* Add several alternative projection computations, e.g., `ortho_lh`, `ortho_lh_no`, `perspective_lh`, etc.
|
||||||
|
* Add features matching those of nalgebra, in particular: `serde-serialize`, `abmonation-serialize`, std` (enabled by default).
|
||||||
|
|
||||||
## [0.16.0]
|
## [0.16.0]
|
||||||
All dependencies have been updated to their latest versions.
|
All dependencies have been updated to their latest versions.
|
||||||
|
|
19
Cargo.toml
19
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nalgebra"
|
name = "nalgebra"
|
||||||
version = "0.16.10"
|
version = "0.16.13"
|
||||||
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
|
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
|
||||||
|
|
||||||
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
|
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
|
||||||
|
@ -23,26 +23,31 @@ stdweb = [ "rand/stdweb" ]
|
||||||
arbitrary = [ "quickcheck" ]
|
arbitrary = [ "quickcheck" ]
|
||||||
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
|
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
|
||||||
abomonation-serialize = [ "abomonation" ]
|
abomonation-serialize = [ "abomonation" ]
|
||||||
|
sparse = [ ]
|
||||||
debug = [ ]
|
debug = [ ]
|
||||||
alloc = [ ]
|
alloc = [ ]
|
||||||
|
io = [ "pest", "pest_derive" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
typenum = "1.10"
|
typenum = "1.10"
|
||||||
generic-array = "0.11"
|
generic-array = "0.12"
|
||||||
rand = { version = "0.5", default-features = false }
|
rand = { version = "0.6", default-features = false }
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
num-complex = { version = "0.2", default-features = false }
|
num-complex = { version = "0.2", default-features = false }
|
||||||
approx = { version = "0.3", default-features = false }
|
approx = { version = "0.3", default-features = false }
|
||||||
alga = { version = "0.7", default-features = false }
|
alga = { version = "0.8", default-features = false }
|
||||||
matrixmultiply = { version = "0.1", optional = true }
|
matrixmultiply = { version = "0.2", optional = true }
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
serde_derive = { version = "1.0", optional = true }
|
serde_derive = { version = "1.0", optional = true }
|
||||||
abomonation = { version = "0.5", optional = true }
|
abomonation = { version = "0.7", optional = true }
|
||||||
mint = { version = "0.5", optional = true }
|
mint = { version = "0.5", optional = true }
|
||||||
quickcheck = { version = "0.6", optional = true }
|
quickcheck = { version = "0.8", optional = true }
|
||||||
|
pest = { version = "2.0", optional = true }
|
||||||
|
pest_derive = { version = "2.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
rand_xorshift = "0.1"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [ "nalgebra-lapack", "nalgebra-glm" ]
|
members = [ "nalgebra-lapack", "nalgebra-glm" ]
|
|
@ -4,7 +4,8 @@ macro_rules! bench_binop(
|
||||||
($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
|
($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn $name(bh: &mut Bencher) {
|
fn $name(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let a = rng.gen::<$t1>();
|
let a = rng.gen::<$t1>();
|
||||||
let b = rng.gen::<$t2>();
|
let b = rng.gen::<$t2>();
|
||||||
|
|
||||||
|
@ -19,7 +20,8 @@ macro_rules! bench_binop_ref(
|
||||||
($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
|
($name: ident, $t1: ty, $t2: ty, $binop: ident) => {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn $name(bh: &mut Bencher) {
|
fn $name(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let a = rng.gen::<$t1>();
|
let a = rng.gen::<$t1>();
|
||||||
let b = rng.gen::<$t2>();
|
let b = rng.gen::<$t2>();
|
||||||
|
|
||||||
|
@ -34,7 +36,8 @@ macro_rules! bench_binop_fn(
|
||||||
($name: ident, $t1: ty, $t2: ty, $binop: path) => {
|
($name: ident, $t1: ty, $t2: ty, $binop: path) => {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn $name(bh: &mut Bencher) {
|
fn $name(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let a = rng.gen::<$t1>();
|
let a = rng.gen::<$t1>();
|
||||||
let b = rng.gen::<$t2>();
|
let b = rng.gen::<$t2>();
|
||||||
|
|
||||||
|
@ -51,7 +54,8 @@ macro_rules! bench_unop_na(
|
||||||
fn $name(bh: &mut Bencher) {
|
fn $name(bh: &mut Bencher) {
|
||||||
const LEN: usize = 1 << 13;
|
const LEN: usize = 1 << 13;
|
||||||
|
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
|
|
||||||
let elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect();
|
let elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -73,7 +77,8 @@ macro_rules! bench_unop(
|
||||||
fn $name(bh: &mut Bencher) {
|
fn $name(bh: &mut Bencher) {
|
||||||
const LEN: usize = 1 << 13;
|
const LEN: usize = 1 << 13;
|
||||||
|
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
|
|
||||||
let mut elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect();
|
let mut elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -95,7 +100,8 @@ macro_rules! bench_construction(
|
||||||
fn $name(bh: &mut Bencher) {
|
fn $name(bh: &mut Bencher) {
|
||||||
const LEN: usize = 1 << 13;
|
const LEN: usize = 1 << 13;
|
||||||
|
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
|
|
||||||
$(let $args: Vec<$types> = (0usize .. LEN).map(|_| rng.gen::<$types>()).collect();)*
|
$(let $args: Vec<$types> = (0usize .. LEN).map(|_| rng.gen::<$types>()).collect();)*
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
|
@ -50,7 +50,8 @@ bench_binop_ref!(vec10000_dot_f32, VectorN<f32, U10000>, VectorN<f32, U10000>, d
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn vec10000_axpy_f64(bh: &mut Bencher) {
|
fn vec10000_axpy_f64(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let mut a = DVector::new_random(10000);
|
let mut a = DVector::new_random(10000);
|
||||||
let b = DVector::new_random(10000);
|
let b = DVector::new_random(10000);
|
||||||
let n = rng.gen::<f64>();
|
let n = rng.gen::<f64>();
|
||||||
|
@ -60,7 +61,8 @@ fn vec10000_axpy_f64(bh: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn vec10000_axpy_beta_f64(bh: &mut Bencher) {
|
fn vec10000_axpy_beta_f64(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let mut a = DVector::new_random(10000);
|
let mut a = DVector::new_random(10000);
|
||||||
let b = DVector::new_random(10000);
|
let b = DVector::new_random(10000);
|
||||||
let n = rng.gen::<f64>();
|
let n = rng.gen::<f64>();
|
||||||
|
@ -71,7 +73,8 @@ fn vec10000_axpy_beta_f64(bh: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn vec10000_axpy_f64_slice(bh: &mut Bencher) {
|
fn vec10000_axpy_f64_slice(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let mut a = DVector::new_random(10000);
|
let mut a = DVector::new_random(10000);
|
||||||
let b = DVector::new_random(10000);
|
let b = DVector::new_random(10000);
|
||||||
let n = rng.gen::<f64>();
|
let n = rng.gen::<f64>();
|
||||||
|
@ -86,7 +89,8 @@ fn vec10000_axpy_f64_slice(bh: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn vec10000_axpy_f64_static(bh: &mut Bencher) {
|
fn vec10000_axpy_f64_static(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let mut a = VectorN::<f64, U10000>::new_random();
|
let mut a = VectorN::<f64, U10000>::new_random();
|
||||||
let b = VectorN::<f64, U10000>::new_random();
|
let b = VectorN::<f64, U10000>::new_random();
|
||||||
let n = rng.gen::<f64>();
|
let n = rng.gen::<f64>();
|
||||||
|
@ -97,7 +101,8 @@ fn vec10000_axpy_f64_static(bh: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn vec10000_axpy_f32(bh: &mut Bencher) {
|
fn vec10000_axpy_f32(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let mut a = DVector::new_random(10000);
|
let mut a = DVector::new_random(10000);
|
||||||
let b = DVector::new_random(10000);
|
let b = DVector::new_random(10000);
|
||||||
let n = rng.gen::<f32>();
|
let n = rng.gen::<f32>();
|
||||||
|
@ -107,7 +112,8 @@ fn vec10000_axpy_f32(bh: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn vec10000_axpy_beta_f32(bh: &mut Bencher) {
|
fn vec10000_axpy_beta_f32(bh: &mut Bencher) {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
let mut a = DVector::new_random(10000);
|
let mut a = DVector::new_random(10000);
|
||||||
let b = DVector::new_random(10000);
|
let b = DVector::new_random(10000);
|
||||||
let n = rng.gen::<f32>();
|
let n = rng.gen::<f32>();
|
||||||
|
|
|
@ -14,6 +14,7 @@ mod geometry;
|
||||||
mod linalg;
|
mod linalg;
|
||||||
|
|
||||||
fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix<f64> {
|
fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix<f64> {
|
||||||
let mut rng = IsaacRng::new_unseeded();
|
use rand::SeedableRng;
|
||||||
|
let mut rng = IsaacRng::seed_from_u64(0);
|
||||||
DMatrix::<f64>::from_fn(nrows, ncols, |_, _| rng.gen())
|
DMatrix::<f64>::from_fn(nrows, ncols, |_, _| rng.gen())
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ if [ -z "$NO_STD" ]; then
|
||||||
cargo build --verbose -p nalgebra --features "serde-serialize";
|
cargo build --verbose -p nalgebra --features "serde-serialize";
|
||||||
cargo build --verbose -p nalgebra --features "abomonation-serialize";
|
cargo build --verbose -p nalgebra --features "abomonation-serialize";
|
||||||
cargo build --verbose -p nalgebra --features "debug";
|
cargo build --verbose -p nalgebra --features "debug";
|
||||||
cargo build --verbose -p nalgebra --features "debug arbitrary mint serde-serialize abomonation-serialize";
|
cargo build --verbose -p nalgebra --all-features
|
||||||
else
|
else
|
||||||
cargo build -p nalgebra-lapack;
|
cargo build -p nalgebra-lapack;
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -51,8 +51,8 @@ fn main() {
|
||||||
// Components listed column-by-column.
|
// 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,
|
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()
|
.iter()
|
||||||
.cloned(),
|
.cloned(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(dm, dm1);
|
assert_eq!(dm, dm1);
|
||||||
|
|
|
@ -3,7 +3,6 @@ extern crate alga;
|
||||||
extern crate approx;
|
extern crate approx;
|
||||||
extern crate nalgebra as na;
|
extern crate nalgebra as na;
|
||||||
|
|
||||||
use alga::linear::Transformation;
|
|
||||||
use na::{Matrix4, Point3, Vector3};
|
use na::{Matrix4, Point3, Vector3};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
extern crate alga;
|
extern crate alga;
|
||||||
extern crate nalgebra as na;
|
extern crate nalgebra as na;
|
||||||
|
|
||||||
use alga::linear::Transformation;
|
|
||||||
use na::{Matrix4, Point3, Vector3, Vector4};
|
use na::{Matrix4, Point3, Vector3, Vector4};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nalgebra-glm"
|
name = "nalgebra-glm"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["sebcrozet <developer@crozet.re>"]
|
authors = ["sebcrozet <developer@crozet.re>"]
|
||||||
|
|
||||||
description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library."
|
description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library."
|
||||||
|
@ -12,8 +12,16 @@ categories = [ "science" ]
|
||||||
keywords = [ "linear", "algebra", "matrix", "vector", "math" ]
|
keywords = [ "linear", "algebra", "matrix", "vector", "math" ]
|
||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = [ "std" ]
|
||||||
|
std = [ "nalgebra/std", "alga/std" ]
|
||||||
|
stdweb = [ "nalgebra/stdweb" ]
|
||||||
|
arbitrary = [ "nalgebra/arbitrary" ]
|
||||||
|
serde-serialize = [ "nalgebra/serde-serialize" ]
|
||||||
|
abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
approx = { version = "0.3", default-features = false }
|
approx = { version = "0.3", default-features = false }
|
||||||
alga = "0.7"
|
alga = { version = "0.8", default-features = false }
|
||||||
nalgebra = { path = "..", version = "^0.16.4" }
|
nalgebra = { path = "..", version = "^0.16.13", default-features = false }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use aliases::TMat4;
|
use aliases::TMat4;
|
||||||
use na::{Orthographic3, Perspective3, Real};
|
use na::{Real};
|
||||||
|
|
||||||
//pub fn frustum<N: Real>(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4<N> {
|
//pub fn frustum<N: Real>(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4<N> {
|
||||||
// unimplemented!()
|
// unimplemented!()
|
||||||
|
@ -53,119 +53,644 @@ use na::{Orthographic3, Perspective3, Real};
|
||||||
// unimplemented!()
|
// unimplemented!()
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/// Creates a matrix for an orthographic parallel viewing volume, using the right handedness and OpenGL near and far clip planes definition.
|
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
pub fn ortho<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
pub fn ortho<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap()
|
ortho_rh_no(left, right, bottom, top, znear, zfar)
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub fn ortho_lh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
/// Creates a left hand matrix for a orthographic-view frustum with a depth range of -1 to 1
|
||||||
// unimplemented!()
|
///
|
||||||
//}
|
/// # Parameters
|
||||||
//
|
///
|
||||||
//pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
// unimplemented!()
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
//}
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
//
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
//pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
// unimplemented!()
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
//}
|
///
|
||||||
//
|
pub fn ortho_lh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
//pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
ortho_lh_no(left, right, bottom, top, znear, zfar)
|
||||||
// unimplemented!()
|
}
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn ortho_rh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn ortho_rh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn ortho_rh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn ortho_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// Creates a matrix for a perspective-view frustum based on the right handedness and OpenGL near and far clip planes definition.
|
/// Creates a left hand matrix for a orthographic-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
let two : N = ::convert(2.0);
|
||||||
|
let mut mat : TMat4<N> = TMat4::<N>::identity();
|
||||||
|
|
||||||
|
mat[(0, 0)] = two / (right - left);
|
||||||
|
mat[(0, 3)] = -(right + left) / (right - left);
|
||||||
|
mat[(1, 1)] = two / (top-bottom);
|
||||||
|
mat[(1, 3)] = -(top + bottom) / (top - bottom);
|
||||||
|
mat[(2, 2)] = two / (zfar - znear);
|
||||||
|
mat[(2, 3)] = -(zfar + znear) / (zfar - znear);
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand orthographic-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
let one : N = N::one();
|
||||||
|
let two : N = ::convert(2.0);
|
||||||
|
let mut mat : TMat4<N> = TMat4::<N>::identity();
|
||||||
|
|
||||||
|
mat[(0, 0)] = two / (right - left);
|
||||||
|
mat[(0, 3)] = - (right + left) / (right - left);
|
||||||
|
mat[(1, 1)] = two / (top - bottom);
|
||||||
|
mat[(1, 3)] = - (top + bottom) / (top - bottom);
|
||||||
|
mat[(2, 2)] = one / (zfar - znear);
|
||||||
|
mat[(2, 3)] = - znear / (zfar - znear);
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
ortho_rh_no(left, right, bottom, top, znear, zfar)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_rh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
ortho_rh_no(left, right, bottom, top, znear, zfar)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_rh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
let two : N = ::convert(2.0);
|
||||||
|
let mut mat : TMat4<N> = TMat4::<N>::identity();
|
||||||
|
|
||||||
|
mat[(0, 0)] = two / (right - left);
|
||||||
|
mat[(0, 3)] = - (right + left) / (right - left);
|
||||||
|
mat[(1, 1)] = two/(top-bottom);
|
||||||
|
mat[(1, 3)] = - (top + bottom) / (top - bottom);
|
||||||
|
mat[(2, 2)] = - two / (zfar - znear);
|
||||||
|
mat[(2, 3)] = - (zfar + znear) / (zfar - znear);
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a right hand matrix for a orthographic-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_rh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
let one : N = N::one();
|
||||||
|
let two : N = ::convert(2.0);
|
||||||
|
let mut mat : TMat4<N> = TMat4::<N>::identity();
|
||||||
|
|
||||||
|
mat[(0, 0)] = two / (right - left);
|
||||||
|
mat[(0, 3)] = - (right + left) / (right - left);
|
||||||
|
mat[(1, 1)] = two/(top-bottom);
|
||||||
|
mat[(1, 3)] = - (top + bottom) / (top - bottom);
|
||||||
|
mat[(2, 2)] = - one / (zfar - znear);
|
||||||
|
mat[(2, 3)] = - znear / (zfar - znear);
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a right hand matrix for a orthographic-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `left` - Coordinate for left bound of matrix
|
||||||
|
/// * `right` - Coordinate for right bound of matrix
|
||||||
|
/// * `bottom` - Coordinate for bottom bound of matrix
|
||||||
|
/// * `top` - Coordinate for top bound of matrix
|
||||||
|
/// * `znear` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `zfar` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn ortho_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
|
||||||
|
ortho_rh_zo(left, right, bottom, top, znear, zfar)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_fov_rh_no(fov, width, height, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_lh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_fov_lh_no(fov, width, height, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_lh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
width > N::zero(),
|
||||||
|
"The width must be greater than zero"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
height > N::zero(),
|
||||||
|
"The height must be greater than zero."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
fov > N::zero(),
|
||||||
|
"The fov must be greater than zero"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut mat = TMat4::zeros();
|
||||||
|
|
||||||
|
let rad = fov;
|
||||||
|
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
|
||||||
|
let w = h * height / width;
|
||||||
|
|
||||||
|
mat[(0, 0)] = w;
|
||||||
|
mat[(1, 1)] = h;
|
||||||
|
mat[(2, 2)] = (far + near) / (far - near);
|
||||||
|
mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near);
|
||||||
|
mat[(3, 2)] = N::one();
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand perspective-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_lh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
width > N::zero(),
|
||||||
|
"The width must be greater than zero"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
height > N::zero(),
|
||||||
|
"The height must be greater than zero."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
fov > N::zero(),
|
||||||
|
"The fov must be greater than zero"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut mat = TMat4::zeros();
|
||||||
|
|
||||||
|
let rad = fov;
|
||||||
|
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
|
||||||
|
let w = h * height / width;
|
||||||
|
|
||||||
|
mat[(0, 0)] = w;
|
||||||
|
mat[(1, 1)] = h;
|
||||||
|
mat[(2, 2)] = far / (far - near);
|
||||||
|
mat[(2, 3)] = -(far * near) / (far - near);
|
||||||
|
mat[(3, 2)] = N::one();
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_fov_rh_no(fov, width, height, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_rh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_fov_rh_no(fov, width, height, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_rh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
width > N::zero(),
|
||||||
|
"The width must be greater than zero"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
height > N::zero(),
|
||||||
|
"The height must be greater than zero."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
fov > N::zero(),
|
||||||
|
"The fov must be greater than zero"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut mat = TMat4::zeros();
|
||||||
|
|
||||||
|
let rad = fov;
|
||||||
|
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
|
||||||
|
let w = h * height / width;
|
||||||
|
|
||||||
|
mat[(0, 0)] = w;
|
||||||
|
mat[(1, 1)] = h;
|
||||||
|
mat[(2, 2)] = - (far + near) / (far - near);
|
||||||
|
mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near);
|
||||||
|
mat[(3, 2)] = -N::one();
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_rh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
width > N::zero(),
|
||||||
|
"The width must be greater than zero"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
height > N::zero(),
|
||||||
|
"The height must be greater than zero."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
fov > N::zero(),
|
||||||
|
"The fov must be greater than zero"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut mat = TMat4::zeros();
|
||||||
|
|
||||||
|
let rad = fov;
|
||||||
|
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
|
||||||
|
let w = h * height / width;
|
||||||
|
|
||||||
|
mat[(0, 0)] = w;
|
||||||
|
mat[(1, 1)] = h;
|
||||||
|
mat[(2, 2)] = far / (near - far);
|
||||||
|
mat[(2, 3)] = -(far * near) / (far - near);
|
||||||
|
mat[(3, 2)] = -N::one();
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fov` - Field of view, in radians
|
||||||
|
/// * `width` - Width of the viewport
|
||||||
|
/// * `height` - Height of the viewport
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
pub fn perspective_fov_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_fov_rh_zo(fov, width, height, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
///
|
///
|
||||||
/// # Important note
|
/// # Important note
|
||||||
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
pub fn perspective<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
pub fn perspective<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
Perspective3::new(aspect, fovy, near, far).unwrap()
|
// TODO: Breaking change - revert back to proper glm conventions?
|
||||||
|
//
|
||||||
|
// Prior to changes to support configuring the behaviour of this function it was simply
|
||||||
|
// a wrapper around Perspective3::new(). The argument order for that function is different
|
||||||
|
// than the glm convention, but reordering the arguments would've caused pointlessly
|
||||||
|
// un-optimal code to be generated so they were rearranged so the function would just call
|
||||||
|
// straight through.
|
||||||
|
//
|
||||||
|
// Now this call to Perspective3::new() is no longer made so the functions can have their
|
||||||
|
// arguments reordered to the glm convention. Unfortunately this is a breaking change so
|
||||||
|
// can't be cleanly integrated into the existing library version without breaking other
|
||||||
|
// people's code. Reordering to glm isn't a huge deal but if it is done it will have to be
|
||||||
|
// in a major API breaking update.
|
||||||
|
//
|
||||||
|
perspective_rh_no(aspect, fovy, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_lh<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_lh_no(aspect, fovy, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_lh_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(far - near, N::zero()),
|
||||||
|
"The near-plane and far-plane must not be superimposed."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(aspect, N::zero()),
|
||||||
|
"The apsect ratio must not be zero."
|
||||||
|
);
|
||||||
|
|
||||||
|
let one = N::one();
|
||||||
|
let two: N = ::convert( 2.0);
|
||||||
|
let mut mat : TMat4<N> = TMat4::zeros();
|
||||||
|
|
||||||
|
let tan_half_fovy = (fovy / two).tan();
|
||||||
|
|
||||||
|
mat[(0, 0)] = one / (aspect * tan_half_fovy);
|
||||||
|
mat[(1, 1)] = one / tan_half_fovy;
|
||||||
|
mat[(2, 2)] = (far + near) / (far - near);
|
||||||
|
mat[(2, 3)] = -(two * far * near) / (far - near);
|
||||||
|
mat[(3, 2)] = one;
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a left hand perspective-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_lh_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(far - near, N::zero()),
|
||||||
|
"The near-plane and far-plane must not be superimposed."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(aspect, N::zero()),
|
||||||
|
"The apsect ratio must not be zero."
|
||||||
|
);
|
||||||
|
|
||||||
|
let one = N::one();
|
||||||
|
let two: N = ::convert( 2.0);
|
||||||
|
let mut mat: TMat4<N> = TMat4::zeros();
|
||||||
|
|
||||||
|
let tan_half_fovy = (fovy / two).tan();
|
||||||
|
|
||||||
|
mat[(0, 0)] = one / (aspect * tan_half_fovy);
|
||||||
|
mat[(1, 1)] = one / tan_half_fovy;
|
||||||
|
mat[(2, 2)] = far / (far - near);
|
||||||
|
mat[(2, 3)] = -(far * near) / (far - near);
|
||||||
|
mat[(3, 2)] = one;
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_rh_no(aspect, fovy, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_rh<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_rh_no(aspect, fovy, near, far)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_rh_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(far - near, N::zero()),
|
||||||
|
"The near-plane and far-plane must not be superimposed."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(aspect, N::zero()),
|
||||||
|
"The apsect ratio must not be zero."
|
||||||
|
);
|
||||||
|
|
||||||
|
let negone = -N::one();
|
||||||
|
let one = N::one();
|
||||||
|
let two: N = ::convert( 2.0);
|
||||||
|
let mut mat = TMat4::zeros();
|
||||||
|
|
||||||
|
let tan_half_fovy = (fovy / two).tan();
|
||||||
|
|
||||||
|
mat[(0, 0)] = one / (aspect * tan_half_fovy);
|
||||||
|
mat[(1, 1)] = one / tan_half_fovy;
|
||||||
|
mat[(2, 2)] = - (far + near) / (far - near);
|
||||||
|
mat[(2, 3)] = -(two * far * near) / (far - near);
|
||||||
|
mat[(3, 2)] = negone;
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_rh_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(far - near, N::zero()),
|
||||||
|
"The near-plane and far-plane must not be superimposed."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!relative_eq!(aspect, N::zero()),
|
||||||
|
"The apsect ratio must not be zero."
|
||||||
|
);
|
||||||
|
|
||||||
|
let negone = -N::one();
|
||||||
|
let one = N::one();
|
||||||
|
let two = ::convert( 2.0);
|
||||||
|
let mut mat = TMat4::zeros();
|
||||||
|
|
||||||
|
let tan_half_fovy = (fovy / two).tan();
|
||||||
|
|
||||||
|
mat[(0, 0)] = one / (aspect * tan_half_fovy);
|
||||||
|
mat[(1, 1)] = one / tan_half_fovy;
|
||||||
|
mat[(2, 2)] = far / (near - far);
|
||||||
|
mat[(2, 3)] = -(far * near) / (far - near);
|
||||||
|
mat[(3, 2)] = negone;
|
||||||
|
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `fovy` - Field of view, in radians
|
||||||
|
/// * `aspect` - Ratio of viewport width to height (width/height)
|
||||||
|
/// * `near` - Distance from the viewer to the near clipping plane
|
||||||
|
/// * `far` - Distance from the viewer to the far clipping plane
|
||||||
|
///
|
||||||
|
/// # Important note
|
||||||
|
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
|
||||||
|
pub fn perspective_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
|
||||||
|
perspective_rh_zo(aspect, fovy, near, far)
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub fn perspective_fov<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_lh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_lh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_lh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_rh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_rh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_rh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_fov_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_lh<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_lh_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_lh_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_rh<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_rh_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_rh_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn perspective_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
|
|
||||||
// unimplemented!()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//pub fn tweaked_infinite_perspective<N: Real>(fovy: N, aspect: N, near: N) -> TMat4<N> {
|
//pub fn tweaked_infinite_perspective<N: Real>(fovy: N, aspect: N, near: N) -> TMat4<N> {
|
||||||
// unimplemented!()
|
// unimplemented!()
|
||||||
//}
|
//}
|
||||||
|
|
|
@ -24,7 +24,8 @@ pub fn pick_matrix<N: Real>(center: &TVec2<N>, delta: &TVec2<N>, viewport: &TVec
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates using OpenGL near and far clip planes definition.
|
/// Map the specified object coordinates `(obj.x, obj.y, obj.z)` into window coordinates with a
|
||||||
|
/// depth range of -1 to 1
|
||||||
///
|
///
|
||||||
/// # Parameters:
|
/// # Parameters:
|
||||||
///
|
///
|
||||||
|
@ -114,7 +115,8 @@ pub fn project_zo<N: Real>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using OpenGL near and far clip planes definition.
|
/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using a
|
||||||
|
/// depth range of -1 to 1
|
||||||
///
|
///
|
||||||
/// # Parameters:
|
/// # Parameters:
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
//! (Reexported) Additional features not specified by GLSL specification
|
//! (Reexported) Additional features not specified by GLSL specification
|
||||||
|
|
||||||
pub use self::matrix_clip_space::{ortho, perspective};
|
pub use self::matrix_clip_space::{
|
||||||
|
ortho, ortho_lh, ortho_lh_no, ortho_lh_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo,
|
||||||
|
ortho_zo,
|
||||||
|
|
||||||
|
perspective, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no,
|
||||||
|
perspective_rh, perspective_rh_no, perspective_rh_zo, perspective_zo,
|
||||||
|
|
||||||
|
perspective_fov, perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo,
|
||||||
|
perspective_fov_no, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo,
|
||||||
|
perspective_fov_zo,
|
||||||
|
};
|
||||||
pub use self::matrix_projection::{
|
pub use self::matrix_projection::{
|
||||||
pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo,
|
pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo,
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,5 +33,5 @@ pub fn quat_lerp<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
||||||
pub fn quat_slerp<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
pub fn quat_slerp<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
||||||
Unit::new_normalize(*x)
|
Unit::new_normalize(*x)
|
||||||
.slerp(&Unit::new_normalize(*y), a)
|
.slerp(&Unit::new_normalize(*y), a)
|
||||||
.unwrap()
|
.into_inner()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn quat_pow<N: Real>(q: &Qua<N>, y: N) -> Qua<N> {
|
||||||
|
|
||||||
/// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`.
|
/// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`.
|
||||||
pub fn quat_rotate<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> {
|
pub fn quat_rotate<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> {
|
||||||
q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).unwrap()
|
q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub fn quat_sqrt<N: Real>(q: &Qua<N>) -> Qua<N> {
|
//pub fn quat_sqrt<N: Real>(q: &Qua<N>) -> Qua<N> {
|
||||||
|
|
|
@ -9,13 +9,13 @@ pub fn quat_angle<N: Real>(x: &Qua<N>) -> N {
|
||||||
|
|
||||||
/// Creates a quaternion from an axis and an angle.
|
/// Creates a quaternion from an axis and an angle.
|
||||||
pub fn quat_angle_axis<N: Real>(angle: N, axis: &TVec3<N>) -> Qua<N> {
|
pub fn quat_angle_axis<N: Real>(angle: N, axis: &TVec3<N>) -> Qua<N> {
|
||||||
UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).unwrap()
|
UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rotation axis of a quaternion assumed to be normalized.
|
/// The rotation axis of a quaternion assumed to be normalized.
|
||||||
pub fn quat_axis<N: Real>(x: &Qua<N>) -> TVec3<N> {
|
pub fn quat_axis<N: Real>(x: &Qua<N>) -> TVec3<N> {
|
||||||
if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() {
|
if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() {
|
||||||
a.unwrap()
|
a.into_inner()
|
||||||
} else {
|
} else {
|
||||||
TVec3::zeros()
|
TVec3::zeros()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use aliases::{Qua, TMat4, TVec, TVec3};
|
||||||
/// Euler angles of the quaternion `q` as (pitch, yaw, roll).
|
/// Euler angles of the quaternion `q` as (pitch, yaw, roll).
|
||||||
pub fn quat_euler_angles<N: Real>(x: &Qua<N>) -> TVec3<N> {
|
pub fn quat_euler_angles<N: Real>(x: &Qua<N>) -> TVec3<N> {
|
||||||
let q = UnitQuaternion::new_unchecked(*x);
|
let q = UnitQuaternion::new_unchecked(*x);
|
||||||
let a = q.to_euler_angles();
|
let a = q.euler_angles();
|
||||||
TVec3::new(a.2, a.1, a.0)
|
TVec3::new(a.2, a.1, a.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,19 +34,25 @@ pub fn quat_cast<N: Real>(x: &Qua<N>) -> TMat4<N> {
|
||||||
::quat_to_mat4(x)
|
::quat_to_mat4(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix).
|
/// Computes a right hand look-at quaternion
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `direction` - Direction vector point at where to look
|
||||||
|
/// * `up` - Object up vector
|
||||||
|
///
|
||||||
pub fn quat_look_at<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
|
pub fn quat_look_at<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
|
||||||
quat_look_at_rh(direction, up)
|
quat_look_at_rh(direction, up)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a left-handed look-at quaternion (equivalent to a left-handed look-at matrix).
|
/// Computes a left-handed look-at quaternion (equivalent to a left-handed look-at matrix).
|
||||||
pub fn quat_look_at_lh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
|
pub fn quat_look_at_lh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
|
||||||
UnitQuaternion::look_at_lh(direction, up).unwrap()
|
UnitQuaternion::look_at_lh(direction, up).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix).
|
/// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix).
|
||||||
pub fn quat_look_at_rh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
|
pub fn quat_look_at_rh<N: Real>(direction: &TVec3<N>, up: &TVec3<N>) -> Qua<N> {
|
||||||
UnitQuaternion::look_at_rh(direction, up).unwrap()
|
UnitQuaternion::look_at_rh(direction, up).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The "roll" Euler angle of the quaternion `x` assumed to be normalized.
|
/// The "roll" Euler angle of the quaternion `x` assumed to be normalized.
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn quat_extract_real_component<N: Real>(q: &Qua<N>) -> N {
|
||||||
pub fn quat_fast_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
pub fn quat_fast_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
||||||
Unit::new_unchecked(*x)
|
Unit::new_unchecked(*x)
|
||||||
.nlerp(&Unit::new_unchecked(*y), a)
|
.nlerp(&Unit::new_unchecked(*y), a)
|
||||||
.unwrap()
|
.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub fn quat_intermediate<N: Real>(prev: &Qua<N>, curr: &Qua<N>, next: &Qua<N>) -> Qua<N> {
|
//pub fn quat_intermediate<N: Real>(prev: &Qua<N>, curr: &Qua<N>, next: &Qua<N>) -> Qua<N> {
|
||||||
|
@ -40,7 +40,7 @@ pub fn quat_magnitude2<N: Real>(q: &Qua<N>) -> N {
|
||||||
|
|
||||||
/// The quaternion representing the identity rotation.
|
/// The quaternion representing the identity rotation.
|
||||||
pub fn quat_identity<N: Real>() -> Qua<N> {
|
pub fn quat_identity<N: Real>() -> Qua<N> {
|
||||||
UnitQuaternion::identity().unwrap()
|
UnitQuaternion::identity().into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rotates a vector by a quaternion assumed to be normalized.
|
/// Rotates a vector by a quaternion assumed to be normalized.
|
||||||
|
@ -58,14 +58,14 @@ pub fn quat_rotate_vec<N: Real>(q: &Qua<N>, v: &TVec4<N>) -> TVec4<N> {
|
||||||
pub fn quat_rotation<N: Real>(orig: &TVec3<N>, dest: &TVec3<N>) -> Qua<N> {
|
pub fn quat_rotation<N: Real>(orig: &TVec3<N>, dest: &TVec3<N>) -> Qua<N> {
|
||||||
UnitQuaternion::rotation_between(orig, dest)
|
UnitQuaternion::rotation_between(orig, dest)
|
||||||
.unwrap_or_else(UnitQuaternion::identity)
|
.unwrap_or_else(UnitQuaternion::identity)
|
||||||
.unwrap()
|
.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The spherical linear interpolation between two quaternions.
|
/// The spherical linear interpolation between two quaternions.
|
||||||
pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
||||||
Unit::new_normalize(*x)
|
Unit::new_normalize(*x)
|
||||||
.slerp(&Unit::new_normalize(*y), a)
|
.slerp(&Unit::new_normalize(*y), a)
|
||||||
.unwrap()
|
.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub fn quat_squad<N: Real>(q1: &Qua<N>, q2: &Qua<N>, s1: &Qua<N>, s2: &Qua<N>, h: N) -> Qua<N> {
|
//pub fn quat_squad<N: Real>(q1: &Qua<N>, q2: &Qua<N>, s1: &Qua<N>, s2: &Qua<N>, h: N) -> Qua<N> {
|
||||||
|
@ -76,7 +76,7 @@ pub fn quat_short_mix<N: Real>(x: &Qua<N>, y: &Qua<N>, a: N) -> Qua<N> {
|
||||||
pub fn quat_to_mat3<N: Real>(x: &Qua<N>) -> TMat3<N> {
|
pub fn quat_to_mat3<N: Real>(x: &Qua<N>) -> TMat3<N> {
|
||||||
UnitQuaternion::new_unchecked(*x)
|
UnitQuaternion::new_unchecked(*x)
|
||||||
.to_rotation_matrix()
|
.to_rotation_matrix()
|
||||||
.unwrap()
|
.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a quaternion to a rotation matrix in homogenous coordinates.
|
/// Converts a quaternion to a rotation matrix in homogenous coordinates.
|
||||||
|
@ -87,7 +87,7 @@ pub fn quat_to_mat4<N: Real>(x: &Qua<N>) -> TMat4<N> {
|
||||||
/// Converts a rotation matrix to a quaternion.
|
/// Converts a rotation matrix to a quaternion.
|
||||||
pub fn mat3_to_quat<N: Real>(x: &TMat3<N>) -> Qua<N> {
|
pub fn mat3_to_quat<N: Real>(x: &TMat3<N>) -> Qua<N> {
|
||||||
let r = Rotation3::from_matrix_unchecked(*x);
|
let r = Rotation3::from_matrix_unchecked(*x);
|
||||||
UnitQuaternion::from_rotation_matrix(&r).unwrap()
|
UnitQuaternion::from_rotation_matrix(&r).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a rotation matrix in homogeneous coordinates to a quaternion.
|
/// Converts a rotation matrix in homogeneous coordinates to a quaternion.
|
||||||
|
|
|
@ -21,5 +21,5 @@ pub fn rotate_normalized_axis<N: Real>(m: &TMat4<N>, angle: N, axis: &TVec3<N>)
|
||||||
/// * `angle` - Angle expressed in radians.
|
/// * `angle` - Angle expressed in radians.
|
||||||
/// * `axis` - Normalized axis of the rotation, must be normalized.
|
/// * `axis` - Normalized axis of the rotation, must be normalized.
|
||||||
pub fn quat_rotate_normalized_axis<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> {
|
pub fn quat_rotate_normalized_axis<N: Real>(q: &Qua<N>, angle: N, axis: &TVec3<N>) -> Qua<N> {
|
||||||
q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).unwrap()
|
q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).into_inner()
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,5 +60,5 @@ pub fn rotate_z_vec4<N: Real>(v: &TVec4<N>, angle: N) -> TVec4<N> {
|
||||||
pub fn slerp<N: Real>(x: &TVec3<N>, y: &TVec3<N>, a: N) -> TVec3<N> {
|
pub fn slerp<N: Real>(x: &TVec3<N>, y: &TVec3<N>, a: N) -> TVec3<N> {
|
||||||
Unit::new_unchecked(*x)
|
Unit::new_unchecked(*x)
|
||||||
.slerp(&Unit::new_unchecked(*y), a)
|
.slerp(&Unit::new_unchecked(*y), a)
|
||||||
.unwrap()
|
.into_inner()
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,9 @@
|
||||||
and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)).
|
and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
extern crate num_traits as num;
|
extern crate num_traits as num;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate approx;
|
extern crate approx;
|
||||||
|
@ -142,12 +145,17 @@ pub use ext::{
|
||||||
epsilon, equal_columns, equal_columns_eps, equal_columns_eps_vec, equal_eps, equal_eps_vec,
|
epsilon, equal_columns, equal_columns_eps, equal_columns_eps_vec, equal_eps, equal_eps_vec,
|
||||||
identity, look_at, look_at_lh, look_at_rh, max, max2, max3, max3_scalar, max4, max4_scalar,
|
identity, look_at, look_at_lh, look_at_rh, max, max2, max3, max3_scalar, max4, max4_scalar,
|
||||||
min, min2, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps,
|
min, min2, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps,
|
||||||
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, pi,
|
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, perspective_fov,
|
||||||
pick_matrix, project, project_no, project_zo, quat_angle, quat_angle_axis, quat_axis,
|
perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo, perspective_fov_no,
|
||||||
quat_conjugate, quat_cross, quat_dot, quat_equal, quat_equal_eps, quat_exp, quat_inverse,
|
perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, perspective_fov_zo,
|
||||||
quat_length, quat_lerp, quat_log, quat_magnitude, quat_normalize, quat_not_equal,
|
perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, perspective_rh,
|
||||||
quat_not_equal_eps, quat_pow, quat_rotate, quat_slerp, rotate, rotate_x, rotate_y, rotate_z,
|
perspective_rh_no, perspective_rh_zo, perspective_zo, ortho_lh, ortho_lh_no, ortho_lh_zo,
|
||||||
scale, translate, unproject, unproject_no, unproject_zo,
|
ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, ortho_zo, pi, pick_matrix, project, project_no,
|
||||||
|
project_zo, quat_angle, quat_angle_axis, quat_axis, quat_conjugate, quat_cross, quat_dot,
|
||||||
|
quat_equal, quat_equal_eps, quat_exp, quat_inverse, quat_length, quat_lerp, quat_log,
|
||||||
|
quat_magnitude, quat_normalize, quat_not_equal, quat_not_equal_eps, quat_pow, quat_rotate,
|
||||||
|
quat_slerp, rotate, rotate_x, rotate_y, rotate_z, scale, translate, unproject, unproject_no,
|
||||||
|
unproject_zo,
|
||||||
};
|
};
|
||||||
pub use gtc::{
|
pub use gtc::{
|
||||||
affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose,
|
affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose,
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ intel-mkl = ["lapack-src/intel-mkl"]
|
||||||
nalgebra = { version = "0.16", path = ".." }
|
nalgebra = { version = "0.16", path = ".." }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-complex = { version = "0.2", default-features = false }
|
num-complex = { version = "0.2", default-features = false }
|
||||||
alga = { version = "0.7", default-features = false }
|
alga = { version = "0.8", default-features = false }
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
serde_derive = { version = "1.0", optional = true }
|
serde_derive = { version = "1.0", optional = true }
|
||||||
lapack = { version = "0.16", default-features = false }
|
lapack = { version = "0.16", default-features = false }
|
||||||
|
@ -34,6 +34,6 @@ lapack-src = { version = "0.2", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] }
|
nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] }
|
||||||
quickcheck = "0.6"
|
quickcheck = "0.8"
|
||||||
approx = "0.3"
|
approx = "0.3"
|
||||||
rand = "0.5"
|
rand = "0.6"
|
||||||
|
|
|
@ -160,7 +160,7 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
// Copy lower triangle to upper triangle.
|
// Copy lower triangle to upper triangle.
|
||||||
for i in 0..dim {
|
for i in 0..dim {
|
||||||
for j in i + 1..dim {
|
for j in i + 1..dim {
|
||||||
unsafe { *self.l.get_unchecked_mut(i, j) = *self.l.get_unchecked(j, i) };
|
unsafe { *self.l.get_unchecked_mut((i, j)) = *self.l.get_unchecked((j, i)) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,10 @@
|
||||||
#![deny(unused_qualifications)]
|
#![deny(unused_qualifications)]
|
||||||
#![deny(unused_results)]
|
#![deny(unused_results)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico",
|
#![doc(
|
||||||
html_root_url = "http://nalgebra.org/rustdoc")]
|
html_favicon_url = "http://nalgebra.org/img/favicon.ico",
|
||||||
|
html_root_url = "http://nalgebra.org/rustdoc"
|
||||||
|
)]
|
||||||
|
|
||||||
extern crate alga;
|
extern crate alga;
|
||||||
extern crate lapack;
|
extern crate lapack;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use base::dimension::Dynamic;
|
use base::dimension::Dynamic;
|
||||||
use base::dimension::{U1, U2, U3, U4, U5, U6};
|
use base::dimension::{U1, U2, U3, U4, U5, U6};
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use base::matrix_vec::MatrixVec;
|
use base::vec_storage::VecStorage;
|
||||||
use base::storage::Owned;
|
use base::storage::Owned;
|
||||||
use base::Matrix;
|
use base::Matrix;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ pub type Matrix6x5<N> = MatrixMN<N, U6, U5>;
|
||||||
*/
|
*/
|
||||||
/// A dynamically sized column vector.
|
/// A dynamically sized column vector.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type DVector<N> = Matrix<N, Dynamic, U1, MatrixVec<N, Dynamic, U1>>;
|
pub type DVector<N> = Matrix<N, Dynamic, U1, VecStorage<N, Dynamic, U1>>;
|
||||||
|
|
||||||
/// A statically sized D-dimensional column vector.
|
/// A statically sized D-dimensional column vector.
|
||||||
pub type VectorN<N, D> = MatrixMN<N, D, U1>;
|
pub type VectorN<N, D> = MatrixMN<N, D, U1>;
|
||||||
|
@ -146,7 +146,7 @@ pub type Vector6<N> = VectorN<N, U6>;
|
||||||
*/
|
*/
|
||||||
/// A dynamically sized row vector.
|
/// A dynamically sized row vector.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type RowDVector<N> = Matrix<N, U1, Dynamic, MatrixVec<N, U1, Dynamic>>;
|
pub type RowDVector<N> = Matrix<N, U1, Dynamic, VecStorage<N, U1, Dynamic>>;
|
||||||
|
|
||||||
/// A statically sized D-dimensional row vector.
|
/// A statically sized D-dimensional row vector.
|
||||||
pub type RowVectorN<N, D> = MatrixMN<N, U1, D>;
|
pub type RowVectorN<N, D> = MatrixMN<N, U1, D>;
|
||||||
|
|
|
@ -175,24 +175,24 @@ pub type MatrixSliceXx6<'a, N, RStride = U1, CStride = Dynamic> =
|
||||||
MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>;
|
MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>;
|
||||||
|
|
||||||
/// A column vector slice with `D` rows.
|
/// A column vector slice with `D` rows.
|
||||||
pub type VectorSliceN<'a, N, D, Stride = U1> =
|
pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> =
|
||||||
Matrix<N, D, U1, SliceStorage<'a, N, D, U1, Stride, D>>;
|
Matrix<N, D, U1, SliceStorage<'a, N, D, U1, RStride, CStride>>;
|
||||||
|
|
||||||
/// A column vector slice dynamic numbers of rows and columns.
|
/// A column vector slice dynamic numbers of rows and columns.
|
||||||
pub type DVectorSlice<'a, N, Stride = U1> = VectorSliceN<'a, N, Dynamic, Stride>;
|
pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceN<'a, N, Dynamic, RStride, CStride>;
|
||||||
|
|
||||||
/// A 1D column vector slice.
|
/// A 1D column vector slice.
|
||||||
pub type VectorSlice1<'a, N, Stride = U1> = VectorSliceN<'a, N, U1, Stride>;
|
pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = VectorSliceN<'a, N, U1, RStride, CStride>;
|
||||||
/// A 2D column vector slice.
|
/// A 2D column vector slice.
|
||||||
pub type VectorSlice2<'a, N, Stride = U1> = VectorSliceN<'a, N, U2, Stride>;
|
pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = VectorSliceN<'a, N, U2, RStride, CStride>;
|
||||||
/// A 3D column vector slice.
|
/// A 3D column vector slice.
|
||||||
pub type VectorSlice3<'a, N, Stride = U1> = VectorSliceN<'a, N, U3, Stride>;
|
pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = VectorSliceN<'a, N, U3, RStride, CStride>;
|
||||||
/// A 4D column vector slice.
|
/// A 4D column vector slice.
|
||||||
pub type VectorSlice4<'a, N, Stride = U1> = VectorSliceN<'a, N, U4, Stride>;
|
pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = VectorSliceN<'a, N, U4, RStride, CStride>;
|
||||||
/// A 5D column vector slice.
|
/// A 5D column vector slice.
|
||||||
pub type VectorSlice5<'a, N, Stride = U1> = VectorSliceN<'a, N, U5, Stride>;
|
pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = VectorSliceN<'a, N, U5, RStride, CStride>;
|
||||||
/// A 6D column vector slice.
|
/// A 6D column vector slice.
|
||||||
pub type VectorSlice6<'a, N, Stride = U1> = VectorSliceN<'a, N, U6, Stride>;
|
pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = VectorSliceN<'a, N, U6, RStride, CStride>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
@ -367,21 +367,21 @@ pub type MatrixSliceMutXx6<'a, N, RStride = U1, CStride = Dynamic> =
|
||||||
MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>;
|
MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>;
|
||||||
|
|
||||||
/// A mutable column vector slice with `D` rows.
|
/// A mutable column vector slice with `D` rows.
|
||||||
pub type VectorSliceMutN<'a, N, D, Stride = U1> =
|
pub type VectorSliceMutN<'a, N, D, RStride = U1, CStride = D> =
|
||||||
Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, Stride, D>>;
|
Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, RStride, CStride>>;
|
||||||
|
|
||||||
/// A mutable column vector slice dynamic numbers of rows and columns.
|
/// A mutable column vector slice dynamic numbers of rows and columns.
|
||||||
pub type DVectorSliceMut<'a, N, Stride = U1> = VectorSliceMutN<'a, N, Dynamic, Stride>;
|
pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceMutN<'a, N, Dynamic, RStride, CStride>;
|
||||||
|
|
||||||
/// A 1D mutable column vector slice.
|
/// A 1D mutable column vector slice.
|
||||||
pub type VectorSliceMut1<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U1, Stride>;
|
pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = VectorSliceMutN<'a, N, U1, RStride, CStride>;
|
||||||
/// A 2D mutable column vector slice.
|
/// A 2D mutable column vector slice.
|
||||||
pub type VectorSliceMut2<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U2, Stride>;
|
pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = VectorSliceMutN<'a, N, U2, RStride, CStride>;
|
||||||
/// A 3D mutable column vector slice.
|
/// A 3D mutable column vector slice.
|
||||||
pub type VectorSliceMut3<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U3, Stride>;
|
pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = VectorSliceMutN<'a, N, U3, RStride, CStride>;
|
||||||
/// A 4D mutable column vector slice.
|
/// A 4D mutable column vector slice.
|
||||||
pub type VectorSliceMut4<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U4, Stride>;
|
pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = VectorSliceMutN<'a, N, U4, RStride, CStride>;
|
||||||
/// A 5D mutable column vector slice.
|
/// A 5D mutable column vector slice.
|
||||||
pub type VectorSliceMut5<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U5, Stride>;
|
pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = VectorSliceMutN<'a, N, U5, RStride, CStride>;
|
||||||
/// A 6D mutable column vector slice.
|
/// A 6D mutable column vector slice.
|
||||||
pub type VectorSliceMut6<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U6, Stride>;
|
pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = VectorSliceMutN<'a, N, U6, RStride, CStride>;
|
||||||
|
|
|
@ -34,7 +34,7 @@ use base::Scalar;
|
||||||
*/
|
*/
|
||||||
/// A array-based statically sized matrix data storage.
|
/// A array-based statically sized matrix data storage.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct MatrixArray<N, R, C>
|
pub struct ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
R: DimName,
|
R: DimName,
|
||||||
C: DimName,
|
C: DimName,
|
||||||
|
@ -44,7 +44,11 @@ where
|
||||||
data: GenericArray<N, Prod<R::Value, C::Value>>,
|
data: GenericArray<N, Prod<R::Value, C::Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, C> Hash for MatrixArray<N, R, C>
|
#[deprecated(note="renamed to `ArrayStorage`")]
|
||||||
|
/// Renamed to [ArrayStorage].
|
||||||
|
pub type MatrixArray<N, R, C> = ArrayStorage<N, R, C>;
|
||||||
|
|
||||||
|
impl<N, R, C> Hash for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Hash,
|
N: Hash,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -57,7 +61,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, C> Deref for MatrixArray<N, R, C>
|
impl<N, R, C> Deref for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
R: DimName,
|
R: DimName,
|
||||||
C: DimName,
|
C: DimName,
|
||||||
|
@ -72,7 +76,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, C> DerefMut for MatrixArray<N, R, C>
|
impl<N, R, C> DerefMut for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
R: DimName,
|
R: DimName,
|
||||||
C: DimName,
|
C: DimName,
|
||||||
|
@ -85,7 +89,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, C> Debug for MatrixArray<N, R, C>
|
impl<N, R, C> Debug for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Debug,
|
N: Debug,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -99,7 +103,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, C> Copy for MatrixArray<N, R, C>
|
impl<N, R, C> Copy for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Copy,
|
N: Copy,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -109,7 +113,7 @@ where
|
||||||
GenericArray<N, Prod<R::Value, C::Value>>: Copy,
|
GenericArray<N, Prod<R::Value, C::Value>>: Copy,
|
||||||
{}
|
{}
|
||||||
|
|
||||||
impl<N, R, C> Clone for MatrixArray<N, R, C>
|
impl<N, R, C> Clone for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Clone,
|
N: Clone,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -119,13 +123,13 @@ where
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
MatrixArray {
|
ArrayStorage {
|
||||||
data: self.data.clone(),
|
data: self.data.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, C> Eq for MatrixArray<N, R, C>
|
impl<N, R, C> Eq for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Eq,
|
N: Eq,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -134,7 +138,7 @@ where
|
||||||
Prod<R::Value, C::Value>: ArrayLength<N>,
|
Prod<R::Value, C::Value>: ArrayLength<N>,
|
||||||
{}
|
{}
|
||||||
|
|
||||||
impl<N, R, C> PartialEq for MatrixArray<N, R, C>
|
impl<N, R, C> PartialEq for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: PartialEq,
|
N: PartialEq,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -148,7 +152,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<N, R, C> Storage<N, R, C> for MatrixArray<N, R, C>
|
unsafe impl<N, R, C> Storage<N, R, C> for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -200,7 +204,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<N, R, C> StorageMut<N, R, C> for MatrixArray<N, R, C>
|
unsafe impl<N, R, C> StorageMut<N, R, C> for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -220,7 +224,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<N, R, C> ContiguousStorage<N, R, C> for MatrixArray<N, R, C>
|
unsafe impl<N, R, C> ContiguousStorage<N, R, C> for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -230,7 +234,7 @@ where
|
||||||
DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
|
DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
|
||||||
{}
|
{}
|
||||||
|
|
||||||
unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for MatrixArray<N, R, C>
|
unsafe impl<N, R, C> ContiguousStorageMut<N, R, C> for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -247,7 +251,7 @@ where
|
||||||
*/
|
*/
|
||||||
// XXX: open an issue for GenericArray so that it implements serde traits?
|
// XXX: open an issue for GenericArray so that it implements serde traits?
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
impl<N, R, C> Serialize for MatrixArray<N, R, C>
|
impl<N, R, C> Serialize for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar + Serialize,
|
N: Scalar + Serialize,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -268,7 +272,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
impl<'a, N, R, C> Deserialize<'a> for MatrixArray<N, R, C>
|
impl<'a, N, R, C> Deserialize<'a> for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar + Deserialize<'a>,
|
N: Scalar + Deserialize<'a>,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -278,18 +282,18 @@ where
|
||||||
{
|
{
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: Deserializer<'a> {
|
where D: Deserializer<'a> {
|
||||||
deserializer.deserialize_seq(MatrixArrayVisitor::new())
|
deserializer.deserialize_seq(ArrayStorageVisitor::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
/// A visitor that produces a matrix array.
|
/// A visitor that produces a matrix array.
|
||||||
struct MatrixArrayVisitor<N, R, C> {
|
struct ArrayStorageVisitor<N, R, C> {
|
||||||
marker: PhantomData<(N, R, C)>,
|
marker: PhantomData<(N, R, C)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
impl<N, R, C> MatrixArrayVisitor<N, R, C>
|
impl<N, R, C> ArrayStorageVisitor<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -299,14 +303,14 @@ where
|
||||||
{
|
{
|
||||||
/// Construct a new sequence visitor.
|
/// Construct a new sequence visitor.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
MatrixArrayVisitor {
|
ArrayStorageVisitor {
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
impl<'a, N, R, C> Visitor<'a> for MatrixArrayVisitor<N, R, C>
|
impl<'a, N, R, C> Visitor<'a> for ArrayStorageVisitor<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar + Deserialize<'a>,
|
N: Scalar + Deserialize<'a>,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -314,20 +318,20 @@ where
|
||||||
R::Value: Mul<C::Value>,
|
R::Value: Mul<C::Value>,
|
||||||
Prod<R::Value, C::Value>: ArrayLength<N>,
|
Prod<R::Value, C::Value>: ArrayLength<N>,
|
||||||
{
|
{
|
||||||
type Value = MatrixArray<N, R, C>;
|
type Value = ArrayStorage<N, R, C>;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
formatter.write_str("a matrix array")
|
formatter.write_str("a matrix array")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<V>(self, mut visitor: V) -> Result<MatrixArray<N, R, C>, V::Error>
|
fn visit_seq<V>(self, mut visitor: V) -> Result<ArrayStorage<N, R, C>, V::Error>
|
||||||
where V: SeqAccess<'a> {
|
where V: SeqAccess<'a> {
|
||||||
let mut out: Self::Value = unsafe { mem::uninitialized() };
|
let mut out: Self::Value = unsafe { mem::uninitialized() };
|
||||||
let mut curr = 0;
|
let mut curr = 0;
|
||||||
|
|
||||||
while let Some(value) = try!(visitor.next_element()) {
|
while let Some(value) = try!(visitor.next_element()) {
|
||||||
out[curr] = value;
|
*out.get_mut(curr).ok_or_else(|| V::Error::invalid_length(curr, &self))? = value;
|
||||||
curr += 1;
|
curr += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +344,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<N, R, C> Abomonation for MatrixArray<N, R, C>
|
impl<N, R, C> Abomonation for ArrayStorage<N, R, C>
|
||||||
where
|
where
|
||||||
R: DimName,
|
R: DimName,
|
||||||
C: DimName,
|
C: DimName,
|
128
src/base/blas.rs
128
src/base/blas.rs
|
@ -13,18 +13,18 @@ use base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
|
||||||
use base::storage::{Storage, StorageMut};
|
use base::storage::{Storage, StorageMut};
|
||||||
use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector};
|
use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector};
|
||||||
|
|
||||||
impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
impl<N: Scalar + PartialOrd, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
/// Computes the index of the vector component with the largest value.
|
/// Computes the index and value of the vector component with the largest value.
|
||||||
///
|
///
|
||||||
/// # Examples:
|
/// # Examples:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use nalgebra::Vector3;
|
/// # use nalgebra::Vector3;
|
||||||
/// let vec = Vector3::new(11, -15, 13);
|
/// let vec = Vector3::new(11, -15, 13);
|
||||||
/// assert_eq!(vec.imax(), 2);
|
/// assert_eq!(vec.argmax(), (2, 13));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn imax(&self) -> usize {
|
pub fn argmax(&self) -> (usize, N) {
|
||||||
assert!(!self.is_empty(), "The input vector must not be empty.");
|
assert!(!self.is_empty(), "The input vector must not be empty.");
|
||||||
|
|
||||||
let mut the_max = unsafe { self.vget_unchecked(0) };
|
let mut the_max = unsafe { self.vget_unchecked(0) };
|
||||||
|
@ -39,7 +39,21 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
the_i
|
(the_i, *the_max)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the index of the vector component with the largest value.
|
||||||
|
///
|
||||||
|
/// # Examples:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::Vector3;
|
||||||
|
/// let vec = Vector3::new(11, -15, 13);
|
||||||
|
/// assert_eq!(vec.imax(), 2);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn imax(&self) -> usize {
|
||||||
|
self.argmax().0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the index of the vector component with the largest absolute value.
|
/// Computes the index of the vector component with the largest absolute value.
|
||||||
|
@ -52,7 +66,8 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
|
||||||
/// assert_eq!(vec.iamax(), 1);
|
/// assert_eq!(vec.iamax(), 1);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iamax(&self) -> usize {
|
pub fn iamax(&self) -> usize
|
||||||
|
where N: Signed {
|
||||||
assert!(!self.is_empty(), "The input vector must not be empty.");
|
assert!(!self.is_empty(), "The input vector must not be empty.");
|
||||||
|
|
||||||
let mut the_max = unsafe { self.vget_unchecked(0).abs() };
|
let mut the_max = unsafe { self.vget_unchecked(0).abs() };
|
||||||
|
@ -70,6 +85,34 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
|
||||||
the_i
|
the_i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the index and value of the vector component with the smallest value.
|
||||||
|
///
|
||||||
|
/// # Examples:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::Vector3;
|
||||||
|
/// let vec = Vector3::new(11, -15, 13);
|
||||||
|
/// assert_eq!(vec.argmin(), (1, -15));
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn argmin(&self) -> (usize, N) {
|
||||||
|
assert!(!self.is_empty(), "The input vector must not be empty.");
|
||||||
|
|
||||||
|
let mut the_min = unsafe { self.vget_unchecked(0) };
|
||||||
|
let mut the_i = 0;
|
||||||
|
|
||||||
|
for i in 1..self.nrows() {
|
||||||
|
let val = unsafe { self.vget_unchecked(i) };
|
||||||
|
|
||||||
|
if val < the_min {
|
||||||
|
the_min = val;
|
||||||
|
the_i = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(the_i, *the_min)
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the index of the vector component with the smallest value.
|
/// Computes the index of the vector component with the smallest value.
|
||||||
///
|
///
|
||||||
/// # Examples:
|
/// # Examples:
|
||||||
|
@ -81,21 +124,7 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn imin(&self) -> usize {
|
pub fn imin(&self) -> usize {
|
||||||
assert!(!self.is_empty(), "The input vector must not be empty.");
|
self.argmin().0
|
||||||
|
|
||||||
let mut the_max = unsafe { self.vget_unchecked(0) };
|
|
||||||
let mut the_i = 0;
|
|
||||||
|
|
||||||
for i in 1..self.nrows() {
|
|
||||||
let val = unsafe { self.vget_unchecked(i) };
|
|
||||||
|
|
||||||
if val < the_max {
|
|
||||||
the_max = val;
|
|
||||||
the_i = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
the_i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the index of the vector component with the smallest absolute value.
|
/// Computes the index of the vector component with the smallest absolute value.
|
||||||
|
@ -108,17 +137,18 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
|
||||||
/// assert_eq!(vec.iamin(), 0);
|
/// assert_eq!(vec.iamin(), 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iamin(&self) -> usize {
|
pub fn iamin(&self) -> usize
|
||||||
|
where N: Signed {
|
||||||
assert!(!self.is_empty(), "The input vector must not be empty.");
|
assert!(!self.is_empty(), "The input vector must not be empty.");
|
||||||
|
|
||||||
let mut the_max = unsafe { self.vget_unchecked(0).abs() };
|
let mut the_min = unsafe { self.vget_unchecked(0).abs() };
|
||||||
let mut the_i = 0;
|
let mut the_i = 0;
|
||||||
|
|
||||||
for i in 1..self.nrows() {
|
for i in 1..self.nrows() {
|
||||||
let val = unsafe { self.vget_unchecked(i).abs() };
|
let val = unsafe { self.vget_unchecked(i).abs() };
|
||||||
|
|
||||||
if val < the_max {
|
if val < the_min {
|
||||||
the_max = val;
|
the_min = val;
|
||||||
the_i = i;
|
the_i = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,12 +172,12 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
|
||||||
pub fn iamax_full(&self) -> (usize, usize) {
|
pub fn iamax_full(&self) -> (usize, usize) {
|
||||||
assert!(!self.is_empty(), "The input matrix must not be empty.");
|
assert!(!self.is_empty(), "The input matrix must not be empty.");
|
||||||
|
|
||||||
let mut the_max = unsafe { self.get_unchecked(0, 0).abs() };
|
let mut the_max = unsafe { self.get_unchecked((0, 0)).abs() };
|
||||||
let mut the_ij = (0, 0);
|
let mut the_ij = (0, 0);
|
||||||
|
|
||||||
for j in 0..self.ncols() {
|
for j in 0..self.ncols() {
|
||||||
for i in 0..self.nrows() {
|
for i in 0..self.nrows() {
|
||||||
let val = unsafe { self.get_unchecked(i, j).abs() };
|
let val = unsafe { self.get_unchecked((i, j)).abs() };
|
||||||
|
|
||||||
if val > the_max {
|
if val > the_max {
|
||||||
the_max = val;
|
the_max = val;
|
||||||
|
@ -197,27 +227,27 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
// because the `for` loop below won't be very efficient on those.
|
// because the `for` loop below won't be very efficient on those.
|
||||||
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0);
|
let a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0));
|
||||||
let b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0);
|
let b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
|
||||||
|
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0);
|
let a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0));
|
||||||
let b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0);
|
let b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
|
||||||
let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0);
|
let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0));
|
||||||
|
|
||||||
return a + b + c;
|
return a + b + c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut a = *self.get_unchecked(0, 0) * *rhs.get_unchecked(0, 0);
|
let mut a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0));
|
||||||
let mut b = *self.get_unchecked(1, 0) * *rhs.get_unchecked(1, 0);
|
let mut b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0));
|
||||||
let c = *self.get_unchecked(2, 0) * *rhs.get_unchecked(2, 0);
|
let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0));
|
||||||
let d = *self.get_unchecked(3, 0) * *rhs.get_unchecked(3, 0);
|
let d = *self.get_unchecked((3, 0)) * *rhs.get_unchecked((3, 0));
|
||||||
|
|
||||||
a += c;
|
a += c;
|
||||||
b += d;
|
b += d;
|
||||||
|
@ -257,14 +287,14 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
acc7 = N::zero();
|
acc7 = N::zero();
|
||||||
|
|
||||||
while self.nrows() - i >= 8 {
|
while self.nrows() - i >= 8 {
|
||||||
acc0 += unsafe { *self.get_unchecked(i + 0, j) * *rhs.get_unchecked(i + 0, j) };
|
acc0 += unsafe { *self.get_unchecked((i + 0, j)) * *rhs.get_unchecked((i + 0, j)) };
|
||||||
acc1 += unsafe { *self.get_unchecked(i + 1, j) * *rhs.get_unchecked(i + 1, j) };
|
acc1 += unsafe { *self.get_unchecked((i + 1, j)) * *rhs.get_unchecked((i + 1, j)) };
|
||||||
acc2 += unsafe { *self.get_unchecked(i + 2, j) * *rhs.get_unchecked(i + 2, j) };
|
acc2 += unsafe { *self.get_unchecked((i + 2, j)) * *rhs.get_unchecked((i + 2, j)) };
|
||||||
acc3 += unsafe { *self.get_unchecked(i + 3, j) * *rhs.get_unchecked(i + 3, j) };
|
acc3 += unsafe { *self.get_unchecked((i + 3, j)) * *rhs.get_unchecked((i + 3, j)) };
|
||||||
acc4 += unsafe { *self.get_unchecked(i + 4, j) * *rhs.get_unchecked(i + 4, j) };
|
acc4 += unsafe { *self.get_unchecked((i + 4, j)) * *rhs.get_unchecked((i + 4, j)) };
|
||||||
acc5 += unsafe { *self.get_unchecked(i + 5, j) * *rhs.get_unchecked(i + 5, j) };
|
acc5 += unsafe { *self.get_unchecked((i + 5, j)) * *rhs.get_unchecked((i + 5, j)) };
|
||||||
acc6 += unsafe { *self.get_unchecked(i + 6, j) * *rhs.get_unchecked(i + 6, j) };
|
acc6 += unsafe { *self.get_unchecked((i + 6, j)) * *rhs.get_unchecked((i + 6, j)) };
|
||||||
acc7 += unsafe { *self.get_unchecked(i + 7, j) * *rhs.get_unchecked(i + 7, j) };
|
acc7 += unsafe { *self.get_unchecked((i + 7, j)) * *rhs.get_unchecked((i + 7, j)) };
|
||||||
i += 8;
|
i += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +304,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
res += acc3 + acc7;
|
res += acc3 + acc7;
|
||||||
|
|
||||||
for k in i..self.nrows() {
|
for k in i..self.nrows() {
|
||||||
res += unsafe { *self.get_unchecked(k, j) * *rhs.get_unchecked(k, j) }
|
res += unsafe { *self.get_unchecked((k, j)) * *rhs.get_unchecked((k, j)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +344,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
|
|
||||||
for j in 0..self.nrows() {
|
for j in 0..self.nrows() {
|
||||||
for i in 0..self.ncols() {
|
for i in 0..self.ncols() {
|
||||||
res += unsafe { *self.get_unchecked(j, i) * *rhs.get_unchecked(i, j) }
|
res += unsafe { *self.get_unchecked((j, i)) * *rhs.get_unchecked((i, j)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +657,6 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
|
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
|
||||||
/// let mut mat1 = Matrix2x4::identity();
|
/// let mut mat1 = Matrix2x4::identity();
|
||||||
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
|
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
|
||||||
|
@ -760,7 +789,6 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4};
|
/// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4};
|
||||||
/// let mut mat1 = Matrix2x4::identity();
|
/// let mut mat1 = Matrix2x4::identity();
|
||||||
/// let mat2 = Matrix3x2::new(1.0, 4.0,
|
/// let mat2 = Matrix3x2::new(1.0, 4.0,
|
||||||
|
@ -879,7 +907,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{DMatrix, DVector};
|
/// # use nalgebra::{DMatrix, DVector};
|
||||||
/// // Note that all those would also work with statically-sized matrices.
|
/// // Note that all those would also work with statically-sized matrices.
|
||||||
/// // We use DMatrix/DVector since that's the only case where pre-allocating the
|
/// // We use DMatrix/DVector since that's the only case where pre-allocating the
|
||||||
|
@ -934,7 +961,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
|
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
|
||||||
/// let mut mat = Matrix2::identity();
|
/// let mut mat = Matrix2::identity();
|
||||||
/// let lhs = Matrix2x3::new(1.0, 2.0, 3.0,
|
/// let lhs = Matrix2x3::new(1.0, 2.0, 3.0,
|
||||||
|
@ -971,7 +997,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{DMatrix, DVector};
|
/// # use nalgebra::{DMatrix, DVector};
|
||||||
/// // Note that all those would also work with statically-sized matrices.
|
/// // Note that all those would also work with statically-sized matrices.
|
||||||
/// // We use DMatrix/DVector since that's the only case where pre-allocating the
|
/// // We use DMatrix/DVector since that's the only case where pre-allocating the
|
||||||
|
@ -1026,7 +1051,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
|
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
|
||||||
/// let mut mat = Matrix2::identity();
|
/// let mut mat = Matrix2::identity();
|
||||||
/// let rhs = Matrix3x2::new(1.0, 2.0,
|
/// let rhs = Matrix3x2::new(1.0, 2.0,
|
||||||
|
|
|
@ -115,13 +115,13 @@ impl<N: Real> Matrix4<N> {
|
||||||
/// Creates a new homogeneous matrix for an orthographic projection.
|
/// Creates a new homogeneous matrix for an orthographic projection.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
|
pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
|
||||||
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap()
|
Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new homogeneous matrix for a perspective projection.
|
/// Creates a new homogeneous matrix for a perspective projection.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self {
|
pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self {
|
||||||
Perspective3::new(aspect, fovy, znear, zfar).unwrap()
|
Perspective3::new(aspect, fovy, znear, zfar).into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
||||||
|
@ -130,8 +130,14 @@ impl<N: Real> Matrix4<N> {
|
||||||
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
|
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
|
||||||
/// `eye`.
|
/// `eye`.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn face_towards(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
|
||||||
|
IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated: Use [Matrix4::face_towards] instead.
|
||||||
|
#[deprecated(note="renamed to `face_towards`")]
|
||||||
pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
|
pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
|
||||||
IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous()
|
Matrix4::face_towards(eye, target, up)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a right-handed look-at view matrix.
|
/// Builds a right-handed look-at view matrix.
|
||||||
|
@ -348,7 +354,7 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
|
let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
|
||||||
let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
|
let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
|
||||||
let n = normalizer.tr_dot(&pt.coords)
|
let n = normalizer.tr_dot(&pt.coords)
|
||||||
+ unsafe { *self.get_unchecked(D::dim() - 1, D::dim() - 1) };
|
+ unsafe { *self.get_unchecked((D::dim() - 1, D::dim() - 1)) };
|
||||||
|
|
||||||
if !n.is_zero() {
|
if !n.is_zero() {
|
||||||
return transform * (pt / n) + translation;
|
return transform * (pt / n) + translation;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Non-conventional componentwise operators.
|
// Non-conventional component-wise operators.
|
||||||
|
|
||||||
use num::{Signed, Zero};
|
use num::{Signed, Zero};
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{Add, Mul};
|
||||||
|
@ -61,7 +61,7 @@ macro_rules! component_binop_impl(
|
||||||
for j in 0 .. res.ncols() {
|
for j in 0 .. res.ncols() {
|
||||||
for i in 0 .. res.nrows() {
|
for i in 0 .. res.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
res.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
|
res.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,8 @@ macro_rules! component_binop_impl(
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
|
let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
|
||||||
*self.get_unchecked_mut(i, j) = res;
|
*self.get_unchecked_mut((i, j)) = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,8 @@ macro_rules! component_binop_impl(
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
|
let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
|
||||||
*self.get_unchecked_mut(i, j) = beta * *self.get_unchecked(i, j) + res;
|
*self.get_unchecked_mut((i, j)) = beta * *self.get_unchecked((i, j)) + res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ macro_rules! component_binop_impl(
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
|
self.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ where DefaultAllocator: Allocator<N, R, C>
|
||||||
|
|
||||||
for i in 0..nrows.value() {
|
for i in 0..nrows.value() {
|
||||||
for j in 0..ncols.value() {
|
for j in 0..ncols.value() {
|
||||||
unsafe { *res.get_unchecked_mut(i, j) = *iter.next().unwrap() }
|
unsafe { *res.get_unchecked_mut((i, j)) = *iter.next().unwrap() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ where DefaultAllocator: Allocator<N, R, C>
|
||||||
|
|
||||||
for j in 0..ncols.value() {
|
for j in 0..ncols.value() {
|
||||||
for i in 0..nrows.value() {
|
for i in 0..nrows.value() {
|
||||||
unsafe { *res.get_unchecked_mut(i, j) = f(i, j) }
|
unsafe { *res.get_unchecked_mut((i, j)) = f(i, j) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ where DefaultAllocator: Allocator<N, R, C>
|
||||||
let mut res = Self::zeros_generic(nrows, ncols);
|
let mut res = Self::zeros_generic(nrows, ncols);
|
||||||
|
|
||||||
for i in 0..::min(nrows.value(), ncols.value()) {
|
for i in 0..::min(nrows.value(), ncols.value()) {
|
||||||
unsafe { *res.get_unchecked_mut(i, i) = elt }
|
unsafe { *res.get_unchecked_mut((i, i)) = elt }
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
|
@ -152,7 +152,7 @@ where DefaultAllocator: Allocator<N, R, C>
|
||||||
);
|
);
|
||||||
|
|
||||||
for (i, elt) in elts.iter().enumerate() {
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
unsafe { *res.get_unchecked_mut(i, i) = *elt }
|
unsafe { *res.get_unchecked_mut((i, i)) = *elt }
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
|
@ -270,7 +270,7 @@ where DefaultAllocator: Allocator<N, R, C>
|
||||||
/// let vec_ptr = vec.as_ptr();
|
/// let vec_ptr = vec.as_ptr();
|
||||||
///
|
///
|
||||||
/// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec);
|
/// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec);
|
||||||
/// let matrix_storage_ptr = matrix.data.as_ptr();
|
/// let matrix_storage_ptr = matrix.data.as_vec().as_ptr();
|
||||||
///
|
///
|
||||||
/// // `matrix` is backed by exactly the same `Vec` as it was constructed from.
|
/// // `matrix` is backed by exactly the same `Vec` as it was constructed from.
|
||||||
/// assert_eq!(matrix_storage_ptr, vec_ptr);
|
/// assert_eq!(matrix_storage_ptr, vec_ptr);
|
||||||
|
@ -296,7 +296,7 @@ where
|
||||||
///
|
///
|
||||||
/// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0));
|
/// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// // The two additional arguments represent the matrix dimensions.
|
/// // The two additional arguments represent the matrix dimensions.
|
||||||
/// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(3, &[1.0, 2.0, 3.0]));
|
/// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(&[1.0, 2.0, 3.0]));
|
||||||
///
|
///
|
||||||
/// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
|
/// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
|
||||||
/// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 &&
|
/// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 &&
|
||||||
|
@ -313,7 +313,7 @@ where
|
||||||
|
|
||||||
for i in 0..diag.len() {
|
for i in 0..diag.len() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked_mut(i, i) = *diag.vget_unchecked(i);
|
*res.get_unchecked_mut((i, i)) = *diag.vget_unchecked(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,63 +444,6 @@ macro_rules! impl_constructors(
|
||||||
Self::from_iterator_generic($($gargs, )* iter)
|
Self::from_iterator_generic($($gargs, )* iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a matrix with its elements filled with the components provided by a slice
|
|
||||||
/// in row-major order.
|
|
||||||
///
|
|
||||||
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
|
|
||||||
/// row-by-row.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
|
|
||||||
/// # use std::iter;
|
|
||||||
///
|
|
||||||
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
|
|
||||||
/// // The additional argument represents the vector dimension.
|
|
||||||
/// let dv = DVector::from_row_slice(3, &[0, 1, 2]);
|
|
||||||
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
|
|
||||||
/// // The two additional arguments represent the matrix dimensions.
|
|
||||||
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
|
|
||||||
///
|
|
||||||
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
|
|
||||||
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
|
|
||||||
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
|
|
||||||
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
|
|
||||||
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
|
|
||||||
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Self {
|
|
||||||
Self::from_row_slice_generic($($gargs, )* slice)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a matrix with its elements filled with the components provided by a slice
|
|
||||||
/// in column-major order.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
|
|
||||||
/// # use std::iter;
|
|
||||||
///
|
|
||||||
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
|
|
||||||
/// // The additional argument represents the vector dimension.
|
|
||||||
/// let dv = DVector::from_column_slice(3, &[0, 1, 2]);
|
|
||||||
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
|
|
||||||
/// // The two additional arguments represent the matrix dimensions.
|
|
||||||
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
|
|
||||||
///
|
|
||||||
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
|
|
||||||
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
|
|
||||||
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
|
|
||||||
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
|
|
||||||
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
|
|
||||||
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Self {
|
|
||||||
Self::from_column_slice_generic($($gargs, )* slice)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a matrix or vector filled with the results of a function applied to each of its
|
/// Creates a matrix or vector filled with the results of a function applied to each of its
|
||||||
/// component coordinates.
|
/// component coordinates.
|
||||||
///
|
///
|
||||||
|
@ -612,32 +555,6 @@ macro_rules! impl_constructors(
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::from_distribution_generic($($gargs, )* distribution, rng)
|
Self::from_distribution_generic($($gargs, )* distribution, rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a matrix backed by a given `Vec`.
|
|
||||||
///
|
|
||||||
/// The output matrix is filled column-by-column.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```
|
|
||||||
/// # use nalgebra::{DMatrix, Matrix2x3};
|
|
||||||
///
|
|
||||||
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
|
|
||||||
///
|
|
||||||
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
|
|
||||||
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// // The two additional arguments represent the matrix dimensions.
|
|
||||||
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
|
|
||||||
///
|
|
||||||
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
|
|
||||||
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn from_vec($($args: usize,)* data: Vec<N>) -> Self {
|
|
||||||
Self::from_vec_generic($($gargs, )* data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
|
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
|
||||||
|
@ -676,6 +593,125 @@ impl_constructors!(Dynamic, Dynamic;
|
||||||
Dynamic::new(nrows), Dynamic::new(ncols);
|
Dynamic::new(nrows), Dynamic::new(ncols);
|
||||||
nrows, ncols);
|
nrows, ncols);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Constructors that don't necessarily require all dimensions
|
||||||
|
* to be specified whon one dimension is already known.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
macro_rules! impl_constructors_from_data(
|
||||||
|
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
|
||||||
|
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
|
||||||
|
where DefaultAllocator: Allocator<N $(, $Dims)*> {
|
||||||
|
/// Creates a matrix with its elements filled with the components provided by a slice
|
||||||
|
/// in row-major order.
|
||||||
|
///
|
||||||
|
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
|
||||||
|
/// row-by-row.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
|
||||||
|
/// # use std::iter;
|
||||||
|
///
|
||||||
|
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
|
||||||
|
/// // The additional argument represents the vector dimension.
|
||||||
|
/// let dv = DVector::from_row_slice(&[0, 1, 2]);
|
||||||
|
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
|
||||||
|
/// // The two additional arguments represent the matrix dimensions.
|
||||||
|
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
|
||||||
|
///
|
||||||
|
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
|
||||||
|
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
|
||||||
|
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
|
||||||
|
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
|
||||||
|
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
|
||||||
|
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn from_row_slice($($args: usize,)* $data: &[N]) -> Self {
|
||||||
|
Self::from_row_slice_generic($($gargs, )* $data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix with its elements filled with the components provided by a slice
|
||||||
|
/// in column-major order.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
|
||||||
|
/// # use std::iter;
|
||||||
|
///
|
||||||
|
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
|
||||||
|
/// // The additional argument represents the vector dimension.
|
||||||
|
/// let dv = DVector::from_column_slice(&[0, 1, 2]);
|
||||||
|
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
|
||||||
|
/// // The two additional arguments represent the matrix dimensions.
|
||||||
|
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
|
||||||
|
///
|
||||||
|
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
|
||||||
|
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
|
||||||
|
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
|
||||||
|
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
|
||||||
|
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
|
||||||
|
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn from_column_slice($($args: usize,)* $data: &[N]) -> Self {
|
||||||
|
Self::from_column_slice_generic($($gargs, )* $data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a matrix backed by a given `Vec`.
|
||||||
|
///
|
||||||
|
/// The output matrix is filled column-by-column.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{DMatrix, Matrix2x3};
|
||||||
|
///
|
||||||
|
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
|
||||||
|
///
|
||||||
|
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
|
||||||
|
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// // The two additional arguments represent the matrix dimensions.
|
||||||
|
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
|
||||||
|
///
|
||||||
|
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
|
||||||
|
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn from_vec($($args: usize,)* $data: Vec<N>) -> Self {
|
||||||
|
Self::from_vec_generic($($gargs, )* $data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// FIXME: this is not very pretty. We could find a better call syntax.
|
||||||
|
impl_constructors_from_data!(data; R, C; // Arguments for Matrix<N, ..., S>
|
||||||
|
=> R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
|
||||||
|
R::name(), C::name(); // Arguments for `_generic` constructors.
|
||||||
|
); // Arguments for non-generic constructors.
|
||||||
|
|
||||||
|
impl_constructors_from_data!(data; R, Dynamic;
|
||||||
|
=> R: DimName;
|
||||||
|
R::name(), Dynamic::new(data.len() / R::dim());
|
||||||
|
);
|
||||||
|
|
||||||
|
impl_constructors_from_data!(data; Dynamic, C;
|
||||||
|
=> C: DimName;
|
||||||
|
Dynamic::new(data.len() / C::dim()), C::name();
|
||||||
|
);
|
||||||
|
|
||||||
|
impl_constructors_from_data!(data; Dynamic, Dynamic;
|
||||||
|
;
|
||||||
|
Dynamic::new(nrows), Dynamic::new(ncols);
|
||||||
|
nrows, ncols);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Zero, One, Rand traits.
|
* Zero, One, Rand traits.
|
||||||
|
@ -791,7 +827,7 @@ macro_rules! componentwise_constructors_impl(
|
||||||
pub fn new($($args: N),*) -> Self {
|
pub fn new($($args: N),*) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut res = Self::new_uninitialized();
|
let mut res = Self::new_uninitialized();
|
||||||
$( *res.get_unchecked_mut($irow, $icol) = $args; )*
|
$( *res.get_unchecked_mut(($irow, $icol)) = $args; )*
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@ use typenum::Prod;
|
||||||
use base::allocator::{Allocator, SameShapeAllocator};
|
use base::allocator::{Allocator, SameShapeAllocator};
|
||||||
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||||
use base::dimension::{
|
use base::dimension::{
|
||||||
Dim, DimName, Dynamic, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
|
Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
|
||||||
};
|
};
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
use base::dimension::Dynamic;
|
||||||
use base::iter::{MatrixIter, MatrixIterMut};
|
use base::iter::{MatrixIter, MatrixIterMut};
|
||||||
use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
|
use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use base::MatrixVec;
|
use base::VecStorage;
|
||||||
use base::{DefaultAllocator, Matrix, MatrixArray, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
|
use base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
|
||||||
|
|
||||||
// FIXME: too bad this won't work allo slice conversions.
|
// FIXME: too bad this won't work allo slice conversions.
|
||||||
impl<N1, N2, R1, C1, R2, C2> SubsetOf<MatrixMN<N2, R2, C2>> for MatrixMN<N1, R1, C1>
|
impl<N1, N2, R1, C1, R2, C2> SubsetOf<MatrixMN<N2, R2, C2>> for MatrixMN<N1, R1, C1>
|
||||||
|
@ -42,7 +44,7 @@ where
|
||||||
let mut res = unsafe { MatrixMN::<N2, R2, C2>::new_uninitialized_generic(nrows2, ncols2) };
|
let mut res = unsafe { MatrixMN::<N2, R2, C2>::new_uninitialized_generic(nrows2, ncols2) };
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
unsafe { *res.get_unchecked_mut(i, j) = N2::from_subset(self.get_unchecked(i, j)) }
|
unsafe { *res.get_unchecked_mut((i, j)) = N2::from_subset(self.get_unchecked((i, j))) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ where
|
||||||
let mut res = Self::new_uninitialized_generic(nrows, ncols);
|
let mut res = Self::new_uninitialized_generic(nrows, ncols);
|
||||||
for i in 0..nrows2 {
|
for i in 0..nrows2 {
|
||||||
for j in 0..ncols2 {
|
for j in 0..ncols2 {
|
||||||
*res.get_unchecked_mut(i, j) = m.get_unchecked(i, j).to_subset_unchecked()
|
*res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +338,7 @@ impl_from_into_mint_2D!(
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, N, R, C, RStride, CStride> From<MatrixSlice<'a, N, R, C, RStride, CStride>>
|
impl<'a, N, R, C, RStride, CStride> From<MatrixSlice<'a, N, R, C, RStride, CStride>>
|
||||||
for Matrix<N, R, C, MatrixArray<N, R, C>>
|
for Matrix<N, R, C, ArrayStorage<N, R, C>>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -353,7 +355,7 @@ where
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, N, C, RStride, CStride> From<MatrixSlice<'a, N, Dynamic, C, RStride, CStride>>
|
impl<'a, N, C, RStride, CStride> From<MatrixSlice<'a, N, Dynamic, C, RStride, CStride>>
|
||||||
for Matrix<N, Dynamic, C, MatrixVec<N, Dynamic, C>>
|
for Matrix<N, Dynamic, C, VecStorage<N, Dynamic, C>>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
|
@ -367,7 +369,7 @@ where
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, N, R, RStride, CStride> From<MatrixSlice<'a, N, R, Dynamic, RStride, CStride>>
|
impl<'a, N, R, RStride, CStride> From<MatrixSlice<'a, N, R, Dynamic, RStride, CStride>>
|
||||||
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>>
|
for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -380,7 +382,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
|
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
|
||||||
for Matrix<N, R, C, MatrixArray<N, R, C>>
|
for Matrix<N, R, C, ArrayStorage<N, R, C>>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
@ -397,7 +399,7 @@ where
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, N, C, RStride, CStride> From<MatrixSliceMut<'a, N, Dynamic, C, RStride, CStride>>
|
impl<'a, N, C, RStride, CStride> From<MatrixSliceMut<'a, N, Dynamic, C, RStride, CStride>>
|
||||||
for Matrix<N, Dynamic, C, MatrixVec<N, Dynamic, C>>
|
for Matrix<N, Dynamic, C, VecStorage<N, Dynamic, C>>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
C: Dim,
|
C: Dim,
|
||||||
|
@ -411,7 +413,7 @@ where
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>>
|
impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>>
|
||||||
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>>
|
for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: DimName,
|
R: DimName,
|
||||||
|
|
|
@ -18,9 +18,9 @@ use base::allocator::{Allocator, Reallocator};
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
use base::dimension::Dynamic;
|
use base::dimension::Dynamic;
|
||||||
use base::dimension::{Dim, DimName};
|
use base::dimension::{Dim, DimName};
|
||||||
use base::matrix_array::MatrixArray;
|
use base::array_storage::ArrayStorage;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use base::matrix_vec::MatrixVec;
|
use base::vec_storage::VecStorage;
|
||||||
use base::storage::{Storage, StorageMut};
|
use base::storage::{Storage, StorageMut};
|
||||||
use base::Scalar;
|
use base::Scalar;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ use base::Scalar;
|
||||||
* Allocator.
|
* Allocator.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/// An allocator based on `GenericArray` and `MatrixVec` for statically-sized and dynamically-sized
|
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
|
||||||
/// matrices respectively.
|
/// matrices respectively.
|
||||||
pub struct DefaultAllocator;
|
pub struct DefaultAllocator;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ where
|
||||||
R::Value: Mul<C::Value>,
|
R::Value: Mul<C::Value>,
|
||||||
Prod<R::Value, C::Value>: ArrayLength<N>,
|
Prod<R::Value, C::Value>: ArrayLength<N>,
|
||||||
{
|
{
|
||||||
type Buffer = MatrixArray<N, R, C>;
|
type Buffer = ArrayStorage<N, R, C>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
|
unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer {
|
||||||
|
@ -77,7 +77,7 @@ where
|
||||||
// Dynamic - Dynamic
|
// Dynamic - Dynamic
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
|
impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
|
||||||
type Buffer = MatrixVec<N, Dynamic, C>;
|
type Buffer = VecStorage<N, Dynamic, C>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer {
|
unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer {
|
||||||
|
@ -86,7 +86,7 @@ impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
|
||||||
res.reserve_exact(length);
|
res.reserve_exact(length);
|
||||||
res.set_len(length);
|
res.set_len(length);
|
||||||
|
|
||||||
MatrixVec::new(nrows, ncols, res)
|
VecStorage::new(nrows, ncols, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -101,14 +101,14 @@ impl<N: Scalar, C: Dim> Allocator<N, Dynamic, C> for DefaultAllocator {
|
||||||
assert!(res.len() == nrows.value() * ncols.value(),
|
assert!(res.len() == nrows.value() * ncols.value(),
|
||||||
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
|
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
|
||||||
|
|
||||||
MatrixVec::new(nrows, ncols, res)
|
VecStorage::new(nrows, ncols, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static - Dynamic
|
// Static - Dynamic
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
|
impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
|
||||||
type Buffer = MatrixVec<N, R, Dynamic>;
|
type Buffer = VecStorage<N, R, Dynamic>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer {
|
unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer {
|
||||||
|
@ -117,7 +117,7 @@ impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
|
||||||
res.reserve_exact(length);
|
res.reserve_exact(length);
|
||||||
res.set_len(length);
|
res.set_len(length);
|
||||||
|
|
||||||
MatrixVec::new(nrows, ncols, res)
|
VecStorage::new(nrows, ncols, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -132,7 +132,7 @@ impl<N: Scalar, R: DimName> Allocator<N, R, Dynamic> for DefaultAllocator {
|
||||||
assert!(res.len() == nrows.value() * ncols.value(),
|
assert!(res.len() == nrows.value() * ncols.value(),
|
||||||
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
|
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
|
||||||
|
|
||||||
MatrixVec::new(nrows, ncols, res)
|
VecStorage::new(nrows, ncols, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ where
|
||||||
rto: RTo,
|
rto: RTo,
|
||||||
cto: CTo,
|
cto: CTo,
|
||||||
buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer,
|
buf: <Self as Allocator<N, RFrom, CFrom>>::Buffer,
|
||||||
) -> MatrixArray<N, RTo, CTo>
|
) -> ArrayStorage<N, RTo, CTo>
|
||||||
{
|
{
|
||||||
let mut res = <Self as Allocator<N, RTo, CTo>>::allocate_uninitialized(rto, cto);
|
let mut res = <Self as Allocator<N, RTo, CTo>>::allocate_uninitialized(rto, cto);
|
||||||
|
|
||||||
|
@ -185,8 +185,8 @@ where
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: Dynamic,
|
rto: Dynamic,
|
||||||
cto: CTo,
|
cto: CTo,
|
||||||
buf: MatrixArray<N, RFrom, CFrom>,
|
buf: ArrayStorage<N, RFrom, CFrom>,
|
||||||
) -> MatrixVec<N, Dynamic, CTo>
|
) -> VecStorage<N, Dynamic, CTo>
|
||||||
{
|
{
|
||||||
let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto);
|
let mut res = <Self as Allocator<N, Dynamic, CTo>>::allocate_uninitialized(rto, cto);
|
||||||
|
|
||||||
|
@ -214,8 +214,8 @@ where
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: RTo,
|
rto: RTo,
|
||||||
cto: Dynamic,
|
cto: Dynamic,
|
||||||
buf: MatrixArray<N, RFrom, CFrom>,
|
buf: ArrayStorage<N, RFrom, CFrom>,
|
||||||
) -> MatrixVec<N, RTo, Dynamic>
|
) -> VecStorage<N, RTo, Dynamic>
|
||||||
{
|
{
|
||||||
let mut res = <Self as Allocator<N, RTo, Dynamic>>::allocate_uninitialized(rto, cto);
|
let mut res = <Self as Allocator<N, RTo, Dynamic>>::allocate_uninitialized(rto, cto);
|
||||||
|
|
||||||
|
@ -238,11 +238,11 @@ impl<N: Scalar, CFrom: Dim, CTo: Dim> Reallocator<N, Dynamic, CFrom, Dynamic, CT
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: Dynamic,
|
rto: Dynamic,
|
||||||
cto: CTo,
|
cto: CTo,
|
||||||
buf: MatrixVec<N, Dynamic, CFrom>,
|
buf: VecStorage<N, Dynamic, CFrom>,
|
||||||
) -> MatrixVec<N, Dynamic, CTo>
|
) -> VecStorage<N, Dynamic, CTo>
|
||||||
{
|
{
|
||||||
let new_buf = buf.resize(rto.value() * cto.value());
|
let new_buf = buf.resize(rto.value() * cto.value());
|
||||||
MatrixVec::new(rto, cto, new_buf)
|
VecStorage::new(rto, cto, new_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,11 +254,11 @@ impl<N: Scalar, CFrom: Dim, RTo: DimName> Reallocator<N, Dynamic, CFrom, RTo, Dy
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: RTo,
|
rto: RTo,
|
||||||
cto: Dynamic,
|
cto: Dynamic,
|
||||||
buf: MatrixVec<N, Dynamic, CFrom>,
|
buf: VecStorage<N, Dynamic, CFrom>,
|
||||||
) -> MatrixVec<N, RTo, Dynamic>
|
) -> VecStorage<N, RTo, Dynamic>
|
||||||
{
|
{
|
||||||
let new_buf = buf.resize(rto.value() * cto.value());
|
let new_buf = buf.resize(rto.value() * cto.value());
|
||||||
MatrixVec::new(rto, cto, new_buf)
|
VecStorage::new(rto, cto, new_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,11 +270,11 @@ impl<N: Scalar, RFrom: DimName, CTo: Dim> Reallocator<N, RFrom, Dynamic, Dynamic
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: Dynamic,
|
rto: Dynamic,
|
||||||
cto: CTo,
|
cto: CTo,
|
||||||
buf: MatrixVec<N, RFrom, Dynamic>,
|
buf: VecStorage<N, RFrom, Dynamic>,
|
||||||
) -> MatrixVec<N, Dynamic, CTo>
|
) -> VecStorage<N, Dynamic, CTo>
|
||||||
{
|
{
|
||||||
let new_buf = buf.resize(rto.value() * cto.value());
|
let new_buf = buf.resize(rto.value() * cto.value());
|
||||||
MatrixVec::new(rto, cto, new_buf)
|
VecStorage::new(rto, cto, new_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,10 +286,10 @@ impl<N: Scalar, RFrom: DimName, RTo: DimName> Reallocator<N, RFrom, Dynamic, RTo
|
||||||
unsafe fn reallocate_copy(
|
unsafe fn reallocate_copy(
|
||||||
rto: RTo,
|
rto: RTo,
|
||||||
cto: Dynamic,
|
cto: Dynamic,
|
||||||
buf: MatrixVec<N, RFrom, Dynamic>,
|
buf: VecStorage<N, RFrom, Dynamic>,
|
||||||
) -> MatrixVec<N, RTo, Dynamic>
|
) -> VecStorage<N, RTo, Dynamic>
|
||||||
{
|
{
|
||||||
let new_buf = buf.resize(rto.value() * cto.value());
|
let new_buf = buf.resize(rto.value() * cto.value());
|
||||||
MatrixVec::new(rto, cto, new_buf)
|
VecStorage::new(rto, cto, new_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,7 @@ dim_ops!(
|
||||||
DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod;
|
DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod;
|
||||||
DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff;
|
DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff;
|
||||||
DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot;
|
DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot;
|
||||||
DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameNimimum, Minimum;
|
DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum;
|
||||||
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
|
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -364,7 +364,8 @@ impl<
|
||||||
G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
|
G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
|
||||||
> IsNotStaticOne
|
> IsNotStaticOne
|
||||||
for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
|
for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim
|
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim
|
||||||
for UInt<U, B>
|
for UInt<U, B>
|
||||||
|
@ -405,4 +406,5 @@ impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Syn
|
||||||
|
|
||||||
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne
|
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne
|
||||||
for UInt<U, B>
|
for UInt<U, B>
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
use num::{One, Zero};
|
use num::{One, Zero};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
use std::iter::ExactSizeIterator;
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use base::allocator::{Allocator, Reallocator};
|
use base::allocator::{Allocator, Reallocator};
|
||||||
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||||
use base::dimension::{
|
use base::dimension::{
|
||||||
Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, Dynamic, U1,
|
Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1,
|
||||||
};
|
};
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
use base::dimension::Dynamic;
|
||||||
use base::storage::{Storage, StorageMut};
|
use base::storage::{Storage, StorageMut};
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use base::DMatrix;
|
use base::DMatrix;
|
||||||
|
@ -23,7 +29,7 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts the upper triangular part of this matrix (including the diagonal).
|
/// Extracts the lower triangular part of this matrix (including the diagonal).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lower_triangle(&self) -> MatrixMN<N, R, C>
|
pub fn lower_triangle(&self) -> MatrixMN<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
|
@ -32,6 +38,54 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new matrix by extracting the given set of rows from `self`.
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn select_rows<'a, I>(&self, irows: I) -> MatrixMN<N, Dynamic, C>
|
||||||
|
where I: IntoIterator<Item = &'a usize>,
|
||||||
|
I::IntoIter: ExactSizeIterator + Clone,
|
||||||
|
DefaultAllocator: Allocator<N, Dynamic, C> {
|
||||||
|
let irows = irows.into_iter();
|
||||||
|
let ncols = self.data.shape().1;
|
||||||
|
let mut res = unsafe { MatrixMN::new_uninitialized_generic(Dynamic::new(irows.len()), ncols) };
|
||||||
|
|
||||||
|
// First, check that all the indices from irows are valid.
|
||||||
|
// This will allow us to use unchecked access in the inner loop.
|
||||||
|
for i in irows.clone() {
|
||||||
|
assert!(*i < self.nrows(), "Row index out of bounds.")
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in 0..ncols.value() {
|
||||||
|
// FIXME: use unchecked column indexing
|
||||||
|
let mut res = res.column_mut(j);
|
||||||
|
let mut src = self.column(j);
|
||||||
|
|
||||||
|
for (destination, source) in irows.clone().enumerate() {
|
||||||
|
unsafe {
|
||||||
|
*res.vget_unchecked_mut(destination) = *src.vget_unchecked(*source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new matrix by extracting the given set of columns from `self`.
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn select_columns<'a, I>(&self, icols: I) -> MatrixMN<N, R, Dynamic>
|
||||||
|
where I: IntoIterator<Item = &'a usize>,
|
||||||
|
I::IntoIter: ExactSizeIterator,
|
||||||
|
DefaultAllocator: Allocator<N, R, Dynamic> {
|
||||||
|
let icols = icols.into_iter();
|
||||||
|
let nrows = self.data.shape().0;
|
||||||
|
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, Dynamic::new(icols.len())) };
|
||||||
|
|
||||||
|
for (destination, source) in icols.enumerate() {
|
||||||
|
res.column_mut(destination).copy_from(&self.column(*source))
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
@ -58,7 +112,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
let n = cmp::min(nrows, ncols);
|
let n = cmp::min(nrows, ncols);
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
unsafe { *self.get_unchecked_mut(i, i) = val }
|
unsafe { *self.get_unchecked_mut((i, i)) = val }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +121,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
pub fn fill_row(&mut self, i: usize, val: N) {
|
pub fn fill_row(&mut self, i: usize, val: N) {
|
||||||
assert!(i < self.nrows(), "Row index out of bounds.");
|
assert!(i < self.nrows(), "Row index out of bounds.");
|
||||||
for j in 0..self.ncols() {
|
for j in 0..self.ncols() {
|
||||||
unsafe { *self.get_unchecked_mut(i, j) = val }
|
unsafe { *self.get_unchecked_mut((i, j)) = val }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +130,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
pub fn fill_column(&mut self, j: usize, val: N) {
|
pub fn fill_column(&mut self, j: usize, val: N) {
|
||||||
assert!(j < self.ncols(), "Row index out of bounds.");
|
assert!(j < self.ncols(), "Row index out of bounds.");
|
||||||
for i in 0..self.nrows() {
|
for i in 0..self.nrows() {
|
||||||
unsafe { *self.get_unchecked_mut(i, j) = val }
|
unsafe { *self.get_unchecked_mut((i, j)) = val }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +147,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
|
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
|
||||||
|
|
||||||
for i in 0..min_nrows_ncols {
|
for i in 0..min_nrows_ncols {
|
||||||
unsafe { *self.get_unchecked_mut(i, i) = *diag.vget_unchecked(i) }
|
unsafe { *self.get_unchecked_mut((i, i)) = *diag.vget_unchecked(i) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +182,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
pub fn fill_lower_triangle(&mut self, val: N, shift: usize) {
|
pub fn fill_lower_triangle(&mut self, val: N, shift: usize) {
|
||||||
for j in 0..self.ncols() {
|
for j in 0..self.ncols() {
|
||||||
for i in (j + shift)..self.nrows() {
|
for i in (j + shift)..self.nrows() {
|
||||||
unsafe { *self.get_unchecked_mut(i, j) = val }
|
unsafe { *self.get_unchecked_mut((i, j)) = val }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +200,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
// FIXME: is there a more efficient way to avoid the min ?
|
// FIXME: is there a more efficient way to avoid the min ?
|
||||||
// (necessary for rectangular matrices)
|
// (necessary for rectangular matrices)
|
||||||
for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
|
for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
|
||||||
unsafe { *self.get_unchecked_mut(i, j) = val }
|
unsafe { *self.get_unchecked_mut((i, j)) = val }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +245,7 @@ impl<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
||||||
for j in 0..dim {
|
for j in 0..dim {
|
||||||
for i in j + 1..dim {
|
for i in j + 1..dim {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i);
|
*self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +260,7 @@ impl<N: Scalar, D: Dim, S: StorageMut<N, D, D>> Matrix<N, D, D, S> {
|
||||||
for j in 1..self.ncols() {
|
for j in 1..self.ncols() {
|
||||||
for i in 0..j {
|
for i in 0..j {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i);
|
*self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +302,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
|
||||||
/// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included).
|
/// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included).
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic>
|
pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic>
|
||||||
where
|
where
|
||||||
C: DimSub<Dynamic, Output = Dynamic>,
|
C: DimSub<Dynamic, Output = Dynamic>,
|
||||||
|
@ -330,6 +385,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
|
||||||
/// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included).
|
/// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included).
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C>
|
pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C>
|
||||||
where
|
where
|
||||||
R: DimSub<Dynamic, Output = Dynamic>,
|
R: DimSub<Dynamic, Output = Dynamic>,
|
||||||
|
@ -407,6 +463,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
|
||||||
/// Inserts `n` columns filled with `val` starting at the `i-th` position.
|
/// Inserts `n` columns filled with `val` starting at the `i-th` position.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic>
|
pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic>
|
||||||
where
|
where
|
||||||
C: DimAdd<Dynamic, Output = Dynamic>,
|
C: DimAdd<Dynamic, Output = Dynamic>,
|
||||||
|
@ -484,6 +541,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
|
||||||
/// Inserts `n` rows filled with `val` starting at the `i-th` position.
|
/// Inserts `n` rows filled with `val` starting at the `i-th` position.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C>
|
pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C>
|
||||||
where
|
where
|
||||||
R: DimAdd<Dynamic, Output = Dynamic>,
|
R: DimAdd<Dynamic, Output = Dynamic>,
|
||||||
|
@ -549,6 +607,29 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val)
|
self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resizes this matrix vertically, i.e., so that it contains `new_nrows` rows while keeping the same number of columns.
|
||||||
|
///
|
||||||
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
/// rows than `self`, then the extra rows are filled with `val`.
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn resize_vertically(self, new_nrows: usize, val: N) -> MatrixMN<N, Dynamic, C>
|
||||||
|
where DefaultAllocator: Reallocator<N, R, C, Dynamic, C> {
|
||||||
|
let ncols = self.data.shape().1;
|
||||||
|
self.resize_generic(Dynamic::new(new_nrows), ncols, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resizes this matrix horizontally, i.e., so that it contains `new_ncolumns` columns while keeping the same number of columns.
|
||||||
|
///
|
||||||
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
/// columns than `self`, then the extra columns are filled with `val`.
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn resize_horizontally(self, new_ncols: usize, val: N) -> MatrixMN<N, R, Dynamic>
|
||||||
|
where DefaultAllocator: Reallocator<N, R, C, R, Dynamic> {
|
||||||
|
let nrows = self.data.shape().0;
|
||||||
|
self.resize_generic(nrows, Dynamic::new(new_ncols), val)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns.
|
/// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns.
|
||||||
///
|
///
|
||||||
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
@ -626,6 +707,61 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<N: Scalar> DMatrix<N> {
|
||||||
|
/// Resizes this matrix in-place.
|
||||||
|
///
|
||||||
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
/// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
|
||||||
|
///
|
||||||
|
/// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`.
|
||||||
|
pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: N)
|
||||||
|
where DefaultAllocator: Reallocator<N, Dynamic, Dynamic, Dynamic, Dynamic> {
|
||||||
|
let placeholder = unsafe { Self::new_uninitialized(0, 0) };
|
||||||
|
let old = mem::replace(self, placeholder);
|
||||||
|
let new = old.resize(new_nrows, new_ncols, val);
|
||||||
|
let _ = mem::replace(self, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<N: Scalar, C: Dim> MatrixMN<N, Dynamic, C>
|
||||||
|
where DefaultAllocator: Allocator<N, Dynamic, C> {
|
||||||
|
/// Changes the number of rows of this matrix in-place.
|
||||||
|
///
|
||||||
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
/// rows than `self`, then the extra rows are filled with `val`.
|
||||||
|
///
|
||||||
|
/// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`).
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: N)
|
||||||
|
where DefaultAllocator: Reallocator<N, Dynamic, C, Dynamic, C> {
|
||||||
|
let placeholder = unsafe { Self::new_uninitialized_generic(Dynamic::new(0), self.data.shape().1) };
|
||||||
|
let old = mem::replace(self, placeholder);
|
||||||
|
let new = old.resize_vertically(new_nrows, val);
|
||||||
|
let _ = mem::replace(self, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<N: Scalar, R: Dim> MatrixMN<N, R, Dynamic>
|
||||||
|
where DefaultAllocator: Allocator<N, R, Dynamic> {
|
||||||
|
/// Changes the number of column of this matrix in-place.
|
||||||
|
///
|
||||||
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
|
/// columns than `self`, then the extra columns are filled with `val`.
|
||||||
|
///
|
||||||
|
/// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`).
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: N)
|
||||||
|
where DefaultAllocator: Reallocator<N, R, Dynamic, R, Dynamic> {
|
||||||
|
let placeholder = unsafe { Self::new_uninitialized_generic(self.data.shape().0, Dynamic::new(0)) };
|
||||||
|
let old = mem::replace(self, placeholder);
|
||||||
|
let new = old.resize_horizontally(new_ncols, val);
|
||||||
|
let _ = mem::replace(self, new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn compress_rows<N: Scalar>(
|
unsafe fn compress_rows<N: Scalar>(
|
||||||
data: &mut [N],
|
data: &mut [N],
|
||||||
nrows: usize,
|
nrows: usize,
|
||||||
|
@ -706,6 +842,7 @@ unsafe fn extend_rows<N: Scalar>(
|
||||||
|
|
||||||
/// Extend the number of columns of the `Matrix` with elements from
|
/// Extend the number of columns of the `Matrix` with elements from
|
||||||
/// a given iterator.
|
/// a given iterator.
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S>
|
impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
|
@ -753,6 +890,7 @@ where
|
||||||
|
|
||||||
/// Extend the number of rows of the `Vector` with elements from
|
/// Extend the number of rows of the `Vector` with elements from
|
||||||
/// a given iterator.
|
/// a given iterator.
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S>
|
impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
|
@ -764,15 +902,16 @@ where
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # use nalgebra::DVector;
|
/// # use nalgebra::DVector;
|
||||||
/// let mut vector = DVector::from_vec(3, vec![0, 1, 2]);
|
/// let mut vector = DVector::from_vec(vec![0, 1, 2]);
|
||||||
/// vector.extend(vec![3, 4, 5]);
|
/// vector.extend(vec![3, 4, 5]);
|
||||||
/// assert!(vector.eq(&DVector::from_vec(6, vec![0, 1, 2, 3, 4, 5])));
|
/// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5])));
|
||||||
/// ```
|
/// ```
|
||||||
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) {
|
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) {
|
||||||
self.data.extend(iter);
|
self.data.extend(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S>
|
impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
|
|
|
@ -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>],
|
||||||
|
}
|
||||||
|
}
|
227
src/base/iter.rs
227
src/base/iter.rs
|
@ -3,9 +3,9 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use base::dimension::Dim;
|
use base::dimension::{Dim, U1};
|
||||||
use base::storage::{Storage, StorageMut};
|
use base::storage::{Storage, StorageMut};
|
||||||
use base::Scalar;
|
use base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut};
|
||||||
|
|
||||||
macro_rules! iterator {
|
macro_rules! iterator {
|
||||||
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
|
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
|
||||||
|
@ -96,3 +96,226 @@ macro_rules! iterator {
|
||||||
|
|
||||||
iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S);
|
iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S);
|
||||||
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S);
|
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Row iterators.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// An iterator through the rows of a matrix.
|
||||||
|
pub struct RowIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
|
||||||
|
mat: &'a Matrix<N, R, C, S>,
|
||||||
|
curr: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> RowIter<'a, N, R, C, S> {
|
||||||
|
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
|
||||||
|
RowIter {
|
||||||
|
mat, curr: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for RowIter<'a, N, R, C, S> {
|
||||||
|
type Item = MatrixSlice<'a, N, U1, C, S::RStride, S::CStride>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.curr < self.mat.nrows() {
|
||||||
|
let res = self.mat.row(self.curr);
|
||||||
|
self.curr += 1;
|
||||||
|
Some(res)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.mat.nrows() - self.curr, Some(self.mat.nrows() - self.curr))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.mat.nrows() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for RowIter<'a, N, R, C, S> {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.mat.nrows() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// An iterator through the mutable rows of a matrix.
|
||||||
|
pub struct RowIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
|
||||||
|
mat: *mut Matrix<N, R, C, S>,
|
||||||
|
curr: usize,
|
||||||
|
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> RowIterMut<'a, N, R, C, S> {
|
||||||
|
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
|
||||||
|
RowIterMut {
|
||||||
|
mat,
|
||||||
|
curr: 0,
|
||||||
|
phantom: PhantomData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nrows(&self) -> usize {
|
||||||
|
unsafe {
|
||||||
|
(*self.mat).nrows()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for RowIterMut<'a, N, R, C, S> {
|
||||||
|
type Item = MatrixSliceMut<'a, N, U1, C, S::RStride, S::CStride>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.curr < self.nrows() {
|
||||||
|
let res = unsafe { (*self.mat).row_mut(self.curr) };
|
||||||
|
self.curr += 1;
|
||||||
|
Some(res)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.nrows() - self.curr, Some(self.nrows() - self.curr))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.nrows() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for RowIterMut<'a, N, R, C, S> {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.nrows() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Column iterators.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// An iterator through the columns of a matrix.
|
||||||
|
pub struct ColumnIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
|
||||||
|
mat: &'a Matrix<N, R, C, S>,
|
||||||
|
curr: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ColumnIter<'a, N, R, C, S> {
|
||||||
|
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
|
||||||
|
ColumnIter {
|
||||||
|
mat, curr: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for ColumnIter<'a, N, R, C, S> {
|
||||||
|
type Item = MatrixSlice<'a, N, R, U1, S::RStride, S::CStride>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.curr < self.mat.ncols() {
|
||||||
|
let res = self.mat.column(self.curr);
|
||||||
|
self.curr += 1;
|
||||||
|
Some(res)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.mat.ncols() - self.curr, Some(self.mat.ncols() - self.curr))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.mat.ncols() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for ColumnIter<'a, N, R, C, S> {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.mat.ncols() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// An iterator through the mutable columns of a matrix.
|
||||||
|
pub struct ColumnIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
|
||||||
|
mat: *mut Matrix<N, R, C, S>,
|
||||||
|
curr: usize,
|
||||||
|
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ColumnIterMut<'a, N, R, C, S> {
|
||||||
|
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
|
||||||
|
ColumnIterMut {
|
||||||
|
mat,
|
||||||
|
curr: 0,
|
||||||
|
phantom: PhantomData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ncols(&self) -> usize {
|
||||||
|
unsafe {
|
||||||
|
(*self.mat).ncols()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for ColumnIterMut<'a, N, R, C, S> {
|
||||||
|
type Item = MatrixSliceMut<'a, N, R, U1, S::RStride, S::CStride>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.curr < self.ncols() {
|
||||||
|
let res = unsafe { (*self.mat).column_mut(self.curr) };
|
||||||
|
self.curr += 1;
|
||||||
|
Some(res)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.ncols() - self.curr, Some(self.ncols() - self.curr))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.ncols() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for ColumnIterMut<'a, N, R, C, S> {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.ncols() - self.curr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -20,8 +21,8 @@ use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Real, Ring};
|
||||||
|
|
||||||
use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
|
||||||
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||||
use base::dimension::{Dim, DimAdd, DimSum, U1, U2, U3};
|
use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
|
||||||
use base::iter::{MatrixIter, MatrixIterMut};
|
use base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut};
|
||||||
use base::storage::{
|
use base::storage::{
|
||||||
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
|
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
|
||||||
};
|
};
|
||||||
|
@ -72,7 +73,7 @@ pub type MatrixCross<N, R1, C1, R2, C2> =
|
||||||
/// dynamically-sized column vector should be represented as a `Matrix<N, Dynamic, U1, S>` (given
|
/// dynamically-sized column vector should be represented as a `Matrix<N, Dynamic, U1, S>` (given
|
||||||
/// some concrete types for `N` and a compatible data storage type `S`).
|
/// some concrete types for `N` and a compatible data storage type `S`).
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Hash, Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
|
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
|
||||||
/// The data storage that contains all the matrix components and informations about its number
|
/// The data storage that contains all the matrix components and informations about its number
|
||||||
/// of rows and column (if needed).
|
/// of rows and column (if needed).
|
||||||
|
@ -246,6 +247,37 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
MatrixIter::new(&self.data)
|
MatrixIter::new(&self.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate through the rows of this matrix.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::Matrix2x3;
|
||||||
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
||||||
|
/// 4, 5, 6);
|
||||||
|
/// for (i, row) in a.row_iter().enumerate() {
|
||||||
|
/// assert_eq!(row, a.row(i))
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn row_iter(&self) -> RowIter<N, R, C, S> {
|
||||||
|
RowIter::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate through the columns of this matrix.
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::Matrix2x3;
|
||||||
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
||||||
|
/// 4, 5, 6);
|
||||||
|
/// for (i, column) in a.column_iter().enumerate() {
|
||||||
|
/// assert_eq!(column, a.column(i))
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn column_iter(&self) -> ColumnIter<N, R, C, S> {
|
||||||
|
ColumnIter::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the row and column coordinates of the i-th element of this matrix seen as a
|
/// Computes the row and column coordinates of the i-th element of this matrix seen as a
|
||||||
/// vector.
|
/// vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -263,17 +295,6 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a reference to the element of this matrix at row `irow` and column `icol` without
|
|
||||||
/// bound-checking.
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N {
|
|
||||||
debug_assert!(
|
|
||||||
irow < self.nrows() && icol < self.ncols(),
|
|
||||||
"Matrix index out of bounds."
|
|
||||||
);
|
|
||||||
self.data.get_unchecked(irow, icol)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a pointer to the start of the matrix.
|
/// Returns a pointer to the start of the matrix.
|
||||||
///
|
///
|
||||||
/// If the matrix is not empty, this pointer is guaranteed to be aligned
|
/// If the matrix is not empty, this pointer is guaranteed to be aligned
|
||||||
|
@ -383,7 +404,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
for j in 0..res.ncols() {
|
for j in 0..res.ncols() {
|
||||||
for i in 0..res.nrows() {
|
for i in 0..res.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.get_unchecked_mut(i, j) = *self.get_unchecked(i, j);
|
*res.get_unchecked_mut((i, j)) = *self.get_unchecked((i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,7 +433,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
|
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
|
||||||
/// `f` also gets passed the row and column index, i.e. `f(value, row, col)`.
|
/// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
|
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -512,6 +533,57 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Folds a function `f` on each entry of `self`.
|
||||||
|
#[inline]
|
||||||
|
pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, N) -> Acc) -> Acc {
|
||||||
|
let (nrows, ncols) = self.data.shape();
|
||||||
|
|
||||||
|
let mut res = init;
|
||||||
|
|
||||||
|
for j in 0..ncols.value() {
|
||||||
|
for i in 0..nrows.value() {
|
||||||
|
unsafe {
|
||||||
|
let a = *self.data.get_unchecked(i, j);
|
||||||
|
res = f(res, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
|
||||||
|
#[inline]
|
||||||
|
pub fn zip_fold<N2, R2, C2, S2, Acc>(&self, rhs: &Matrix<N2, R2, C2, S2>, init: Acc, mut f: impl FnMut(Acc, N, N2) -> Acc) -> Acc
|
||||||
|
where
|
||||||
|
N2: Scalar,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N2, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>
|
||||||
|
{
|
||||||
|
let (nrows, ncols) = self.data.shape();
|
||||||
|
|
||||||
|
let mut res = init;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
(nrows.value(), ncols.value()) == rhs.shape(),
|
||||||
|
"Matrix simultaneous traversal error: dimension mismatch."
|
||||||
|
);
|
||||||
|
|
||||||
|
for j in 0..ncols.value() {
|
||||||
|
for i in 0..nrows.value() {
|
||||||
|
unsafe {
|
||||||
|
let a = *self.data.get_unchecked(i, j);
|
||||||
|
let b = *rhs.data.get_unchecked(i, j);
|
||||||
|
res = f(res, a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
/// Transposes `self` and store the result into `out`.
|
/// Transposes `self` and store the result into `out`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
|
||||||
|
@ -531,7 +603,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
unsafe {
|
unsafe {
|
||||||
*out.get_unchecked_mut(j, i) = *self.get_unchecked(i, j);
|
*out.get_unchecked_mut((j, i)) = *self.get_unchecked((i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,14 +640,44 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
self.data.ptr_mut()
|
self.data.ptr_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable reference to the i-th element of this matrix.
|
/// Mutably iterates through this matrix rows.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::Matrix2x3;
|
||||||
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
||||||
|
/// 4, 5, 6);
|
||||||
|
/// for (i, mut row) in a.row_iter_mut().enumerate() {
|
||||||
|
/// row *= (i + 1) * 10;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let expected = Matrix2x3::new(10, 20, 30,
|
||||||
|
/// 80, 100, 120);
|
||||||
|
/// assert_eq!(a, expected);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut N {
|
pub fn row_iter_mut(&mut self) -> RowIterMut<N, R, C, S> {
|
||||||
debug_assert!(
|
RowIterMut::new(self)
|
||||||
irow < self.nrows() && icol < self.ncols(),
|
}
|
||||||
"Matrix index out of bounds."
|
|
||||||
);
|
/// Mutably iterates through this matrix columns.
|
||||||
self.data.get_unchecked_mut(irow, icol)
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::Matrix2x3;
|
||||||
|
/// let mut a = Matrix2x3::new(1, 2, 3,
|
||||||
|
/// 4, 5, 6);
|
||||||
|
/// for (i, mut col) in a.column_iter_mut().enumerate() {
|
||||||
|
/// col *= (i + 1) * 10;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let expected = Matrix2x3::new(10, 40, 90,
|
||||||
|
/// 40, 100, 180);
|
||||||
|
/// assert_eq!(a, expected);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn column_iter_mut(&mut self) -> ColumnIterMut<N, R, C, S> {
|
||||||
|
ColumnIterMut::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Swaps two entries without bound-checking.
|
/// Swaps two entries without bound-checking.
|
||||||
|
@ -616,7 +718,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut(i, j) = *slice.get_unchecked(i + j * nrows);
|
*self.get_unchecked_mut((i, j)) = *slice.get_unchecked(i + j * nrows);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -639,7 +741,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
for j in 0..self.ncols() {
|
for j in 0..self.ncols() {
|
||||||
for i in 0..self.nrows() {
|
for i in 0..self.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut(i, j) = *other.get_unchecked(i, j);
|
*self.get_unchecked_mut((i, j)) = *other.get_unchecked((i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -663,7 +765,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked_mut(i, j) = *other.get_unchecked(j, i);
|
*self.get_unchecked_mut((i, j)) = *other.get_unchecked((j, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -671,8 +773,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
|
|
||||||
/// Replaces each component of `self` by the result of a closure `f` applied on it.
|
/// Replaces each component of `self` by the result of a closure `f` applied on it.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F)
|
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) {
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
|
||||||
let (nrows, ncols) = self.shape();
|
let (nrows, ncols) = self.shape();
|
||||||
|
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
|
@ -684,6 +785,71 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
||||||
|
/// joined with the components from `rhs`.
|
||||||
|
#[inline]
|
||||||
|
pub fn zip_apply<N2, R2, C2, S2>(&mut self, rhs: &Matrix<N2, R2, C2, S2>, mut f: impl FnMut(N, N2) -> N)
|
||||||
|
where N2: Scalar,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N2, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
|
||||||
|
let (nrows, ncols) = self.shape();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
(nrows, ncols) == rhs.shape(),
|
||||||
|
"Matrix simultaneous traversal error: dimension mismatch."
|
||||||
|
);
|
||||||
|
|
||||||
|
for j in 0..ncols {
|
||||||
|
for i in 0..nrows {
|
||||||
|
unsafe {
|
||||||
|
let e = self.data.get_unchecked_mut(i, j);
|
||||||
|
let rhs = rhs.get_unchecked((i, j));
|
||||||
|
*e = f(*e, *rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Replaces each component of `self` by the result of a closure `f` applied on its components
|
||||||
|
/// joined with the components from `b` and `c`.
|
||||||
|
#[inline]
|
||||||
|
pub fn zip_zip_apply<N2, R2, C2, S2, N3, R3, C3, S3>(&mut self, b: &Matrix<N2, R2, C2, S2>, c: &Matrix<N3, R3, C3, S3>, mut f: impl FnMut(N, N2, N3) -> N)
|
||||||
|
where N2: Scalar,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S2: Storage<N2, R2, C2>,
|
||||||
|
N3: Scalar,
|
||||||
|
R3: Dim,
|
||||||
|
C3: Dim,
|
||||||
|
S3: Storage<N3, R3, C3>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
|
||||||
|
let (nrows, ncols) = self.shape();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
(nrows, ncols) == b.shape(),
|
||||||
|
"Matrix simultaneous traversal error: dimension mismatch."
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
(nrows, ncols) == c.shape(),
|
||||||
|
"Matrix simultaneous traversal error: dimension mismatch."
|
||||||
|
);
|
||||||
|
|
||||||
|
for j in 0..ncols {
|
||||||
|
for i in 0..nrows {
|
||||||
|
unsafe {
|
||||||
|
let e = self.data.get_unchecked_mut(i, j);
|
||||||
|
let b = b.get_unchecked((i, j));
|
||||||
|
let c = c.get_unchecked((i, j));
|
||||||
|
*e = f(*e, *b, *c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
|
@ -760,7 +926,7 @@ impl<N: Real, R: Dim, C: Dim, S: Storage<Complex<N>, R, C>> Matrix<Complex<N>, R
|
||||||
for i in 0..nrows {
|
for i in 0..nrows {
|
||||||
for j in 0..ncols {
|
for j in 0..ncols {
|
||||||
unsafe {
|
unsafe {
|
||||||
*out.get_unchecked_mut(j, i) = self.get_unchecked(i, j).conj();
|
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conj();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,8 +960,8 @@ impl<N: Real, D: Dim, S: StorageMut<Complex<N>, D, D>> Matrix<Complex<N>, D, D,
|
||||||
for i in 1..dim {
|
for i in 1..dim {
|
||||||
for j in 0..i {
|
for j in 0..i {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ref_ij = self.get_unchecked_mut(i, j) as *mut Complex<N>;
|
let ref_ij = self.get_unchecked_mut((i, j)) as *mut Complex<N>;
|
||||||
let ref_ji = self.get_unchecked_mut(j, i) as *mut Complex<N>;
|
let ref_ji = self.get_unchecked_mut((j, i)) as *mut Complex<N>;
|
||||||
let conj_ij = (*ref_ij).conj();
|
let conj_ij = (*ref_ij).conj();
|
||||||
let conj_ji = (*ref_ji).conj();
|
let conj_ji = (*ref_ji).conj();
|
||||||
*ref_ij = conj_ji;
|
*ref_ij = conj_ji;
|
||||||
|
@ -821,7 +987,7 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
|
|
||||||
for i in 0..dim.value() {
|
for i in 0..dim.value() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*res.vget_unchecked_mut(i) = *self.get_unchecked(i, i);
|
*res.vget_unchecked_mut(i) = *self.get_unchecked((i, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,27 +1007,36 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
let mut res = N::zero();
|
let mut res = N::zero();
|
||||||
|
|
||||||
for i in 0..dim.value() {
|
for i in 0..dim.value() {
|
||||||
res += unsafe { *self.get_unchecked(i, i) };
|
res += unsafe { *self.get_unchecked((i, i)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: Scalar + One + Zero, D: DimAdd<U1> + IsNotStaticOne, S: Storage<N, D, D>> Matrix<N, D, D, S> {
|
||||||
|
|
||||||
|
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
|
||||||
|
/// and setting the diagonal element to `1`.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_homogeneous(&self) -> MatrixN<N, DimSum<D, U1>>
|
||||||
|
where DefaultAllocator: Allocator<N, DimSum<D, U1>, DimSum<D, U1>> {
|
||||||
|
assert!(self.is_square(), "Only square matrices can currently be transformed to homogeneous coordinates.");
|
||||||
|
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
|
||||||
|
let mut res = MatrixN::identity_generic(dim, dim);
|
||||||
|
res.generic_slice_mut::<D, D>((0, 0), self.data.shape()).copy_from(&self);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
|
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
|
||||||
/// coordinates.
|
/// coordinates.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>>
|
pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>>
|
||||||
where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
|
where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
|
||||||
let len = self.len();
|
self.push(N::zero())
|
||||||
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
|
|
||||||
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
|
|
||||||
res.generic_slice_mut((0, 0), self.data.shape())
|
|
||||||
.copy_from(self);
|
|
||||||
res[(len, 0)] = N::zero();
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
|
/// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
|
||||||
|
@ -881,6 +1056,22 @@ impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
|
||||||
|
/// Constructs a new vector of higher dimension by appending `element` to the end of `self`.
|
||||||
|
#[inline]
|
||||||
|
pub fn push(&self, element: N) -> VectorN<N, DimSum<D, U1>>
|
||||||
|
where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
|
||||||
|
let len = self.len();
|
||||||
|
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
|
||||||
|
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
|
||||||
|
res.generic_slice_mut((0, 0), self.data.shape())
|
||||||
|
.copy_from(self);
|
||||||
|
res[(len, 0)] = element;
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S>
|
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S>
|
||||||
where
|
where
|
||||||
N: Scalar + AbsDiffEq,
|
N: Scalar + AbsDiffEq,
|
||||||
|
@ -1141,8 +1332,8 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
assert!(self.shape() == (2, 1), "2D perpendicular product ");
|
assert!(self.shape() == (2, 1), "2D perpendicular product ");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.get_unchecked(0, 0) * *b.get_unchecked(1, 0)
|
*self.get_unchecked((0, 0)) * *b.get_unchecked((1, 0))
|
||||||
- *self.get_unchecked(1, 0) * *b.get_unchecked(0, 0)
|
- *self.get_unchecked((1, 0)) * *b.get_unchecked((0, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,17 +1368,17 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
let ncols = SameShapeC::<C, C2>::from_usize(1);
|
let ncols = SameShapeC::<C, C2>::from_usize(1);
|
||||||
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
||||||
|
|
||||||
let ax = *self.get_unchecked(0, 0);
|
let ax = *self.get_unchecked((0, 0));
|
||||||
let ay = *self.get_unchecked(1, 0);
|
let ay = *self.get_unchecked((1, 0));
|
||||||
let az = *self.get_unchecked(2, 0);
|
let az = *self.get_unchecked((2, 0));
|
||||||
|
|
||||||
let bx = *b.get_unchecked(0, 0);
|
let bx = *b.get_unchecked((0, 0));
|
||||||
let by = *b.get_unchecked(1, 0);
|
let by = *b.get_unchecked((1, 0));
|
||||||
let bz = *b.get_unchecked(2, 0);
|
let bz = *b.get_unchecked((2, 0));
|
||||||
|
|
||||||
*res.get_unchecked_mut(0, 0) = ay * bz - az * by;
|
*res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
|
||||||
*res.get_unchecked_mut(1, 0) = az * bx - ax * bz;
|
*res.get_unchecked_mut((1, 0)) = az * bx - ax * bz;
|
||||||
*res.get_unchecked_mut(2, 0) = ax * by - ay * bx;
|
*res.get_unchecked_mut((2, 0)) = ax * by - ay * bx;
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -1198,17 +1389,17 @@ impl<N: Scalar + Ring, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
let ncols = SameShapeC::<C, C2>::from_usize(3);
|
let ncols = SameShapeC::<C, C2>::from_usize(3);
|
||||||
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
let mut res = Matrix::new_uninitialized_generic(nrows, ncols);
|
||||||
|
|
||||||
let ax = *self.get_unchecked(0, 0);
|
let ax = *self.get_unchecked((0, 0));
|
||||||
let ay = *self.get_unchecked(0, 1);
|
let ay = *self.get_unchecked((0, 1));
|
||||||
let az = *self.get_unchecked(0, 2);
|
let az = *self.get_unchecked((0, 2));
|
||||||
|
|
||||||
let bx = *b.get_unchecked(0, 0);
|
let bx = *b.get_unchecked((0, 0));
|
||||||
let by = *b.get_unchecked(0, 1);
|
let by = *b.get_unchecked((0, 1));
|
||||||
let bz = *b.get_unchecked(0, 2);
|
let bz = *b.get_unchecked((0, 2));
|
||||||
|
|
||||||
*res.get_unchecked_mut(0, 0) = ay * bz - az * by;
|
*res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
|
||||||
*res.get_unchecked_mut(0, 1) = az * bx - ax * bz;
|
*res.get_unchecked_mut((0, 1)) = az * bx - ax * bz;
|
||||||
*res.get_unchecked_mut(0, 2) = ax * by - ay * bx;
|
*res.get_unchecked_mut((0, 2)) = ax * by - ay * bx;
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -1264,67 +1455,6 @@ impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
|
||||||
/// The squared L2 norm of this vector.
|
|
||||||
#[inline]
|
|
||||||
pub fn norm_squared(&self) -> N {
|
|
||||||
let mut res = N::zero();
|
|
||||||
|
|
||||||
for i in 0..self.ncols() {
|
|
||||||
let col = self.column(i);
|
|
||||||
res += col.dot(&col)
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The L2 norm of this matrix.
|
|
||||||
#[inline]
|
|
||||||
pub fn norm(&self) -> N {
|
|
||||||
self.norm_squared().sqrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A synonym for the norm of this matrix.
|
|
||||||
///
|
|
||||||
/// Aka the length.
|
|
||||||
///
|
|
||||||
/// This function is simply implemented as a call to `norm()`
|
|
||||||
#[inline]
|
|
||||||
pub fn magnitude(&self) -> N {
|
|
||||||
self.norm()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A synonym for the squared norm of this matrix.
|
|
||||||
///
|
|
||||||
/// Aka the squared length.
|
|
||||||
///
|
|
||||||
/// This function is simply implemented as a call to `norm_squared()`
|
|
||||||
#[inline]
|
|
||||||
pub fn magnitude_squared(&self) -> N {
|
|
||||||
self.norm_squared()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a normalized version of this matrix.
|
|
||||||
#[inline]
|
|
||||||
pub fn normalize(&self) -> MatrixMN<N, R, C>
|
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
|
||||||
self / self.norm()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
|
|
||||||
#[inline]
|
|
||||||
pub fn try_normalize(&self, min_norm: N) -> Option<MatrixMN<N, R, C>>
|
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
|
||||||
let n = self.norm();
|
|
||||||
|
|
||||||
if n <= min_norm {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(self / n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
|
impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
|
||||||
Vector<N, D, S>
|
Vector<N, D, S>
|
||||||
{
|
{
|
||||||
|
@ -1399,32 +1529,6 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
|
||||||
/// Normalizes this matrix in-place and returns its norm.
|
|
||||||
#[inline]
|
|
||||||
pub fn normalize_mut(&mut self) -> N {
|
|
||||||
let n = self.norm();
|
|
||||||
*self /= n;
|
|
||||||
|
|
||||||
n
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
|
|
||||||
///
|
|
||||||
/// If the normalization succeeded, returns the old normal of this matrix.
|
|
||||||
#[inline]
|
|
||||||
pub fn try_normalize_mut(&mut self, min_norm: N) -> Option<N> {
|
|
||||||
let n = self.norm();
|
|
||||||
|
|
||||||
if n <= min_norm {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
*self /= n;
|
|
||||||
Some(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>>
|
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>>
|
||||||
where
|
where
|
||||||
N: Scalar + AbsDiffEq,
|
N: Scalar + AbsDiffEq,
|
||||||
|
@ -1484,3 +1588,24 @@ where
|
||||||
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
|
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N, R, C, S> Hash for Matrix<N, R, C, S>
|
||||||
|
where
|
||||||
|
N: Scalar + Hash,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: Storage<N, R, C>,
|
||||||
|
{
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
let (nrows, ncols) = self.shape();
|
||||||
|
(nrows, ncols).hash(state);
|
||||||
|
|
||||||
|
for j in 0..ncols {
|
||||||
|
for i in 0..nrows {
|
||||||
|
unsafe {
|
||||||
|
self.get_unchecked((i, j)).hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use num::{One, Zero};
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
|
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
|
||||||
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul,
|
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul,
|
||||||
ClosedNeg, Field, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice, Module,
|
ClosedNeg, Field, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice, Module,
|
||||||
Multiplicative, Real, RingCommutative,
|
Multiplicative, Real, RingCommutative,
|
||||||
};
|
};
|
||||||
use alga::linear::{
|
use alga::linear::{
|
||||||
|
@ -45,18 +45,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R: DimName, C: DimName> Inverse<Additive> for MatrixMN<N, R, C>
|
impl<N, R: DimName, C: DimName> TwoSidedInverse<Additive> for MatrixMN<N, R, C>
|
||||||
where
|
where
|
||||||
N: Scalar + ClosedNeg,
|
N: Scalar + ClosedNeg,
|
||||||
DefaultAllocator: Allocator<N, R, C>,
|
DefaultAllocator: Allocator<N, R, C>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> MatrixMN<N, R, C> {
|
fn two_sided_inverse(&self) -> MatrixMN<N, R, C> {
|
||||||
-self
|
-self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
*self = -self.clone()
|
*self = -self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ use std::slice;
|
||||||
|
|
||||||
use base::allocator::Allocator;
|
use base::allocator::Allocator;
|
||||||
use base::default_allocator::DefaultAllocator;
|
use base::default_allocator::DefaultAllocator;
|
||||||
use base::dimension::{Dim, DimName, Dynamic, U1};
|
use base::dimension::{Dim, DimName, Dynamic, U1, IsNotStaticOne};
|
||||||
use base::iter::MatrixIter;
|
use base::iter::MatrixIter;
|
||||||
use base::storage::{Owned, Storage, StorageMut};
|
use base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut};
|
||||||
use base::{Matrix, Scalar};
|
use base::{Matrix, Scalar};
|
||||||
|
|
||||||
macro_rules! slice_storage_impl(
|
macro_rules! slice_storage_impl(
|
||||||
|
@ -91,7 +91,8 @@ slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Onl
|
||||||
|
|
||||||
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
|
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
|
||||||
for SliceStorage<'a, N, R, C, RStride, CStride>
|
for SliceStorage<'a, N, R, C, RStride, CStride>
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
|
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
|
||||||
for SliceStorage<'a, N, R, C, RStride, CStride>
|
for SliceStorage<'a, N, R, C, RStride, CStride>
|
||||||
|
@ -146,8 +147,6 @@ macro_rules! storage_impl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_owned(self) -> Owned<N, R, C>
|
fn into_owned(self) -> Owned<N, R, C>
|
||||||
where DefaultAllocator: Allocator<N, R, C> {
|
where DefaultAllocator: Allocator<N, R, C> {
|
||||||
|
@ -199,6 +198,14 @@ unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage<N, R, U1> for SliceStorage<'a, N, R, U1, U1, CStride> { }
|
||||||
|
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage<N, R, U1> for SliceStorageMut<'a, N, R, U1, U1, CStride> { }
|
||||||
|
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorageMut<N, R, U1> for SliceStorageMut<'a, N, R, U1, U1, CStride> { }
|
||||||
|
|
||||||
|
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<N, R, C> for SliceStorage<'a, N, R, C, U1, R> { }
|
||||||
|
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<N, R, C> for SliceStorageMut<'a, N, R, C, U1, R> { }
|
||||||
|
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<N, R, C> for SliceStorageMut<'a, N, R, C, U1, R> { }
|
||||||
|
|
||||||
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn assert_slice_index(
|
fn assert_slice_index(
|
||||||
|
@ -859,3 +866,25 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
|
||||||
self.slice_range_mut(.., cols)
|
self.slice_range_mut(.., cols)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
|
||||||
|
for MatrixSlice<'a, N, R, C, RStride, CStride>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
RStride: Dim,
|
||||||
|
CStride: Dim,
|
||||||
|
{
|
||||||
|
fn from(slice_mut: MatrixSliceMut<'a, N, R, C, RStride, CStride>) -> Self {
|
||||||
|
let data = SliceStorage {
|
||||||
|
ptr: slice_mut.data.ptr,
|
||||||
|
shape: slice_mut.data.shape,
|
||||||
|
strides: slice_mut.data.strides,
|
||||||
|
_phantoms: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe { Matrix::from_data_statically_unchecked(data) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,16 +18,19 @@ mod construction;
|
||||||
mod construction_slice;
|
mod construction_slice;
|
||||||
mod conversion;
|
mod conversion;
|
||||||
mod edition;
|
mod edition;
|
||||||
|
pub mod indexing;
|
||||||
mod matrix;
|
mod matrix;
|
||||||
mod matrix_alga;
|
mod matrix_alga;
|
||||||
mod matrix_array;
|
mod array_storage;
|
||||||
mod matrix_slice;
|
mod matrix_slice;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
mod matrix_vec;
|
mod vec_storage;
|
||||||
mod properties;
|
mod properties;
|
||||||
mod scalar;
|
mod scalar;
|
||||||
mod swizzle;
|
mod swizzle;
|
||||||
mod unit;
|
mod unit;
|
||||||
|
mod statistics;
|
||||||
|
mod norm;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod helper;
|
pub mod helper;
|
||||||
|
@ -35,13 +38,14 @@ pub mod helper;
|
||||||
pub use self::matrix::*;
|
pub use self::matrix::*;
|
||||||
pub use self::scalar::*;
|
pub use self::scalar::*;
|
||||||
pub use self::unit::*;
|
pub use self::unit::*;
|
||||||
|
pub use self::norm::*;
|
||||||
|
|
||||||
pub use self::default_allocator::*;
|
pub use self::default_allocator::*;
|
||||||
pub use self::dimension::*;
|
pub use self::dimension::*;
|
||||||
|
|
||||||
pub use self::alias::*;
|
pub use self::alias::*;
|
||||||
pub use self::alias_slice::*;
|
pub use self::alias_slice::*;
|
||||||
pub use self::matrix_array::*;
|
pub use self::array_storage::*;
|
||||||
pub use self::matrix_slice::*;
|
pub use self::matrix_slice::*;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub use self::matrix_vec::*;
|
pub use self::vec_storage::*;
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ where
|
||||||
"Matrix index out of bounds."
|
"Matrix index out of bounds."
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe { self.get_unchecked(ij.0, ij.1) }
|
unsafe { self.get_unchecked((ij.0, ij.1)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ where
|
||||||
"Matrix index out of bounds."
|
"Matrix index out of bounds."
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe { self.get_unchecked_mut(ij.0, ij.1) }
|
unsafe { self.get_unchecked_mut((ij.0, ij.1)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,8 +172,8 @@ macro_rules! componentwise_binop_impl(
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = self.get_unchecked(i, j).$method(*rhs.get_unchecked(i, j));
|
let val = self.get_unchecked((i, j)).$method(*rhs.get_unchecked((i, j)));
|
||||||
*out.get_unchecked_mut(i, j) = val;
|
*out.get_unchecked_mut((i, j)) = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ macro_rules! componentwise_binop_impl(
|
||||||
for j in 0 .. rhs.ncols() {
|
for j in 0 .. rhs.ncols() {
|
||||||
for i in 0 .. rhs.nrows() {
|
for i in 0 .. rhs.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_unchecked_mut(i, j).$method_assign(*rhs.get_unchecked(i, j))
|
self.get_unchecked_mut((i, j)).$method_assign(*rhs.get_unchecked((i, j)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,8 +235,8 @@ macro_rules! componentwise_binop_impl(
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let r = rhs.get_unchecked_mut(i, j);
|
let r = rhs.get_unchecked_mut((i, j));
|
||||||
*r = self.get_unchecked(i, j).$method(*r)
|
*r = self.get_unchecked((i, j)).$method(*r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,7 @@ macro_rules! componentwise_scalarop_impl(
|
||||||
fn $method_assign(&mut self, rhs: N) {
|
fn $method_assign(&mut self, rhs: N) {
|
||||||
for j in 0 .. self.ncols() {
|
for j in 0 .. self.ncols() {
|
||||||
for i in 0 .. self.nrows() {
|
for i in 0 .. self.nrows() {
|
||||||
unsafe { self.get_unchecked_mut(i, j).$method_assign(rhs) };
|
unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -657,7 +657,7 @@ where
|
||||||
for i in 0..ncols1 {
|
for i in 0..ncols1 {
|
||||||
for j in 0..ncols2 {
|
for j in 0..ncols2 {
|
||||||
let dot = self.column(i).dot(&rhs.column(j));
|
let dot = self.column(i).dot(&rhs.column(j));
|
||||||
unsafe { *out.get_unchecked_mut(i, j) = dot };
|
unsafe { *out.get_unchecked_mut((i, j)) = dot };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -704,10 +704,10 @@ where
|
||||||
for j2 in 0..ncols2.value() {
|
for j2 in 0..ncols2.value() {
|
||||||
for i1 in 0..nrows1.value() {
|
for i1 in 0..nrows1.value() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let coeff = *self.get_unchecked(i1, j1);
|
let coeff = *self.get_unchecked((i1, j1));
|
||||||
|
|
||||||
for i2 in 0..nrows2.value() {
|
for i2 in 0..nrows2.value() {
|
||||||
*data_res = coeff * *rhs.get_unchecked(i2, j2);
|
*data_res = coeff * *rhs.get_unchecked((i2, j2));
|
||||||
data_res = data_res.offset(1);
|
data_res = data_res.offset(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -761,7 +761,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
/// Returns the absolute value of the coefficient with the largest absolute value.
|
/// Returns the absolute value of the component with the largest absolute value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn amax(&self) -> N {
|
pub fn amax(&self) -> N {
|
||||||
let mut max = N::zero();
|
let mut max = N::zero();
|
||||||
|
@ -777,7 +777,7 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
|
||||||
max
|
max
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the absolute value of the coefficient with the smallest absolute value.
|
/// Returns the absolute value of the component with the smallest absolute value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn amin(&self) -> N {
|
pub fn amin(&self) -> N {
|
||||||
let mut it = self.iter();
|
let mut it = self.iter();
|
||||||
|
@ -796,4 +796,42 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
|
||||||
|
|
||||||
min
|
min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the component with the largest value.
|
||||||
|
#[inline]
|
||||||
|
pub fn max(&self) -> N {
|
||||||
|
let mut it = self.iter();
|
||||||
|
let mut max = it
|
||||||
|
.next()
|
||||||
|
.expect("max: empty matrices not supported.");
|
||||||
|
|
||||||
|
for e in it {
|
||||||
|
let ae = e;
|
||||||
|
|
||||||
|
if ae > max {
|
||||||
|
max = ae;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*max
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the component with the smallest value.
|
||||||
|
#[inline]
|
||||||
|
pub fn min(&self) -> N {
|
||||||
|
let mut it = self.iter();
|
||||||
|
let mut min = it
|
||||||
|
.next()
|
||||||
|
.expect("min: empty matrices not supported.");
|
||||||
|
|
||||||
|
for e in it {
|
||||||
|
let ae = e;
|
||||||
|
|
||||||
|
if ae < min {
|
||||||
|
min = ae;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*min
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ pub type CStride<N, R, C = U1> =
|
||||||
/// Note that `Self` must always have a number of elements compatible with the matrix length (given
|
/// Note that `Self` must always have a number of elements compatible with the matrix length (given
|
||||||
/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait
|
/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait
|
||||||
/// should **not** allow the user to modify the size of the underlying buffer with safe methods
|
/// should **not** allow the user to modify the size of the underlying buffer with safe methods
|
||||||
/// (for example the `MatrixVec::data_mut` method is unsafe because the user could change the
|
/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
|
||||||
/// vector's size so that it no longer contains enough elements: this will lead to UB.
|
/// vector's size so that it no longer contains enough elements: this will lead to UB.
|
||||||
pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
|
pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
|
||||||
/// The static stride of this storage's rows.
|
/// The static stride of this storage's rows.
|
||||||
|
|
|
@ -3,64 +3,60 @@ use storage::Storage;
|
||||||
use typenum::{self, Cmp, Greater};
|
use typenum::{self, Cmp, Greater};
|
||||||
|
|
||||||
macro_rules! impl_swizzle {
|
macro_rules! impl_swizzle {
|
||||||
($(where $BaseDim: ident: $name: ident() -> $Result: ident[$($i: expr),*]);*) => {
|
($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => {
|
||||||
$(
|
$(
|
||||||
impl<N: Scalar, D: DimName, S: Storage<N, D>> Vector<N, D, S> {
|
impl<N: Scalar, D: DimName, S: Storage<N, D>> Vector<N, D, S>
|
||||||
/// Builds a new vector from components of `self`.
|
where D::Value: Cmp<typenum::$BaseDim, Output=Greater>
|
||||||
#[inline]
|
{
|
||||||
pub fn $name(&self) -> $Result<N>
|
$(
|
||||||
where D::Value: Cmp<typenum::$BaseDim, Output=Greater> {
|
/// Builds a new vector from components of `self`.
|
||||||
$Result::new($(self[$i]),*)
|
#[inline]
|
||||||
}
|
pub fn $name(&self) -> $Result<N> {
|
||||||
|
$Result::new($(self[$i]),*)
|
||||||
|
}
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_swizzle!(
|
impl_swizzle!(
|
||||||
where U0: xx() -> Vector2[0, 0];
|
where U0: xx() -> Vector2[0, 0],
|
||||||
where U1: xy() -> Vector2[0, 1];
|
xxx() -> Vector3[0, 0, 0];
|
||||||
where U2: xz() -> Vector2[0, 2];
|
|
||||||
where U1: yx() -> Vector2[1, 0];
|
|
||||||
where U1: yy() -> Vector2[1, 1];
|
|
||||||
where U1: yz() -> Vector2[1, 2];
|
|
||||||
where U2: zx() -> Vector2[2, 0];
|
|
||||||
where U2: zy() -> Vector2[2, 1];
|
|
||||||
where U2: zz() -> Vector2[2, 2];
|
|
||||||
|
|
||||||
where U0: xxx() -> Vector3[0, 0, 0];
|
where U1: xy() -> Vector2[0, 1],
|
||||||
where U1: xxy() -> Vector3[0, 0, 1];
|
yx() -> Vector2[1, 0],
|
||||||
where U2: xxz() -> Vector3[0, 0, 2];
|
yy() -> Vector2[1, 1],
|
||||||
|
xxy() -> Vector3[0, 0, 1],
|
||||||
|
xyx() -> Vector3[0, 1, 0],
|
||||||
|
xyy() -> Vector3[0, 1, 1],
|
||||||
|
yxx() -> Vector3[1, 0, 0],
|
||||||
|
yxy() -> Vector3[1, 0, 1],
|
||||||
|
yyx() -> Vector3[1, 1, 0],
|
||||||
|
yyy() -> Vector3[1, 1, 1];
|
||||||
|
|
||||||
where U1: xyx() -> Vector3[0, 1, 0];
|
where U2: xz() -> Vector2[0, 2],
|
||||||
where U1: xyy() -> Vector3[0, 1, 1];
|
yz() -> Vector2[1, 2],
|
||||||
where U2: xyz() -> Vector3[0, 1, 2];
|
zx() -> Vector2[2, 0],
|
||||||
|
zy() -> Vector2[2, 1],
|
||||||
where U2: xzx() -> Vector3[0, 2, 0];
|
zz() -> Vector2[2, 2],
|
||||||
where U2: xzy() -> Vector3[0, 2, 1];
|
xxz() -> Vector3[0, 0, 2],
|
||||||
where U2: xzz() -> Vector3[0, 2, 2];
|
xyz() -> Vector3[0, 1, 2],
|
||||||
|
xzx() -> Vector3[0, 2, 0],
|
||||||
where U1: yxx() -> Vector3[1, 0, 0];
|
xzy() -> Vector3[0, 2, 1],
|
||||||
where U1: yxy() -> Vector3[1, 0, 1];
|
xzz() -> Vector3[0, 2, 2],
|
||||||
where U2: yxz() -> Vector3[1, 0, 2];
|
yxz() -> Vector3[1, 0, 2],
|
||||||
|
yyz() -> Vector3[1, 1, 2],
|
||||||
where U1: yyx() -> Vector3[1, 1, 0];
|
yzx() -> Vector3[1, 2, 0],
|
||||||
where U1: yyy() -> Vector3[1, 1, 1];
|
yzy() -> Vector3[1, 2, 1],
|
||||||
where U2: yyz() -> Vector3[1, 1, 2];
|
yzz() -> Vector3[1, 2, 2],
|
||||||
|
zxx() -> Vector3[2, 0, 0],
|
||||||
where U2: yzx() -> Vector3[1, 2, 0];
|
zxy() -> Vector3[2, 0, 1],
|
||||||
where U2: yzy() -> Vector3[1, 2, 1];
|
zxz() -> Vector3[2, 0, 2],
|
||||||
where U2: yzz() -> Vector3[1, 2, 2];
|
zyx() -> Vector3[2, 1, 0],
|
||||||
|
zyy() -> Vector3[2, 1, 1],
|
||||||
where U2: zxx() -> Vector3[2, 0, 0];
|
zyz() -> Vector3[2, 1, 2],
|
||||||
where U2: zxy() -> Vector3[2, 0, 1];
|
zzx() -> Vector3[2, 2, 0],
|
||||||
where U2: zxz() -> Vector3[2, 0, 2];
|
zzy() -> Vector3[2, 2, 1],
|
||||||
|
zzz() -> Vector3[2, 2, 2];
|
||||||
where U2: zyx() -> Vector3[2, 1, 0];
|
|
||||||
where U2: zyy() -> Vector3[2, 1, 1];
|
|
||||||
where U2: zyz() -> Vector3[2, 1, 2];
|
|
||||||
|
|
||||||
where U2: zzx() -> Vector3[2, 2, 0];
|
|
||||||
where U2: zzy() -> Vector3[2, 2, 1];
|
|
||||||
where U2: zzz() -> Vector3[2, 2, 2]
|
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,7 +15,7 @@ use alga::linear::NormedSpace;
|
||||||
|
|
||||||
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
||||||
///
|
///
|
||||||
/// Use `.as_ref()` or `.unwrap()` to obtain the underlying value by-reference or by-move.
|
/// Use `.as_ref()` or `.into_inner()` to obtain the underlying value by-reference or by-move.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
|
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
|
||||||
pub struct Unit<T> {
|
pub struct Unit<T> {
|
||||||
|
@ -113,6 +113,14 @@ impl<T> Unit<T> {
|
||||||
|
|
||||||
/// Retrieves the underlying value.
|
/// Retrieves the underlying value.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the underlying value.
|
||||||
|
/// Deprecated: use [Unit::into_inner] instead.
|
||||||
|
#[deprecated(note="use `.into_inner()` instead")]
|
||||||
|
#[inline]
|
||||||
pub fn unwrap(self) -> T {
|
pub fn unwrap(self) -> T {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
@ -143,7 +151,7 @@ where T::Field: RelativeEq
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_superset(&self) -> T {
|
fn to_superset(&self) -> T {
|
||||||
self.clone().unwrap()
|
self.clone().into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use std::io::{Result as IOResult, Write};
|
use std::io::{Result as IOResult, Write};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
@ -24,21 +23,25 @@ use abomonation::Abomonation;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Eq, Debug, Clone, PartialEq)]
|
#[derive(Eq, Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||||
pub struct MatrixVec<N, R: Dim, C: Dim> {
|
pub struct VecStorage<N, R: Dim, C: Dim> {
|
||||||
data: Vec<N>,
|
data: Vec<N>,
|
||||||
nrows: R,
|
nrows: R,
|
||||||
ncols: C,
|
ncols: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
|
#[deprecated(note="renamed to `VecStorage`")]
|
||||||
|
/// Renamed to [VecStorage].
|
||||||
|
pub type MatrixVec<N, R, C> = VecStorage<N, R, C>;
|
||||||
|
|
||||||
|
impl<N, R: Dim, C: Dim> VecStorage<N, R, C> {
|
||||||
/// Creates a new dynamic matrix data storage from the given vector and shape.
|
/// Creates a new dynamic matrix data storage from the given vector and shape.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(nrows: R, ncols: C, data: Vec<N>) -> MatrixVec<N, R, C> {
|
pub fn new(nrows: R, ncols: C, data: Vec<N>) -> VecStorage<N, R, C> {
|
||||||
assert!(
|
assert!(
|
||||||
nrows.value() * ncols.value() == data.len(),
|
nrows.value() * ncols.value() == data.len(),
|
||||||
"Data storage buffer dimension mismatch."
|
"Data storage buffer dimension mismatch."
|
||||||
);
|
);
|
||||||
MatrixVec {
|
VecStorage {
|
||||||
data: data,
|
data: data,
|
||||||
nrows: nrows,
|
nrows: nrows,
|
||||||
ncols: ncols,
|
ncols: ncols,
|
||||||
|
@ -47,15 +50,16 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
|
||||||
|
|
||||||
/// The underlying data storage.
|
/// The underlying data storage.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn data(&self) -> &Vec<N> {
|
pub fn as_vec(&self) -> &Vec<N> {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The underlying mutable data storage.
|
/// The underlying mutable data storage.
|
||||||
///
|
///
|
||||||
/// This is unsafe because this may cause UB if the vector is modified by the user.
|
/// This is unsafe because this may cause UB if the size of the vector is changed
|
||||||
|
/// by the user.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn data_mut(&mut self) -> &mut Vec<N> {
|
pub unsafe fn as_vec_mut(&mut self) -> &mut Vec<N> {
|
||||||
&mut self.data
|
&mut self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +81,18 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
|
||||||
|
|
||||||
self.data
|
self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of elements on the underlying vector.
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
|
impl<N, R: Dim, C: Dim> Into<Vec<N>> for VecStorage<N, R, C>
|
||||||
type Target = Vec<N>;
|
{
|
||||||
|
fn into(self) -> Vec<N> {
|
||||||
#[inline]
|
self.data
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +102,7 @@ impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
|
||||||
* Dynamic − Dynamic
|
* Dynamic − Dynamic
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
|
unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for VecStorage<N, Dynamic, C>
|
||||||
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
||||||
{
|
{
|
||||||
type RStride = U1;
|
type RStride = U1;
|
||||||
|
@ -134,11 +142,11 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_slice(&self) -> &[N] {
|
fn as_slice(&self) -> &[N] {
|
||||||
&self[..]
|
&self.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
|
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for VecStorage<N, R, Dynamic>
|
||||||
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
{
|
{
|
||||||
type RStride = U1;
|
type RStride = U1;
|
||||||
|
@ -178,7 +186,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_slice(&self) -> &[N] {
|
fn as_slice(&self) -> &[N] {
|
||||||
&self[..]
|
&self.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +195,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
* StorageMut, ContiguousStorage.
|
* StorageMut, ContiguousStorage.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
unsafe impl<N: Scalar, C: Dim> StorageMut<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
|
unsafe impl<N: Scalar, C: Dim> StorageMut<N, Dynamic, C> for VecStorage<N, Dynamic, C>
|
||||||
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -201,13 +209,13 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, C: Dim> ContiguousStorage<N, Dynamic, C> for MatrixVec<N, Dynamic, C> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
unsafe impl<N: Scalar, C: Dim> ContiguousStorage<N, Dynamic, C> for VecStorage<N, Dynamic, C> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, C: Dim> ContiguousStorageMut<N, Dynamic, C> for MatrixVec<N, Dynamic, C> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
unsafe impl<N: Scalar, C: Dim> ContiguousStorageMut<N, Dynamic, C> for VecStorage<N, Dynamic, C> where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
|
unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for VecStorage<N, R, Dynamic>
|
||||||
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -222,7 +230,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for MatrixVec<N, R, C> {
|
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<N, R, C> {
|
||||||
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
||||||
self.data.entomb(writer)
|
self.data.entomb(writer)
|
||||||
}
|
}
|
||||||
|
@ -236,21 +244,21 @@ impl<N: Abomonation, R: Dim, C: Dim> Abomonation for MatrixVec<N, R, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, R: DimName> ContiguousStorage<N, R, Dynamic> for MatrixVec<N, R, Dynamic> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
unsafe impl<N: Scalar, R: DimName> ContiguousStorage<N, R, Dynamic> for VecStorage<N, R, Dynamic> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, R: DimName> ContiguousStorageMut<N, R, Dynamic> for MatrixVec<N, R, Dynamic> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
unsafe impl<N: Scalar, R: DimName> ContiguousStorageMut<N, R, Dynamic> for VecStorage<N, R, Dynamic> where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
impl<N, R: Dim> Extend<N> for MatrixVec<N, R, Dynamic>
|
impl<N, R: Dim> Extend<N> for VecStorage<N, R, Dynamic>
|
||||||
{
|
{
|
||||||
/// Extends the number of columns of the `MatrixVec` with elements
|
/// Extends the number of columns of the `VecStorage` with elements
|
||||||
/// from the given iterator.
|
/// from the given iterator.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// This function panics if the number of elements yielded by the
|
/// This function panics if the number of elements yielded by the
|
||||||
/// given iterator is not a multiple of the number of rows of the
|
/// given iterator is not a multiple of the number of rows of the
|
||||||
/// `MatrixVec`.
|
/// `VecStorage`.
|
||||||
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
|
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
|
||||||
{
|
{
|
||||||
self.data.extend(iter);
|
self.data.extend(iter);
|
||||||
|
@ -260,7 +268,7 @@ impl<N, R: Dim> Extend<N> for MatrixVec<N, R, Dynamic>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N, R, RV, SV> Extend<Vector<N, RV, SV>> for MatrixVec<N, R, Dynamic>
|
impl<N, R, RV, SV> Extend<Vector<N, RV, SV>> for VecStorage<N, R, Dynamic>
|
||||||
where
|
where
|
||||||
N: Scalar,
|
N: Scalar,
|
||||||
R: Dim,
|
R: Dim,
|
||||||
|
@ -268,13 +276,13 @@ where
|
||||||
SV: Storage<N, RV>,
|
SV: Storage<N, RV>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, RV>,
|
ShapeConstraint: SameNumberOfRows<R, RV>,
|
||||||
{
|
{
|
||||||
/// Extends the number of columns of the `MatrixVec` with vectors
|
/// Extends the number of columns of the `VecStorage` with vectors
|
||||||
/// from the given iterator.
|
/// from the given iterator.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// This function panics if the number of rows of each `Vector`
|
/// This function panics if the number of rows of each `Vector`
|
||||||
/// yielded by the iterator is not equal to the number of rows
|
/// yielded by the iterator is not equal to the number of rows
|
||||||
/// of this `MatrixVec`.
|
/// of this `VecStorage`.
|
||||||
fn extend<I: IntoIterator<Item=Vector<N, RV, SV>>>(&mut self, iter: I)
|
fn extend<I: IntoIterator<Item=Vector<N, RV, SV>>>(&mut self, iter: I)
|
||||||
{
|
{
|
||||||
let nrows = self.nrows.value();
|
let nrows = self.nrows.value();
|
||||||
|
@ -289,9 +297,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N> Extend<N> for MatrixVec<N, Dynamic, U1>
|
impl<N> Extend<N> for VecStorage<N, Dynamic, U1>
|
||||||
{
|
{
|
||||||
/// Extends the number of rows of the `MatrixVec` with elements
|
/// Extends the number of rows of the `VecStorage` with elements
|
||||||
/// from the given iterator.
|
/// from the given iterator.
|
||||||
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
|
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
|
||||||
{
|
{
|
|
@ -48,6 +48,7 @@ where
|
||||||
Owned<N, D, D>: Clone + Send,
|
Owned<N, D, D>: Clone + Send,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
||||||
|
use rand::Rng;
|
||||||
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
|
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
|
||||||
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ where
|
||||||
Owned<N, D, D>: Clone + Send,
|
Owned<N, D, D>: Clone + Send,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
||||||
|
use rand::Rng;
|
||||||
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
|
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
|
||||||
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
|
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
|
||||||
/// let tra = Translation3::new(0.0, 0.0, 3.0);
|
/// let tra = Translation3::new(0.0, 0.0, 3.0);
|
||||||
|
@ -167,7 +166,7 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inverse_mut(&mut self) {
|
pub fn inverse_mut(&mut self) {
|
||||||
self.rotation.inverse_mut();
|
self.rotation.two_sided_inverse_mut();
|
||||||
self.translation.inverse_mut();
|
self.translation.inverse_mut();
|
||||||
self.translation.vector = self.rotation.transform_vector(&self.translation.vector);
|
self.translation.vector = self.rotation.transform_vector(&self.translation.vector);
|
||||||
}
|
}
|
||||||
|
@ -197,7 +196,6 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
|
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
|
||||||
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0);
|
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0);
|
||||||
|
@ -220,7 +218,6 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
|
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
|
||||||
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
|
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
|
||||||
|
@ -272,7 +269,6 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry2, Vector2, Matrix3};
|
/// # use nalgebra::{Isometry2, Vector2, Matrix3};
|
||||||
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);
|
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
||||||
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real,
|
AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::Isometry as AlgaIsometry;
|
use alga::linear::Isometry as AlgaIsometry;
|
||||||
use alga::linear::{
|
use alga::linear::{
|
||||||
|
@ -30,18 +30,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Isometry<N, D, R>
|
impl<N: Real, D: DimName, R> TwoSidedInverse<Multiplicative> for Isometry<N, D, R>
|
||||||
where
|
where
|
||||||
R: Rotation<Point<N, D>>,
|
R: Rotation<Point<N, D>>,
|
||||||
DefaultAllocator: Allocator<N, D>,
|
DefaultAllocator: Allocator<N, D>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.inverse()
|
self.inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.inverse_mut()
|
self.inverse_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use base::{DefaultAllocator, Vector2, Vector3};
|
||||||
|
|
||||||
use geometry::{
|
use geometry::{
|
||||||
Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex,
|
Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex,
|
||||||
UnitQuaternion,
|
UnitQuaternion, Translation2, Translation3
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R>
|
impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R>
|
||||||
|
@ -49,7 +49,6 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry2, Point2, UnitComplex};
|
/// # use nalgebra::{Isometry2, Point2, UnitComplex};
|
||||||
/// let rot = UnitComplex::new(f32::consts::PI);
|
/// let rot = UnitComplex::new(f32::consts::PI);
|
||||||
|
@ -130,6 +129,18 @@ impl<N: Real> Isometry<N, U2, Rotation2<N>> {
|
||||||
Rotation::<N, U2>::new(angle),
|
Rotation::<N, U2>::new(angle),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new isometry from the given translation coordinates.
|
||||||
|
#[inline]
|
||||||
|
pub fn translation(x: N, y: N) -> Self {
|
||||||
|
Self::new(Vector2::new(x, y), N::zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new isometry from the given rotation angle.
|
||||||
|
#[inline]
|
||||||
|
pub fn rotation(angle: N) -> Self {
|
||||||
|
Self::new(Vector2::zeros(), angle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
|
impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
|
||||||
|
@ -153,6 +164,18 @@ impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
|
||||||
UnitComplex::from_angle(angle),
|
UnitComplex::from_angle(angle),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new isometry from the given translation coordinates.
|
||||||
|
#[inline]
|
||||||
|
pub fn translation(x: N, y: N) -> Self {
|
||||||
|
Self::from_parts(Translation2::new(x, y), UnitComplex::identity())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new isometry from the given rotation angle.
|
||||||
|
#[inline]
|
||||||
|
pub fn rotation(angle: N) -> Self {
|
||||||
|
Self::new(Vector2::zeros(), angle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3D rotation.
|
// 3D rotation.
|
||||||
|
@ -165,7 +188,6 @@ macro_rules! isometry_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -191,6 +213,18 @@ macro_rules! isometry_construction_impl(
|
||||||
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
|
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new isometry from the given translation coordinates.
|
||||||
|
#[inline]
|
||||||
|
pub fn translation(x: N, y: N, z: N) -> Self {
|
||||||
|
Self::from_parts(Translation3::new(x, y, z), $RotId::identity())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new isometry from the given rotation angle.
|
||||||
|
#[inline]
|
||||||
|
pub fn rotation(axisangle: Vector3<N>) -> Self {
|
||||||
|
Self::new(Vector3::zeros(), axisangle)
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
||||||
/// point `eye` and looking toward `target`.
|
/// point `eye` and looking toward `target`.
|
||||||
///
|
///
|
||||||
|
@ -206,7 +240,6 @@ macro_rules! isometry_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -214,23 +247,32 @@ macro_rules! isometry_construction_impl(
|
||||||
/// let up = Vector3::y();
|
/// let up = Vector3::y();
|
||||||
///
|
///
|
||||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||||
/// let iso = Isometry3::new_observer_frame(&eye, &target, &up);
|
/// let iso = Isometry3::face_towards(&eye, &target, &up);
|
||||||
/// assert_eq!(iso * Point3::origin(), eye);
|
/// assert_eq!(iso * Point3::origin(), eye);
|
||||||
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
||||||
///
|
///
|
||||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||||
/// let iso = IsometryMatrix3::new_observer_frame(&eye, &target, &up);
|
/// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
|
||||||
/// assert_eq!(iso * Point3::origin(), eye);
|
/// assert_eq!(iso * Point3::origin(), eye);
|
||||||
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_observer_frame(eye: &Point3<N>,
|
pub fn face_towards(eye: &Point3<N>,
|
||||||
target: &Point3<N>,
|
target: &Point3<N>,
|
||||||
up: &Vector3<N>)
|
up: &Vector3<N>)
|
||||||
-> Self {
|
-> Self {
|
||||||
Self::from_parts(
|
Self::from_parts(
|
||||||
Translation::from(eye.coords.clone()),
|
Translation::from(eye.coords.clone()),
|
||||||
$RotId::new_observer_frame(&(target - eye), up))
|
$RotId::face_towards(&(target - eye), up))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated: Use [Isometry::face_towards] instead.
|
||||||
|
#[deprecated(note="renamed to `face_towards`")]
|
||||||
|
pub fn new_observer_frame(eye: &Point3<N>,
|
||||||
|
target: &Point3<N>,
|
||||||
|
up: &Vector3<N>)
|
||||||
|
-> Self {
|
||||||
|
Self::face_towards(eye, target, up)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a right-handed look-at view matrix.
|
/// Builds a right-handed look-at view matrix.
|
||||||
|
@ -249,7 +291,6 @@ macro_rules! isometry_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -293,7 +334,6 @@ macro_rules! isometry_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
|
|
@ -200,8 +200,8 @@ isometry_binop_assign_impl_all!(
|
||||||
DivAssign, div_assign;
|
DivAssign, div_assign;
|
||||||
self: Isometry<N, D, R>, rhs: R;
|
self: Isometry<N, D, R>, rhs: R;
|
||||||
// FIXME: don't invert explicitly?
|
// FIXME: don't invert explicitly?
|
||||||
[val] => *self *= rhs.inverse();
|
[val] => *self *= rhs.two_sided_inverse();
|
||||||
[ref] => *self *= rhs.inverse();
|
[ref] => *self *= rhs.two_sided_inverse();
|
||||||
);
|
);
|
||||||
|
|
||||||
// Isometry × R
|
// Isometry × R
|
||||||
|
|
|
@ -37,6 +37,7 @@ mod translation_alga;
|
||||||
mod translation_alias;
|
mod translation_alias;
|
||||||
mod translation_construction;
|
mod translation_construction;
|
||||||
mod translation_conversion;
|
mod translation_conversion;
|
||||||
|
mod translation_coordinates;
|
||||||
mod translation_ops;
|
mod translation_ops;
|
||||||
|
|
||||||
mod isometry;
|
mod isometry;
|
||||||
|
@ -53,6 +54,8 @@ mod similarity_construction;
|
||||||
mod similarity_conversion;
|
mod similarity_conversion;
|
||||||
mod similarity_ops;
|
mod similarity_ops;
|
||||||
|
|
||||||
|
mod swizzle;
|
||||||
|
|
||||||
mod transform;
|
mod transform;
|
||||||
mod transform_alga;
|
mod transform_alga;
|
||||||
mod transform_alias;
|
mod transform_alias;
|
||||||
|
|
|
@ -69,7 +69,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Orthographic3, Point3};
|
/// # use nalgebra::{Orthographic3, Point3};
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// // Check this projection actually transforms the view cuboid into the double-unit cube.
|
/// // Check this projection actually transforms the view cuboid into the double-unit cube.
|
||||||
|
@ -170,7 +169,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
|
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// let inv = proj.inverse();
|
/// let inv = proj.inverse();
|
||||||
|
@ -271,7 +269,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
|
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// let expected = Matrix4::new(
|
/// let expected = Matrix4::new(
|
||||||
|
@ -280,9 +277,17 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
|
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
|
||||||
/// 0.0, 0.0, 0.0, 1.0
|
/// 0.0, 0.0, 0.0, 1.0
|
||||||
/// );
|
/// );
|
||||||
/// assert_eq!(proj.unwrap(), expected);
|
/// assert_eq!(proj.into_inner(), expected);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn into_inner(self) -> Matrix4<N> {
|
||||||
|
self.matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the underlying homogeneous matrix.
|
||||||
|
/// Deprecated: Use [Orthographic3::into_inner] instead.
|
||||||
|
#[deprecated(note="use `.into_inner()` instead")]
|
||||||
|
#[inline]
|
||||||
pub fn unwrap(self) -> Matrix4<N> {
|
pub fn unwrap(self) -> Matrix4<N> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
|
@ -291,7 +296,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6);
|
||||||
|
@ -308,7 +312,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6);
|
||||||
|
@ -325,7 +328,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6);
|
||||||
|
@ -342,7 +344,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6);
|
||||||
|
@ -359,7 +360,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6);
|
/// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6);
|
||||||
|
@ -376,7 +376,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6);
|
||||||
|
@ -395,7 +394,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Orthographic3, Point3};
|
/// # use nalgebra::{Orthographic3, Point3};
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
///
|
///
|
||||||
|
@ -431,7 +429,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Orthographic3, Point3};
|
/// # use nalgebra::{Orthographic3, Point3};
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
///
|
///
|
||||||
|
@ -470,7 +467,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Orthographic3, Vector3};
|
/// # use nalgebra::{Orthographic3, Vector3};
|
||||||
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
///
|
///
|
||||||
|
@ -496,7 +492,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_left(2.0);
|
/// proj.set_left(2.0);
|
||||||
|
@ -516,7 +511,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_right(15.0);
|
/// proj.set_right(15.0);
|
||||||
|
@ -536,7 +530,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_bottom(8.0);
|
/// proj.set_bottom(8.0);
|
||||||
|
@ -556,7 +549,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_top(15.0);
|
/// proj.set_top(15.0);
|
||||||
|
@ -576,7 +568,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_znear(8.0);
|
/// proj.set_znear(8.0);
|
||||||
|
@ -596,7 +587,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_zfar(15.0);
|
/// proj.set_zfar(15.0);
|
||||||
|
@ -616,7 +606,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_left_and_right(7.0, 70.0);
|
/// proj.set_left_and_right(7.0, 70.0);
|
||||||
|
@ -642,7 +631,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_bottom_and_top(7.0, 70.0);
|
/// proj.set_bottom_and_top(7.0, 70.0);
|
||||||
|
@ -668,7 +656,6 @@ impl<N: Real> Orthographic3<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Orthographic3;
|
/// # use nalgebra::Orthographic3;
|
||||||
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
|
||||||
/// proj.set_znear_and_zfar(50.0, 5000.0);
|
/// proj.set_znear_and_zfar(50.0, 5000.0);
|
||||||
|
@ -725,6 +712,6 @@ where Matrix4<N>: Send
|
||||||
impl<N: Real> From<Orthographic3<N>> for Matrix4<N> {
|
impl<N: Real> From<Orthographic3<N>> for Matrix4<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(orth: Orthographic3<N>) -> Self {
|
fn from(orth: Orthographic3<N>) -> Self {
|
||||||
orth.unwrap()
|
orth.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,14 @@ impl<N: Real> Perspective3<N> {
|
||||||
|
|
||||||
/// Retrieves the underlying homogeneous matrix.
|
/// Retrieves the underlying homogeneous matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn into_inner(self) -> Matrix4<N> {
|
||||||
|
self.matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the underlying homogeneous matrix.
|
||||||
|
/// Deprecated: Use [Perspective3::into_inner] instead.
|
||||||
|
#[deprecated(note="use `.into_inner()` instead")]
|
||||||
|
#[inline]
|
||||||
pub fn unwrap(self) -> Matrix4<N> {
|
pub fn unwrap(self) -> Matrix4<N> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
|
@ -279,6 +287,6 @@ impl<N: Real + Arbitrary> Arbitrary for Perspective3<N> {
|
||||||
impl<N: Real> From<Perspective3<N>> for Matrix4<N> {
|
impl<N: Real> From<Perspective3<N>> for Matrix4<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(orth: Perspective3<N>) -> Self {
|
fn from(orth: Perspective3<N>) -> Self {
|
||||||
orth.unwrap()
|
orth.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
/// let q_normalized = q.normalize();
|
/// let q_normalized = q.normalize();
|
||||||
|
@ -150,7 +149,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
/// let inv_q = q.try_inverse();
|
/// let inv_q = q.try_inverse();
|
||||||
|
@ -240,7 +238,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
/// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6);
|
/// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6);
|
||||||
|
@ -258,7 +255,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
/// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6);
|
/// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6);
|
||||||
|
@ -345,7 +341,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0);
|
/// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0);
|
||||||
/// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6)
|
/// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6)
|
||||||
|
@ -364,7 +359,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
|
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
|
||||||
/// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5)
|
/// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5)
|
||||||
|
@ -380,7 +374,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
|
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
|
||||||
/// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5);
|
/// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5);
|
||||||
|
@ -410,7 +403,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
/// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6);
|
/// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6);
|
||||||
|
@ -476,7 +468,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
///
|
///
|
||||||
|
@ -506,7 +497,6 @@ impl<N: Real> Quaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Quaternion;
|
/// # use nalgebra::Quaternion;
|
||||||
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
/// q.normalize_mut();
|
/// q.normalize_mut();
|
||||||
|
@ -672,7 +662,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Vector3};
|
||||||
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
|
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
|
||||||
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
|
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
|
||||||
|
@ -691,7 +680,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Vector3};
|
||||||
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
|
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
|
||||||
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
|
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
|
||||||
|
@ -747,7 +735,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
Unit::new_unchecked(Quaternion::from(
|
Unit::new_unchecked(Quaternion::from(
|
||||||
Unit::new_unchecked(self.coords)
|
Unit::new_unchecked(self.coords)
|
||||||
.slerp(&Unit::new_unchecked(other.coords), t)
|
.slerp(&Unit::new_unchecked(other.coords), t)
|
||||||
.unwrap(),
|
.into_inner(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +759,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
{
|
{
|
||||||
Unit::new_unchecked(self.coords)
|
Unit::new_unchecked(self.coords)
|
||||||
.try_slerp(&Unit::new_unchecked(other.coords), t, epsilon)
|
.try_slerp(&Unit::new_unchecked(other.coords), t, epsilon)
|
||||||
.map(|q| Unit::new_unchecked(Quaternion::from(q.unwrap())))
|
.map(|q| Unit::new_unchecked(Quaternion::from(q.into_inner())))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the conjugate of this unit quaternion in-place.
|
/// Compute the conjugate of this unit quaternion in-place.
|
||||||
|
@ -785,7 +773,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
|
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
|
||||||
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
||||||
/// let mut rot = UnitQuaternion::new(axisangle);
|
/// let mut rot = UnitQuaternion::new(axisangle);
|
||||||
|
@ -828,7 +815,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
|
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
|
||||||
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
||||||
/// let rot = UnitQuaternion::new(axisangle);
|
/// let rot = UnitQuaternion::new(axisangle);
|
||||||
|
@ -837,7 +823,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scaled_axis(&self) -> Vector3<N> {
|
pub fn scaled_axis(&self) -> Vector3<N> {
|
||||||
if let Some(axis) = self.axis() {
|
if let Some(axis) = self.axis() {
|
||||||
axis.unwrap() * self.angle()
|
axis.into_inner() * self.angle()
|
||||||
} else {
|
} else {
|
||||||
Vector3::zero()
|
Vector3::zero()
|
||||||
}
|
}
|
||||||
|
@ -885,7 +871,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector3, UnitQuaternion};
|
/// # use nalgebra::{Vector3, UnitQuaternion};
|
||||||
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
||||||
/// let q = UnitQuaternion::new(axisangle);
|
/// let q = UnitQuaternion::new(axisangle);
|
||||||
|
@ -894,7 +879,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ln(&self) -> Quaternion<N> {
|
pub fn ln(&self) -> Quaternion<N> {
|
||||||
if let Some(v) = self.axis() {
|
if let Some(v) = self.axis() {
|
||||||
Quaternion::from_parts(N::zero(), v.unwrap() * self.angle())
|
Quaternion::from_parts(N::zero(), v.into_inner() * self.angle())
|
||||||
} else {
|
} else {
|
||||||
Quaternion::zero()
|
Quaternion::zero()
|
||||||
}
|
}
|
||||||
|
@ -908,7 +893,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
|
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
|
||||||
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let angle = 1.2;
|
/// let angle = 1.2;
|
||||||
|
@ -932,7 +916,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix3};
|
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix3};
|
||||||
/// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
|
/// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
|
||||||
|
@ -990,7 +973,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitQuaternion;
|
/// # use nalgebra::UnitQuaternion;
|
||||||
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
|
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
|
||||||
/// let euler = rot.euler_angles();
|
/// let euler = rot.euler_angles();
|
||||||
|
@ -1009,7 +991,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix4};
|
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix4};
|
||||||
/// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
|
/// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
|
||||||
|
@ -1029,7 +1010,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> {
|
impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if let Some(axis) = self.axis() {
|
if let Some(axis) = self.axis() {
|
||||||
let axis = axis.unwrap();
|
let axis = axis.into_inner();
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"UnitQuaternion angle: {} − axis: ({}, {}, {})",
|
"UnitQuaternion angle: {} − axis: ({}, {}, {})",
|
||||||
|
|
|
@ -2,7 +2,7 @@ use num::Zero;
|
||||||
|
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
|
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
|
||||||
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Inverse, Module,
|
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module,
|
||||||
Multiplicative, Real,
|
Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::{
|
use alga::linear::{
|
||||||
|
@ -42,9 +42,9 @@ impl<N: Real> AbstractMagma<Additive> for Quaternion<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real> Inverse<Additive> for Quaternion<N> {
|
impl<N: Real> TwoSidedInverse<Additive> for Quaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
-self
|
-self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,14 +173,14 @@ impl<N: Real> AbstractMagma<Multiplicative> for UnitQuaternion<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real> Inverse<Multiplicative> for UnitQuaternion<N> {
|
impl<N: Real> TwoSidedInverse<Multiplicative> for UnitQuaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.inverse()
|
self.inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.inverse_mut()
|
self.inverse_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ impl<N: Real> Quaternion<N> {
|
||||||
where SB: Storage<N, U3> {
|
where SB: Storage<N, U3> {
|
||||||
let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64));
|
let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64));
|
||||||
|
|
||||||
rot.unwrap() * scale
|
rot.into_inner() * scale
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The quaternion multiplicative identity.
|
/// The quaternion multiplicative identity.
|
||||||
|
@ -166,7 +166,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
||||||
/// let axis = Vector3::y_axis();
|
/// let axis = Vector3::y_axis();
|
||||||
|
@ -208,7 +207,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitQuaternion;
|
/// # use nalgebra::UnitQuaternion;
|
||||||
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
|
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
|
||||||
/// let euler = rot.euler_angles();
|
/// let euler = rot.euler_angles();
|
||||||
|
@ -237,7 +235,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, UnitQuaternion, Vector3};
|
/// # use nalgebra::{Rotation3, UnitQuaternion, Vector3};
|
||||||
/// let axis = Vector3::y_axis();
|
/// let axis = Vector3::y_axis();
|
||||||
/// let angle = 0.1;
|
/// let angle = 0.1;
|
||||||
|
@ -302,7 +299,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector3, UnitQuaternion};
|
/// # use nalgebra::{Vector3, UnitQuaternion};
|
||||||
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
||||||
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
||||||
|
@ -325,7 +321,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector3, UnitQuaternion};
|
/// # use nalgebra::{Vector3, UnitQuaternion};
|
||||||
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
||||||
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
||||||
|
@ -361,7 +356,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
|
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
|
||||||
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
|
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
|
||||||
|
@ -387,7 +381,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
|
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
|
||||||
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
|
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
|
||||||
|
@ -446,22 +439,31 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Vector3};
|
||||||
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
||||||
/// let up = Vector3::y();
|
/// let up = Vector3::y();
|
||||||
///
|
///
|
||||||
/// let q = UnitQuaternion::new_observer_frame(&dir, &up);
|
/// let q = UnitQuaternion::face_towards(&dir, &up);
|
||||||
/// assert_relative_eq!(q * Vector3::z(), dir.normalize());
|
/// assert_relative_eq!(q * Vector3::z(), dir.normalize());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
||||||
where
|
where
|
||||||
SB: Storage<N, U3>,
|
SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3>,
|
SC: Storage<N, U3>,
|
||||||
{
|
{
|
||||||
Self::from_rotation_matrix(&Rotation::<N, U3>::new_observer_frame(dir, up))
|
Self::from_rotation_matrix(&Rotation::<N, U3>::face_towards(dir, up))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated: Use [UnitQuaternion::face_towards] instead.
|
||||||
|
#[deprecated(note="renamed to `face_towards`")]
|
||||||
|
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
||||||
|
where
|
||||||
|
SB: Storage<N, U3>,
|
||||||
|
SC: Storage<N, U3>,
|
||||||
|
{
|
||||||
|
Self::face_towards(dir, up)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a right-handed look-at view matrix without translation.
|
/// Builds a right-handed look-at view matrix without translation.
|
||||||
|
@ -478,7 +480,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Vector3};
|
||||||
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -493,7 +494,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
SB: Storage<N, U3>,
|
SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3>,
|
SC: Storage<N, U3>,
|
||||||
{
|
{
|
||||||
Self::new_observer_frame(&-dir, up).inverse()
|
Self::face_towards(&-dir, up).inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a left-handed look-at view matrix without translation.
|
/// Builds a left-handed look-at view matrix without translation.
|
||||||
|
@ -510,7 +511,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Vector3};
|
||||||
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -525,7 +525,7 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
SB: Storage<N, U3>,
|
SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3>,
|
SC: Storage<N, U3>,
|
||||||
{
|
{
|
||||||
Self::new_observer_frame(dir, up).inverse()
|
Self::face_towards(dir, up).inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
|
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
|
||||||
|
@ -535,7 +535,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -565,7 +564,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -596,7 +594,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -625,7 +622,6 @@ impl<N: Real> UnitQuaternion<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -693,15 +689,16 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
extern crate rand_xorshift;
|
||||||
use super::*;
|
use super::*;
|
||||||
use rand::{self, SeedableRng};
|
use rand::SeedableRng;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn random_unit_quats_are_unit() {
|
fn random_unit_quats_are_unit() {
|
||||||
let mut rng = rand::prng::XorShiftRng::from_seed([0xAB; 16]);
|
let mut rng = rand_xorshift::XorShiftRng::from_seed([0xAB; 16]);
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let x = rng.gen::<UnitQuaternion<f32>>();
|
let x = rng.gen::<UnitQuaternion<f32>>();
|
||||||
assert!(relative_eq!(x.unwrap().norm(), 1.0))
|
assert!(relative_eq!(x.into_inner().norm(), 1.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,7 @@ impl<N: Real> From<UnitQuaternion<N>> for Matrix4<N> {
|
||||||
impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> {
|
impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(q: UnitQuaternion<N>) -> Matrix3<N> {
|
fn from(q: UnitQuaternion<N>) -> Matrix3<N> {
|
||||||
q.to_rotation_matrix().unwrap()
|
q.to_rotation_matrix().into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -469,7 +469,7 @@ quaternion_op_impl!(
|
||||||
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
|
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
|
||||||
self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
|
self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
|
||||||
Output = Unit<Vector3<N>> => U3, U4;
|
Output = Unit<Vector3<N>> => U3, U4;
|
||||||
Unit::new_unchecked(self * rhs.unwrap());
|
Unit::new_unchecked(self * rhs.into_inner());
|
||||||
'a);
|
'a);
|
||||||
|
|
||||||
quaternion_op_impl!(
|
quaternion_op_impl!(
|
||||||
|
@ -485,7 +485,7 @@ quaternion_op_impl!(
|
||||||
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
|
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
|
||||||
self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
|
self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
|
||||||
Output = Unit<Vector3<N>> => U3, U4;
|
Output = Unit<Vector3<N>> => U3, U4;
|
||||||
Unit::new_unchecked(self * rhs.unwrap());
|
Unit::new_unchecked(self * rhs.into_inner());
|
||||||
);
|
);
|
||||||
|
|
||||||
macro_rules! scalar_op_impl(
|
macro_rules! scalar_op_impl(
|
||||||
|
|
|
@ -20,7 +20,7 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
|
||||||
/// represents a plane that passes through the origin.
|
/// represents a plane that passes through the origin.
|
||||||
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> {
|
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> {
|
||||||
Reflection {
|
Reflection {
|
||||||
axis: axis.unwrap(),
|
axis: axis.into_inner(),
|
||||||
bias: bias,
|
bias: bias,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3};
|
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3};
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
|
/// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
|
||||||
/// let mat = rot.unwrap();
|
/// let mat = rot.into_inner();
|
||||||
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
|
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
|
||||||
/// 0.5, 0.8660254, 0.0,
|
/// 0.5, 0.8660254, 0.0,
|
||||||
/// 0.0, 0.0, 1.0);
|
/// 0.0, 0.0, 1.0);
|
||||||
|
@ -162,12 +162,20 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// let rot = Rotation2::new(f32::consts::FRAC_PI_6);
|
/// let rot = Rotation2::new(f32::consts::FRAC_PI_6);
|
||||||
/// let mat = rot.unwrap();
|
/// let mat = rot.into_inner();
|
||||||
/// let expected = Matrix2::new(0.8660254, -0.5,
|
/// let expected = Matrix2::new(0.8660254, -0.5,
|
||||||
/// 0.5, 0.8660254);
|
/// 0.5, 0.8660254);
|
||||||
/// assert_eq!(mat, expected);
|
/// assert_eq!(mat, expected);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn into_inner(self) -> MatrixN<N, D> {
|
||||||
|
self.matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unwraps the underlying matrix.
|
||||||
|
/// Deprecated: Use [Rotation::into_inner] instead.
|
||||||
|
#[deprecated(note="use `.into_inner()` instead")]
|
||||||
|
#[inline]
|
||||||
pub fn unwrap(self) -> MatrixN<N, D> {
|
pub fn unwrap(self) -> MatrixN<N, D> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
|
@ -201,6 +209,9 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
D: DimNameAdd<U1>,
|
D: DimNameAdd<U1>,
|
||||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||||
{
|
{
|
||||||
|
// We could use `MatrixN::to_homogeneous()` here, but that would imply
|
||||||
|
// adding the additional traits `DimAdd` and `IsNotStaticOne`. Maybe
|
||||||
|
// these things will get nicer once specialization lands in Rust.
|
||||||
let mut res = MatrixN::<N, DimNameSum<D, U1>>::identity();
|
let mut res = MatrixN::<N, DimNameSum<D, U1>>::identity();
|
||||||
res.fixed_slice_mut::<D, D>(0, 0).copy_from(&self.matrix);
|
res.fixed_slice_mut::<D, D>(0, 0).copy_from(&self.matrix);
|
||||||
|
|
||||||
|
@ -246,7 +257,6 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
||||||
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let tr_rot = rot.transpose();
|
/// let tr_rot = rot.transpose();
|
||||||
|
@ -270,7 +280,6 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
||||||
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let inv = rot.inverse();
|
/// let inv = rot.inverse();
|
||||||
|
@ -294,7 +303,6 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
||||||
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
/// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
||||||
|
@ -322,7 +330,6 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
|
||||||
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
/// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
||||||
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real,
|
AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::{
|
use alga::linear::{
|
||||||
self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
|
self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
|
||||||
|
@ -27,16 +27,16 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, D: DimName> Inverse<Multiplicative> for Rotation<N, D>
|
impl<N: Real, D: DimName> TwoSidedInverse<Multiplicative> for Rotation<N, D>
|
||||||
where DefaultAllocator: Allocator<N, D, D>
|
where DefaultAllocator: Allocator<N, D, D>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.transpose()
|
self.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.transpose_mut()
|
self.transpose_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,7 +227,7 @@ impl<N: Real> From<Rotation2<N>> for Matrix3<N> {
|
||||||
impl<N: Real> From<Rotation2<N>> for Matrix2<N> {
|
impl<N: Real> From<Rotation2<N>> for Matrix2<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(q: Rotation2<N>) -> Matrix2<N> {
|
fn from(q: Rotation2<N>) -> Matrix2<N> {
|
||||||
q.unwrap()
|
q.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +241,6 @@ impl<N: Real> From<Rotation3<N>> for Matrix4<N> {
|
||||||
impl<N: Real> From<Rotation3<N>> for Matrix3<N> {
|
impl<N: Real> From<Rotation3<N>> for Matrix3<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(q: Rotation3<N>) -> Matrix3<N> {
|
fn from(q: Rotation3<N>) -> Matrix3<N> {
|
||||||
q.unwrap()
|
q.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,9 @@ md_impl_all!(
|
||||||
Mul, mul;
|
Mul, mul;
|
||||||
(D, D), (D, D) for D: DimName;
|
(D, D), (D, D) for D: DimName;
|
||||||
self: Rotation<N, D>, right: Rotation<N, D>, Output = Rotation<N, D>;
|
self: Rotation<N, D>, right: Rotation<N, D>, Output = Rotation<N, D>;
|
||||||
[val val] => Rotation::from_matrix_unchecked(self.unwrap() * right.unwrap());
|
[val val] => Rotation::from_matrix_unchecked(self.into_inner() * right.into_inner());
|
||||||
[ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.unwrap());
|
[ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.into_inner());
|
||||||
[val ref] => Rotation::from_matrix_unchecked(self.unwrap() * right.matrix());
|
[val ref] => Rotation::from_matrix_unchecked(self.into_inner() * right.matrix());
|
||||||
[ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix());
|
[ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -71,9 +71,9 @@ md_impl_all!(
|
||||||
where DefaultAllocator: Allocator<N, D1, C2>
|
where DefaultAllocator: Allocator<N, D1, C2>
|
||||||
where ShapeConstraint: AreMultipliable<D1, D1, R2, C2>;
|
where ShapeConstraint: AreMultipliable<D1, D1, R2, C2>;
|
||||||
self: Rotation<N, D1>, right: Matrix<N, R2, C2, SB>, Output = MatrixMN<N, D1, C2>;
|
self: Rotation<N, D1>, right: Matrix<N, R2, C2, SB>, Output = MatrixMN<N, D1, C2>;
|
||||||
[val val] => self.unwrap() * right;
|
[val val] => self.into_inner() * right;
|
||||||
[ref val] => self.matrix() * right;
|
[ref val] => self.matrix() * right;
|
||||||
[val ref] => self.unwrap() * right;
|
[val ref] => self.into_inner() * right;
|
||||||
[ref ref] => self.matrix() * right;
|
[ref ref] => self.matrix() * right;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -84,8 +84,8 @@ md_impl_all!(
|
||||||
where DefaultAllocator: Allocator<N, R1, D2>
|
where DefaultAllocator: Allocator<N, R1, D2>
|
||||||
where ShapeConstraint: AreMultipliable<R1, C1, D2, D2>;
|
where ShapeConstraint: AreMultipliable<R1, C1, D2, D2>;
|
||||||
self: Matrix<N, R1, C1, SA>, right: Rotation<N, D2>, Output = MatrixMN<N, R1, D2>;
|
self: Matrix<N, R1, C1, SA>, right: Rotation<N, D2>, Output = MatrixMN<N, R1, D2>;
|
||||||
[val val] => self * right.unwrap();
|
[val val] => self * right.into_inner();
|
||||||
[ref val] => self * right.unwrap();
|
[ref val] => self * right.into_inner();
|
||||||
[val ref] => self * right.matrix();
|
[val ref] => self * right.matrix();
|
||||||
[ref ref] => self * right.matrix();
|
[ref ref] => self * right.matrix();
|
||||||
);
|
);
|
||||||
|
@ -112,9 +112,9 @@ md_impl_all!(
|
||||||
where DefaultAllocator: Allocator<N, D>
|
where DefaultAllocator: Allocator<N, D>
|
||||||
where ShapeConstraint: AreMultipliable<D, D, D, U1>;
|
where ShapeConstraint: AreMultipliable<D, D, D, U1>;
|
||||||
self: Rotation<N, D>, right: Point<N, D>, Output = Point<N, D>;
|
self: Rotation<N, D>, right: Point<N, D>, Output = Point<N, D>;
|
||||||
[val val] => self.unwrap() * right;
|
[val val] => self.into_inner() * right;
|
||||||
[ref val] => self.matrix() * right;
|
[ref val] => self.matrix() * right;
|
||||||
[val ref] => self.unwrap() * right;
|
[val ref] => self.into_inner() * right;
|
||||||
[ref ref] => self.matrix() * right;
|
[ref ref] => self.matrix() * right;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -125,9 +125,9 @@ md_impl_all!(
|
||||||
where DefaultAllocator: Allocator<N, D>
|
where DefaultAllocator: Allocator<N, D>
|
||||||
where ShapeConstraint: AreMultipliable<D, D, D, U1>;
|
where ShapeConstraint: AreMultipliable<D, D, D, U1>;
|
||||||
self: Rotation<N, D>, right: Unit<Vector<N, D, S>>, Output = Unit<VectorN<N, D>>;
|
self: Rotation<N, D>, right: Unit<Vector<N, D, S>>, Output = Unit<VectorN<N, D>>;
|
||||||
[val val] => Unit::new_unchecked(self.unwrap() * right.unwrap());
|
[val val] => Unit::new_unchecked(self.into_inner() * right.into_inner());
|
||||||
[ref val] => Unit::new_unchecked(self.matrix() * right.unwrap());
|
[ref val] => Unit::new_unchecked(self.matrix() * right.into_inner());
|
||||||
[val ref] => Unit::new_unchecked(self.unwrap() * right.as_ref());
|
[val ref] => Unit::new_unchecked(self.into_inner() * right.as_ref());
|
||||||
[ref ref] => Unit::new_unchecked(self.matrix() * right.as_ref());
|
[ref ref] => Unit::new_unchecked(self.matrix() * right.as_ref());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ md_assign_impl_all!(
|
||||||
MulAssign, mul_assign;
|
MulAssign, mul_assign;
|
||||||
(D, D), (D, D) for D: DimName;
|
(D, D), (D, D) for D: DimName;
|
||||||
self: Rotation<N, D>, right: Rotation<N, D>;
|
self: Rotation<N, D>, right: Rotation<N, D>;
|
||||||
[val] => self.matrix_mut_unchecked().mul_assign(right.unwrap());
|
[val] => self.matrix_mut_unchecked().mul_assign(right.into_inner());
|
||||||
[ref] => self.matrix_mut_unchecked().mul_assign(right.matrix());
|
[ref] => self.matrix_mut_unchecked().mul_assign(right.matrix());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ md_assign_impl_all!(
|
||||||
DivAssign, div_assign;
|
DivAssign, div_assign;
|
||||||
(D, D), (D, D) for D: DimName;
|
(D, D), (D, D) for D: DimName;
|
||||||
self: Rotation<N, D>, right: Rotation<N, D>;
|
self: Rotation<N, D>, right: Rotation<N, D>;
|
||||||
[val] => self.matrix_mut_unchecked().mul_assign(right.inverse().unwrap());
|
[val] => self.matrix_mut_unchecked().mul_assign(right.inverse().into_inner());
|
||||||
[ref] => self.matrix_mut_unchecked().mul_assign(right.inverse().matrix());
|
[ref] => self.matrix_mut_unchecked().mul_assign(right.inverse().matrix());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ md_assign_impl_all!(
|
||||||
MulAssign, mul_assign;
|
MulAssign, mul_assign;
|
||||||
(R1, C1), (C1, C1) for R1: DimName, C1: DimName;
|
(R1, C1), (C1, C1) for R1: DimName, C1: DimName;
|
||||||
self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
|
self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
|
||||||
[val] => self.mul_assign(right.unwrap());
|
[val] => self.mul_assign(right.into_inner());
|
||||||
[ref] => self.mul_assign(right.matrix());
|
[ref] => self.mul_assign(right.matrix());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -168,6 +168,6 @@ md_assign_impl_all!(
|
||||||
DivAssign, div_assign;
|
DivAssign, div_assign;
|
||||||
(R1, C1), (C1, C1) for R1: DimName, C1: DimName;
|
(R1, C1), (C1, C1) for R1: DimName, C1: DimName;
|
||||||
self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
|
self: MatrixMN<N, R1, C1>, right: Rotation<N, C1>;
|
||||||
[val] => self.mul_assign(right.inverse().unwrap());
|
[val] => self.mul_assign(right.inverse().into_inner());
|
||||||
[ref] => self.mul_assign(right.inverse().matrix());
|
[ref] => self.mul_assign(right.inverse().matrix());
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,7 +27,6 @@ impl<N: Real> Rotation2<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation2, Point2};
|
/// # use nalgebra::{Rotation2, Point2};
|
||||||
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
|
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
|
||||||
|
@ -56,7 +55,6 @@ impl<N: Real> Rotation2<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector2, Rotation2};
|
/// # use nalgebra::{Vector2, Rotation2};
|
||||||
/// let a = Vector2::new(1.0, 2.0);
|
/// let a = Vector2::new(1.0, 2.0);
|
||||||
/// let b = Vector2::new(2.0, 1.0);
|
/// let b = Vector2::new(2.0, 1.0);
|
||||||
|
@ -79,7 +77,6 @@ impl<N: Real> Rotation2<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector2, Rotation2};
|
/// # use nalgebra::{Vector2, Rotation2};
|
||||||
/// let a = Vector2::new(1.0, 2.0);
|
/// let a = Vector2::new(1.0, 2.0);
|
||||||
/// let b = Vector2::new(2.0, 1.0);
|
/// let b = Vector2::new(2.0, 1.0);
|
||||||
|
@ -107,9 +104,10 @@ impl<N: Real> Rotation2<N> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # use nalgebra::Rotation2;
|
/// # use nalgebra::Rotation2;
|
||||||
/// let rot = Rotation2::new(1.78);
|
/// let rot = Rotation2::new(1.78);
|
||||||
/// assert_eq!(rot.angle(), 1.78);
|
/// assert_relative_eq!(rot.angle(), 1.78);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn angle(&self) -> N {
|
pub fn angle(&self) -> N {
|
||||||
|
@ -121,7 +119,6 @@ impl<N: Real> Rotation2<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Rotation2;
|
/// # use nalgebra::Rotation2;
|
||||||
/// let rot1 = Rotation2::new(0.1);
|
/// let rot1 = Rotation2::new(0.1);
|
||||||
/// let rot2 = Rotation2::new(1.7);
|
/// let rot2 = Rotation2::new(1.7);
|
||||||
|
@ -139,7 +136,6 @@ impl<N: Real> Rotation2<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Rotation2;
|
/// # use nalgebra::Rotation2;
|
||||||
/// let rot1 = Rotation2::new(0.1);
|
/// let rot1 = Rotation2::new(0.1);
|
||||||
/// let rot2 = Rotation2::new(1.7);
|
/// let rot2 = Rotation2::new(1.7);
|
||||||
|
@ -158,10 +154,11 @@ impl<N: Real> Rotation2<N> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # use nalgebra::Rotation2;
|
/// # use nalgebra::Rotation2;
|
||||||
/// let rot = Rotation2::new(0.78);
|
/// let rot = Rotation2::new(0.78);
|
||||||
/// let pow = rot.powf(2.0);
|
/// let pow = rot.powf(2.0);
|
||||||
/// assert_eq!(pow.angle(), 2.0 * 0.78);
|
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn powf(&self, n: N) -> Rotation2<N> {
|
pub fn powf(&self, n: N) -> Rotation2<N> {
|
||||||
|
@ -213,7 +210,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation3, Point3, Vector3};
|
/// # use nalgebra::{Rotation3, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -241,7 +237,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation3, Point3, Vector3};
|
/// # use nalgebra::{Rotation3, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -265,7 +260,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation3, Point3, Vector3};
|
/// # use nalgebra::{Rotation3, Point3, Vector3};
|
||||||
/// let axis = Vector3::y_axis();
|
/// let axis = Vector3::y_axis();
|
||||||
|
@ -318,7 +312,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Rotation3;
|
/// # use nalgebra::Rotation3;
|
||||||
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
|
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
|
||||||
/// let euler = rot.euler_angles();
|
/// let euler = rot.euler_angles();
|
||||||
|
@ -359,7 +352,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::Rotation3;
|
/// # use nalgebra::Rotation3;
|
||||||
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
|
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
|
||||||
/// let euler = rot.euler_angles();
|
/// let euler = rot.euler_angles();
|
||||||
|
@ -370,12 +362,12 @@ impl<N: Real> Rotation3<N> {
|
||||||
pub fn euler_angles(&self) -> (N, N, N) {
|
pub fn euler_angles(&self) -> (N, N, N) {
|
||||||
// Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh
|
// Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh
|
||||||
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
|
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
|
||||||
if self[(2, 0)].abs() != N::one() {
|
if self[(2, 0)].abs() < N::one() {
|
||||||
let yaw = -self[(2, 0)].asin();
|
let yaw = -self[(2, 0)].asin();
|
||||||
let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos());
|
let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos());
|
||||||
let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos());
|
let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos());
|
||||||
(roll, yaw, pitch)
|
(roll, yaw, pitch)
|
||||||
} else if self[(2, 0)] == -N::one() {
|
} else if self[(2, 0)] <= -N::one() {
|
||||||
(self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero())
|
(self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero())
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
|
@ -399,17 +391,16 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation3, Vector3};
|
/// # use nalgebra::{Rotation3, Vector3};
|
||||||
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
||||||
/// let up = Vector3::y();
|
/// let up = Vector3::y();
|
||||||
///
|
///
|
||||||
/// let rot = Rotation3::new_observer_frame(&dir, &up);
|
/// let rot = Rotation3::face_towards(&dir, &up);
|
||||||
/// assert_relative_eq!(rot * Vector3::z(), dir.normalize());
|
/// assert_relative_eq!(rot * Vector3::z(), dir.normalize());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
||||||
where
|
where
|
||||||
SB: Storage<N, U3>,
|
SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3>,
|
SC: Storage<N, U3>,
|
||||||
|
@ -423,6 +414,16 @@ impl<N: Real> Rotation3<N> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deprecated: Use [Rotation3::face_towards] instead.
|
||||||
|
#[deprecated(note="renamed to `face_towards`")]
|
||||||
|
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
|
||||||
|
where
|
||||||
|
SB: Storage<N, U3>,
|
||||||
|
SC: Storage<N, U3>,
|
||||||
|
{
|
||||||
|
Self::face_towards(dir, up)
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a right-handed look-at view matrix without translation.
|
/// Builds a right-handed look-at view matrix without translation.
|
||||||
///
|
///
|
||||||
/// It maps the view direction `dir` to the **negative** `z` axis.
|
/// It maps the view direction `dir` to the **negative** `z` axis.
|
||||||
|
@ -437,7 +438,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation3, Vector3};
|
/// # use nalgebra::{Rotation3, Vector3};
|
||||||
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -452,7 +452,7 @@ impl<N: Real> Rotation3<N> {
|
||||||
SB: Storage<N, U3>,
|
SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3>,
|
SC: Storage<N, U3>,
|
||||||
{
|
{
|
||||||
Self::new_observer_frame(&dir.neg(), up).inverse()
|
Self::face_towards(&dir.neg(), up).inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a left-handed look-at view matrix without translation.
|
/// Builds a left-handed look-at view matrix without translation.
|
||||||
|
@ -469,7 +469,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Rotation3, Vector3};
|
/// # use nalgebra::{Rotation3, Vector3};
|
||||||
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
/// let dir = Vector3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -484,7 +483,7 @@ impl<N: Real> Rotation3<N> {
|
||||||
SB: Storage<N, U3>,
|
SB: Storage<N, U3>,
|
||||||
SC: Storage<N, U3>,
|
SC: Storage<N, U3>,
|
||||||
{
|
{
|
||||||
Self::new_observer_frame(dir, up).inverse()
|
Self::face_towards(dir, up).inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rotation matrix required to align `a` and `b` but with its angle.
|
/// The rotation matrix required to align `a` and `b` but with its angle.
|
||||||
|
@ -494,7 +493,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector3, Rotation3};
|
/// # use nalgebra::{Vector3, Rotation3};
|
||||||
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
||||||
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
||||||
|
@ -517,7 +515,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector3, Rotation3};
|
/// # use nalgebra::{Vector3, Rotation3};
|
||||||
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
/// let a = Vector3::new(1.0, 2.0, 3.0);
|
||||||
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
/// let b = Vector3::new(3.0, 1.0, 2.0);
|
||||||
|
@ -562,7 +559,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Unit, Rotation3, Vector3};
|
/// # use nalgebra::{Unit, Rotation3, Vector3};
|
||||||
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let rot = Rotation3::from_axis_angle(&axis, 1.78);
|
/// let rot = Rotation3::from_axis_angle(&axis, 1.78);
|
||||||
|
@ -580,7 +576,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
||||||
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let angle = 1.2;
|
/// let angle = 1.2;
|
||||||
|
@ -607,7 +602,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
||||||
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
|
||||||
/// let rot = Rotation3::new(axisangle);
|
/// let rot = Rotation3::new(axisangle);
|
||||||
|
@ -616,7 +610,7 @@ impl<N: Real> Rotation3<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scaled_axis(&self) -> Vector3<N> {
|
pub fn scaled_axis(&self) -> Vector3<N> {
|
||||||
if let Some(axis) = self.axis() {
|
if let Some(axis) = self.axis() {
|
||||||
axis.unwrap() * self.angle()
|
axis.into_inner() * self.angle()
|
||||||
} else {
|
} else {
|
||||||
Vector::zero()
|
Vector::zero()
|
||||||
}
|
}
|
||||||
|
@ -629,7 +623,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
||||||
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let angle = 1.2;
|
/// let angle = 1.2;
|
||||||
|
@ -656,7 +649,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, Vector3};
|
/// # use nalgebra::{Rotation3, Vector3};
|
||||||
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
|
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
|
||||||
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
|
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
|
||||||
|
@ -674,7 +666,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, Vector3};
|
/// # use nalgebra::{Rotation3, Vector3};
|
||||||
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
|
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
|
||||||
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
|
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
|
||||||
|
@ -692,7 +683,6 @@ impl<N: Real> Rotation3<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
/// # use nalgebra::{Rotation3, Vector3, Unit};
|
||||||
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
|
||||||
/// let angle = 1.2;
|
/// let angle = 1.2;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
||||||
AbstractSemigroup, Identity, Inverse, Multiplicative, Real,
|
AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::Similarity as AlgaSimilarity;
|
use alga::linear::Similarity as AlgaSimilarity;
|
||||||
use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation};
|
use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation};
|
||||||
|
@ -27,18 +27,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Similarity<N, D, R>
|
impl<N: Real, D: DimName, R> TwoSidedInverse<Multiplicative> for Similarity<N, D, R>
|
||||||
where
|
where
|
||||||
R: Rotation<Point<N, D>>,
|
R: Rotation<Point<N, D>>,
|
||||||
DefaultAllocator: Allocator<N, D>,
|
DefaultAllocator: Allocator<N, D>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.inverse()
|
self.inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.inverse_mut()
|
self.inverse_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,6 @@ where
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Similarity2, Point2, UnitComplex};
|
/// # use nalgebra::{Similarity2, Point2, UnitComplex};
|
||||||
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
|
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
|
||||||
|
@ -135,7 +134,6 @@ impl<N: Real> Similarity<N, U2, Rotation2<N>> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
|
/// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
|
||||||
/// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
|
/// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
|
||||||
|
@ -159,7 +157,6 @@ impl<N: Real> Similarity<N, U2, UnitComplex<N>> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Similarity2, Vector2, Point2};
|
/// # use nalgebra::{Similarity2, Vector2, Point2};
|
||||||
/// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
|
/// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
|
||||||
|
@ -187,7 +184,6 @@ macro_rules! similarity_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
||||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||||
|
@ -227,7 +223,6 @@ macro_rules! similarity_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
||||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -235,22 +230,32 @@ macro_rules! similarity_construction_impl(
|
||||||
/// let up = Vector3::y();
|
/// let up = Vector3::y();
|
||||||
///
|
///
|
||||||
/// // Similarity with its rotation part represented as a UnitQuaternion
|
/// // Similarity with its rotation part represented as a UnitQuaternion
|
||||||
/// let sim = Similarity3::new_observer_frame(&eye, &target, &up, 3.0);
|
/// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0);
|
||||||
/// assert_eq!(sim * Point3::origin(), eye);
|
/// assert_eq!(sim * Point3::origin(), eye);
|
||||||
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
|
||||||
///
|
///
|
||||||
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||||
/// let sim = SimilarityMatrix3::new_observer_frame(&eye, &target, &up, 3.0);
|
/// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0);
|
||||||
/// assert_eq!(sim * Point3::origin(), eye);
|
/// assert_eq!(sim * Point3::origin(), eye);
|
||||||
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
|
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_observer_frame(eye: &Point3<N>,
|
pub fn face_towards(eye: &Point3<N>,
|
||||||
target: &Point3<N>,
|
target: &Point3<N>,
|
||||||
up: &Vector3<N>,
|
up: &Vector3<N>,
|
||||||
scaling: N)
|
scaling: N)
|
||||||
-> Self {
|
-> Self {
|
||||||
Self::from_isometry(Isometry::<_, U3, $Rot>::new_observer_frame(eye, target, up), scaling)
|
Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated: Use [SimilarityMatrix3::face_towards] instead.
|
||||||
|
#[deprecated(note="renamed to `face_towards`")]
|
||||||
|
pub fn new_observer_frames(eye: &Point3<N>,
|
||||||
|
target: &Point3<N>,
|
||||||
|
up: &Vector3<N>,
|
||||||
|
scaling: N)
|
||||||
|
-> Self {
|
||||||
|
Self::face_towards(eye, target, up, scaling)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a right-handed look-at view matrix including scaling factor.
|
/// Builds a right-handed look-at view matrix including scaling factor.
|
||||||
|
@ -268,7 +273,6 @@ macro_rules! similarity_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
||||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
@ -307,7 +311,6 @@ macro_rules! similarity_construction_impl(
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
|
||||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
|
|
@ -222,8 +222,8 @@ similarity_binop_assign_impl_all!(
|
||||||
DivAssign, div_assign;
|
DivAssign, div_assign;
|
||||||
self: Similarity<N, D, R>, rhs: R;
|
self: Similarity<N, D, R>, rhs: R;
|
||||||
// FIXME: don't invert explicitly?
|
// FIXME: don't invert explicitly?
|
||||||
[val] => *self *= rhs.inverse();
|
[val] => *self *= rhs.two_sided_inverse();
|
||||||
[ref] => *self *= rhs.inverse();
|
[ref] => *self *= rhs.two_sided_inverse();
|
||||||
);
|
);
|
||||||
|
|
||||||
// Similarity × R
|
// Similarity × R
|
||||||
|
|
|
@ -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];
|
||||||
|
);
|
|
@ -248,9 +248,17 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
/// 3.0, 4.0, 0.0,
|
/// 3.0, 4.0, 0.0,
|
||||||
/// 0.0, 0.0, 1.0);
|
/// 0.0, 0.0, 1.0);
|
||||||
/// let t = Transform2::from_matrix_unchecked(m);
|
/// let t = Transform2::from_matrix_unchecked(m);
|
||||||
/// assert_eq!(t.unwrap(), m);
|
/// assert_eq!(t.into_inner(), m);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn into_inner(self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||||
|
self.matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the underlying matrix.
|
||||||
|
/// Deprecated: Use [Transform::into_inner] instead.
|
||||||
|
#[deprecated(note="use `.into_inner()` instead")]
|
||||||
|
#[inline]
|
||||||
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
|
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
|
@ -329,7 +337,7 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
/// 3.0, 4.0, 0.0,
|
/// 3.0, 4.0, 0.0,
|
||||||
/// 0.0, 0.0, 1.0);
|
/// 0.0, 0.0, 1.0);
|
||||||
/// let t = Transform2::from_matrix_unchecked(m);
|
/// let t = Transform2::from_matrix_unchecked(m);
|
||||||
/// assert_eq!(t.unwrap(), m);
|
/// assert_eq!(t.into_inner(), m);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
|
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||||
|
@ -342,7 +350,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix3, Transform2};
|
/// # use nalgebra::{Matrix3, Transform2};
|
||||||
///
|
///
|
||||||
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
||||||
|
@ -375,7 +382,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix3, Projective2};
|
/// # use nalgebra::{Matrix3, Projective2};
|
||||||
///
|
///
|
||||||
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
||||||
|
@ -399,7 +405,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix3, Transform2};
|
/// # use nalgebra::{Matrix3, Transform2};
|
||||||
///
|
///
|
||||||
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
||||||
|
@ -429,7 +434,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Matrix3, Projective2};
|
/// # use nalgebra::{Matrix3, Projective2};
|
||||||
///
|
///
|
||||||
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
/// let m = Matrix3::new(2.0, 2.0, -0.3,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
||||||
AbstractSemigroup, Identity, Inverse, Multiplicative, Real,
|
AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::{ProjectiveTransformation, Transformation};
|
use alga::linear::{ProjectiveTransformation, Transformation};
|
||||||
|
|
||||||
|
@ -26,18 +26,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, D: DimNameAdd<U1>, C> Inverse<Multiplicative> for Transform<N, D, C>
|
impl<N: Real, D: DimNameAdd<U1>, C> TwoSidedInverse<Multiplicative> for Transform<N, D, C>
|
||||||
where
|
where
|
||||||
C: SubTCategoryOf<TProjective>,
|
C: SubTCategoryOf<TProjective>,
|
||||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.clone().inverse()
|
self.clone().inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.inverse_mut()
|
self.inverse_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,12 +116,12 @@ where
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||||
self.inverse() * pt
|
self.two_sided_inverse() * pt
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||||
self.inverse() * v
|
self.two_sided_inverse() * v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ md_impl_all!(
|
||||||
|
|
||||||
if C::has_normalizer() {
|
if C::has_normalizer() {
|
||||||
let normalizer = self.matrix().fixed_slice::<U1, D>(D::dim(), 0);
|
let normalizer = self.matrix().fixed_slice::<U1, D>(D::dim(), 0);
|
||||||
let n = normalizer.tr_dot(&rhs.coords) + unsafe { *self.matrix().get_unchecked(D::dim(), D::dim()) };
|
let n = normalizer.tr_dot(&rhs.coords) + unsafe { *self.matrix().get_unchecked((D::dim(), D::dim())) };
|
||||||
|
|
||||||
if !n.is_zero() {
|
if !n.is_zero() {
|
||||||
return (transform * rhs + translation) / n;
|
return (transform * rhs + translation) / n;
|
||||||
|
@ -159,9 +159,9 @@ md_impl_all!(
|
||||||
Mul, mul where N: Real;
|
Mul, mul where N: Real;
|
||||||
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory;
|
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategoryMul<CB>, CB: TCategory;
|
||||||
self: Transform<N, D, CA>, rhs: Transform<N, D, CB>, Output = Transform<N, D, CA::Representative>;
|
self: Transform<N, D, CA>, rhs: Transform<N, D, CB>, Output = Transform<N, D, CA::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.unwrap());
|
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.into_inner());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.unwrap());
|
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.into_inner());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.matrix());
|
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.matrix());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.matrix());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.matrix());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -170,9 +170,9 @@ md_impl_all!(
|
||||||
Mul, mul where N: Real;
|
Mul, mul where N: Real;
|
||||||
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, D) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
||||||
self: Transform<N, D, C>, rhs: Rotation<N, D>, Output = Transform<N, D, C::Representative>;
|
self: Transform<N, D, C>, rhs: Rotation<N, D>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -181,8 +181,8 @@ md_impl_all!(
|
||||||
Mul, mul where N: Real;
|
Mul, mul where N: Real;
|
||||||
(D, D), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
(D, D), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
||||||
self: Rotation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
self: Rotation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
);
|
);
|
||||||
|
@ -192,9 +192,9 @@ md_impl_all!(
|
||||||
Mul, mul where N: Real;
|
Mul, mul where N: Real;
|
||||||
(U4, U4), (U4, U1) for C: TCategoryMul<TAffine>;
|
(U4, U4), (U4, U1) for C: TCategoryMul<TAffine>;
|
||||||
self: Transform<N, U3, C>, rhs: UnitQuaternion<N>, Output = Transform<N, U3, C::Representative>;
|
self: Transform<N, U3, C>, rhs: UnitQuaternion<N>, Output = Transform<N, U3, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -203,8 +203,8 @@ md_impl_all!(
|
||||||
Mul, mul where N: Real;
|
Mul, mul where N: Real;
|
||||||
(U4, U1), (U4, U4) for C: TCategoryMul<TAffine>;
|
(U4, U1), (U4, U4) for C: TCategoryMul<TAffine>;
|
||||||
self: UnitQuaternion<N>, rhs: Transform<N, U3, C>, Output = Transform<N, U3, C::Representative>;
|
self: UnitQuaternion<N>, rhs: Transform<N, U3, C>, Output = Transform<N, U3, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
);
|
);
|
||||||
|
@ -215,9 +215,9 @@ md_impl_all!(
|
||||||
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
|
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
|
||||||
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
||||||
self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, C::Representative>;
|
self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -227,8 +227,8 @@ md_impl_all!(
|
||||||
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
|
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
|
||||||
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
||||||
self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
);
|
);
|
||||||
|
@ -239,9 +239,9 @@ md_impl_all!(
|
||||||
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
|
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1)
|
||||||
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
||||||
self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, C::Representative>;
|
self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -251,8 +251,8 @@ md_impl_all!(
|
||||||
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
|
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
|
||||||
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >;
|
||||||
self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
);
|
);
|
||||||
|
@ -270,9 +270,9 @@ md_impl_all!(
|
||||||
Mul, mul where N: Real;
|
Mul, mul where N: Real;
|
||||||
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
(DimNameSum<D, U1>, DimNameSum<D, U1>), (D, U1) for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
||||||
self: Transform<N, D, C>, rhs: Translation<N, D>, Output = Transform<N, D, C::Representative>;
|
self: Transform<N, D, C>, rhs: Translation<N, D>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
[val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -282,8 +282,8 @@ md_impl_all!(
|
||||||
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
|
(D, U1), (DimNameSum<D, U1>, DimNameSum<D, U1>)
|
||||||
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>;
|
||||||
self: Translation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
self: Translation<N, D>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
||||||
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
[ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
[ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
);
|
);
|
||||||
|
@ -350,9 +350,9 @@ md_impl_all!(
|
||||||
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
|
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
|
||||||
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
||||||
// self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, C::Representative>;
|
// self: Transform<N, D, C>, rhs: Isometry<N, D, R>, Output = Transform<N, D, C::Representative>;
|
||||||
// [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.inverse().to_homogeneous());
|
// [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.inverse().to_homogeneous());
|
||||||
// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
|
// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
|
||||||
// [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.inverse().to_homogeneous());
|
// [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.inverse().to_homogeneous());
|
||||||
// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
|
// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous());
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
@ -363,8 +363,8 @@ md_impl_all!(
|
||||||
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
|
// for D: DimNameAdd<U1>, C: TCategoryMul<TAffine>, R: SubsetOf<MatrixN<N, DimNameSum<D, U1>> >
|
||||||
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
||||||
// self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
// self: Isometry<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
||||||
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
// );
|
// );
|
||||||
|
@ -377,9 +377,9 @@ md_impl_all!(
|
||||||
// where SB::Alloc: Allocator<N, D, D >
|
// where SB::Alloc: Allocator<N, D, D >
|
||||||
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
// where SB::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
||||||
// self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, C::Representative>;
|
// self: Transform<N, D, C>, rhs: Similarity<N, D, R>, Output = Transform<N, D, C::Representative>;
|
||||||
// [val val] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
// [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
// [val ref] => Self::Output::from_matrix_unchecked(self.unwrap() * rhs.to_homogeneous());
|
// [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous());
|
||||||
// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous());
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
@ -391,8 +391,8 @@ md_impl_all!(
|
||||||
// where SA::Alloc: Allocator<N, D, D >
|
// where SA::Alloc: Allocator<N, D, D >
|
||||||
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
// where SA::Alloc: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1> >;
|
||||||
// self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
// self: Similarity<N, D, R>, rhs: Transform<N, D, C>, Output = Transform<N, D, C::Representative>;
|
||||||
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.unwrap());
|
// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner());
|
||||||
// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix());
|
||||||
// );
|
// );
|
||||||
|
@ -425,7 +425,7 @@ md_assign_impl_all!(
|
||||||
MulAssign, mul_assign where N: Real;
|
MulAssign, mul_assign where N: Real;
|
||||||
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>;
|
(DimNameSum<D, U1>, DimNameSum<D, U1>), (DimNameSum<D, U1>, DimNameSum<D, U1>) for D: DimNameAdd<U1>, CA: TCategory, CB: SubTCategoryOf<CA>;
|
||||||
self: Transform<N, D, CA>, rhs: Transform<N, D, CB>;
|
self: Transform<N, D, CA>, rhs: Transform<N, D, CB>;
|
||||||
[val] => *self.matrix_mut_unchecked() *= rhs.unwrap();
|
[val] => *self.matrix_mut_unchecked() *= rhs.into_inner();
|
||||||
[ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
|
[ref] => *self.matrix_mut_unchecked() *= rhs.matrix();
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
||||||
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real,
|
AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::Translation as AlgaTranslation;
|
use alga::linear::Translation as AlgaTranslation;
|
||||||
use alga::linear::{
|
use alga::linear::{
|
||||||
|
@ -28,16 +28,16 @@ where DefaultAllocator: Allocator<N, D>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real, D: DimName> Inverse<Multiplicative> for Translation<N, D>
|
impl<N: Real, D: DimName> TwoSidedInverse<Multiplicative> for Translation<N, D>
|
||||||
where DefaultAllocator: Allocator<N, D>
|
where DefaultAllocator: Allocator<N, D>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.inverse()
|
self.inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.inverse_mut()
|
self.inverse_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -85,7 +85,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # extern crate num_complex;
|
/// # extern crate num_complex;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use num_complex::Complex;
|
/// # use num_complex::Complex;
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let angle = 1.78f32;
|
/// let angle = 1.78f32;
|
||||||
|
@ -117,7 +116,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let rot = UnitComplex::new(1.2);
|
/// let rot = UnitComplex::new(1.2);
|
||||||
/// let inv = rot.inverse();
|
/// let inv = rot.inverse();
|
||||||
|
@ -134,7 +132,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let rot1 = UnitComplex::new(0.1);
|
/// let rot1 = UnitComplex::new(0.1);
|
||||||
/// let rot2 = UnitComplex::new(1.7);
|
/// let rot2 = UnitComplex::new(1.7);
|
||||||
|
@ -153,7 +150,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let rot1 = UnitComplex::new(0.1);
|
/// let rot1 = UnitComplex::new(0.1);
|
||||||
/// let rot2 = UnitComplex::new(1.7);
|
/// let rot2 = UnitComplex::new(1.7);
|
||||||
|
@ -172,7 +168,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let angle = 1.7;
|
/// let angle = 1.7;
|
||||||
/// let rot = UnitComplex::new(angle);
|
/// let rot = UnitComplex::new(angle);
|
||||||
|
@ -192,7 +187,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let angle = 1.7;
|
/// let angle = 1.7;
|
||||||
/// let mut rot = UnitComplex::new(angle);
|
/// let mut rot = UnitComplex::new(angle);
|
||||||
|
@ -212,10 +206,11 @@ impl<N: Real> UnitComplex<N> {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # use nalgebra::UnitComplex;
|
/// # use nalgebra::UnitComplex;
|
||||||
/// let rot = UnitComplex::new(0.78);
|
/// let rot = UnitComplex::new(0.78);
|
||||||
/// let pow = rot.powf(2.0);
|
/// let pow = rot.powf(2.0);
|
||||||
/// assert_eq!(pow.angle(), 2.0 * 0.78);
|
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn powf(&self, n: N) -> Self {
|
pub fn powf(&self, n: N) -> Self {
|
||||||
|
@ -320,6 +315,6 @@ impl<N: Real> From<UnitComplex<N>> for Matrix3<N> {
|
||||||
impl<N: Real> From<UnitComplex<N>> for Matrix2<N> {
|
impl<N: Real> From<UnitComplex<N>> for Matrix2<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(q: UnitComplex<N>) -> Matrix2<N> {
|
fn from(q: UnitComplex<N>) -> Matrix2<N> {
|
||||||
q.to_rotation_matrix().unwrap()
|
q.to_rotation_matrix().into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
|
||||||
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real,
|
AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
|
||||||
};
|
};
|
||||||
use alga::linear::{
|
use alga::linear::{
|
||||||
AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
|
AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
|
||||||
|
@ -31,14 +31,14 @@ impl<N: Real> AbstractMagma<Multiplicative> for UnitComplex<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Real> Inverse<Multiplicative> for UnitComplex<N> {
|
impl<N: Real> TwoSidedInverse<Multiplicative> for UnitComplex<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse(&self) -> Self {
|
fn two_sided_inverse(&self) -> Self {
|
||||||
self.inverse()
|
self.inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inverse_mut(&mut self) {
|
fn two_sided_inverse_mut(&mut self) {
|
||||||
self.inverse_mut()
|
self.inverse_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,9 @@ use rand::distributions::{Distribution, OpenClosed01, Standard};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use alga::general::Real;
|
use alga::general::Real;
|
||||||
use base::allocator::Allocator;
|
|
||||||
use base::dimension::{U1, U2};
|
use base::dimension::{U1, U2};
|
||||||
use base::storage::Storage;
|
use base::storage::Storage;
|
||||||
use base::{DefaultAllocator, Unit, Vector};
|
use base::{Unit, Vector};
|
||||||
use geometry::{Rotation2, UnitComplex};
|
use geometry::{Rotation2, UnitComplex};
|
||||||
|
|
||||||
impl<N: Real> UnitComplex<N> {
|
impl<N: Real> UnitComplex<N> {
|
||||||
|
@ -36,7 +35,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitComplex, Point2};
|
/// # use nalgebra::{UnitComplex, Point2};
|
||||||
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
|
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
|
||||||
|
@ -57,7 +55,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitComplex, Point2};
|
/// # use nalgebra::{UnitComplex, Point2};
|
||||||
/// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
|
/// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
|
||||||
|
@ -79,7 +76,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use std::f32;
|
/// # use std::f32;
|
||||||
/// # use nalgebra::{UnitComplex, Vector2, Point2};
|
/// # use nalgebra::{UnitComplex, Vector2, Point2};
|
||||||
/// let angle = f32::consts::FRAC_PI_2;
|
/// let angle = f32::consts::FRAC_PI_2;
|
||||||
|
@ -139,7 +135,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector2, UnitComplex};
|
/// # use nalgebra::{Vector2, UnitComplex};
|
||||||
/// let a = Vector2::new(1.0, 2.0);
|
/// let a = Vector2::new(1.0, 2.0);
|
||||||
/// let b = Vector2::new(2.0, 1.0);
|
/// let b = Vector2::new(2.0, 1.0);
|
||||||
|
@ -162,7 +157,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Vector2, UnitComplex};
|
/// # use nalgebra::{Vector2, UnitComplex};
|
||||||
/// let a = Vector2::new(1.0, 2.0);
|
/// let a = Vector2::new(1.0, 2.0);
|
||||||
/// let b = Vector2::new(2.0, 1.0);
|
/// let b = Vector2::new(2.0, 1.0);
|
||||||
|
@ -198,7 +192,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Unit, Vector2, UnitComplex};
|
/// # use nalgebra::{Unit, Vector2, UnitComplex};
|
||||||
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
|
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
|
||||||
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
|
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
|
||||||
|
@ -224,7 +217,6 @@ impl<N: Real> UnitComplex<N> {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate approx;
|
/// # #[macro_use] extern crate approx;
|
||||||
/// # extern crate nalgebra;
|
|
||||||
/// # use nalgebra::{Unit, Vector2, UnitComplex};
|
/// # use nalgebra::{Unit, Vector2, UnitComplex};
|
||||||
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
|
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
|
||||||
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
|
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
|
||||||
|
|
|
@ -50,7 +50,7 @@ impl<N: Real> Mul<UnitComplex<N>> for UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.unwrap() * rhs.unwrap())
|
Unit::new_unchecked(self.into_inner() * rhs.into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ impl<'a, N: Real> Mul<UnitComplex<N>> for &'a UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.complex() * rhs.unwrap())
|
Unit::new_unchecked(self.complex() * rhs.into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ impl<'b, N: Real> Mul<&'b UnitComplex<N>> for UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
|
fn mul(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.unwrap() * rhs.complex())
|
Unit::new_unchecked(self.into_inner() * rhs.complex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ impl<N: Real> Div<UnitComplex<N>> for UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.unwrap() * rhs.conjugate().unwrap())
|
Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ impl<'a, N: Real> Div<UnitComplex<N>> for &'a UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.complex() * rhs.conjugate().unwrap())
|
Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ impl<'b, N: Real> Div<&'b UnitComplex<N>> for UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
|
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.unwrap() * rhs.conjugate().unwrap())
|
Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ impl<'a, 'b, N: Real> Div<&'b UnitComplex<N>> for &'a UnitComplex<N> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
|
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> {
|
||||||
Unit::new_unchecked(self.complex() * rhs.conjugate().unwrap())
|
Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,11 +425,11 @@ impl<N: Real> UnitComplex<N> {
|
||||||
|
|
||||||
for j in 0..rhs.ncols() {
|
for j in 0..rhs.ncols() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let a = *rhs.get_unchecked(0, j);
|
let a = *rhs.get_unchecked((0, j));
|
||||||
let b = *rhs.get_unchecked(1, j);
|
let b = *rhs.get_unchecked((1, j));
|
||||||
|
|
||||||
*rhs.get_unchecked_mut(0, j) = r * a - i * b;
|
*rhs.get_unchecked_mut((0, j)) = r * a - i * b;
|
||||||
*rhs.get_unchecked_mut(1, j) = i * a + r * b;
|
*rhs.get_unchecked_mut((1, j)) = i * a + r * b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,11 +452,11 @@ impl<N: Real> UnitComplex<N> {
|
||||||
// FIXME: can we optimize that to iterate on one column at a time ?
|
// FIXME: can we optimize that to iterate on one column at a time ?
|
||||||
for j in 0..lhs.nrows() {
|
for j in 0..lhs.nrows() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let a = *lhs.get_unchecked(j, 0);
|
let a = *lhs.get_unchecked((j, 0));
|
||||||
let b = *lhs.get_unchecked(j, 1);
|
let b = *lhs.get_unchecked((j, 1));
|
||||||
|
|
||||||
*lhs.get_unchecked_mut(j, 0) = r * a + i * b;
|
*lhs.get_unchecked_mut((j, 0)) = r * a + i * b;
|
||||||
*lhs.get_unchecked_mut(j, 1) = -i * a + r * b;
|
*lhs.get_unchecked_mut((j, 1)) = -i * a + r * b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
|
@ -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,
|
||||||
|
))
|
||||||
|
}
|
|
@ -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;
|
97
src/lib.rs
97
src/lib.rs
|
@ -81,10 +81,12 @@ an optimized set of tools for computer graphics and physics. Those features incl
|
||||||
#![deny(non_upper_case_globals)]
|
#![deny(non_upper_case_globals)]
|
||||||
#![deny(unused_qualifications)]
|
#![deny(unused_qualifications)]
|
||||||
#![deny(unused_results)]
|
#![deny(unused_results)]
|
||||||
#![deny(missing_docs)]
|
#![warn(missing_docs)] // FIXME: deny this
|
||||||
#![warn(incoherent_fundamental_impls)]
|
#![warn(incoherent_fundamental_impls)]
|
||||||
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico",
|
#![doc(
|
||||||
html_root_url = "http://nalgebra.org/rustdoc")]
|
html_favicon_url = "http://nalgebra.org/img/favicon.ico",
|
||||||
|
html_root_url = "http://nalgebra.org/rustdoc"
|
||||||
|
)]
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
|
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
|
||||||
|
|
||||||
|
@ -121,11 +123,21 @@ extern crate alloc;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
extern crate core as std;
|
extern crate core as std;
|
||||||
|
|
||||||
|
#[cfg(feature = "io")]
|
||||||
|
extern crate pest;
|
||||||
|
#[macro_use]
|
||||||
|
#[cfg(feature = "io")]
|
||||||
|
extern crate pest_derive;
|
||||||
|
|
||||||
pub mod base;
|
pub mod base;
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
#[cfg(feature = "io")]
|
||||||
|
pub mod io;
|
||||||
pub mod linalg;
|
pub mod linalg;
|
||||||
|
#[cfg(feature = "sparse")]
|
||||||
|
pub mod sparse;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
|
@ -135,11 +147,13 @@ pub use base as core;
|
||||||
pub use base::*;
|
pub use base::*;
|
||||||
pub use geometry::*;
|
pub use geometry::*;
|
||||||
pub use linalg::*;
|
pub use linalg::*;
|
||||||
|
#[cfg(feature = "sparse")]
|
||||||
|
pub use sparse::*;
|
||||||
|
|
||||||
use std::cmp::{self, Ordering, PartialOrd};
|
use std::cmp::{self, Ordering, PartialOrd};
|
||||||
|
|
||||||
use alga::general::{
|
use alga::general::{
|
||||||
Additive, AdditiveGroup, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice,
|
Additive, AdditiveGroup, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice,
|
||||||
Multiplicative, SupersetOf,
|
Multiplicative, SupersetOf,
|
||||||
};
|
};
|
||||||
use alga::linear::SquareMatrix as AlgaSquareMatrix;
|
use alga::linear::SquareMatrix as AlgaSquareMatrix;
|
||||||
|
@ -189,6 +203,12 @@ pub fn zero<T: Identity<Additive>>() -> T {
|
||||||
///
|
///
|
||||||
/// * [`one`](fn.one.html)
|
/// * [`one`](fn.one.html)
|
||||||
/// * [`zero`](fn.zero.html)
|
/// * [`zero`](fn.zero.html)
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use [Point::origin] instead.
|
||||||
|
///
|
||||||
|
/// Or, use [EuclideanSpace::origin](https://docs.rs/alga/0.7.2/alga/linear/trait.EuclideanSpace.html#tymethod.origin).
|
||||||
|
#[deprecated(note = "use `Point::origin` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn origin<P: EuclideanSpace>() -> P {
|
pub fn origin<P: EuclideanSpace>() -> P {
|
||||||
P::origin()
|
P::origin()
|
||||||
|
@ -275,6 +295,9 @@ pub fn min<T: Ord>(a: T, b: T) -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The absolute value of `a`.
|
/// The absolute value of `a`.
|
||||||
|
///
|
||||||
|
/// Deprecated: Use [Matrix::abs] or [Real::abs] instead.
|
||||||
|
#[deprecated(note = "use `Matrix::abs` or `Real::abs` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn abs<T: Signed>(a: &T) -> T {
|
pub fn abs<T: Signed>(a: &T) -> T {
|
||||||
a.abs()
|
a.abs()
|
||||||
|
@ -404,8 +427,8 @@ pub fn try_inverse<M: AlgaSquareMatrix>(m: &M) -> Option<M> {
|
||||||
///
|
///
|
||||||
/// * [`try_inverse`](fn.try_inverse.html)
|
/// * [`try_inverse`](fn.try_inverse.html)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
|
pub fn inverse<M: TwoSidedInverse<Multiplicative>>(m: &M) -> M {
|
||||||
m.inverse()
|
m.two_sided_inverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -413,12 +436,26 @@ pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Computes the dot product of two vectors.
|
/// Computes the dot product of two vectors.
|
||||||
|
///
|
||||||
|
/// ## Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// - [Matrix::dot]
|
||||||
|
/// - [Quaternion::dot]
|
||||||
|
///
|
||||||
|
/// Or, use [FiniteDimVectorSpace::dot](https://docs.rs/alga/0.7.2/alga/linear/trait.FiniteDimVectorSpace.html#tymethod.dot).
|
||||||
|
#[deprecated(note = "use `Matrix::dot` or `Quaternion::dot` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field {
|
pub fn dot<V: FiniteDimVectorSpace>(a: &V, b: &V) -> V::Field {
|
||||||
a.dot(b)
|
a.dot(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the smallest angle between two vectors.
|
/// Computes the smallest angle between two vectors.
|
||||||
|
///
|
||||||
|
/// ## Deprecated
|
||||||
|
/// Use [Matrix::angle] instead.
|
||||||
|
///
|
||||||
|
/// Or, use [InnerSpace::angle](https://docs.rs/alga/0.7.2/alga/linear/trait.InnerSpace.html#method.angle).
|
||||||
|
#[deprecated(note = "use `Matrix::angle` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
|
pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
|
||||||
a.angle(b)
|
a.angle(b)
|
||||||
|
@ -435,6 +472,14 @@ pub fn angle<V: InnerSpace>(a: &V, b: &V) -> V::Real {
|
||||||
/// * [`magnitude`](fn.magnitude.html)
|
/// * [`magnitude`](fn.magnitude.html)
|
||||||
/// * [`magnitude_squared`](fn.magnitude_squared.html)
|
/// * [`magnitude_squared`](fn.magnitude_squared.html)
|
||||||
/// * [`norm_squared`](fn.norm_squared.html)
|
/// * [`norm_squared`](fn.norm_squared.html)
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// * [Matrix::norm]
|
||||||
|
/// * [Quaternion::norm]
|
||||||
|
///
|
||||||
|
/// Or, use [NormedSpace::norm](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm).
|
||||||
|
#[deprecated(note = "use `Matrix::norm` or `Quaternion::norm` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
|
pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
v.norm()
|
v.norm()
|
||||||
|
@ -447,6 +492,14 @@ pub fn norm<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
/// * [`magnitude`](fn.magnitude.html)
|
/// * [`magnitude`](fn.magnitude.html)
|
||||||
/// * [`magnitude_squared`](fn.magnitude_squared.html)
|
/// * [`magnitude_squared`](fn.magnitude_squared.html)
|
||||||
/// * [`norm`](fn.norm.html)
|
/// * [`norm`](fn.norm.html)
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// * [Matrix::norm_squared]
|
||||||
|
/// * [Quaternion::norm_squared]
|
||||||
|
///
|
||||||
|
/// Or, use [NormedSpace::norm_squared](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm_squared).
|
||||||
|
#[deprecated(note = "use `Matrix::norm_squared` or `Quaternion::norm_squared` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
|
pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
v.norm_squared()
|
v.norm_squared()
|
||||||
|
@ -459,6 +512,14 @@ pub fn norm_squared<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
/// * [`magnitude_squared`](fn.magnitude_squared.html)
|
/// * [`magnitude_squared`](fn.magnitude_squared.html)
|
||||||
/// * [`norm`](fn.norm.html)
|
/// * [`norm`](fn.norm.html)
|
||||||
/// * [`norm_squared`](fn.norm_squared.html)
|
/// * [`norm_squared`](fn.norm_squared.html)
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// * [Matrix::magnitude]
|
||||||
|
/// * [Quaternion::magnitude]
|
||||||
|
///
|
||||||
|
/// Or, use [NormedSpace::norm](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm).
|
||||||
|
#[deprecated(note = "use `Matrix::magnitude` or `Quaternion::magnitude` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
|
pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
v.norm()
|
v.norm()
|
||||||
|
@ -472,18 +533,42 @@ pub fn magnitude<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
/// * [`magnitude`](fn.magnitude.html)
|
/// * [`magnitude`](fn.magnitude.html)
|
||||||
/// * [`norm`](fn.norm.html)
|
/// * [`norm`](fn.norm.html)
|
||||||
/// * [`norm_squared`](fn.norm_squared.html)
|
/// * [`norm_squared`](fn.norm_squared.html)
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// * [Matrix::magnitude_squared]
|
||||||
|
/// * [Quaternion::magnitude_squared]
|
||||||
|
///
|
||||||
|
/// Or, use [NormedSpace::norm_squared](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm_squared).
|
||||||
|
#[deprecated(note = "use `Matrix::magnitude_squared` or `Quaternion::magnitude_squared` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn magnitude_squared<V: NormedSpace>(v: &V) -> V::Field {
|
pub fn magnitude_squared<V: NormedSpace>(v: &V) -> V::Field {
|
||||||
v.norm_squared()
|
v.norm_squared()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the normalized version of the vector `v`.
|
/// Computes the normalized version of the vector `v`.
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// * [Matrix::normalize]
|
||||||
|
/// * [Quaternion::normalize]
|
||||||
|
///
|
||||||
|
/// Or, use [NormedSpace::normalize](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.normalize).
|
||||||
|
#[deprecated(note = "use `Matrix::normalize` or `Quaternion::normalize` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn normalize<V: NormedSpace>(v: &V) -> V {
|
pub fn normalize<V: NormedSpace>(v: &V) -> V {
|
||||||
v.normalize()
|
v.normalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`.
|
/// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`.
|
||||||
|
///
|
||||||
|
/// # Deprecated
|
||||||
|
/// Use these methods instead:
|
||||||
|
/// * [Matrix::try_normalize]
|
||||||
|
/// * [Quaternion::try_normalize]
|
||||||
|
///
|
||||||
|
/// Or, use [NormedSpace::try_normalize](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.try_normalize).
|
||||||
|
#[deprecated(note = "use `Matrix::try_normalize` or `Quaternion::try_normalize` instead")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> {
|
pub fn try_normalize<V: NormedSpace>(v: &V, min_norm: V::Field) -> Option<V> {
|
||||||
v.try_normalize(min_norm)
|
v.try_normalize(min_norm)
|
||||||
|
|
|
@ -52,7 +52,7 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
|
|
||||||
for j in 0..n {
|
for j in 0..n {
|
||||||
for k in 0..j {
|
for k in 0..j {
|
||||||
let factor = unsafe { -*matrix.get_unchecked(j, k) };
|
let factor = unsafe { -*matrix.get_unchecked((j, k)) };
|
||||||
|
|
||||||
let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k);
|
let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k);
|
||||||
let mut col_j = col_j.rows_range_mut(j..);
|
let mut col_j = col_j.rows_range_mut(j..);
|
||||||
|
@ -61,11 +61,11 @@ where DefaultAllocator: Allocator<N, D, D>
|
||||||
col_j.axpy(factor, &col_k, N::one());
|
col_j.axpy(factor, &col_k, N::one());
|
||||||
}
|
}
|
||||||
|
|
||||||
let diag = unsafe { *matrix.get_unchecked(j, j) };
|
let diag = unsafe { *matrix.get_unchecked((j, j)) };
|
||||||
if diag > N::zero() {
|
if diag > N::zero() {
|
||||||
let denom = diag.sqrt();
|
let denom = diag.sqrt();
|
||||||
unsafe {
|
unsafe {
|
||||||
*matrix.get_unchecked_mut(j, j) = denom;
|
*matrix.get_unchecked_mut((j, j)) = denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut col = matrix.slice_range_mut(j + 1.., j);
|
let mut col = matrix.slice_range_mut(j + 1.., j);
|
||||||
|
|
|
@ -23,27 +23,27 @@ impl<N: Real, D: DimMin<D, Output = D>, S: Storage<N, D, D>> SquareMatrix<N, D,
|
||||||
unsafe {
|
unsafe {
|
||||||
match dim {
|
match dim {
|
||||||
0 => N::one(),
|
0 => N::one(),
|
||||||
1 => *self.get_unchecked(0, 0),
|
1 => *self.get_unchecked((0, 0)),
|
||||||
2 => {
|
2 => {
|
||||||
let m11 = *self.get_unchecked(0, 0);
|
let m11 = *self.get_unchecked((0, 0));
|
||||||
let m12 = *self.get_unchecked(0, 1);
|
let m12 = *self.get_unchecked((0, 1));
|
||||||
let m21 = *self.get_unchecked(1, 0);
|
let m21 = *self.get_unchecked((1, 0));
|
||||||
let m22 = *self.get_unchecked(1, 1);
|
let m22 = *self.get_unchecked((1, 1));
|
||||||
|
|
||||||
m11 * m22 - m21 * m12
|
m11 * m22 - m21 * m12
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
let m11 = *self.get_unchecked(0, 0);
|
let m11 = *self.get_unchecked((0, 0));
|
||||||
let m12 = *self.get_unchecked(0, 1);
|
let m12 = *self.get_unchecked((0, 1));
|
||||||
let m13 = *self.get_unchecked(0, 2);
|
let m13 = *self.get_unchecked((0, 2));
|
||||||
|
|
||||||
let m21 = *self.get_unchecked(1, 0);
|
let m21 = *self.get_unchecked((1, 0));
|
||||||
let m22 = *self.get_unchecked(1, 1);
|
let m22 = *self.get_unchecked((1, 1));
|
||||||
let m23 = *self.get_unchecked(1, 2);
|
let m23 = *self.get_unchecked((1, 2));
|
||||||
|
|
||||||
let m31 = *self.get_unchecked(2, 0);
|
let m31 = *self.get_unchecked((2, 0));
|
||||||
let m32 = *self.get_unchecked(2, 1);
|
let m32 = *self.get_unchecked((2, 1));
|
||||||
let m33 = *self.get_unchecked(2, 2);
|
let m33 = *self.get_unchecked((2, 2));
|
||||||
|
|
||||||
let minor_m12_m23 = m22 * m33 - m32 * m23;
|
let minor_m12_m23 = m22 * m33 - m32 * m23;
|
||||||
let minor_m11_m23 = m21 * m33 - m31 * m23;
|
let minor_m11_m23 = m21 * m33 - m31 * m23;
|
||||||
|
|
|
@ -251,7 +251,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
|
||||||
let mut res = self.lu[(dim - 1, dim - 1)];
|
let mut res = self.lu[(dim - 1, dim - 1)];
|
||||||
if !res.is_zero() {
|
if !res.is_zero() {
|
||||||
for i in 0..dim - 1 {
|
for i in 0..dim - 1 {
|
||||||
res *= unsafe { *self.lu.get_unchecked(i, i) };
|
res *= unsafe { *self.lu.get_unchecked((i, i)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
res * self.p.determinant() * self.q.determinant()
|
res * self.p.determinant() * self.q.determinant()
|
||||||
|
|
|
@ -35,46 +35,46 @@ impl<N: Real, D: Dim, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
match dim {
|
match dim {
|
||||||
0 => true,
|
0 => true,
|
||||||
1 => {
|
1 => {
|
||||||
let determinant = self.get_unchecked(0, 0).clone();
|
let determinant = self.get_unchecked((0, 0)).clone();
|
||||||
if determinant == N::zero() {
|
if determinant == N::zero() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
*self.get_unchecked_mut(0, 0) = N::one() / determinant;
|
*self.get_unchecked_mut((0, 0)) = N::one() / determinant;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
let m11 = *self.get_unchecked(0, 0);
|
let m11 = *self.get_unchecked((0, 0));
|
||||||
let m12 = *self.get_unchecked(0, 1);
|
let m12 = *self.get_unchecked((0, 1));
|
||||||
let m21 = *self.get_unchecked(1, 0);
|
let m21 = *self.get_unchecked((1, 0));
|
||||||
let m22 = *self.get_unchecked(1, 1);
|
let m22 = *self.get_unchecked((1, 1));
|
||||||
|
|
||||||
let determinant = m11 * m22 - m21 * m12;
|
let determinant = m11 * m22 - m21 * m12;
|
||||||
|
|
||||||
if determinant == N::zero() {
|
if determinant == N::zero() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
*self.get_unchecked_mut(0, 0) = m22 / determinant;
|
*self.get_unchecked_mut((0, 0)) = m22 / determinant;
|
||||||
*self.get_unchecked_mut(0, 1) = -m12 / determinant;
|
*self.get_unchecked_mut((0, 1)) = -m12 / determinant;
|
||||||
|
|
||||||
*self.get_unchecked_mut(1, 0) = -m21 / determinant;
|
*self.get_unchecked_mut((1, 0)) = -m21 / determinant;
|
||||||
*self.get_unchecked_mut(1, 1) = m11 / determinant;
|
*self.get_unchecked_mut((1, 1)) = m11 / determinant;
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
let m11 = *self.get_unchecked(0, 0);
|
let m11 = *self.get_unchecked((0, 0));
|
||||||
let m12 = *self.get_unchecked(0, 1);
|
let m12 = *self.get_unchecked((0, 1));
|
||||||
let m13 = *self.get_unchecked(0, 2);
|
let m13 = *self.get_unchecked((0, 2));
|
||||||
|
|
||||||
let m21 = *self.get_unchecked(1, 0);
|
let m21 = *self.get_unchecked((1, 0));
|
||||||
let m22 = *self.get_unchecked(1, 1);
|
let m22 = *self.get_unchecked((1, 1));
|
||||||
let m23 = *self.get_unchecked(1, 2);
|
let m23 = *self.get_unchecked((1, 2));
|
||||||
|
|
||||||
let m31 = *self.get_unchecked(2, 0);
|
let m31 = *self.get_unchecked((2, 0));
|
||||||
let m32 = *self.get_unchecked(2, 1);
|
let m32 = *self.get_unchecked((2, 1));
|
||||||
let m33 = *self.get_unchecked(2, 2);
|
let m33 = *self.get_unchecked((2, 2));
|
||||||
|
|
||||||
let minor_m12_m23 = m22 * m33 - m32 * m23;
|
let minor_m12_m23 = m22 * m33 - m32 * m23;
|
||||||
let minor_m11_m23 = m21 * m33 - m31 * m23;
|
let minor_m11_m23 = m21 * m33 - m31 * m23;
|
||||||
|
@ -86,17 +86,17 @@ impl<N: Real, D: Dim, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
if determinant == N::zero() {
|
if determinant == N::zero() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
*self.get_unchecked_mut(0, 0) = minor_m12_m23 / determinant;
|
*self.get_unchecked_mut((0, 0)) = minor_m12_m23 / determinant;
|
||||||
*self.get_unchecked_mut(0, 1) = (m13 * m32 - m33 * m12) / determinant;
|
*self.get_unchecked_mut((0, 1)) = (m13 * m32 - m33 * m12) / determinant;
|
||||||
*self.get_unchecked_mut(0, 2) = (m12 * m23 - m22 * m13) / determinant;
|
*self.get_unchecked_mut((0, 2)) = (m12 * m23 - m22 * m13) / determinant;
|
||||||
|
|
||||||
*self.get_unchecked_mut(1, 0) = -minor_m11_m23 / determinant;
|
*self.get_unchecked_mut((1, 0)) = -minor_m11_m23 / determinant;
|
||||||
*self.get_unchecked_mut(1, 1) = (m11 * m33 - m31 * m13) / determinant;
|
*self.get_unchecked_mut((1, 1)) = (m11 * m33 - m31 * m13) / determinant;
|
||||||
*self.get_unchecked_mut(1, 2) = (m13 * m21 - m23 * m11) / determinant;
|
*self.get_unchecked_mut((1, 2)) = (m13 * m21 - m23 * m11) / determinant;
|
||||||
|
|
||||||
*self.get_unchecked_mut(2, 0) = minor_m11_m22 / determinant;
|
*self.get_unchecked_mut((2, 0)) = minor_m11_m22 / determinant;
|
||||||
*self.get_unchecked_mut(2, 1) = (m12 * m31 - m32 * m11) / determinant;
|
*self.get_unchecked_mut((2, 1)) = (m12 * m31 - m32 * m11) / determinant;
|
||||||
*self.get_unchecked_mut(2, 2) = (m11 * m22 - m21 * m12) / determinant;
|
*self.get_unchecked_mut((2, 2)) = (m11 * m22 - m21 * m12) / determinant;
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,7 +290,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<(usize, usize), D>
|
||||||
|
|
||||||
let mut res = N::one();
|
let mut res = N::one();
|
||||||
for i in 0..dim {
|
for i in 0..dim {
|
||||||
res *= unsafe { *self.lu.get_unchecked(i, i) };
|
res *= unsafe { *self.lu.get_unchecked((i, i)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
res * self.p.determinant()
|
res * self.p.determinant()
|
||||||
|
|
|
@ -412,7 +412,7 @@ where
|
||||||
rot.rotate_rows(&mut m);
|
rot.rotate_rows(&mut m);
|
||||||
|
|
||||||
if compute_q {
|
if compute_q {
|
||||||
let c = rot.unwrap();
|
let c = rot.into_inner();
|
||||||
// XXX: we have to build the matrix manually because
|
// XXX: we have to build the matrix manually because
|
||||||
// rot.to_rotation_matrix().unwrap() causes an ICE.
|
// rot.to_rotation_matrix().unwrap() causes an ICE.
|
||||||
q = Some(MatrixN::from_column_slice_generic(
|
q = Some(MatrixN::from_column_slice_generic(
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
let coeff;
|
let coeff;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let diag = *self.get_unchecked(i, i);
|
let diag = *self.get_unchecked((i, i));
|
||||||
|
|
||||||
if diag.is_zero() {
|
if diag.is_zero() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -161,7 +161,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
let coeff;
|
let coeff;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let diag = *self.get_unchecked(i, i);
|
let diag = *self.get_unchecked((i, i));
|
||||||
|
|
||||||
if diag.is_zero() {
|
if diag.is_zero() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -258,7 +258,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let b_i = b.vget_unchecked_mut(i);
|
let b_i = b.vget_unchecked_mut(i);
|
||||||
|
|
||||||
let diag = *self.get_unchecked(i, i);
|
let diag = *self.get_unchecked((i, i));
|
||||||
|
|
||||||
if diag.is_zero() {
|
if diag.is_zero() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -304,7 +304,7 @@ impl<N: Real, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let b_i = b.vget_unchecked_mut(i);
|
let b_i = b.vget_unchecked_mut(i);
|
||||||
let diag = *self.get_unchecked(i, i);
|
let diag = *self.get_unchecked((i, i));
|
||||||
|
|
||||||
if diag.is_zero() {
|
if diag.is_zero() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -484,90 +484,94 @@ where
|
||||||
|
|
||||||
/// Rebuild the original matrix.
|
/// Rebuild the original matrix.
|
||||||
///
|
///
|
||||||
/// This is useful if some of the singular values have been manually modified. Panics if the
|
/// This is useful if some of the singular values have been manually modified.
|
||||||
/// right- and left- singular vectors have not been computed at construction-time.
|
/// Returns `Err` if the right- and left- singular vectors have not been
|
||||||
pub fn recompose(self) -> MatrixMN<N, R, C> {
|
/// computed at construction-time.
|
||||||
let mut u = self.u.expect("SVD recomposition: U has not been computed.");
|
pub fn recompose(self) -> Result<MatrixMN<N, R, C>, &'static str> {
|
||||||
let v_t = self
|
match (self.u, self.v_t) {
|
||||||
.v_t
|
(Some(mut u), Some(v_t)) => {
|
||||||
.expect("SVD recomposition: V^t has not been computed.");
|
for i in 0..self.singular_values.len() {
|
||||||
|
let val = self.singular_values[i];
|
||||||
for i in 0..self.singular_values.len() {
|
u.column_mut(i).mul_assign(val);
|
||||||
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.
|
/// Computes the pseudo-inverse of the decomposed matrix.
|
||||||
///
|
///
|
||||||
/// Any singular value smaller than `eps` is assumed to be zero.
|
/// Any singular value smaller than `eps` is assumed to be zero.
|
||||||
/// Panics if the right- and left- singular vectors have not been computed at
|
/// Returns `Err` if the right- and left- singular vectors have not
|
||||||
/// construction-time.
|
/// been computed at construction-time.
|
||||||
pub fn pseudo_inverse(mut self, eps: N) -> MatrixMN<N, C, R>
|
pub fn pseudo_inverse(mut self, eps: N) -> Result<MatrixMN<N, C, R>, &'static str>
|
||||||
where DefaultAllocator: Allocator<N, C, R> {
|
where
|
||||||
assert!(
|
DefaultAllocator: Allocator<N, C, R>,
|
||||||
eps >= N::zero(),
|
{
|
||||||
"SVD pseudo inverse: the epsilon must be non-negative."
|
if eps < N::zero() {
|
||||||
);
|
Err("SVD pseudo inverse: the epsilon must be non-negative.")
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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.
|
/// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown.
|
||||||
///
|
///
|
||||||
/// Any singular value smaller than `eps` is assumed to be zero.
|
/// Any singular value smaller than `eps` is assumed to be zero.
|
||||||
/// Returns `None` if the singular vectors `U` and `V` have not been computed.
|
/// Returns `Err` if the singular vectors `U` and `V` have not been computed.
|
||||||
// FIXME: make this more generic wrt the storage types and the dimensions for `b`.
|
// FIXME: make this more generic wrt the storage types and the dimensions for `b`.
|
||||||
pub fn solve<R2: Dim, C2: Dim, S2>(
|
pub fn solve<R2: Dim, C2: Dim, S2>(
|
||||||
&self,
|
&self,
|
||||||
b: &Matrix<N, R2, C2, S2>,
|
b: &Matrix<N, R2, C2, S2>,
|
||||||
eps: N,
|
eps: N,
|
||||||
) -> MatrixMN<N, C, C2>
|
) -> Result<MatrixMN<N, C, C2>, &'static str>
|
||||||
where
|
where
|
||||||
S2: Storage<N, R2, C2>,
|
S2: Storage<N, R2, C2>,
|
||||||
DefaultAllocator: Allocator<N, C, C2> + Allocator<N, DimMinimum<R, C>, C2>,
|
DefaultAllocator: Allocator<N, C, C2> + Allocator<N, DimMinimum<R, C>, C2>,
|
||||||
ShapeConstraint: SameNumberOfRows<R, R2>,
|
ShapeConstraint: SameNumberOfRows<R, R2>,
|
||||||
{
|
{
|
||||||
assert!(
|
if eps < N::zero() {
|
||||||
eps >= N::zero(),
|
Err("SVD solve: the epsilon must be non-negative.")
|
||||||
"SVD solve: the epsilon must be non-negative."
|
}
|
||||||
);
|
else {
|
||||||
let u = self
|
match (&self.u, &self.v_t) {
|
||||||
.u
|
(Some(u), Some(v_t)) => {
|
||||||
.as_ref()
|
let mut ut_b = u.tr_mul(b);
|
||||||
.expect("SVD solve: U has not been computed.");
|
|
||||||
let v_t = self
|
|
||||||
.v_t
|
|
||||||
.as_ref()
|
|
||||||
.expect("SVD solve: V^t has not been computed.");
|
|
||||||
|
|
||||||
let mut ut_b = u.tr_mul(b);
|
for j in 0..ut_b.ncols() {
|
||||||
|
let mut col = ut_b.column_mut(j);
|
||||||
|
|
||||||
for j in 0..ut_b.ncols() {
|
for i in 0..self.singular_values.len() {
|
||||||
let mut col = ut_b.column_mut(j);
|
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() {
|
Ok(v_t.tr_mul(&ut_b))
|
||||||
let val = self.singular_values[i];
|
|
||||||
if val > eps {
|
|
||||||
col[i] /= val;
|
|
||||||
} else {
|
|
||||||
col[i] = N::zero();
|
|
||||||
}
|
}
|
||||||
|
(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.
|
/// Computes the pseudo-inverse of this matrix.
|
||||||
///
|
///
|
||||||
/// All singular values below `eps` are considered equal to 0.
|
/// All singular values below `eps` are considered equal to 0.
|
||||||
pub fn pseudo_inverse(self, eps: N) -> MatrixMN<N, C, R>
|
pub fn pseudo_inverse(self, eps: N) -> Result<MatrixMN<N, C, R>, &'static str>
|
||||||
where DefaultAllocator: Allocator<N, C, R> {
|
where
|
||||||
|
DefaultAllocator: Allocator<N, C, R>,
|
||||||
|
{
|
||||||
SVD::new(self.clone_owned(), true, true).pseudo_inverse(eps)
|
SVD::new(self.clone_owned(), true, true).pseudo_inverse(eps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,304 @@
|
||||||
|
use alga::general::{ClosedAdd, ClosedMul};
|
||||||
|
use num::{One, Zero};
|
||||||
|
use std::ops::{Add, Mul};
|
||||||
|
|
||||||
|
use allocator::Allocator;
|
||||||
|
use constraint::{AreMultipliable, DimEq, ShapeConstraint};
|
||||||
|
use sparse::{CsMatrix, CsStorage, CsStorageMut, CsVector};
|
||||||
|
use storage::StorageMut;
|
||||||
|
use {DefaultAllocator, Dim, Scalar, Vector, VectorN, U1};
|
||||||
|
|
||||||
|
impl<N: Scalar, R: Dim, C: Dim, S: CsStorage<N, R, C>> CsMatrix<N, R, C, S> {
|
||||||
|
fn scatter<R2: Dim, C2: Dim>(
|
||||||
|
&self,
|
||||||
|
j: usize,
|
||||||
|
beta: N,
|
||||||
|
timestamps: &mut [usize],
|
||||||
|
timestamp: usize,
|
||||||
|
workspace: &mut [N],
|
||||||
|
mut nz: usize,
|
||||||
|
res: &mut CsMatrix<N, R2, C2>,
|
||||||
|
) -> usize
|
||||||
|
where
|
||||||
|
N: ClosedAdd + ClosedMul,
|
||||||
|
DefaultAllocator: Allocator<usize, C2>,
|
||||||
|
{
|
||||||
|
for (i, val) in self.data.column_entries(j) {
|
||||||
|
if timestamps[i] < timestamp {
|
||||||
|
timestamps[i] = timestamp;
|
||||||
|
res.data.i[nz] = i;
|
||||||
|
nz += 1;
|
||||||
|
workspace[i] = val * beta;
|
||||||
|
} else {
|
||||||
|
workspace[i] += val * beta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
impl<N: Scalar, R, S> CsVector<N, R, S> {
|
||||||
|
pub fn axpy(&mut self, alpha: N, x: CsVector<N, R, S>, beta: N) {
|
||||||
|
// First, compute the number of non-zero entries.
|
||||||
|
let mut nnzero = 0;
|
||||||
|
|
||||||
|
// Allocate a size large enough.
|
||||||
|
self.data.set_column_len(0, nnzero);
|
||||||
|
|
||||||
|
// Fill with the axpy.
|
||||||
|
let mut i = self.len();
|
||||||
|
let mut j = x.len();
|
||||||
|
let mut k = nnzero - 1;
|
||||||
|
let mut rid1 = self.data.row_index(0, i - 1);
|
||||||
|
let mut rid2 = x.data.row_index(0, j - 1);
|
||||||
|
|
||||||
|
while k > 0 {
|
||||||
|
if rid1 == rid2 {
|
||||||
|
self.data.set_row_index(0, k, rid1);
|
||||||
|
self[k] = alpha * x[j] + beta * self[k];
|
||||||
|
i -= 1;
|
||||||
|
j -= 1;
|
||||||
|
} else if rid1 < rid2 {
|
||||||
|
self.data.set_row_index(0, k, rid1);
|
||||||
|
self[k] = beta * self[i];
|
||||||
|
i -= 1;
|
||||||
|
} else {
|
||||||
|
self.data.set_row_index(0, k, rid2);
|
||||||
|
self[k] = alpha * x[j];
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl<N: Scalar + Zero + ClosedAdd + ClosedMul, D: Dim, S: StorageMut<N, D>> Vector<N, D, S> {
|
||||||
|
/// Perform a sparse axpy operation: `self = alpha * x + beta * self` operation.
|
||||||
|
pub fn axpy_cs<D2: Dim, S2>(&mut self, alpha: N, x: &CsVector<N, D2, S2>, beta: N)
|
||||||
|
where
|
||||||
|
S2: CsStorage<N, D2>,
|
||||||
|
ShapeConstraint: DimEq<D, D2>,
|
||||||
|
{
|
||||||
|
if beta.is_zero() {
|
||||||
|
for i in 0..x.len() {
|
||||||
|
unsafe {
|
||||||
|
let k = x.data.row_index_unchecked(i);
|
||||||
|
let y = self.vget_unchecked_mut(k);
|
||||||
|
*y = alpha * *x.data.get_value_unchecked(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Needed to be sure even components not present on `x` are multiplied.
|
||||||
|
*self *= beta;
|
||||||
|
|
||||||
|
for i in 0..x.len() {
|
||||||
|
unsafe {
|
||||||
|
let k = x.data.row_index_unchecked(i);
|
||||||
|
let y = self.vget_unchecked_mut(k);
|
||||||
|
*y += alpha * *x.data.get_value_unchecked(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn gemv_sparse<R2: Dim, C2: Dim, S2>(&mut self, alpha: N, a: &CsMatrix<N, R2, C2, S2>, x: &DVector<N>, beta: N)
|
||||||
|
where
|
||||||
|
S2: CsStorage<N, R2, C2> {
|
||||||
|
let col2 = a.column(0);
|
||||||
|
let val = unsafe { *x.vget_unchecked(0) };
|
||||||
|
self.axpy_sparse(alpha * val, &col2, beta);
|
||||||
|
|
||||||
|
for j in 1..ncols2 {
|
||||||
|
let col2 = a.column(j);
|
||||||
|
let val = unsafe { *x.vget_unchecked(j) };
|
||||||
|
|
||||||
|
self.axpy_sparse(alpha * val, &col2, N::one());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, N, R1, R2, C1, C2, S1, S2> Mul<&'b CsMatrix<N, R2, C2, S2>>
|
||||||
|
for &'a CsMatrix<N, R1, C1, S1>
|
||||||
|
where
|
||||||
|
N: Scalar + ClosedAdd + ClosedMul + Zero,
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S1: CsStorage<N, R1, C1>,
|
||||||
|
S2: CsStorage<N, R2, C2>,
|
||||||
|
ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
|
||||||
|
DefaultAllocator: Allocator<usize, C2> + Allocator<usize, R1> + Allocator<N, R1>,
|
||||||
|
{
|
||||||
|
type Output = CsMatrix<N, R1, C2>;
|
||||||
|
|
||||||
|
fn mul(self, rhs: &'b CsMatrix<N, R2, C2, S2>) -> CsMatrix<N, R1, C2> {
|
||||||
|
let (nrows1, ncols1) = self.data.shape();
|
||||||
|
let (nrows2, ncols2) = rhs.data.shape();
|
||||||
|
assert_eq!(
|
||||||
|
ncols1.value(),
|
||||||
|
nrows2.value(),
|
||||||
|
"Mismatched dimensions for matrix multiplication."
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
|
||||||
|
let mut workspace = VectorN::<N, R1>::zeros_generic(nrows1, U1);
|
||||||
|
let mut nz = 0;
|
||||||
|
|
||||||
|
for j in 0..ncols2.value() {
|
||||||
|
res.data.p[j] = nz;
|
||||||
|
let new_size_bound = nz + nrows1.value();
|
||||||
|
res.data.i.resize(new_size_bound, 0);
|
||||||
|
res.data.vals.resize(new_size_bound, N::zero());
|
||||||
|
|
||||||
|
for (i, beta) in rhs.data.column_entries(j) {
|
||||||
|
for (k, val) in self.data.column_entries(i) {
|
||||||
|
workspace[k] += val * beta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, val) in workspace.as_mut_slice().iter_mut().enumerate() {
|
||||||
|
if !val.is_zero() {
|
||||||
|
res.data.i[nz] = i;
|
||||||
|
res.data.vals[nz] = *val;
|
||||||
|
*val = N::zero();
|
||||||
|
nz += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: the following has a lower complexity, but is slower in many cases, likely because
|
||||||
|
// of branching inside of the inner loop.
|
||||||
|
//
|
||||||
|
// let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
|
||||||
|
// let mut timestamps = VectorN::zeros_generic(nrows1, U1);
|
||||||
|
// let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows1, U1) };
|
||||||
|
// let mut nz = 0;
|
||||||
|
//
|
||||||
|
// for j in 0..ncols2.value() {
|
||||||
|
// res.data.p[j] = nz;
|
||||||
|
// let new_size_bound = nz + nrows1.value();
|
||||||
|
// res.data.i.resize(new_size_bound, 0);
|
||||||
|
// res.data.vals.resize(new_size_bound, N::zero());
|
||||||
|
//
|
||||||
|
// for (i, val) in rhs.data.column_entries(j) {
|
||||||
|
// nz = self.scatter(
|
||||||
|
// i,
|
||||||
|
// val,
|
||||||
|
// timestamps.as_mut_slice(),
|
||||||
|
// j + 1,
|
||||||
|
// workspace.as_mut_slice(),
|
||||||
|
// nz,
|
||||||
|
// &mut res,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Keep the output sorted.
|
||||||
|
// let range = res.data.p[j]..nz;
|
||||||
|
// res.data.i[range.clone()].sort();
|
||||||
|
//
|
||||||
|
// for p in range {
|
||||||
|
// res.data.vals[p] = workspace[res.data.i[p]]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
res.data.i.truncate(nz);
|
||||||
|
res.data.i.shrink_to_fit();
|
||||||
|
res.data.vals.truncate(nz);
|
||||||
|
res.data.vals.shrink_to_fit();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, N, R1, R2, C1, C2, S1, S2> Add<&'b CsMatrix<N, R2, C2, S2>>
|
||||||
|
for &'a CsMatrix<N, R1, C1, S1>
|
||||||
|
where
|
||||||
|
N: Scalar + ClosedAdd + ClosedMul + One,
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S1: CsStorage<N, R1, C1>,
|
||||||
|
S2: CsStorage<N, R2, C2>,
|
||||||
|
ShapeConstraint: DimEq<R1, R2> + DimEq<C1, C2>,
|
||||||
|
DefaultAllocator: Allocator<usize, C2> + Allocator<usize, R1> + Allocator<N, R1>,
|
||||||
|
{
|
||||||
|
type Output = CsMatrix<N, R1, C2>;
|
||||||
|
|
||||||
|
fn add(self, rhs: &'b CsMatrix<N, R2, C2, S2>) -> CsMatrix<N, R1, C2> {
|
||||||
|
let (nrows1, ncols1) = self.data.shape();
|
||||||
|
let (nrows2, ncols2) = rhs.data.shape();
|
||||||
|
assert_eq!(
|
||||||
|
(nrows1.value(), ncols1.value()),
|
||||||
|
(nrows2.value(), ncols2.value()),
|
||||||
|
"Mismatched dimensions for matrix sum."
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
|
||||||
|
let mut timestamps = VectorN::zeros_generic(nrows1, U1);
|
||||||
|
let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows1, U1) };
|
||||||
|
let mut nz = 0;
|
||||||
|
|
||||||
|
for j in 0..ncols2.value() {
|
||||||
|
res.data.p[j] = nz;
|
||||||
|
|
||||||
|
nz = self.scatter(
|
||||||
|
j,
|
||||||
|
N::one(),
|
||||||
|
timestamps.as_mut_slice(),
|
||||||
|
j + 1,
|
||||||
|
workspace.as_mut_slice(),
|
||||||
|
nz,
|
||||||
|
&mut res,
|
||||||
|
);
|
||||||
|
|
||||||
|
nz = rhs.scatter(
|
||||||
|
j,
|
||||||
|
N::one(),
|
||||||
|
timestamps.as_mut_slice(),
|
||||||
|
j + 1,
|
||||||
|
workspace.as_mut_slice(),
|
||||||
|
nz,
|
||||||
|
&mut res,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Keep the output sorted.
|
||||||
|
let range = res.data.p[j]..nz;
|
||||||
|
res.data.i[range.clone()].sort();
|
||||||
|
|
||||||
|
for p in range {
|
||||||
|
res.data.vals[p] = workspace[res.data.i[p]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.data.i.truncate(nz);
|
||||||
|
res.data.i.shrink_to_fit();
|
||||||
|
res.data.vals.truncate(nz);
|
||||||
|
res.data.vals.shrink_to_fit();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, N, R, C, S> Mul<N> for CsMatrix<N, R, C, S>
|
||||||
|
where
|
||||||
|
N: Scalar + ClosedAdd + ClosedMul + Zero,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: CsStorageMut<N, R, C>,
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(mut self, rhs: N) -> Self {
|
||||||
|
for e in self.values_mut() {
|
||||||
|
*e *= rhs
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,283 @@
|
||||||
|
use allocator::Allocator;
|
||||||
|
use constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
|
use sparse::{CsMatrix, CsStorage, CsVector};
|
||||||
|
use storage::{Storage, StorageMut};
|
||||||
|
use {DefaultAllocator, Dim, Matrix, MatrixMN, Real, VectorN, U1};
|
||||||
|
|
||||||
|
impl<N: Real, D: Dim, S: CsStorage<N, D, D>> CsMatrix<N, D, D, S> {
|
||||||
|
/// Solve a lower-triangular system with a dense right-hand-side.
|
||||||
|
pub fn solve_lower_triangular<R2: Dim, C2: Dim, S2>(
|
||||||
|
&self,
|
||||||
|
b: &Matrix<N, R2, C2, S2>,
|
||||||
|
) -> Option<MatrixMN<N, R2, C2>>
|
||||||
|
where
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
DefaultAllocator: Allocator<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<D, R2>,
|
||||||
|
{
|
||||||
|
let mut b = b.clone_owned();
|
||||||
|
if self.solve_lower_triangular_mut(&mut b) {
|
||||||
|
Some(b)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solve a lower-triangular system with `self` transposed and a dense right-hand-side.
|
||||||
|
pub fn tr_solve_lower_triangular<R2: Dim, C2: Dim, S2>(
|
||||||
|
&self,
|
||||||
|
b: &Matrix<N, R2, C2, S2>,
|
||||||
|
) -> Option<MatrixMN<N, R2, C2>>
|
||||||
|
where
|
||||||
|
S2: Storage<N, R2, C2>,
|
||||||
|
DefaultAllocator: Allocator<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<D, R2>,
|
||||||
|
{
|
||||||
|
let mut b = b.clone_owned();
|
||||||
|
if self.tr_solve_lower_triangular_mut(&mut b) {
|
||||||
|
Some(b)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solve in-place a lower-triangular system with a dense right-hand-side.
|
||||||
|
pub fn solve_lower_triangular_mut<R2: Dim, C2: Dim, S2>(
|
||||||
|
&self,
|
||||||
|
b: &mut Matrix<N, R2, C2, S2>,
|
||||||
|
) -> bool
|
||||||
|
where
|
||||||
|
S2: StorageMut<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<D, R2>,
|
||||||
|
{
|
||||||
|
let (nrows, ncols) = self.data.shape();
|
||||||
|
assert_eq!(nrows.value(), ncols.value(), "The matrix must be square.");
|
||||||
|
assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions.");
|
||||||
|
|
||||||
|
for j2 in 0..b.ncols() {
|
||||||
|
let mut b = b.column_mut(j2);
|
||||||
|
|
||||||
|
for j in 0..ncols.value() {
|
||||||
|
let mut column = self.data.column_entries(j);
|
||||||
|
let mut diag_found = false;
|
||||||
|
|
||||||
|
while let Some((i, val)) = column.next() {
|
||||||
|
if i == j {
|
||||||
|
if val.is_zero() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
b[j] /= val;
|
||||||
|
diag_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !diag_found {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, val) in column {
|
||||||
|
b[i] -= b[j] * val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solve a lower-triangular system with `self` transposed and a dense right-hand-side.
|
||||||
|
pub fn tr_solve_lower_triangular_mut<R2: Dim, C2: Dim, S2>(
|
||||||
|
&self,
|
||||||
|
b: &mut Matrix<N, R2, C2, S2>,
|
||||||
|
) -> bool
|
||||||
|
where
|
||||||
|
S2: StorageMut<N, R2, C2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<D, R2>,
|
||||||
|
{
|
||||||
|
let (nrows, ncols) = self.data.shape();
|
||||||
|
assert_eq!(nrows.value(), ncols.value(), "The matrix must be square.");
|
||||||
|
assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions.");
|
||||||
|
|
||||||
|
for j2 in 0..b.ncols() {
|
||||||
|
let mut b = b.column_mut(j2);
|
||||||
|
|
||||||
|
for j in (0..ncols.value()).rev() {
|
||||||
|
let mut column = self.data.column_entries(j);
|
||||||
|
let mut diag = None;
|
||||||
|
|
||||||
|
while let Some((i, val)) = column.next() {
|
||||||
|
if i == j {
|
||||||
|
if val.is_zero() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
diag = Some(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(diag) = diag {
|
||||||
|
for (i, val) in column {
|
||||||
|
b[j] -= val * b[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
b[j] /= diag;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solve a lower-triangular system with a sparse right-hand-side.
|
||||||
|
pub fn solve_lower_triangular_cs<D2: Dim, S2>(
|
||||||
|
&self,
|
||||||
|
b: &CsVector<N, D2, S2>,
|
||||||
|
) -> Option<CsVector<N, D2>>
|
||||||
|
where
|
||||||
|
S2: CsStorage<N, D2>,
|
||||||
|
DefaultAllocator: Allocator<bool, D> + Allocator<N, D2> + Allocator<usize, D2>,
|
||||||
|
ShapeConstraint: SameNumberOfRows<D, D2>,
|
||||||
|
{
|
||||||
|
let mut reach = Vec::new();
|
||||||
|
// We don't compute a postordered reach here because it will be sorted after anyway.
|
||||||
|
self.lower_triangular_reach(b, &mut reach);
|
||||||
|
// We sort the reach so the result matrix has sorted indices.
|
||||||
|
reach.sort();
|
||||||
|
let mut workspace = unsafe { VectorN::new_uninitialized_generic(b.data.shape().0, U1) };
|
||||||
|
|
||||||
|
for i in reach.iter().cloned() {
|
||||||
|
workspace[i] = N::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, val) in b.data.column_entries(0) {
|
||||||
|
workspace[i] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in reach.iter().cloned() {
|
||||||
|
let mut column = self.data.column_entries(j);
|
||||||
|
let mut diag_found = false;
|
||||||
|
|
||||||
|
while let Some((i, val)) = column.next() {
|
||||||
|
if i == j {
|
||||||
|
if val.is_zero() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace[j] /= val;
|
||||||
|
diag_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !diag_found {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, val) in column {
|
||||||
|
workspace[i] -= workspace[j] * val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the result into a sparse vector.
|
||||||
|
let mut result = CsVector::new_uninitialized_generic(b.data.shape().0, U1, reach.len());
|
||||||
|
|
||||||
|
for (i, val) in reach.iter().zip(result.data.vals.iter_mut()) {
|
||||||
|
*val = workspace[*i];
|
||||||
|
}
|
||||||
|
|
||||||
|
result.data.i = reach;
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Computes the reachable, post-ordered, nodes from `b`.
|
||||||
|
fn lower_triangular_reach_postordered<D2: Dim, S2>(
|
||||||
|
&self,
|
||||||
|
b: &CsVector<N, D2, S2>,
|
||||||
|
xi: &mut Vec<usize>,
|
||||||
|
) where
|
||||||
|
S2: CsStorage<N, D2>,
|
||||||
|
DefaultAllocator: Allocator<bool, D>,
|
||||||
|
{
|
||||||
|
let mut visited = VectorN::repeat_generic(self.data.shape().1, U1, false);
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
for i in b.data.column_range(0) {
|
||||||
|
let row_index = b.data.row_index(i);
|
||||||
|
|
||||||
|
if !visited[row_index] {
|
||||||
|
let rng = self.data.column_range(row_index);
|
||||||
|
stack.push((row_index, rng));
|
||||||
|
self.lower_triangular_dfs(visited.as_mut_slice(), &mut stack, xi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_triangular_dfs(
|
||||||
|
&self,
|
||||||
|
visited: &mut [bool],
|
||||||
|
stack: &mut Vec<(usize, Range<usize>)>,
|
||||||
|
xi: &mut Vec<usize>,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
'recursion: while let Some((j, rng)) = stack.pop() {
|
||||||
|
visited[j] = true;
|
||||||
|
|
||||||
|
for i in rng.clone() {
|
||||||
|
let row_id = self.data.row_index(i);
|
||||||
|
if row_id > j && !visited[row_id] {
|
||||||
|
stack.push((j, (i + 1)..rng.end));
|
||||||
|
stack.push((row_id, self.data.column_range(row_id)));
|
||||||
|
continue 'recursion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xi.push(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Computes the nodes reachable from `b` in an arbitrary order.
|
||||||
|
fn lower_triangular_reach<D2: Dim, S2>(&self, b: &CsVector<N, D2, S2>, xi: &mut Vec<usize>)
|
||||||
|
where
|
||||||
|
S2: CsStorage<N, D2>,
|
||||||
|
DefaultAllocator: Allocator<bool, D>,
|
||||||
|
{
|
||||||
|
let mut visited = VectorN::repeat_generic(self.data.shape().1, U1, false);
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
for irow in b.data.column_row_indices(0) {
|
||||||
|
self.lower_triangular_bfs(irow, visited.as_mut_slice(), &mut stack, xi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_triangular_bfs(
|
||||||
|
&self,
|
||||||
|
start: usize,
|
||||||
|
visited: &mut [bool],
|
||||||
|
stack: &mut Vec<usize>,
|
||||||
|
xi: &mut Vec<usize>,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if !visited[start] {
|
||||||
|
stack.clear();
|
||||||
|
stack.push(start);
|
||||||
|
xi.push(start);
|
||||||
|
visited[start] = true;
|
||||||
|
|
||||||
|
while let Some(j) = stack.pop() {
|
||||||
|
for irow in self.data.column_row_indices(j) {
|
||||||
|
if irow > j && !visited[irow] {
|
||||||
|
stack.push(irow);
|
||||||
|
xi.push(irow);
|
||||||
|
visited[irow] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
use allocator::Allocator;
|
||||||
|
use {DefaultAllocator, Dim, VectorN};
|
||||||
|
|
||||||
|
pub fn cumsum<D: Dim>(a: &mut VectorN<usize, D>, b: &mut VectorN<usize, D>) -> usize
|
||||||
|
where DefaultAllocator: Allocator<usize, D> {
|
||||||
|
assert!(a.len() == b.len());
|
||||||
|
let mut sum = 0;
|
||||||
|
|
||||||
|
for i in 0..a.len() {
|
||||||
|
b[i] = sum;
|
||||||
|
sum += a[i];
|
||||||
|
a[i] = b[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
sum
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue