Merge branch 'master-public' into sparse

# Conflicts:
#	Cargo.toml
#	examples/matrix_construction.rs
#	nalgebra-glm/src/constructors.rs
#	nalgebra-glm/src/ext/matrix_clip_space.rs
#	nalgebra-glm/src/ext/matrix_transform.rs
#	nalgebra-glm/src/ext/mod.rs
#	nalgebra-glm/src/ext/quaternion_common.rs
#	nalgebra-glm/src/gtx/quaternion.rs
#	nalgebra-glm/src/gtx/rotate_vector.rs
#	nalgebra-glm/src/lib.rs
#	nalgebra-glm/src/traits.rs
#	nalgebra-lapack/src/cholesky.rs
#	nalgebra-lapack/src/eigen.rs
#	nalgebra-lapack/src/hessenberg.rs
#	nalgebra-lapack/src/lu.rs
#	nalgebra-lapack/src/qr.rs
#	nalgebra-lapack/src/schur.rs
#	nalgebra-lapack/src/svd.rs
#	nalgebra-lapack/src/symmetric_eigen.rs
#	rustfmt.toml
#	src/base/array_storage.rs
#	src/base/blas.rs
#	src/base/cg.rs
#	src/base/default_allocator.rs
#	src/base/edition.rs
#	src/base/iter.rs
#	src/base/matrix.rs
#	src/base/swizzle.rs
#	src/base/vec_storage.rs
#	src/geometry/mod.rs
#	src/geometry/point_construction.rs
#	src/geometry/quaternion.rs
#	src/geometry/similarity.rs
#	src/geometry/translation.rs
#	src/geometry/unit_complex_construction.rs
#	src/linalg/bidiagonal.rs
#	src/linalg/cholesky.rs
#	src/linalg/full_piv_lu.rs
#	src/linalg/hessenberg.rs
#	src/linalg/lu.rs
#	src/linalg/permutation_sequence.rs
#	src/linalg/qr.rs
#	src/linalg/schur.rs
#	src/linalg/svd.rs
#	src/linalg/symmetric_eigen.rs
#	src/linalg/symmetric_tridiagonal.rs
#	tests/geometry/point.rs
#	tests/geometry/quaternion.rs
#	tests/lib.rs
#	tests/linalg/eigen.rs
#	tests/linalg/svd.rs
This commit is contained in:
sebcrozet 2019-02-03 12:53:41 +01:00
commit fc24db8ff3
132 changed files with 7635 additions and 1773 deletions

View File

@ -7,18 +7,53 @@ 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.
* Add `.slerp` and `.try_slerp` to unit vectors. * Add `.slerp` and `.try_slerp` to unit vectors.
* Add `.lerp` to vectors.
* Add `.to_projective` and `.as_projective` to `Perspective3` and `Orthographic3` in order to * Add `.to_projective` and `.as_projective` to `Perspective3` and `Orthographic3` in order to
use them as `Projective3` structures. use them as `Projective3` structures.
* Add `From/Into` impls to allow the conversion of any transformation type to a matrix. * Add `From/Into` impls to allow the conversion of any transformation type to a matrix.
* Add `Into` impls to convert a matrix slice into an owned matrix. * Add `Into` impls to convert a matrix slice into an owned matrix.
* Add `Point*::from_slice` to create a point from a slice. * Add `Point*::from_slice` to create a point from a slice.
* Add `.map_with_location` to matrices to apply a map which passes the component indices to the user-defined closure alongide * Add `.map_with_location` to matrices to apply a map which passes the component indices to the user-defined closure alongside
the component itself. the component itself.
* Add impl `From<Vector>` for `Point`.
* Add impl `From<Vector4>` for `Quaternion`.
* Add impl `From<Vector>` for `Translation`.
* Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec`
as-is for its storage).
* Add `.to_homogeneous` to square matrices (and with dimensions higher than 1x1). This will increase their number of row
and columns by 1. The new column and row are filled with 0, except for the diagonal element which is set to 1.
* Implement `Extend<Vec>` for matrices with a dynamic storage. The provided `Vec` is assumed to represent a column-major
matrix with the same number of rows as the one being extended. This will effectively append new columns on the right of
the matrix being extended.
* Implement `Extend<Vec>` for vectors with a dynamic storage. This will concatenate the vector with the given `Vec`.
* Implement `Extend<Matrix<...>>` for matrices with dynamic storage. This will concatenate the columns of both matrices.
* Implement `Into<Vec>` for the `MatrixVec` storage.
* Implement `Hash` for all matrices.
* Add a `.len()` method to retrieve the size of a `MatrixVec`.
### Modified
* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The
only restriction now ith that they must not be equal (in which case the projection would be singular).
* The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead.
* The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not have to
explicitly import the `Transform` trait from the alga crate.
* Renamed the matrix storage types: `MatrixArray` -> `ArrayStorage` and `MatrixVec` -> `VecStorage`.
* Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type.
This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`.
* Deprecate several functions at the root of the crate (replaced by methods).
### Removed
* Remove the `Deref` impl for `MatrixVec` as it could cause hard-to-understand compilation errors.
### nalgebra-glm
* Add several alternative projection computations, e.g., `ortho_lh`, `ortho_lh_no`, `perspective_lh`, etc.
* Add features matching those of nalgebra, in particular: `serde-serialize`, `abmonation-serialize`, std` (enabled by default).
## [0.16.0] ## [0.16.0]
All dependencies have been updated to their latest versions. All dependencies have been updated to their latest versions.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra" name = "nalgebra"
version = "0.16.12" 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."
@ -30,23 +30,24 @@ 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.7", 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.7", optional = true }
pest = { version = "2.0", optional = true } pest = { version = "2.0", optional = true }
pest_derive = { version = "2.0", optional = true } pest_derive = { version = "2.0", optional = true }
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" serde_json = "1.0"
rand_xorshift = "0.1"
[workspace] [workspace]
members = [ "nalgebra-lapack", "nalgebra-glm" ] members = [ "nalgebra-lapack", "nalgebra-glm" ]

View File

@ -2,6 +2,9 @@
<img src="http://nalgebra.org/img/logo_nalgebra.svg" alt="crates.io"> <img src="http://nalgebra.org/img/logo_nalgebra.svg" alt="crates.io">
</p> </p>
<p align="center"> <p align="center">
<a href="https://discord.gg/vt9DJSW">
<img src="https://img.shields.io/discord/507548572338880513.svg?logo=discord&colorB=7289DA">
</a>
<a href="https://travis-ci.org/rustsim/nalgebra"> <a href="https://travis-ci.org/rustsim/nalgebra">
<img src="https://travis-ci.org/rustsim/nalgebra.svg?branch=master" alt="Build status"> <img src="https://travis-ci.org/rustsim/nalgebra.svg?branch=master" alt="Build status">
</a> </a>

View File

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

View File

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

View File

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

View File

@ -0,0 +1,39 @@
#![cfg_attr(rustfmt, rustfmt_skip)]
#[macro_use]
extern crate approx; // for assert_relative_eq
extern crate nalgebra as na;
use na::{Matrix4, Matrix4x3, Vector4};
fn main() {
let a = Matrix4::new(
1.0, 1.0, 2.0, -5.0,
2.0, 5.0, -1.0, -9.0,
2.0, 1.0, -1.0, 3.0,
1.0, 3.0, 2.0, 7.0,
);
let mut b = Vector4::new(3.0, -3.0, -11.0, -5.0);
let decomp = a.lu();
let x = decomp.solve(&b).expect("Linear resolution failed.");
assert_relative_eq!(a * x, b);
/*
* It is possible to perform the resolution in-place.
* This is particularly useful to avoid allocations when
* `b` is a `DVector` or a `DMatrix`.
*/
assert!(decomp.solve_mut(&mut b), "Linear resolution failed.");
assert_relative_eq!(x, b);
/*
* It is possible to solve multiple systems
* simultaneously by using a matrix for `b`.
*/
let b = Matrix4x3::new(
3.0, 2.0, 0.0,
-3.0, 0.0, 0.0,
-11.0, 5.0, -3.0,
-5.0, 10.0, 4.0,
);
let x = decomp.solve(&b).expect("Linear resolution failed.");
assert_relative_eq!(a * x, b);
}

View File

@ -8,7 +8,7 @@ fn main() {
// Build from a coordinates vector. // Build from a coordinates vector.
let coords = Vector3::new(2.0, 3.0, 4.0); let coords = Vector3::new(2.0, 3.0, 4.0);
let p1 = Point3::from_coordinates(coords); let p1 = Point3::from(coords);
// Build by translating the origin. // Build by translating the origin.
let translation = Vector3::new(2.0, 3.0, 4.0); let translation = Vector3::new(2.0, 3.0, 4.0);

View File

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

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-glm" name = "nalgebra-glm"
version = "0.1.3" 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.7", default-features = false }
nalgebra = { path = "..", version = "^0.16.4" } nalgebra = { path = "..", version = "^0.16.13", default-features = false }

View File

@ -315,13 +315,151 @@ where DefaultAllocator: Alloc<f32, D> {
// x * (exp).exp2() // x * (exp).exp2()
//} //}
/// Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of x and y using the floating-point value a. /// Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of the scalars x and y using the scalar value a.
/// ///
/// The value for a is not restricted to the range `[0, 1]`. /// The value for a is not restricted to the range `[0, 1]`.
pub fn mix<N: Number>(x: N, y: N, a: N) -> N { ///
/// # Examples:
///
/// ```
/// # use nalgebra_glm as glm;
/// assert_eq!(glm::mix_scalar(2.0, 20.0, 0.1), 3.8);
/// ```
///
/// # See also:
///
/// * [`mix`](fn.mix.html)
/// * [`mix_vec`](fn.mix_vec.html)
pub fn mix_scalar<N: Number>(x: N, y: N, a: N) -> N {
x * (N::one() - a) + y * a x * (N::one() - a) + y * a
} }
/// Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of the vectors x and y using the scalar value a.
///
/// The value for a is not restricted to the range `[0, 1]`.
///
/// # Examples:
///
/// ```
/// # use nalgebra_glm as glm;
/// let x = glm::vec3(1.0, 2.0, 3.0);
/// let y = glm::vec3(10.0, 20.0, 30.0);
/// assert_eq!(glm::mix(&x, &y, 0.1), glm::vec3(1.9, 3.8, 5.7));
/// ```
///
/// # See also:
///
/// * [`mix_scalar`](fn.mix_scalar.html)
/// * [`mix_vec`](fn.mix_vec.html)
pub fn mix<N: Number, D: Dimension>(x: &TVec<N, D>, y: &TVec<N, D>, a: N) -> TVec<N, D>
where DefaultAllocator: Alloc<N, D> {
x * (N::one() - a) + y * a
}
/// Returns `x * (1.0 - a) + y * a`, i.e., the component-wise linear blend of `x` and `y` using the components of
/// the vector `a` as coefficients.
///
/// The value for a is not restricted to the range `[0, 1]`.
///
/// # Examples:
///
/// ```
/// # use nalgebra_glm as glm;
/// let x = glm::vec3(1.0, 2.0, 3.0);
/// let y = glm::vec3(10.0, 20.0, 30.0);
/// let a = glm::vec3(0.1, 0.2, 0.3);
/// assert_eq!(glm::mix_vec(&x, &y, &a), glm::vec3(1.9, 5.6, 11.1));
/// ```
///
/// # See also:
///
/// * [`mix_scalar`](fn.mix_scalar.html)
/// * [`mix`](fn.mix.html)
pub fn mix_vec<N: Number, D: Dimension>(
x: &TVec<N, D>,
y: &TVec<N, D>,
a: &TVec<N, D>,
) -> TVec<N, D>
where
DefaultAllocator: Alloc<N, D>,
{
x.component_mul(&(TVec::<N, D>::repeat(N::one()) - a)) + y.component_mul(&a)
}
/// Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of the scalars x and y using the scalar value a.
///
/// The value for a is not restricted to the range `[0, 1]`.
/// This is an alias for `mix_scalar`.
///
/// # Examples:
///
/// ```
/// # use nalgebra_glm as glm;
/// assert_eq!(glm::lerp_scalar(2.0, 20.0, 0.1), 3.8);
/// ```
///
/// # See also:
///
/// * [`lerp`](fn.lerp.html)
/// * [`lerp_vec`](fn.lerp_vec.html)
pub fn lerp_scalar<N: Number>(x: N, y: N, a: N) -> N {
mix_scalar(x, y, a)
}
/// Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of the vectors x and y using the scalar value a.
///
/// The value for a is not restricted to the range `[0, 1]`.
/// This is an alias for `mix`.
///
/// # Examples:
///
/// ```
/// # use nalgebra_glm as glm;
/// let x = glm::vec3(1.0, 2.0, 3.0);
/// let y = glm::vec3(10.0, 20.0, 30.0);
/// assert_eq!(glm::lerp(&x, &y, 0.1), glm::vec3(1.9, 3.8, 5.7));
/// ```
///
/// # See also:
///
/// * [`lerp_scalar`](fn.lerp_scalar.html)
/// * [`lerp_vec`](fn.lerp_vec.html)
pub fn lerp<N: Number, D: Dimension>(x: &TVec<N, D>, y: &TVec<N, D>, a: N) -> TVec<N, D>
where DefaultAllocator: Alloc<N, D> {
mix(x, y, a)
}
/// Returns `x * (1.0 - a) + y * a`, i.e., the component-wise linear blend of `x` and `y` using the components of
/// the vector `a` as coefficients.
///
/// The value for a is not restricted to the range `[0, 1]`.
/// This is an alias for `mix_vec`.
///
/// # Examples:
///
/// ```
/// # use nalgebra_glm as glm;
/// let x = glm::vec3(1.0, 2.0, 3.0);
/// let y = glm::vec3(10.0, 20.0, 30.0);
/// let a = glm::vec3(0.1, 0.2, 0.3);
/// assert_eq!(glm::lerp_vec(&x, &y, &a), glm::vec3(1.9, 5.6, 11.1));
/// ```
///
/// # See also:
///
/// * [`lerp_scalar`](fn.lerp_scalar.html)
/// * [`lerp`](fn.lerp.html)
pub fn lerp_vec<N: Number, D: Dimension>(
x: &TVec<N, D>,
y: &TVec<N, D>,
a: &TVec<N, D>,
) -> TVec<N, D>
where
DefaultAllocator: Alloc<N, D>,
{
mix_vec(x, y, a)
}
/// Component-wise modulus. /// Component-wise modulus.
/// ///
/// Returns `x - y * floor(x / y)` for each component in `x` using the corresponding component of `y`. /// Returns `x - y * floor(x / y)` for each component in `x` using the corresponding component of `y`.

View File

@ -1,8 +1,9 @@
use aliases::{ #![cfg_attr(rustfmt, rustfmt_skip)]
Qua, TMat, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3, TVec1,
TVec2, TVec3, TVec4, use na::{Scalar, Real, U2, U3, U4};
}; use aliases::{TMat, Qua, TVec1, TVec2, TVec3, TVec4, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4,
use na::{Real, Scalar, U2, U3, U4}; TMat4, TMat4x2, TMat4x3};
/// Creates a new 1D vector. /// Creates a new 1D vector.
/// ///
@ -33,173 +34,136 @@ pub fn vec4<N: Scalar>(x: N, y: N, z: N, w: N) -> TVec4<N> {
TVec4::new(x, y, z, w) TVec4::new(x, y, z, w)
} }
/// Create a new 2x2 matrix. /// Create a new 2x2 matrix.
pub fn mat2<N: Scalar>(m11: N, m12: N, m21: N, m22: N) -> TMat2<N> { pub fn mat2<N: Scalar>(m11: N, m12: N,
TMat::<N, U2, U2>::new(m11, m12, m21, m22) m21: N, m22: N) -> TMat2<N> {
TMat::<N, U2, U2>::new(
m11, m12,
m21, m22,
)
} }
/// Create a new 2x2 matrix. /// Create a new 2x2 matrix.
pub fn mat2x2<N: Scalar>(m11: N, m12: N, m21: N, m22: N) -> TMat2<N> { pub fn mat2x2<N: Scalar>(m11: N, m12: N,
TMat::<N, U2, U2>::new(m11, m12, m21, m22) m21: N, m22: N) -> TMat2<N> {
TMat::<N, U2, U2>::new(
m11, m12,
m21, m22,
)
} }
/// Create a new 2x3 matrix. /// Create a new 2x3 matrix.
pub fn mat2x3<N: Scalar>(m11: N, m12: N, m13: N, m21: N, m22: N, m23: N) -> TMat2x3<N> { pub fn mat2x3<N: Scalar>(m11: N, m12: N, m13: N,
TMat::<N, U2, U3>::new(m11, m12, m13, m21, m22, m23) m21: N, m22: N, m23: N) -> TMat2x3<N> {
TMat::<N, U2, U3>::new(
m11, m12, m13,
m21, m22, m23,
)
} }
/// Create a new 2x4 matrix. /// Create a new 2x4 matrix.
pub fn mat2x4<N: Scalar>( pub fn mat2x4<N: Scalar>(m11: N, m12: N, m13: N, m14: N,
m11: N, m21: N, m22: N, m23: N, m24: N) -> TMat2x4<N> {
m12: N, TMat::<N, U2, U4>::new(
m13: N, m11, m12, m13, m14,
m14: N, m21, m22, m23, m24,
m21: N, )
m22: N,
m23: N,
m24: N,
) -> TMat2x4<N>
{
TMat::<N, U2, U4>::new(m11, m12, m13, m14, m21, m22, m23, m24)
} }
/// Create a new 3x3 matrix. /// Create a new 3x3 matrix.
pub fn mat3<N: Scalar>( pub fn mat3<N: Scalar>(m11: N, m12: N, m13: N,
m11: N, m21: N, m22: N, m23: N,
m12: N, m31: N, m32: N, m33: N) -> TMat3<N> {
m13: N, TMat::<N, U3, U3>::new(
m21: N, m11, m12, m13,
m22: N, m21, m22, m23,
m23: N, m31, m32, m33,
m31: N, )
m32: N,
m33: N,
) -> TMat3<N>
{
TMat::<N, U3, U3>::new(m11, m12, m13, m21, m22, m23, m31, m32, m33)
} }
/// Create a new 3x2 matrix. /// Create a new 3x2 matrix.
pub fn mat3x2<N: Scalar>(m11: N, m12: N, m21: N, m22: N, m31: N, m32: N) -> TMat3x2<N> { pub fn mat3x2<N: Scalar>(m11: N, m12: N,
TMat::<N, U3, U2>::new(m11, m12, m21, m22, m31, m32) m21: N, m22: N,
m31: N, m32: N) -> TMat3x2<N> {
TMat::<N, U3, U2>::new(
m11, m12,
m21, m22,
m31, m32,
)
} }
/// Create a new 3x3 matrix. /// Create a new 3x3 matrix.
pub fn mat3x3<N: Scalar>( pub fn mat3x3<N: Scalar>(m11: N, m12: N, m13: N,
m11: N, m21: N, m22: N, m23: N,
m12: N, m31: N, m32: N, m33: N) -> TMat3<N> {
m13: N, TMat::<N, U3, U3>::new(
m21: N, m11, m12, m13,
m22: N, m31, m32, m33,
m23: N, m21, m22, m23,
m31: N, )
m32: N,
m33: N,
) -> TMat3<N>
{
TMat::<N, U3, U3>::new(m11, m12, m13, m31, m32, m33, m21, m22, m23)
} }
/// Create a new 3x4 matrix. /// Create a new 3x4 matrix.
pub fn mat3x4<N: Scalar>( pub fn mat3x4<N: Scalar>(m11: N, m12: N, m13: N, m14: N,
m11: N, m21: N, m22: N, m23: N, m24: N,
m12: N, m31: N, m32: N, m33: N, m34: N) -> TMat3x4<N> {
m13: N, TMat::<N, U3, U4>::new(
m14: N, m11, m12, m13, m14,
m21: N, m21, m22, m23, m24,
m22: N, m31, m32, m33, m34,
m23: N, )
m24: N,
m31: N,
m32: N,
m33: N,
m34: N,
) -> TMat3x4<N>
{
TMat::<N, U3, U4>::new(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34)
} }
/// Create a new 4x2 matrix. /// Create a new 4x2 matrix.
pub fn mat4x2<N: Scalar>( pub fn mat4x2<N: Scalar>(m11: N, m12: N,
m11: N, m21: N, m22: N,
m12: N, m31: N, m32: N,
m21: N, m41: N, m42: N) -> TMat4x2<N> {
m22: N, TMat::<N, U4, U2>::new(
m31: N, m11, m12,
m32: N, m21, m22,
m41: N, m31, m32,
m42: N, m41, m42,
) -> TMat4x2<N> )
{
TMat::<N, U4, U2>::new(m11, m12, m21, m22, m31, m32, m41, m42)
} }
/// Create a new 4x3 matrix. /// Create a new 4x3 matrix.
pub fn mat4x3<N: Scalar>( pub fn mat4x3<N: Scalar>(m11: N, m12: N, m13: N,
m11: N, m21: N, m22: N, m23: N,
m12: N, m31: N, m32: N, m33: N,
m13: N, m41: N, m42: N, m43: N) -> TMat4x3<N> {
m21: N, TMat::<N, U4, U3>::new(
m22: N, m11, m12, m13,
m23: N, m21, m22, m23,
m31: N, m31, m32, m33,
m32: N, m41, m42, m43,
m33: N,
m41: N,
m42: N,
m43: N,
) -> TMat4x3<N>
{
TMat::<N, U4, U3>::new(m11, m12, m13, m21, m22, m23, m31, m32, m33, m41, m42, m43)
}
/// Create a new 4x4 matrix.
pub fn mat4x4<N: Scalar>(
m11: N,
m12: N,
m13: N,
m14: N,
m21: N,
m22: N,
m23: N,
m24: N,
m31: N,
m32: N,
m33: N,
m34: N,
m41: N,
m42: N,
m43: N,
m44: N,
) -> TMat4<N>
{
TMat::<N, U4, U4>::new(
m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44,
) )
} }
/// Create a new 4x4 matrix. /// Create a new 4x4 matrix.
pub fn mat4<N: Scalar>( pub fn mat4x4<N: Scalar>(m11: N, m12: N, m13: N, m14: N,
m11: N, m21: N, m22: N, m23: N, m24: N,
m12: N, m31: N, m32: N, m33: N, m34: N,
m13: N, m41: N, m42: N, m43: N, m44: N) -> TMat4<N> {
m14: N,
m21: N,
m22: N,
m23: N,
m24: N,
m31: N,
m32: N,
m33: N,
m34: N,
m41: N,
m42: N,
m43: N,
m44: N,
) -> TMat4<N>
{
TMat::<N, U4, U4>::new( TMat::<N, U4, U4>::new(
m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44, m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44,
)
}
/// Create a new 4x4 matrix.
pub fn mat4<N: Scalar>(m11: N, m12: N, m13: N, m14: N,
m21: N, m22: N, m23: N, m24: N,
m31: N, m32: N, m33: N, m34: N,
m41: N, m42: N, m43: N, m44: N) -> TMat4<N> {
TMat::<N, U4, U4>::new(
m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44,
) )
} }

View File

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

View File

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

View File

@ -38,11 +38,7 @@ pub fn look_at<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMa
/// * [`look_at`](fn.look_at.html) /// * [`look_at`](fn.look_at.html)
/// * [`look_at_rh`](fn.look_at_rh.html) /// * [`look_at_rh`](fn.look_at_rh.html)
pub fn look_at_lh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> { pub fn look_at_lh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
TMat::look_at_lh( TMat::look_at_lh(&Point3::from(*eye), &Point3::from(*center), up)
&Point3::from_coordinates(*eye),
&Point3::from_coordinates(*center),
up,
)
} }
/// Build a right handed look at view matrix. /// Build a right handed look at view matrix.
@ -58,11 +54,7 @@ pub fn look_at_lh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) ->
/// * [`look_at`](fn.look_at.html) /// * [`look_at`](fn.look_at.html)
/// * [`look_at_lh`](fn.look_at_lh.html) /// * [`look_at_lh`](fn.look_at_lh.html)
pub fn look_at_rh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> { pub fn look_at_rh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
TMat::look_at_rh( TMat::look_at_rh(&Point3::from(*eye), &Point3::from(*center), up)
&Point3::from_coordinates(*eye),
&Point3::from_coordinates(*center),
up,
)
} }
/// Builds a rotation 4 * 4 matrix created from an axis vector and an angle and right-multiply it to `m`. /// Builds a rotation 4 * 4 matrix created from an axis vector and an angle and right-multiply it to `m`.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -113,7 +113,7 @@ pub fn mat4_to_mat2<N: Scalar>(m: &TMat4<N>) -> TMat2<N> {
/// Creates a quaternion from a slice arranged as `[x, y, z, w]`. /// Creates a quaternion from a slice arranged as `[x, y, z, w]`.
pub fn make_quat<N: Real>(ptr: &[N]) -> Qua<N> { pub fn make_quat<N: Real>(ptr: &[N]) -> Qua<N> {
Quaternion::from_vector(TVec4::from_column_slice(ptr)) Quaternion::from(TVec4::from_column_slice(ptr))
} }
/// Creates a 1D vector from a slice. /// Creates a 1D vector from a slice.

View File

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

View File

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

View File

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

View File

@ -111,6 +111,7 @@
*/ */
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")] #![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]
@ -122,8 +123,9 @@ pub use aliases::*;
pub use common::{ pub use common::{
abs, ceil, clamp, clamp_scalar, clamp_vec, float_bits_to_int, float_bits_to_int_vec, abs, ceil, clamp, clamp_scalar, clamp_vec, float_bits_to_int, float_bits_to_int_vec,
float_bits_to_uint, float_bits_to_uint_vec, floor, fract, int_bits_to_float, float_bits_to_uint, float_bits_to_uint_vec, floor, fract, int_bits_to_float,
int_bits_to_float_vec, mix, modf, modf_vec, round, sign, smoothstep, step, step_scalar, int_bits_to_float_vec, lerp, lerp_scalar, lerp_vec, mix, mix_scalar, mix_vec, modf, modf_vec,
step_vec, trunc, uint_bits_to_float, uint_bits_to_float_scalar, round, sign, smoothstep, step, step_scalar, step_vec, trunc, uint_bits_to_float,
uint_bits_to_float_scalar,
}; };
pub use constructors::*; pub use constructors::*;
pub use exponential::{exp, exp2, inversesqrt, log, log2, pow, sqrt}; pub use exponential::{exp, exp2, inversesqrt, log, log2, pow, sqrt};
@ -143,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,

View File

@ -17,8 +17,7 @@ pub trait Number:
impl<T: Scalar + Ring + Lattice + AbsDiffEq<Epsilon = Self> + Signed + FromPrimitive + Bounded> impl<T: Scalar + Ring + Lattice + AbsDiffEq<Epsilon = Self> + Signed + FromPrimitive + Bounded>
Number for T Number for T
{ {}
}
#[doc(hidden)] #[doc(hidden)]
pub trait Alloc<N: Scalar, R: Dimension, C: Dimension = U1>: pub trait Alloc<N: Scalar, R: Dimension, C: Dimension = U1>:
@ -77,5 +76,4 @@ impl<N: Scalar, R: Dimension, C: Dimension, T> Alloc<N, R, C> for T where T: All
+ Allocator<i16, C> + Allocator<i16, C>
+ Allocator<(usize, usize), R> + Allocator<(usize, usize), R>
+ Allocator<(usize, usize), C> + Allocator<(usize, usize), C>
{ {}
}

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

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

View File

@ -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.7"
approx = "0.3" approx = "0.3"
rand = "0.5" rand = "0.6"

View File

@ -15,13 +15,17 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, D>, serde(bound(
MatrixN<N, D>: Serialize")) serialize = "DefaultAllocator: Allocator<N, D>,
MatrixN<N, D>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, D>, serde(bound(
MatrixN<N, D>: Deserialize<'de>")) deserialize = "DefaultAllocator: Allocator<N, D>,
MatrixN<N, D>: Deserialize<'de>"
))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Cholesky<N: Scalar, D: Dim> pub struct Cholesky<N: Scalar, D: Dim>
@ -34,8 +38,7 @@ impl<N: Scalar, D: Dim> Copy for Cholesky<N, D>
where where
DefaultAllocator: Allocator<N, D, D>, DefaultAllocator: Allocator<N, D, D>,
MatrixN<N, D>: Copy, MatrixN<N, D>: Copy,
{ {}
}
impl<N: CholeskyScalar + Zero, D: Dim> Cholesky<N, D> impl<N: CholeskyScalar + Zero, D: Dim> Cholesky<N, D>
where DefaultAllocator: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>
@ -157,7 +160,7 @@ where DefaultAllocator: Allocator<N, D, D>
// Copy lower triangle to upper triangle. // Copy lower triangle to upper triangle.
for i in 0..dim { for i in 0..dim {
for j in i + 1..dim { for j in i + 1..dim {
unsafe { *self.l.get_unchecked_mut(i, j) = *self.l.get_unchecked(j, i) }; unsafe { *self.l.get_unchecked_mut((i, j)) = *self.l.get_unchecked((j, i)) };
} }
} }

View File

@ -18,19 +18,19 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde( serde(bound(
bound(serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>, serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize, VectorN<N, D>: Serialize,
MatrixN<N, D>: Serialize") MatrixN<N, D>: Serialize"
) ))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde( serde(bound(
bound(deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>, deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize, VectorN<N, D>: Serialize,
MatrixN<N, D>: Deserialize<'de>") MatrixN<N, D>: Deserialize<'de>"
) ))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Eigen<N: Scalar, D: Dim> pub struct Eigen<N: Scalar, D: Dim>
@ -49,8 +49,7 @@ where
DefaultAllocator: Allocator<N, D> + Allocator<N, D, D>, DefaultAllocator: Allocator<N, D> + Allocator<N, D, D>,
VectorN<N, D>: Copy, VectorN<N, D>: Copy,
MatrixN<N, D>: Copy, MatrixN<N, D>: Copy,
{ {}
}
impl<N: EigenScalar + Real, D: Dim> Eigen<N, D> impl<N: EigenScalar + Real, D: Dim> Eigen<N, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>

View File

@ -13,17 +13,21 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, D, D> + serde(bound(
serialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, DimDiff<D, U1>>, Allocator<N, DimDiff<D, U1>>,
MatrixN<N, D>: Serialize, MatrixN<N, D>: Serialize,
VectorN<N, DimDiff<D, U1>>: Serialize")) VectorN<N, DimDiff<D, U1>>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, D, D> + serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, DimDiff<D, U1>>, Allocator<N, DimDiff<D, U1>>,
MatrixN<N, D>: Deserialize<'de>, MatrixN<N, D>: Deserialize<'de>,
VectorN<N, DimDiff<D, U1>>: Deserialize<'de>")) VectorN<N, DimDiff<D, U1>>: Deserialize<'de>"
))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Hessenberg<N: Scalar, D: DimSub<U1>> pub struct Hessenberg<N: Scalar, D: DimSub<U1>>
@ -38,8 +42,7 @@ where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>, DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>,
MatrixN<N, D>: Copy, MatrixN<N, D>: Copy,
VectorN<N, DimDiff<D, U1>>: Copy, VectorN<N, DimDiff<D, U1>>: Copy,
{ {}
}
impl<N: HessenbergScalar + Zero, D: DimSub<U1>> Hessenberg<N, D> impl<N: HessenbergScalar + Zero, D: DimSub<U1>> Hessenberg<N, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>> where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>

View File

@ -20,17 +20,21 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, R, C> + serde(bound(
serialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<i32, DimMinimum<R, C>>, Allocator<i32, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Serialize, MatrixMN<N, R, C>: Serialize,
PermutationSequence<DimMinimum<R, C>>: Serialize")) PermutationSequence<DimMinimum<R, C>>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, R, C> + serde(bound(
deserialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<i32, DimMinimum<R, C>>, Allocator<i32, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Deserialize<'de>, MatrixMN<N, R, C>: Deserialize<'de>,
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>")) PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"
))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct LU<N: Scalar, R: DimMin<C>, C: Dim> pub struct LU<N: Scalar, R: DimMin<C>, C: Dim>
@ -45,8 +49,7 @@ where
DefaultAllocator: Allocator<N, R, C> + Allocator<i32, DimMinimum<R, C>>, DefaultAllocator: Allocator<N, R, C> + Allocator<i32, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Copy, MatrixMN<N, R, C>: Copy,
VectorN<i32, DimMinimum<R, C>>: Copy, VectorN<i32, DimMinimum<R, C>>: Copy,
{ {}
}
impl<N: LUScalar, R: Dim, C: Dim> LU<N, R, C> impl<N: LUScalar, R: Dim, C: Dim> LU<N, R, C>
where where

View File

@ -16,17 +16,21 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, R, C> + serde(bound(
serialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<N, DimMinimum<R, C>>, Allocator<N, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Serialize, MatrixMN<N, R, C>: Serialize,
VectorN<N, DimMinimum<R, C>>: Serialize")) VectorN<N, DimMinimum<R, C>>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, R, C> + serde(bound(
deserialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<N, DimMinimum<R, C>>, Allocator<N, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Deserialize<'de>, MatrixMN<N, R, C>: Deserialize<'de>,
VectorN<N, DimMinimum<R, C>>: Deserialize<'de>")) VectorN<N, DimMinimum<R, C>>: Deserialize<'de>"
))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct QR<N: Scalar, R: DimMin<C>, C: Dim> pub struct QR<N: Scalar, R: DimMin<C>, C: Dim>
@ -41,8 +45,7 @@ where
DefaultAllocator: Allocator<N, R, C> + Allocator<N, DimMinimum<R, C>>, DefaultAllocator: Allocator<N, R, C> + Allocator<N, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Copy, MatrixMN<N, R, C>: Copy,
VectorN<N, DimMinimum<R, C>>: Copy, VectorN<N, DimMinimum<R, C>>: Copy,
{ {}
}
impl<N: QRScalar + Zero, R: DimMin<C>, C: Dim> QR<N, R, C> impl<N: QRScalar + Zero, R: DimMin<C>, C: Dim> QR<N, R, C>
where DefaultAllocator: Allocator<N, R, C> where DefaultAllocator: Allocator<N, R, C>

View File

@ -18,19 +18,19 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde( serde(bound(
bound(serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>, serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize, VectorN<N, D>: Serialize,
MatrixN<N, D>: Serialize") MatrixN<N, D>: Serialize"
) ))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde( serde(bound(
bound(deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>, deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize, VectorN<N, D>: Serialize,
MatrixN<N, D>: Deserialize<'de>") MatrixN<N, D>: Deserialize<'de>"
) ))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RealSchur<N: Scalar, D: Dim> pub struct RealSchur<N: Scalar, D: Dim>
@ -47,8 +47,7 @@ where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>, DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
MatrixN<N, D>: Copy, MatrixN<N, D>: Copy,
VectorN<N, D>: Copy, VectorN<N, D>: Copy,
{ {}
}
impl<N: RealSchurScalar + Real, D: Dim> RealSchur<N, D> impl<N: RealSchurScalar + Real, D: Dim> RealSchur<N, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>

View File

@ -15,21 +15,25 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, DimMinimum<R, C>> + serde(bound(
serialize = "DefaultAllocator: Allocator<N, DimMinimum<R, C>> +
Allocator<N, R, R> + Allocator<N, R, R> +
Allocator<N, C, C>, Allocator<N, C, C>,
MatrixN<N, R>: Serialize, MatrixN<N, R>: Serialize,
MatrixN<N, C>: Serialize, MatrixN<N, C>: Serialize,
VectorN<N, DimMinimum<R, C>>: Serialize")) VectorN<N, DimMinimum<R, C>>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, DimMinimum<R, C>> + serde(bound(
serialize = "DefaultAllocator: Allocator<N, DimMinimum<R, C>> +
Allocator<N, R, R> + Allocator<N, R, R> +
Allocator<N, C, C>, Allocator<N, C, C>,
MatrixN<N, R>: Deserialize<'de>, MatrixN<N, R>: Deserialize<'de>,
MatrixN<N, C>: Deserialize<'de>, MatrixN<N, C>: Deserialize<'de>,
VectorN<N, DimMinimum<R, C>>: Deserialize<'de>")) VectorN<N, DimMinimum<R, C>>: Deserialize<'de>"
))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SVD<N: Scalar, R: DimMin<C>, C: Dim> pub struct SVD<N: Scalar, R: DimMin<C>, C: Dim>
@ -49,8 +53,7 @@ where
MatrixMN<N, R, R>: Copy, MatrixMN<N, R, R>: Copy,
MatrixMN<N, C, C>: Copy, MatrixMN<N, C, C>: Copy,
VectorN<N, DimMinimum<R, C>>: Copy, VectorN<N, DimMinimum<R, C>>: Copy,
{ {}
}
/// Trait implemented by floats (`f32`, `f64`) and complex floats (`Complex<f32>`, `Complex<f64>`) /// Trait implemented by floats (`f32`, `f64`) and complex floats (`Complex<f32>`, `Complex<f64>`)
/// supported by the Singular Value Decompotition. /// supported by the Singular Value Decompotition.

View File

@ -18,17 +18,21 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, D, D> + serde(bound(
serialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, D>, Allocator<N, D>,
VectorN<N, D>: Serialize, VectorN<N, D>: Serialize,
MatrixN<N, D>: Serialize")) MatrixN<N, D>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, D, D> + serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, D>, Allocator<N, D>,
VectorN<N, D>: Deserialize<'de>, VectorN<N, D>: Deserialize<'de>,
MatrixN<N, D>: Deserialize<'de>")) MatrixN<N, D>: Deserialize<'de>"
))
)] )]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SymmetricEigen<N: Scalar, D: Dim> pub struct SymmetricEigen<N: Scalar, D: Dim>
@ -46,8 +50,7 @@ where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>, DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
MatrixN<N, D>: Copy, MatrixN<N, D>: Copy,
VectorN<N, D>: Copy, VectorN<N, D>: Copy,
{ {}
}
impl<N: SymmetricEigenScalar + Real, D: Dim> SymmetricEigen<N, D> impl<N: SymmetricEigenScalar + Real, D: Dim> SymmetricEigen<N, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>

View File

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

View File

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

View File

@ -79,8 +79,7 @@ where
N: Scalar, N: Scalar,
DefaultAllocator: Allocator<N, R1, C1> + Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>, DefaultAllocator: Allocator<N, R1, C1> + Allocator<N, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>, ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{ {}
}
// XXX: Bad name. // XXX: Bad name.
/// Restricts the given number of rows to be equal. /// Restricts the given number of rows to be equal.
@ -101,5 +100,4 @@ where
N: Scalar, N: Scalar,
DefaultAllocator: Allocator<N, R1, U1> + Allocator<N, SameShapeR<R1, R2>>, DefaultAllocator: Allocator<N, R1, U1> + Allocator<N, SameShapeR<R1, R2>>,
ShapeConstraint: SameNumberOfRows<R1, R2>, ShapeConstraint: SameNumberOfRows<R1, R2>,
{ {}
}

View File

@ -34,7 +34,7 @@ use base::Scalar;
*/ */
/// A array-based statically sized matrix data storage. /// A array-based statically sized matrix data storage.
#[repr(C)] #[repr(C)]
pub struct MatrixArray<N, R, C> pub struct ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,
@ -44,7 +44,11 @@ where
data: GenericArray<N, Prod<R::Value, C::Value>>, data: GenericArray<N, Prod<R::Value, C::Value>>,
} }
impl<N, R, C> Hash for MatrixArray<N, R, C> #[deprecated(note="renamed to `ArrayStorage`")]
/// Renamed to [ArrayStorage].
pub type MatrixArray<N, R, C> = ArrayStorage<N, R, C>;
impl<N, R, C> Hash for ArrayStorage<N, R, C>
where where
N: Hash, N: Hash,
R: DimName, R: DimName,
@ -57,7 +61,7 @@ where
} }
} }
impl<N, R, C> Deref for MatrixArray<N, R, C> impl<N, R, C> Deref for ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,
@ -72,7 +76,7 @@ where
} }
} }
impl<N, R, C> DerefMut for MatrixArray<N, R, C> impl<N, R, C> DerefMut for ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,
@ -85,7 +89,7 @@ where
} }
} }
impl<N, R, C> Debug for MatrixArray<N, R, C> impl<N, R, C> Debug for ArrayStorage<N, R, C>
where where
N: Debug, N: Debug,
R: DimName, R: DimName,
@ -99,7 +103,7 @@ where
} }
} }
impl<N, R, C> Copy for MatrixArray<N, R, C> impl<N, R, C> Copy for ArrayStorage<N, R, C>
where where
N: Copy, N: Copy,
R: DimName, R: DimName,
@ -107,10 +111,9 @@ 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>,
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,
@ -120,23 +123,22 @@ 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,
C: DimName, C: DimName,
R::Value: Mul<C::Value>, R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>, Prod<R::Value, C::Value>: ArrayLength<N>,
{ {}
}
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,
@ -150,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,
@ -202,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,
@ -222,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,10 +232,9 @@ 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>,
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,
@ -241,8 +242,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>,
DefaultAllocator: Allocator<N, R, C, Buffer = Self>, DefaultAllocator: Allocator<N, R, C, Buffer = Self>,
{ {}
}
/* /*
* *
@ -251,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,
@ -272,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,
@ -282,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,
@ -303,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,
@ -318,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;
} }
@ -344,7 +344,7 @@ where
} }
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for MatrixArray<N, R, C> impl<N, R, C> Abomonation for ArrayStorage<N, R, C>
where where
R: DimName, R: DimName,
C: DimName, C: DimName,

View File

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

View File

@ -115,13 +115,13 @@ impl<N: Real> Matrix4<N> {
/// Creates a new homogeneous matrix for an orthographic projection. /// Creates a new homogeneous matrix for an orthographic projection.
#[inline] #[inline]
pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self { pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap() Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner()
} }
/// Creates a new homogeneous matrix for a perspective projection. /// Creates a new homogeneous matrix for a perspective projection.
#[inline] #[inline]
pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self { pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self {
Perspective3::new(aspect, fovy, znear, zfar).unwrap() Perspective3::new(aspect, fovy, znear, zfar).into_inner()
} }
/// Creates an isometry that corresponds to the local frame of an observer standing at the /// Creates an isometry that corresponds to the local frame of an observer standing at the
@ -130,8 +130,14 @@ impl<N: Real> Matrix4<N> {
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
/// `eye`. /// `eye`.
#[inline] #[inline]
pub fn face_towards(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
}
/// Deprecated: Use [Matrix4::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self { pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous() Matrix4::face_towards(eye, target, up)
} }
/// Builds a right-handed look-at view matrix. /// Builds a right-handed look-at view matrix.
@ -314,13 +320,14 @@ impl<N: Scalar + Ring, D: DimName, S: StorageMut<N, D, D>> SquareMatrix<N, D, S>
} }
} }
impl<N: Real, D: DimNameSub<U1>> Transformation<Point<N, DimNameDiff<D, U1>>> for MatrixN<N, D> impl<N: Real, D: DimNameSub<U1>, S: Storage<N, D, D>> SquareMatrix<N, D, S>
where DefaultAllocator: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>
+ Allocator<N, DimNameDiff<D, U1>> + Allocator<N, DimNameDiff<D, U1>>
+ Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>> + Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{ {
/// Transforms the given vector, assuming the matrix `self` uses homogeneous coordinates.
#[inline] #[inline]
fn transform_vector( pub fn transform_vector(
&self, &self,
v: &VectorN<N, DimNameDiff<D, U1>>, v: &VectorN<N, DimNameDiff<D, U1>>,
) -> VectorN<N, DimNameDiff<D, U1>> ) -> VectorN<N, DimNameDiff<D, U1>>
@ -336,13 +343,18 @@ where DefaultAllocator: Allocator<N, D, D>
transform * v transform * v
} }
/// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates.
#[inline] #[inline]
fn transform_point(&self, pt: &Point<N, DimNameDiff<D, U1>>) -> Point<N, DimNameDiff<D, U1>> { pub fn transform_point(
&self,
pt: &Point<N, DimNameDiff<D, U1>>,
) -> Point<N, DimNameDiff<D, U1>>
{
let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0); let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1); let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0); let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
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;
@ -351,3 +363,23 @@ where DefaultAllocator: Allocator<N, D, D>
transform * pt + translation transform * pt + translation
} }
} }
impl<N: Real, D: DimNameSub<U1>> Transformation<Point<N, DimNameDiff<D, U1>>> for MatrixN<N, D>
where DefaultAllocator: Allocator<N, D, D>
+ Allocator<N, DimNameDiff<D, U1>>
+ Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{
#[inline]
fn transform_vector(
&self,
v: &VectorN<N, DimNameDiff<D, U1>>,
) -> VectorN<N, DimNameDiff<D, U1>>
{
self.transform_vector(v)
}
#[inline]
fn transform_point(&self, pt: &Point<N, DimNameDiff<D, U1>>) -> Point<N, DimNameDiff<D, U1>> {
self.transform_point(pt)
}
}

View File

@ -11,11 +11,20 @@ use base::dimension::Dim;
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar}; use base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar};
/// The type of the result of a matrix componentwise operation. /// The type of the result of a matrix component-wise operation.
pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>; pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>;
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Computes the componentwise absolute value. /// Computes the component-wise absolute value.
///
/// # Example
///
/// ```
/// # use nalgebra::Matrix2;
/// let a = Matrix2::new(0.0, 1.0,
/// -2.0, -3.0);
/// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0))
/// ```
#[inline] #[inline]
pub fn abs(&self) -> MatrixMN<N, R, C> pub fn abs(&self) -> MatrixMN<N, R, C>
where where
@ -52,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)));
} }
} }
} }
@ -80,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;
} }
} }
} }
@ -90,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;
} }
} }
} }
@ -112,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)));
} }
} }
} }
@ -135,12 +144,94 @@ macro_rules! component_binop_impl(
component_binop_impl!( component_binop_impl!(
component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign, component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign,
"Componentwise matrix multiplication.", r"
"Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.", Componentwise matrix or vector multiplication.
"Inplace componentwise matrix multiplication.";
# Example
```
# use nalgebra::Matrix2;
let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);
assert_eq!(a.component_mul(&b), expected);
```
",
r"
Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.
# Example
```
# use nalgebra::Matrix2;
let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let expected = (a.component_mul(&b) * 5.0) + m * 10.0;
m.cmpy(5.0, &a, &b, 10.0);
assert_eq!(m, expected);
```
",
r"
Inplace componentwise matrix or vector multiplication.
# Example
```
# use nalgebra::Matrix2;
let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);
a.component_mul_assign(&b);
assert_eq!(a, expected);
```
";
component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign, component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign,
"Componentwise matrix division.", r"
"Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.", Componentwise matrix or vector division.
"Inplace componentwise matrix division.";
# Example
```
# use nalgebra::Matrix2;
let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);
assert_eq!(a.component_div(&b), expected);
```
",
r"
Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.
# Example
```
# use nalgebra::Matrix2;
let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let a = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let expected = (a.component_div(&b) * 5.0) + m * 10.0;
m.cdpy(5.0, &a, &b, 10.0);
assert_eq!(m, expected);
```
",
r"
Inplace componentwise matrix or vector division.
# Example
```
# use nalgebra::Matrix2;
let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);
a.component_div_assign(&b);
assert_eq!(a, expected);
```
";
// FIXME: add other operators like bitshift, etc. ? // FIXME: add other operators like bitshift, etc. ?
); );

View File

@ -82,7 +82,7 @@ where DefaultAllocator: Allocator<N, R, C>
for i in 0..nrows.value() { for i in 0..nrows.value() {
for j in 0..ncols.value() { for j in 0..ncols.value() {
unsafe { *res.get_unchecked_mut(i, j) = *iter.next().unwrap() } unsafe { *res.get_unchecked_mut((i, j)) = *iter.next().unwrap() }
} }
} }
@ -105,7 +105,7 @@ where DefaultAllocator: Allocator<N, R, C>
for j in 0..ncols.value() { for j in 0..ncols.value() {
for i in 0..nrows.value() { for i in 0..nrows.value() {
unsafe { *res.get_unchecked_mut(i, j) = f(i, j) } unsafe { *res.get_unchecked_mut((i, j)) = f(i, j) }
} }
} }
@ -132,7 +132,7 @@ where DefaultAllocator: Allocator<N, R, C>
let mut res = Self::zeros_generic(nrows, ncols); let mut res = Self::zeros_generic(nrows, ncols);
for i in 0..::min(nrows.value(), ncols.value()) { for i in 0..::min(nrows.value(), ncols.value()) {
unsafe { *res.get_unchecked_mut(i, i) = elt } unsafe { *res.get_unchecked_mut((i, i)) = elt }
} }
res res
@ -152,7 +152,7 @@ where DefaultAllocator: Allocator<N, R, C>
); );
for (i, elt) in elts.iter().enumerate() { for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut(i, i) = *elt } unsafe { *res.get_unchecked_mut((i, i)) = *elt }
} }
res res
@ -162,6 +162,18 @@ where DefaultAllocator: Allocator<N, R, C>
/// ///
/// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do /// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do
/// not have the same dimensions. /// not have the same dimensions.
///
/// # Example
/// ```
/// # use nalgebra::{RowVector3, Matrix3};
/// # use std::iter;
///
/// let m = Matrix3::from_rows(&[ RowVector3::new(1.0, 2.0, 3.0), RowVector3::new(4.0, 5.0, 6.0), RowVector3::new(7.0, 8.0, 9.0) ]);
///
/// assert!(m.m11 == 1.0 && m.m12 == 2.0 && m.m13 == 3.0 &&
/// m.m21 == 4.0 && m.m22 == 5.0 && m.m23 == 6.0 &&
/// m.m31 == 7.0 && m.m32 == 8.0 && m.m33 == 9.0);
/// ```
#[inline] #[inline]
pub fn from_rows<SB>(rows: &[Matrix<N, U1, C, SB>]) -> Self pub fn from_rows<SB>(rows: &[Matrix<N, U1, C, SB>]) -> Self
where SB: Storage<N, U1, C> { where SB: Storage<N, U1, C> {
@ -190,6 +202,18 @@ where DefaultAllocator: Allocator<N, R, C>
/// ///
/// Panics if not enough columns are provided (for statically-sized matrices), or if all /// Panics if not enough columns are provided (for statically-sized matrices), or if all
/// columns do not have the same dimensions. /// columns do not have the same dimensions.
///
/// # Example
/// ```
/// # use nalgebra::{Vector3, Matrix3};
/// # use std::iter;
///
/// let m = Matrix3::from_columns(&[ Vector3::new(1.0, 2.0, 3.0), Vector3::new(4.0, 5.0, 6.0), Vector3::new(7.0, 8.0, 9.0) ]);
///
/// assert!(m.m11 == 1.0 && m.m12 == 4.0 && m.m13 == 7.0 &&
/// m.m21 == 2.0 && m.m22 == 5.0 && m.m23 == 8.0 &&
/// m.m31 == 3.0 && m.m32 == 6.0 && m.m33 == 9.0);
/// ```
#[inline] #[inline]
pub fn from_columns<SB>(columns: &[Vector<N, R, SB>]) -> Self pub fn from_columns<SB>(columns: &[Vector<N, R, SB>]) -> Self
where SB: Storage<N, R> { where SB: Storage<N, R> {
@ -227,12 +251,35 @@ where DefaultAllocator: Allocator<N, R, C>
pub fn from_distribution_generic<Distr: Distribution<N> + ?Sized, G: Rng + ?Sized>( pub fn from_distribution_generic<Distr: Distribution<N> + ?Sized, G: Rng + ?Sized>(
nrows: R, nrows: R,
ncols: C, ncols: C,
distribution: &mut Distr, distribution: &Distr,
rng: &mut G, rng: &mut G,
) -> Self ) -> Self
{ {
Self::from_fn_generic(nrows, ncols, |_, _| distribution.sample(rng)) Self::from_fn_generic(nrows, ncols, |_, _| distribution.sample(rng))
} }
/// Creates a matrix backed by a given `Vec`.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{Dynamic, DMatrix, Matrix, U1};
///
/// let vec = vec![0, 1, 2, 3, 4, 5];
/// let vec_ptr = vec.as_ptr();
///
/// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec);
/// let matrix_storage_ptr = matrix.data.as_vec().as_ptr();
///
/// // `matrix` is backed by exactly the same `Vec` as it was constructed from.
/// assert_eq!(matrix_storage_ptr, vec_ptr);
/// ```
#[inline]
#[cfg(feature = "std")]
pub fn from_vec_generic(nrows: R, ncols: C, data: Vec<N>) -> Self {
Self::from_iterator_generic(nrows, ncols, data)
}
} }
impl<N, D: Dim> MatrixN<N, D> impl<N, D: Dim> MatrixN<N, D>
@ -241,6 +288,23 @@ where
DefaultAllocator: Allocator<N, D, D>, DefaultAllocator: Allocator<N, D, D>,
{ {
/// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0.
///
/// # Example
/// ```
/// # use nalgebra::{Vector3, DVector, Matrix3, DMatrix};
/// # use std::iter;
///
/// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0));
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(&[1.0, 2.0, 3.0]));
///
/// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
/// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 &&
/// m.m31 == 0.0 && m.m32 == 0.0 && m.m33 == 3.0);
/// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 &&
/// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 0.0 &&
/// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0);
/// ```
#[inline] #[inline]
pub fn from_diagonal<SB: Storage<N, D>>(diag: &Vector<N, D, SB>) -> Self pub fn from_diagonal<SB: Storage<N, D>>(diag: &Vector<N, D, SB>) -> Self
where N: Zero { where N: Zero {
@ -249,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);
} }
} }
@ -267,60 +331,141 @@ macro_rules! impl_constructors(
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*> impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where DefaultAllocator: Allocator<N $(, $Dims)*> { where DefaultAllocator: Allocator<N $(, $Dims)*> {
/// Creates a new uninitialized matrix. /// Creates a new uninitialized matrix or vector.
#[inline] #[inline]
pub unsafe fn new_uninitialized($($args: usize),*) -> Self { pub unsafe fn new_uninitialized($($args: usize),*) -> Self {
Self::new_uninitialized_generic($($gargs),*) Self::new_uninitialized_generic($($gargs),*)
} }
/// Creates a matrix with all its elements set to `elem`. /// Creates a matrix or vector with all its elements set to `elem`.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
///
/// let v = Vector3::from_element(2.0);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_element(3, 2.0);
/// let m = Matrix2x3::from_element(2.0);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_element(2, 3, 2.0);
///
/// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0);
/// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0);
/// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 &&
/// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0);
/// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 &&
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
/// ```
#[inline] #[inline]
pub fn from_element($($args: usize,)* elem: N) -> Self { pub fn from_element($($args: usize,)* elem: N) -> Self {
Self::from_element_generic($($gargs, )* elem) Self::from_element_generic($($gargs, )* elem)
} }
/// Creates a matrix with all its elements set to `elem`. /// Creates a matrix or vector with all its elements set to `elem`.
/// ///
/// Same as `.from_element`. /// Same as `.from_element`.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
///
/// let v = Vector3::repeat(2.0);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::repeat(3, 2.0);
/// let m = Matrix2x3::repeat(2.0);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::repeat(2, 3, 2.0);
///
/// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0);
/// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0);
/// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 &&
/// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0);
/// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 &&
/// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0);
/// ```
#[inline] #[inline]
pub fn repeat($($args: usize,)* elem: N) -> Self { pub fn repeat($($args: usize,)* elem: N) -> Self {
Self::repeat_generic($($gargs, )* elem) Self::repeat_generic($($gargs, )* elem)
} }
/// Creates a matrix with all its elements set to `0`. /// Creates a matrix or vector with all its elements set to `0`.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
///
/// let v = Vector3::<f32>::zeros();
/// // The argument represents the vector dimension.
/// let dv = DVector::<f32>::zeros(3);
/// let m = Matrix2x3::<f32>::zeros();
/// // The two arguments represent the matrix dimensions.
/// let dm = DMatrix::<f32>::zeros(2, 3);
///
/// assert!(v.x == 0.0 && v.y == 0.0 && v.z == 0.0);
/// assert!(dv[0] == 0.0 && dv[1] == 0.0 && dv[2] == 0.0);
/// assert!(m.m11 == 0.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
/// m.m21 == 0.0 && m.m22 == 0.0 && m.m23 == 0.0);
/// assert!(dm[(0, 0)] == 0.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 &&
/// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 0.0 && dm[(1, 2)] == 0.0);
/// ```
#[inline] #[inline]
pub fn zeros($($args: usize),*) -> Self pub fn zeros($($args: usize),*) -> Self
where N: Zero { where N: Zero {
Self::zeros_generic($($gargs),*) Self::zeros_generic($($gargs),*)
} }
/// Creates a matrix with all its elements filled by an iterator. /// Creates a matrix or vector with all its elements filled by an iterator.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_iterator((0..3).into_iter());
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_iterator(3, (0..3).into_iter());
/// let m = Matrix2x3::from_iterator((0..6).into_iter());
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_iterator(2, 3, (0..6).into_iter());
///
/// 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] #[inline]
pub fn from_iterator<I>($($args: usize,)* iter: I) -> Self pub fn from_iterator<I>($($args: usize,)* iter: I) -> Self
where I: IntoIterator<Item = N> { where I: IntoIterator<Item = N> {
Self::from_iterator_generic($($gargs, )* iter) Self::from_iterator_generic($($gargs, )* iter)
} }
/// Creates a matrix with its elements filled with the components provided by a slice /// Creates a matrix or vector filled with the results of a function applied to each of its
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
#[inline]
pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* slice)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order.
#[inline]
pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* slice)
}
/// Creates a matrix filled with the results of a function applied to each of its
/// component coordinates. /// component coordinates.
// FIXME: don't take a dimension of the matrix is statically sized. ///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_fn(|i, _| i);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_fn(3, |i, _| i);
/// let m = Matrix2x3::from_fn(|i, j| i * 3 + j);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_fn(2, 3, |i, j| i * 3 + j);
///
/// 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] #[inline]
pub fn from_fn<F>($($args: usize,)* f: F) -> Self pub fn from_fn<F>($($args: usize,)* f: F) -> Self
where F: FnMut(usize, usize) -> N { where F: FnMut(usize, usize) -> N {
@ -330,6 +475,21 @@ macro_rules! impl_constructors(
/// Creates an identity matrix. If the matrix is not square, the largest square /// Creates an identity matrix. If the matrix is not square, the largest square
/// submatrix (starting at the first row and column) is set to the identity while all /// submatrix (starting at the first row and column) is set to the identity while all
/// other entries are set to zero. /// other entries are set to zero.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, DMatrix};
/// # use std::iter;
///
/// let m = Matrix2x3::<f32>::identity();
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::<f32>::identity(2, 3);
///
/// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
/// m.m21 == 0.0 && m.m22 == 1.0 && m.m23 == 0.0);
/// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 &&
/// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 1.0 && dm[(1, 2)] == 0.0);
/// ```
#[inline] #[inline]
pub fn identity($($args: usize,)*) -> Self pub fn identity($($args: usize,)*) -> Self
where N: Zero + One { where N: Zero + One {
@ -338,6 +498,21 @@ macro_rules! impl_constructors(
/// Creates a matrix filled with its diagonal filled with `elt` and all other /// Creates a matrix filled with its diagonal filled with `elt` and all other
/// components set to zero. /// components set to zero.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, DMatrix};
/// # use std::iter;
///
/// let m = Matrix2x3::from_diagonal_element(5.0);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_diagonal_element(2, 3, 5.0);
///
/// assert!(m.m11 == 5.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
/// m.m21 == 0.0 && m.m22 == 5.0 && m.m23 == 0.0);
/// assert!(dm[(0, 0)] == 5.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 &&
/// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 5.0 && dm[(1, 2)] == 0.0);
/// ```
#[inline] #[inline]
pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self
where N: Zero + One { where N: Zero + One {
@ -348,17 +523,34 @@ macro_rules! impl_constructors(
/// elements are filled with the content of `elts`. Others are set to 0. /// elements are filled with the content of `elts`. Others are set to 0.
/// ///
/// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix3, DMatrix};
/// # use std::iter;
///
/// let m = Matrix3::from_partial_diagonal(&[1.0, 2.0]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_partial_diagonal(3, 3, &[1.0, 2.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.m31 == 0.0 && m.m32 == 0.0 && m.m33 == 0.0);
/// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 &&
/// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 0.0 &&
/// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 0.0);
/// ```
#[inline] #[inline]
pub fn from_partial_diagonal($($args: usize,)* elts: &[N]) -> Self pub fn from_partial_diagonal($($args: usize,)* elts: &[N]) -> Self
where N: Zero { where N: Zero {
Self::from_partial_diagonal_generic($($gargs, )* elts) Self::from_partial_diagonal_generic($($gargs, )* elts)
} }
/// Creates a matrix filled with random values from the given distribution. /// Creates a matrix or vector filled with random values from the given distribution.
#[inline] #[inline]
pub fn from_distribution<Distr: Distribution<N> + ?Sized, G: Rng + ?Sized>( pub fn from_distribution<Distr: Distribution<N> + ?Sized, G: Rng + ?Sized>(
$($args: usize,)* $($args: usize,)*
distribution: &mut Distr, distribution: &Distr,
rng: &mut G, rng: &mut G,
) -> Self { ) -> Self {
Self::from_distribution_generic($($gargs, )* distribution, rng) Self::from_distribution_generic($($gargs, )* distribution, rng)
@ -401,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.
@ -495,7 +806,7 @@ where
Unit::new_normalize(VectorN::from_distribution_generic( Unit::new_normalize(VectorN::from_distribution_generic(
D::name(), D::name(),
U1, U1,
&mut StandardNormal, &StandardNormal,
rng, rng,
)) ))
} }
@ -516,7 +827,7 @@ macro_rules! componentwise_constructors_impl(
pub fn new($($args: N),*) -> Self { pub fn new($($args: N),*) -> Self {
unsafe { unsafe {
let mut res = Self::new_uninitialized(); let mut res = Self::new_uninitialized();
$( *res.get_unchecked_mut($irow, $icol) = $args; )* $( *res.get_unchecked_mut(($irow, $icol)) = $args; )*
res res
} }

View File

@ -17,8 +17,8 @@ use base::dimension::{
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 +42,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 +63,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 +336,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 +353,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 +367,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 +380,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 +397,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 +411,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>> impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>>
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>> for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
where where
N: Scalar, N: Scalar,
R: DimName, R: DimName,

View File

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

View File

@ -181,7 +181,7 @@ dim_ops!(
DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod; DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod;
DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff; DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff;
DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot; DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot;
DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameNimimum, Minimum; DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum;
DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum; DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
); );

View File

@ -1,6 +1,7 @@
use num::{One, Zero}; use num::{One, Zero};
use std::cmp; use std::cmp;
use std::ptr; use std::ptr;
use std::iter::ExactSizeIterator;
use std::mem; use std::mem;
use base::allocator::{Allocator, Reallocator}; use base::allocator::{Allocator, Reallocator};
@ -24,7 +25,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> {
@ -33,6 +34,52 @@ 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`.
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`.
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> {
@ -59,7 +106,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 }
} }
} }
@ -68,7 +115,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 }
} }
} }
@ -77,7 +124,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 }
} }
} }
@ -94,7 +141,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) }
} }
} }
@ -129,7 +176,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 }
} }
} }
} }
@ -147,7 +194,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 }
} }
} }
} }
@ -192,7 +239,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));
} }
} }
} }
@ -207,7 +254,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));
} }
} }
} }
@ -780,3 +827,136 @@ unsafe fn extend_rows<N: Scalar>(
); );
} }
} }
/// Extend the number of columns of the `Matrix` with elements from
/// a given iterator.
impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S>
where
N: Scalar,
R: Dim,
S: Extend<N>,
{
/// Extend the number of columns of the `Matrix` with elements
/// from the given iterator.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Dynamic, Matrix, MatrixMN, Matrix3};
///
/// let data = vec![0, 1, 2, // column 1
/// 3, 4, 5]; // column 2
///
/// let mut matrix = DMatrix::from_vec(3, 2, data);
///
/// matrix.extend(vec![6, 7, 8]); // column 3
///
/// assert!(matrix.eq(&Matrix3::new(0, 3, 6,
/// 1, 4, 7,
/// 2, 5, 8)));
/// ```
///
/// # Panics
/// This function panics if the number of elements yielded by the
/// given iterator is not a multiple of the number of rows of the
/// `Matrix`.
///
/// ```should_panic
/// # use nalgebra::{DMatrix, Dynamic, MatrixMN};
/// let data = vec![0, 1, 2, // column 1
/// 3, 4, 5]; // column 2
///
/// let mut matrix = DMatrix::from_vec(3, 2, data);
///
/// // The following panics because the vec length is not a multiple of 3.
/// matrix.extend(vec![6, 7, 8, 9]);
/// ```
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) {
self.data.extend(iter);
}
}
/// Extend the number of rows of the `Vector` with elements from
/// a given iterator.
impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S>
where
N: Scalar,
S: Extend<N>,
{
/// Extend the number of rows of a `Vector` with elements
/// from the given iterator.
///
/// # Example
/// ```
/// # use nalgebra::DVector;
/// let mut vector = DVector::from_vec(vec![0, 1, 2]);
/// vector.extend(vec![3, 4, 5]);
/// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5])));
/// ```
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) {
self.data.extend(iter);
}
}
impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S>
where
N: Scalar,
R: Dim,
S: Extend<Vector<N, RV, SV>>,
RV: Dim,
SV: Storage<N, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>,
{
/// Extends the number of columns of a `Matrix` with `Vector`s
/// from a given iterator.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Vector3, Matrix3x4};
///
/// let data = vec![0, 1, 2, // column 1
/// 3, 4, 5]; // column 2
///
/// let mut matrix = DMatrix::from_vec(3, 2, data);
///
/// matrix.extend(
/// vec![Vector3::new(6, 7, 8), // column 3
/// Vector3::new(9, 10, 11)]); // column 4
///
/// assert!(matrix.eq(&Matrix3x4::new(0, 3, 6, 9,
/// 1, 4, 7, 10,
/// 2, 5, 8, 11)));
/// ```
///
/// # Panics
/// This function panics if the dimension of each `Vector` yielded
/// by the given iterator is not equal to the number of rows of
/// this `Matrix`.
///
/// ```should_panic
/// # use nalgebra::{DMatrix, Vector2, Matrix3x4};
/// let mut matrix =
/// DMatrix::from_vec(3, 2,
/// vec![0, 1, 2, // column 1
/// 3, 4, 5]); // column 2
///
/// // The following panics because this matrix can only be extended with 3-dimensional vectors.
/// matrix.extend(
/// vec![Vector2::new(6, 7)]); // too few dimensions!
/// ```
///
/// ```should_panic
/// # use nalgebra::{DMatrix, Vector4, Matrix3x4};
/// let mut matrix =
/// DMatrix::from_vec(3, 2,
/// vec![0, 1, 2, // column 1
/// 3, 4, 5]); // column 2
///
/// // The following panics because this matrix can only be extended with 3-dimensional vectors.
/// matrix.extend(
/// vec![Vector4::new(6, 7, 8, 9)]); // too few dimensions!
/// ```
fn extend<I: IntoIterator<Item=Vector<N, RV, SV>>>(&mut self, iter: I)
{
self.data.extend(iter);
}
}

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

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

View File

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

View File

@ -1,4 +1,4 @@
use num::Zero; use num::{One, Zero};
use num_complex::Complex; use num_complex::Complex;
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
@ -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;
@ -16,12 +17,12 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation; use abomonation::Abomonation;
use alga::general::{Real, Ring}; 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)
}
/// Tests whether `self` and `rhs` are equal up to a given epsilon. /// Tests whether `self` and `rhs` are equal up to a given epsilon.
/// ///
/// See `relative_eq` from the `RelativeEq` trait for more details. /// See `relative_eq` from the `RelativeEq` trait for more details.
@ -374,7 +395,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));
} }
} }
} }
@ -403,7 +424,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,
@ -503,6 +524,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>)
@ -522,7 +594,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));
} }
} }
} }
@ -550,14 +622,44 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
MatrixIterMut::new(&mut self.data) MatrixIterMut::new(&mut self.data)
} }
/// 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.
@ -598,7 +700,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);
} }
} }
} }
@ -621,7 +723,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));
} }
} }
} }
@ -645,7 +747,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));
} }
} }
} }
@ -653,8 +755,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 {
@ -666,6 +767,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> {
@ -742,7 +908,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();
} }
} }
} }
@ -776,8 +942,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;
@ -803,7 +969,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));
} }
} }
@ -823,27 +989,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
@ -863,6 +1038,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,
@ -1019,8 +1210,7 @@ impl<N, R: Dim, C: Dim, S> Eq for Matrix<N, R, C, S>
where where
N: Scalar + Eq, N: Scalar + Eq,
S: Storage<N, R, C>, S: Storage<N, R, C>,
{ {}
}
impl<N, R: Dim, C: Dim, S> PartialEq for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim, S> PartialEq for Matrix<N, R, C, S>
where where
@ -1124,8 +1314,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))
} }
} }
@ -1160,17 +1350,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
} }
@ -1181,17 +1371,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
} }
@ -1247,65 +1437,27 @@ 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> { impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
/// The squared L2 norm of this vector. Vector<N, D, S>
#[inline] {
pub fn norm_squared(&self) -> N { /// Returns `self * (1.0 - t) + rhs * t`, i.e., the linear blend of the vectors x and y using the scalar value a.
let mut res = N::zero(); ///
/// The value for a is not restricted to the range `[0, 1]`.
for i in 0..self.ncols() { ///
let col = self.column(i); /// # Examples:
res += col.dot(&col) ///
} /// ```
/// # use nalgebra::Vector3;
/// let x = Vector3::new(1.0, 2.0, 3.0);
/// let y = Vector3::new(10.0, 20.0, 30.0);
/// assert_eq!(x.lerp(&y, 0.1), Vector3::new(1.9, 3.8, 5.7));
/// ```
pub fn lerp<S2: Storage<N, D>>(&self, rhs: &Vector<N, D, S2>, t: N) -> VectorN<N, D>
where DefaultAllocator: Allocator<N, D> {
let mut res = self.clone_owned();
res.axpy(t, rhs, N::one() - t);
res 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: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> { impl<N: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
@ -1359,32 +1511,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,
@ -1444,3 +1570,24 @@ where
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
} }
} }
impl<N, R, C, S> Hash for Matrix<N, R, C, S>
where
N: Scalar + Hash,
R: Dim,
C: Dim,
S: Storage<N, R, C>,
{
fn hash<H: Hasher>(&self, state: &mut H) {
let (nrows, ncols) = self.shape();
(nrows, ncols).hash(state);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
self.get_unchecked((i, j)).hash(state);
}
}
}
}
}

View File

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

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

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

View File

@ -45,7 +45,7 @@ where
"Matrix index out of bounds." "Matrix index out of bounds."
); );
unsafe { self.get_unchecked(ij.0, ij.1) } unsafe { self.get_unchecked((ij.0, ij.1)) }
} }
} }
@ -71,7 +71,7 @@ where
"Matrix index out of bounds." "Matrix index out of bounds."
); );
unsafe { self.get_unchecked_mut(ij.0, ij.1) } unsafe { self.get_unchecked_mut((ij.0, ij.1)) }
} }
} }
@ -172,8 +172,8 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
let val = self.get_unchecked(i, j).$method(*rhs.get_unchecked(i, j)); let val = self.get_unchecked((i, j)).$method(*rhs.get_unchecked((i, j)));
*out.get_unchecked_mut(i, j) = val; *out.get_unchecked_mut((i, j)) = val;
} }
} }
} }
@ -204,7 +204,7 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. rhs.ncols() { for j in 0 .. rhs.ncols() {
for i in 0 .. rhs.nrows() { for i in 0 .. rhs.nrows() {
unsafe { unsafe {
self.get_unchecked_mut(i, j).$method_assign(*rhs.get_unchecked(i, j)) self.get_unchecked_mut((i, j)).$method_assign(*rhs.get_unchecked((i, j)))
} }
} }
} }
@ -235,8 +235,8 @@ macro_rules! componentwise_binop_impl(
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { unsafe {
let r = rhs.get_unchecked_mut(i, j); let r = rhs.get_unchecked_mut((i, j));
*r = self.get_unchecked(i, j).$method(*r) *r = self.get_unchecked((i, j)).$method(*r)
} }
} }
} }
@ -448,7 +448,7 @@ macro_rules! componentwise_scalarop_impl(
fn $method_assign(&mut self, rhs: N) { fn $method_assign(&mut self, rhs: N) {
for j in 0 .. self.ncols() { for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() { for i in 0 .. self.nrows() {
unsafe { self.get_unchecked_mut(i, j).$method_assign(rhs) }; unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs) };
} }
} }
} }
@ -657,7 +657,7 @@ where
for i in 0..ncols1 { for i in 0..ncols1 {
for j in 0..ncols2 { for j in 0..ncols2 {
let dot = self.column(i).dot(&rhs.column(j)); let dot = self.column(i).dot(&rhs.column(j));
unsafe { *out.get_unchecked_mut(i, j) = dot }; unsafe { *out.get_unchecked_mut((i, j)) = dot };
} }
} }
} }
@ -704,10 +704,10 @@ where
for j2 in 0..ncols2.value() { for j2 in 0..ncols2.value() {
for i1 in 0..nrows1.value() { for i1 in 0..nrows1.value() {
unsafe { unsafe {
let coeff = *self.get_unchecked(i1, j1); let coeff = *self.get_unchecked((i1, j1));
for i2 in 0..nrows2.value() { for i2 in 0..nrows2.value() {
*data_res = coeff * *rhs.get_unchecked(i2, j2); *data_res = coeff * *rhs.get_unchecked((i2, j2));
data_res = data_res.offset(1); data_res = data_res.offset(1);
} }
} }

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

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

View File

@ -34,7 +34,7 @@ pub type CStride<N, R, C = U1> =
/// Note that `Self` must always have a number of elements compatible with the matrix length (given /// Note that `Self` must always have a number of elements compatible with the matrix length (given
/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait /// by `R` and `C` if they are known at compile-time). For example, implementors of this trait
/// should **not** allow the user to modify the size of the underlying buffer with safe methods /// should **not** allow the user to modify the size of the underlying buffer with safe methods
/// (for example the `MatrixVec::data_mut` method is unsafe because the user could change the /// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
/// vector's size so that it no longer contains enough elements: this will lead to UB. /// vector's size so that it no longer contains enough elements: this will lead to UB.
pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized { pub unsafe trait Storage<N: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
/// The static stride of this storage's rows. /// The static stride of this storage's rows.

View File

@ -3,64 +3,60 @@ use storage::Storage;
use typenum::{self, Cmp, Greater}; use typenum::{self, Cmp, Greater};
macro_rules! impl_swizzle { macro_rules! impl_swizzle {
($(where $BaseDim: ident: $name: ident() -> $Result: ident[$($i: expr),*]);*) => { ($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => {
$( $(
impl<N: Scalar, D: DimName, S: Storage<N, D>> Vector<N, D, S> { 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]
); );

View File

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

View File

@ -1,6 +1,5 @@
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
use std::ops::Deref;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
@ -9,7 +8,8 @@ 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};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut}; use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
use base::Scalar; use base::{Scalar, Vector};
use base::constraint::{SameNumberOfRows, ShapeConstraint};
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation; use abomonation::Abomonation;
@ -23,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,
@ -46,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
} }
@ -76,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
} }
} }
@ -93,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;
@ -133,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;
@ -177,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
} }
} }
@ -186,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]
@ -200,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]
@ -221,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)
} }
@ -235,8 +244,66 @@ 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 VecStorage<N, R, Dynamic>
{
/// Extends the number of columns of the `VecStorage` with elements
/// from the given iterator.
///
/// # Panics
/// This function panics if the number of elements yielded by the
/// given iterator is not a multiple of the number of rows of the
/// `VecStorage`.
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
{
self.data.extend(iter);
self.ncols = Dynamic::new(self.data.len() / self.nrows.value());
assert!(self.data.len() % self.nrows.value() == 0,
"The number of elements produced by the given iterator was not a multiple of the number of rows.");
}
}
impl<N, R, RV, SV> Extend<Vector<N, RV, SV>> for VecStorage<N, R, Dynamic>
where
N: Scalar,
R: Dim,
RV: Dim,
SV: Storage<N, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>,
{
/// Extends the number of columns of the `VecStorage` with vectors
/// from the given iterator.
///
/// # Panics
/// This function panics if the number of rows of each `Vector`
/// yielded by the iterator is not equal to the number of rows
/// of this `VecStorage`.
fn extend<I: IntoIterator<Item=Vector<N, RV, SV>>>(&mut self, iter: I)
{
let nrows = self.nrows.value();
let iter = iter.into_iter();
let (lower, _upper) = iter.size_hint();
self.data.reserve(nrows * lower);
for vector in iter {
assert_eq!(nrows, vector.shape().0);
self.data.extend(vector.iter());
}
self.ncols = Dynamic::new(self.data.len() / nrows);
}
}
impl<N> Extend<N> for VecStorage<N, Dynamic, U1>
{
/// Extends the number of rows of the `VecStorage` with elements
/// from the given iterator.
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I)
{
self.data.extend(iter);
self.nrows = Dynamic::new(self.data.len());
}
}

View File

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

View File

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

View File

@ -108,6 +108,19 @@ impl<N: Real, D: DimName, R: Rotation<Point<N, D>>> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
/// Creates a new isometry from its rotational and translational parts. /// Creates a new isometry from its rotational and translational parts.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// assert_relative_eq!(iso * Point3::new(1.0, 2.0, 3.0), Point3::new(-1.0, 2.0, 0.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> { pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> {
Isometry { Isometry {
@ -118,6 +131,18 @@ where DefaultAllocator: Allocator<N, D>
} }
/// Inverts `self`. /// Inverts `self`.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, Vector2};
/// let iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let inv = iso.inverse();
/// let pt = Point2::new(1.0, 2.0);
///
/// assert_eq!(inv * (iso * pt), pt);
/// ```
#[inline] #[inline]
pub fn inverse(&self) -> Isometry<N, D, R> { pub fn inverse(&self) -> Isometry<N, D, R> {
let mut res = self.clone(); let mut res = self.clone();
@ -125,7 +150,20 @@ where DefaultAllocator: Allocator<N, D>
res res
} }
/// Inverts `self`. /// Inverts `self` in-place.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let pt = Point2::new(1.0, 2.0);
/// let transformed_pt = iso * pt;
/// iso.inverse_mut();
///
/// assert_eq!(iso * transformed_pt, pt);
/// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
self.rotation.inverse_mut(); self.rotation.inverse_mut();
@ -134,12 +172,39 @@ where DefaultAllocator: Allocator<N, D>
} }
/// Appends to `self` the given translation in-place. /// Appends to `self` the given translation in-place.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let tra = Translation2::new(3.0, 4.0);
/// // Same as `iso = tra * iso`.
/// iso.append_translation_mut(&tra);
///
/// assert_eq!(iso.translation, Translation2::new(4.0, 6.0));
/// ```
#[inline] #[inline]
pub fn append_translation_mut(&mut self, t: &Translation<N, D>) { pub fn append_translation_mut(&mut self, t: &Translation<N, D>) {
self.translation.vector += &t.vector self.translation.vector += &t.vector
} }
/// Appends to `self` the given rotation in-place. /// Appends to `self` the given rotation in-place.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0);
/// let rot = UnitComplex::new(f32::consts::PI / 2.0);
/// // Same as `iso = rot * iso`.
/// iso.append_rotation_mut(&rot);
///
/// assert_relative_eq!(iso, Isometry2::new(Vector2::new(-2.0, 1.0), f32::consts::PI * 2.0 / 3.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn append_rotation_mut(&mut self, r: &R) { pub fn append_rotation_mut(&mut self, r: &R) {
self.rotation = self.rotation.append_rotation(&r); self.rotation = self.rotation.append_rotation(&r);
@ -148,6 +213,20 @@ where DefaultAllocator: Allocator<N, D>
/// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that
/// lets `p` invariant. /// lets `p` invariant.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let pt = Point2::new(1.0, 0.0);
/// iso.append_rotation_wrt_point_mut(&rot, &pt);
///
/// assert_relative_eq!(iso * pt, Point2::new(-2.0, 0.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point<N, D>) { pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point<N, D>) {
self.translation.vector -= &p.coords; self.translation.vector -= &p.coords;
@ -157,10 +236,23 @@ where DefaultAllocator: Allocator<N, D>
/// Appends in-place to `self` a rotation centered at the point with coordinates /// Appends in-place to `self` a rotation centered at the point with coordinates
/// `self.translation`. /// `self.translation`.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// iso.append_rotation_wrt_center_mut(&rot);
///
/// // The translation part should not have changed.
/// assert_eq!(iso.translation.vector, Vector2::new(1.0, 2.0));
/// assert_eq!(iso.rotation, UnitComplex::new(f32::consts::PI));
/// ```
#[inline] #[inline]
pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { pub fn append_rotation_wrt_center_mut(&mut self, r: &R) {
let center = Point::from_coordinates(self.translation.vector.clone()); self.rotation = self.rotation.append_rotation(r);
self.append_rotation_wrt_point_mut(r, &center)
} }
} }
@ -172,6 +264,20 @@ impl<N: Real, D: DimName, R> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
/// Converts this isometry into its equivalent homogeneous transformation matrix. /// Converts this isometry into its equivalent homogeneous transformation matrix.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Vector2, Matrix3};
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);
/// let expected = Matrix3::new(0.8660254, -0.5, 10.0,
/// 0.5, 0.8660254, 20.0,
/// 0.0, 0.0, 1.0);
///
/// assert_relative_eq!(iso.to_homogeneous(), expected, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where where

View File

@ -143,10 +143,7 @@ where
#[inline] #[inline]
fn append_rotation(&self, r: &Self::Rotation) -> Self { fn append_rotation(&self, r: &Self::Rotation) -> Self {
let shift = r.transform_vector(&self.translation.vector); let shift = r.transform_vector(&self.translation.vector);
Isometry::from_parts( Isometry::from_parts(Translation::from(shift), r.clone() * self.rotation.clone())
Translation::from_vector(shift),
r.clone() * self.rotation.clone(),
)
} }
#[inline] #[inline]

View File

@ -23,6 +23,20 @@ impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
/// Creates a new identity isometry. /// Creates a new identity isometry.
///
/// # Example
///
/// ```
/// # use nalgebra::{Isometry2, Point2, Isometry3, Point3};
///
/// let iso = Isometry2::identity();
/// let pt = Point2::new(1.0, 2.0);
/// assert_eq!(iso * pt, pt);
///
/// let iso = Isometry3::identity();
/// let pt = Point3::new(1.0, 2.0, 3.0);
/// assert_eq!(iso * pt, pt);
/// ```
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::from_parts(Translation::identity(), R::identity()) Self::from_parts(Translation::identity(), R::identity())
@ -30,10 +44,24 @@ where DefaultAllocator: Allocator<N, D>
/// The isometry that applies the rotation `r` with its axis passing through the point `p`. /// The isometry that applies the rotation `r` with its axis passing through the point `p`.
/// This effectively lets `p` invariant. /// This effectively lets `p` invariant.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::PI);
/// let pt = Point2::new(1.0, 0.0);
/// let iso = Isometry2::rotation_wrt_point(rot, pt);
///
/// assert_eq!(iso * pt, pt); // The rotation center is not affected.
/// assert_relative_eq!(iso * Point2::new(1.0, 2.0), Point2::new(1.0, -2.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_wrt_point(r: R, p: Point<N, D>) -> Self { pub fn rotation_wrt_point(r: R, p: Point<N, D>) -> Self {
let shift = r.transform_vector(&-&p.coords); let shift = r.transform_vector(&-&p.coords);
Self::from_parts(Translation::from_vector(shift + p.coords), r) Self::from_parts(Translation::from(shift + p.coords), r)
} }
} }
@ -81,11 +109,23 @@ where
// 2D rotation. // 2D rotation.
impl<N: Real> Isometry<N, U2, Rotation2<N>> { impl<N: Real> Isometry<N, U2, Rotation2<N>> {
/// Creates a new isometry from a translation and a rotation angle. /// Creates a new 2D isometry from a translation and a rotation angle.
///
/// Its rotational part is represented as a 2x2 rotation matrix.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Vector2, Point2};
/// let iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
///
/// assert_eq!(iso * Point2::new(3.0, 4.0), Point2::new(-3.0, 5.0));
/// ```
#[inline] #[inline]
pub fn new(translation: Vector2<N>, angle: N) -> Self { pub fn new(translation: Vector2<N>, angle: N) -> Self {
Self::from_parts( Self::from_parts(
Translation::from_vector(translation), Translation::from(translation),
Rotation::<N, U2>::new(angle), Rotation::<N, U2>::new(angle),
) )
} }
@ -104,11 +144,23 @@ impl<N: Real> Isometry<N, U2, Rotation2<N>> {
} }
impl<N: Real> Isometry<N, U2, UnitComplex<N>> { impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
/// Creates a new isometry from a translation and a rotation angle. /// Creates a new 2D isometry from a translation and a rotation angle.
///
/// Its rotational part is represented as an unit complex number.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{IsometryMatrix2, Point2, Vector2};
/// let iso = IsometryMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
///
/// assert_eq!(iso * Point2::new(3.0, 4.0), Point2::new(-3.0, 5.0));
/// ```
#[inline] #[inline]
pub fn new(translation: Vector2<N>, angle: N) -> Self { pub fn new(translation: Vector2<N>, angle: N) -> Self {
Self::from_parts( Self::from_parts(
Translation::from_vector(translation), Translation::from(translation),
UnitComplex::from_angle(angle), UnitComplex::from_angle(angle),
) )
} }
@ -131,10 +183,33 @@ macro_rules! isometry_construction_impl(
($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => { ($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => {
impl<N: Real> Isometry<N, U3, $RotId<$($RotParams),*>> { impl<N: Real> Isometry<N, U3, $RotId<$($RotParams),*>> {
/// Creates a new isometry from a translation and a rotation axis-angle. /// Creates a new isometry from a translation and a rotation axis-angle.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// let translation = Vector3::new(1.0, 2.0, 3.0);
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
///
/// // Isometry with its rotation part represented as a UnitQuaternion
/// let iso = Isometry3::new(translation, axisangle);
/// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
/// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // Isometry with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
/// let iso = IsometryMatrix3::new(translation, axisangle);
/// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
/// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>) -> Self { pub fn new(translation: Vector3<N>, axisangle: Vector3<N>) -> Self {
Self::from_parts( Self::from_parts(
Translation::from_vector(translation), Translation::from(translation),
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle)) $RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
} }
@ -153,34 +228,85 @@ macro_rules! isometry_construction_impl(
/// 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`.
/// ///
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the /// It maps the `z` axis to the view direction `target - eye`and the origin to the `eye`.
/// `eye`.
/// ///
/// # Arguments /// # Arguments
/// * eye - The observer position. /// * eye - The observer position.
/// * target - The target position. /// * target - The target position.
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear /// * up - Vertical direction. The only requirement of this parameter is to not be collinear
/// to `eye - at`. Non-collinearity is not checked. /// to `eye - at`. Non-collinearity is not checked.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
/// let target = Point3::new(2.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// // Isometry with its rotation part represented as a UnitQuaternion
/// let iso = Isometry3::face_towards(&eye, &target, &up);
/// assert_eq!(iso * Point3::origin(), eye);
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
///
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
/// assert_eq!(iso * Point3::origin(), eye);
/// 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_vector(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.
/// ///
/// This conforms to the common notion of right handed look-at matrix from the computer /// It maps the view direction `target - eye` to the **negative** `z` axis to and the `eye` to the origin.
/// graphics community. /// This conforms to the common notion of right handed camera look-at **view matrix** from
/// the computer graphics community, i.e. the camera is assumed to look toward its local `-z` axis.
/// ///
/// # Arguments /// # Arguments
/// * eye - The eye position. /// * eye - The eye position.
/// * target - The target position. /// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
/// let target = Point3::new(2.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// // Isometry with its rotation part represented as a UnitQuaternion
/// let iso = Isometry3::look_at_rh(&eye, &target, &up);
/// assert_eq!(iso * eye, Point3::origin());
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
///
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let iso = IsometryMatrix3::look_at_rh(&eye, &target, &up);
/// assert_eq!(iso * eye, Point3::origin());
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_rh(eye: &Point3<N>, pub fn look_at_rh(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
@ -189,19 +315,41 @@ macro_rules! isometry_construction_impl(
let rotation = $RotId::look_at_rh(&(target - eye), up); let rotation = $RotId::look_at_rh(&(target - eye), up);
let trans = &rotation * (-eye); let trans = &rotation * (-eye);
Self::from_parts(Translation::from_vector(trans.coords), rotation) Self::from_parts(Translation::from(trans.coords), rotation)
} }
/// Builds a left-handed look-at view matrix. /// Builds a left-handed look-at view matrix.
/// ///
/// This conforms to the common notion of left handed look-at matrix from the computer /// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin.
/// graphics community. /// This conforms to the common notion of right handed camera look-at **view matrix** from
/// the computer graphics community, i.e. the camera is assumed to look toward its local `z` axis.
/// ///
/// # Arguments /// # Arguments
/// * eye - The eye position. /// * eye - The eye position.
/// * target - The target position. /// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
/// let target = Point3::new(2.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// // Isometry with its rotation part represented as a UnitQuaternion
/// let iso = Isometry3::look_at_lh(&eye, &target, &up);
/// assert_eq!(iso * eye, Point3::origin());
/// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
///
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let iso = IsometryMatrix3::look_at_lh(&eye, &target, &up);
/// assert_eq!(iso * eye, Point3::origin());
/// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_lh(eye: &Point3<N>, pub fn look_at_lh(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
@ -210,7 +358,7 @@ macro_rules! isometry_construction_impl(
let rotation = $RotId::look_at_lh(&(target - eye), up); let rotation = $RotId::look_at_lh(&(target - eye), up);
let trans = &rotation * (-eye); let trans = &rotation * (-eye);
Self::from_parts(Translation::from_vector(trans.coords), rotation) Self::from_parts(Translation::from(trans.coords), rotation)
} }
} }
} }

View File

@ -141,7 +141,9 @@ where
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self {
let t = m.fixed_slice::<D, U1>(0, D::dim()).into_owned(); let t = m.fixed_slice::<D, U1>(0, D::dim()).into_owned();
let t = Translation::from_vector(::convert_unchecked(t)); let t = Translation {
vector: ::convert_unchecked(t),
};
Self::from_parts(t, ::convert_unchecked(m.clone_owned())) Self::from_parts(t, ::convert_unchecked(m.clone_owned()))
} }

View File

@ -142,7 +142,7 @@ isometry_binop_impl_all!(
[ref ref] => { [ref ref] => {
let shift = self.rotation.transform_vector(&rhs.translation.vector); let shift = self.rotation.transform_vector(&rhs.translation.vector);
Isometry::from_parts(Translation::from_vector(&self.translation.vector + shift), Isometry::from_parts(Translation::from(&self.translation.vector + shift),
self.rotation.clone() * rhs.rotation.clone()) // FIXME: too bad we have to clone. self.rotation.clone() * rhs.rotation.clone()) // FIXME: too bad we have to clone.
}; };
); );
@ -267,7 +267,7 @@ isometry_binop_impl_all!(
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let new_tr = &self.translation.vector + self.rotation.transform_vector(&right.vector); let new_tr = &self.translation.vector + self.rotation.transform_vector(&right.vector);
Isometry::from_parts(Translation::from_vector(new_tr), self.rotation.clone()) Isometry::from_parts(Translation::from(new_tr), self.rotation.clone())
}; };
); );
@ -339,10 +339,10 @@ isometry_from_composition_impl_all!(
Mul, mul; Mul, mul;
(D, D), (D, U1) for D: DimName; (D, D), (D, U1) for D: DimName;
self: Rotation<N, D>, right: Translation<N, D>, Output = Isometry<N, D, Rotation<N, D>>; self: Rotation<N, D>, right: Translation<N, D>, Output = Isometry<N, D, Rotation<N, D>>;
[val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self); [val val] => Isometry::from_parts(Translation::from(&self * right.vector), self);
[ref val] => Isometry::from_parts(Translation::from_vector(self * right.vector), self.clone()); [ref val] => Isometry::from_parts(Translation::from(self * right.vector), self.clone());
[val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self); [val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from_vector(self * &right.vector), self.clone()); [ref ref] => Isometry::from_parts(Translation::from(self * &right.vector), self.clone());
); );
// UnitQuaternion × Translation // UnitQuaternion × Translation
@ -351,10 +351,10 @@ isometry_from_composition_impl_all!(
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternion<N>, right: Translation<N, U3>, self: UnitQuaternion<N>, right: Translation<N, U3>,
Output = Isometry<N, U3, UnitQuaternion<N>>; Output = Isometry<N, U3, UnitQuaternion<N>>;
[val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self); [val val] => Isometry::from_parts(Translation::from(&self * right.vector), self);
[ref val] => Isometry::from_parts(Translation::from_vector( self * right.vector), self.clone()); [ref val] => Isometry::from_parts(Translation::from( self * right.vector), self.clone());
[val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self); [val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from_vector( self * &right.vector), self.clone()); [ref ref] => Isometry::from_parts(Translation::from( self * &right.vector), self.clone());
); );
// Rotation × Isometry // Rotation × Isometry
@ -368,7 +368,7 @@ isometry_from_composition_impl_all!(
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let shift = self * &right.translation.vector; let shift = self * &right.translation.vector;
Isometry::from_parts(Translation::from_vector(shift), self * &right.rotation) Isometry::from_parts(Translation::from(shift), self * &right.rotation)
}; };
); );
@ -396,7 +396,7 @@ isometry_from_composition_impl_all!(
[val ref] => &self * right; [val ref] => &self * right;
[ref ref] => { [ref ref] => {
let shift = self * &right.translation.vector; let shift = self * &right.translation.vector;
Isometry::from_parts(Translation::from_vector(shift), self * &right.rotation) Isometry::from_parts(Translation::from(shift), self * &right.rotation)
}; };
); );

View File

@ -54,6 +54,8 @@ mod similarity_construction;
mod similarity_conversion; mod similarity_conversion;
mod similarity_ops; mod similarity_ops;
mod swizzle;
mod transform; mod transform;
mod transform_alga; mod transform_alga;
mod transform_alias; mod transform_alias;

View File

@ -63,21 +63,49 @@ impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Orthographic3<N> {
impl<N: Real> Orthographic3<N> { impl<N: Real> Orthographic3<N> {
/// Creates a new orthographic projection matrix. /// Creates a new orthographic projection matrix.
///
/// This follows the OpenGL convention, so this will flip the `z` axis.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// // Check this projection actually transforms the view cuboid into the double-unit cube.
/// // See https://www.nalgebra.org/projections/#orthographic-projection for more details.
/// let p1 = Point3::new(1.0, 2.0, -0.1);
/// let p2 = Point3::new(1.0, 2.0, -1000.0);
/// let p3 = Point3::new(1.0, 20.0, -0.1);
/// let p4 = Point3::new(1.0, 20.0, -1000.0);
/// let p5 = Point3::new(10.0, 2.0, -0.1);
/// let p6 = Point3::new(10.0, 2.0, -1000.0);
/// let p7 = Point3::new(10.0, 20.0, -0.1);
/// let p8 = Point3::new(10.0, 20.0, -1000.0);
///
/// assert_relative_eq!(proj.project_point(&p1), Point3::new(-1.0, -1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p2), Point3::new(-1.0, -1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p3), Point3::new(-1.0, 1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p4), Point3::new(-1.0, 1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p5), Point3::new( 1.0, -1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p6), Point3::new( 1.0, -1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p7), Point3::new( 1.0, 1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0));
///
/// // This also works with flipped axis. In other words, we allow that
/// // `left > right`, `bottom > top`, and/or `znear > zfar`.
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
///
/// assert_relative_eq!(proj.project_point(&p1), Point3::new( 1.0, 1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p2), Point3::new( 1.0, 1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p3), Point3::new( 1.0, -1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p4), Point3::new( 1.0, -1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p5), Point3::new(-1.0, 1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p6), Point3::new(-1.0, 1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p7), Point3::new(-1.0, -1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0));
/// ```
#[inline] #[inline]
pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self { pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
assert!(
left < right,
"The left corner must be farther than the right corner."
);
assert!(
bottom < top,
"The top corner must be higher than the bottom corner."
);
assert!(
znear < zfar,
"The far plane must be farther than the near plane."
);
let matrix = Matrix4::<N>::identity(); let matrix = Matrix4::<N>::identity();
let mut res = Self::from_matrix_unchecked(matrix); let mut res = Self::from_matrix_unchecked(matrix);
@ -92,6 +120,19 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// It is not checked whether or not the given matrix actually represents an orthographic /// It is not checked whether or not the given matrix actually represents an orthographic
/// projection. /// projection.
///
/// # Example
/// ```
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let mat = Matrix4::new(
/// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
/// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
/// 0.0, 0.0, 0.0, 1.0
/// );
/// let proj = Orthographic3::from_matrix_unchecked(mat);
/// assert_eq!(proj, Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0));
/// ```
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self { pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self {
Orthographic3 { matrix: matrix } Orthographic3 { matrix: matrix }
@ -101,8 +142,8 @@ impl<N: Real> Orthographic3<N> {
#[inline] #[inline]
pub fn from_fov(aspect: N, vfov: N, znear: N, zfar: N) -> Self { pub fn from_fov(aspect: N, vfov: N, znear: N, zfar: N) -> Self {
assert!( assert!(
znear < zfar, znear != zfar,
"The far plane must be farther than the near plane." "The far plane must not be equal to the near plane."
); );
assert!( assert!(
!relative_eq!(aspect, N::zero()), !relative_eq!(aspect, N::zero()),
@ -124,6 +165,22 @@ impl<N: Real> Orthographic3<N> {
} }
/// Retrieves the inverse of the underlying homogeneous matrix. /// Retrieves the inverse of the underlying homogeneous matrix.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let inv = proj.inverse();
///
/// assert_relative_eq!(inv * proj.as_matrix(), Matrix4::identity());
/// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity());
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// let inv = proj.inverse();
/// assert_relative_eq!(inv * proj.as_matrix(), Matrix4::identity());
/// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity());
/// ```
#[inline] #[inline]
pub fn inverse(&self) -> Matrix4<N> { pub fn inverse(&self) -> Matrix4<N> {
let mut res = self.to_homogeneous(); let mut res = self.to_homogeneous();
@ -144,66 +201,188 @@ impl<N: Real> Orthographic3<N> {
} }
/// Computes the corresponding homogeneous matrix. /// Computes the corresponding homogeneous matrix.
///
/// # Example
/// ```
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let expected = Matrix4::new(
/// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
/// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
/// 0.0, 0.0, 0.0, 1.0
/// );
/// assert_eq!(proj.to_homogeneous(), expected);
/// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> Matrix4<N> { pub fn to_homogeneous(&self) -> Matrix4<N> {
self.matrix self.matrix
} }
/// A reference to the underlying homogeneous transformation matrix. /// A reference to the underlying homogeneous transformation matrix.
///
/// # Example
/// ```
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let expected = Matrix4::new(
/// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
/// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
/// 0.0, 0.0, 0.0, 1.0
/// );
/// assert_eq!(*proj.as_matrix(), expected);
/// ```
#[inline] #[inline]
pub fn as_matrix(&self) -> &Matrix4<N> { pub fn as_matrix(&self) -> &Matrix4<N> {
&self.matrix &self.matrix
} }
/// A reference to this transformation seen as a `Projective3`. /// A reference to this transformation seen as a `Projective3`.
///
/// # Example
/// ```
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_eq!(proj.as_projective().to_homogeneous(), proj.to_homogeneous());
/// ```
#[inline] #[inline]
pub fn as_projective(&self) -> &Projective3<N> { pub fn as_projective(&self) -> &Projective3<N> {
unsafe { mem::transmute(self) } unsafe { mem::transmute(self) }
} }
/// This transformation seen as a `Projective3`. /// This transformation seen as a `Projective3`.
///
/// # Example
/// ```
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_eq!(proj.to_projective().to_homogeneous(), proj.to_homogeneous());
/// ```
#[inline] #[inline]
pub fn to_projective(&self) -> Projective3<N> { pub fn to_projective(&self) -> Projective3<N> {
Projective3::from_matrix_unchecked(self.matrix) Projective3::from_matrix_unchecked(self.matrix)
} }
/// Retrieves the underlying homogeneous matrix. /// Retrieves the underlying homogeneous matrix.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let expected = Matrix4::new(
/// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0,
/// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0,
/// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9,
/// 0.0, 0.0, 0.0, 1.0
/// );
/// assert_eq!(proj.into_inner(), expected);
/// ```
#[inline]
pub fn into_inner(self) -> Matrix4<N> {
self.matrix
}
/// Retrieves the underlying homogeneous matrix.
/// Deprecated: Use [Orthographic3::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline] #[inline]
pub fn unwrap(self) -> Matrix4<N> { pub fn unwrap(self) -> Matrix4<N> {
self.matrix self.matrix
} }
/// The smallest x-coordinate of the view cuboid. /// The left offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6);
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// assert_relative_eq!(proj.left(), 10.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn left(&self) -> N { pub fn left(&self) -> N {
(-N::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)] (-N::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)]
} }
/// The largest x-coordinate of the view cuboid. /// The right offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6);
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// assert_relative_eq!(proj.right(), 1.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn right(&self) -> N { pub fn right(&self) -> N {
(N::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)] (N::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)]
} }
/// The smallest y-coordinate of the view cuboid. /// The bottom offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6);
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// assert_relative_eq!(proj.bottom(), 20.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn bottom(&self) -> N { pub fn bottom(&self) -> N {
(-N::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)] (-N::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)]
} }
/// The largest y-coordinate of the view cuboid. /// The top offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6);
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// assert_relative_eq!(proj.top(), 2.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn top(&self) -> N { pub fn top(&self) -> N {
(N::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)] (N::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)]
} }
/// The near plane offset of the view cuboid. /// The near plane offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6);
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// assert_relative_eq!(proj.znear(), 1000.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn znear(&self) -> N { pub fn znear(&self) -> N {
(N::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)] (N::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)]
} }
/// The far plane offset of the view cuboid. /// The far plane offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6);
///
/// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1);
/// assert_relative_eq!(proj.zfar(), 0.1, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn zfar(&self) -> N { pub fn zfar(&self) -> N {
(-N::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)] (-N::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)]
@ -211,6 +390,31 @@ impl<N: Real> Orthographic3<N> {
// FIXME: when we get specialization, specialize the Mul impl instead. // FIXME: when we get specialization, specialize the Mul impl instead.
/// Projects a point. Faster than matrix multiplication. /// Projects a point. Faster than matrix multiplication.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
///
/// let p1 = Point3::new(1.0, 2.0, -0.1);
/// let p2 = Point3::new(1.0, 2.0, -1000.0);
/// let p3 = Point3::new(1.0, 20.0, -0.1);
/// let p4 = Point3::new(1.0, 20.0, -1000.0);
/// let p5 = Point3::new(10.0, 2.0, -0.1);
/// let p6 = Point3::new(10.0, 2.0, -1000.0);
/// let p7 = Point3::new(10.0, 20.0, -0.1);
/// let p8 = Point3::new(10.0, 20.0, -1000.0);
///
/// assert_relative_eq!(proj.project_point(&p1), Point3::new(-1.0, -1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p2), Point3::new(-1.0, -1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p3), Point3::new(-1.0, 1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p4), Point3::new(-1.0, 1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p5), Point3::new( 1.0, -1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p6), Point3::new( 1.0, -1.0, 1.0));
/// assert_relative_eq!(proj.project_point(&p7), Point3::new( 1.0, 1.0, -1.0));
/// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0));
/// ```
#[inline] #[inline]
pub fn project_point(&self, p: &Point3<N>) -> Point3<N> { pub fn project_point(&self, p: &Point3<N>) -> Point3<N> {
Point3::new( Point3::new(
@ -221,6 +425,31 @@ impl<N: Real> Orthographic3<N> {
} }
/// Un-projects a point. Faster than multiplication by the underlying matrix inverse. /// Un-projects a point. Faster than multiplication by the underlying matrix inverse.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
///
/// let p1 = Point3::new(-1.0, -1.0, -1.0);
/// let p2 = Point3::new(-1.0, -1.0, 1.0);
/// let p3 = Point3::new(-1.0, 1.0, -1.0);
/// let p4 = Point3::new(-1.0, 1.0, 1.0);
/// let p5 = Point3::new( 1.0, -1.0, -1.0);
/// let p6 = Point3::new( 1.0, -1.0, 1.0);
/// let p7 = Point3::new( 1.0, 1.0, -1.0);
/// let p8 = Point3::new( 1.0, 1.0, 1.0);
///
/// assert_relative_eq!(proj.unproject_point(&p1), Point3::new(1.0, 2.0, -0.1), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p2), Point3::new(1.0, 2.0, -1000.0), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p3), Point3::new(1.0, 20.0, -0.1), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p4), Point3::new(1.0, 20.0, -1000.0), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p5), Point3::new(10.0, 2.0, -0.1), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p6), Point3::new(10.0, 2.0, -1000.0), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p7), Point3::new(10.0, 20.0, -0.1), epsilon = 1.0e-6);
/// assert_relative_eq!(proj.unproject_point(&p8), Point3::new(10.0, 20.0, -1000.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn unproject_point(&self, p: &Point3<N>) -> Point3<N> { pub fn unproject_point(&self, p: &Point3<N>) -> Point3<N> {
Point3::new( Point3::new(
@ -232,6 +461,23 @@ impl<N: Real> Orthographic3<N> {
// FIXME: when we get specialization, specialize the Mul impl instead. // FIXME: when we get specialization, specialize the Mul impl instead.
/// Projects a vector. Faster than matrix multiplication. /// Projects a vector. Faster than matrix multiplication.
///
/// Vectors are not affected by the translation part of the projection.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Orthographic3, Vector3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
///
/// let v1 = Vector3::x();
/// let v2 = Vector3::y();
/// let v3 = Vector3::z();
///
/// assert_relative_eq!(proj.project_vector(&v1), Vector3::x() * 2.0 / 9.0);
/// assert_relative_eq!(proj.project_vector(&v2), Vector3::y() * 2.0 / 18.0);
/// assert_relative_eq!(proj.project_vector(&v3), Vector3::z() * -2.0 / 999.9);
/// ```
#[inline] #[inline]
pub fn project_vector<SB>(&self, p: &Vector<N, U3, SB>) -> Vector3<N> pub fn project_vector<SB>(&self, p: &Vector<N, U3, SB>) -> Vector3<N>
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
@ -242,28 +488,76 @@ impl<N: Real> Orthographic3<N> {
) )
} }
/// Sets the smallest x-coordinate of the view cuboid. /// Sets the left offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left(2.0);
/// assert_relative_eq!(proj.left(), 2.0, epsilon = 1.0e-6);
///
/// // It is OK to set a left offset greater than the current right offset.
/// proj.set_left(20.0);
/// assert_relative_eq!(proj.left(), 20.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_left(&mut self, left: N) { pub fn set_left(&mut self, left: N) {
let right = self.right(); let right = self.right();
self.set_left_and_right(left, right); self.set_left_and_right(left, right);
} }
/// Sets the largest x-coordinate of the view cuboid. /// Sets the right offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_right(15.0);
/// assert_relative_eq!(proj.right(), 15.0, epsilon = 1.0e-6);
///
/// // It is OK to set a right offset smaller than the current left offset.
/// proj.set_right(-3.0);
/// assert_relative_eq!(proj.right(), -3.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_right(&mut self, right: N) { pub fn set_right(&mut self, right: N) {
let left = self.left(); let left = self.left();
self.set_left_and_right(left, right); self.set_left_and_right(left, right);
} }
/// Sets the smallest y-coordinate of the view cuboid. /// Sets the bottom offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom(8.0);
/// assert_relative_eq!(proj.bottom(), 8.0, epsilon = 1.0e-6);
///
/// // It is OK to set a bottom offset greater than the current top offset.
/// proj.set_bottom(50.0);
/// assert_relative_eq!(proj.bottom(), 50.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_bottom(&mut self, bottom: N) { pub fn set_bottom(&mut self, bottom: N) {
let top = self.top(); let top = self.top();
self.set_bottom_and_top(bottom, top); self.set_bottom_and_top(bottom, top);
} }
/// Sets the largest y-coordinate of the view cuboid. /// Sets the top offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_top(15.0);
/// assert_relative_eq!(proj.top(), 15.0, epsilon = 1.0e-6);
///
/// // It is OK to set a top offset smaller than the current bottom offset.
/// proj.set_top(-3.0);
/// assert_relative_eq!(proj.top(), -3.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_top(&mut self, top: N) { pub fn set_top(&mut self, top: N) {
let bottom = self.bottom(); let bottom = self.bottom();
@ -271,6 +565,18 @@ impl<N: Real> Orthographic3<N> {
} }
/// Sets the near plane offset of the view cuboid. /// Sets the near plane offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear(8.0);
/// assert_relative_eq!(proj.znear(), 8.0, epsilon = 1.0e-6);
///
/// // It is OK to set a znear greater than the current zfar.
/// proj.set_znear(5000.0);
/// assert_relative_eq!(proj.znear(), 5000.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_znear(&mut self, znear: N) { pub fn set_znear(&mut self, znear: N) {
let zfar = self.zfar(); let zfar = self.zfar();
@ -278,39 +584,93 @@ impl<N: Real> Orthographic3<N> {
} }
/// Sets the far plane offset of the view cuboid. /// Sets the far plane offset of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_zfar(15.0);
/// assert_relative_eq!(proj.zfar(), 15.0, epsilon = 1.0e-6);
///
/// // It is OK to set a zfar smaller than the current znear.
/// proj.set_zfar(-3.0);
/// assert_relative_eq!(proj.zfar(), -3.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_zfar(&mut self, zfar: N) { pub fn set_zfar(&mut self, zfar: N) {
let znear = self.znear(); let znear = self.znear();
self.set_znear_and_zfar(znear, zfar); self.set_znear_and_zfar(znear, zfar);
} }
/// Sets the view cuboid coordinates along the `x` axis. /// Sets the view cuboid offsets along the `x` axis.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left_and_right(7.0, 70.0);
/// assert_relative_eq!(proj.left(), 7.0, epsilon = 1.0e-6);
/// assert_relative_eq!(proj.right(), 70.0, epsilon = 1.0e-6);
///
/// // It is also OK to have `left > right`.
/// proj.set_left_and_right(70.0, 7.0);
/// assert_relative_eq!(proj.left(), 70.0, epsilon = 1.0e-6);
/// assert_relative_eq!(proj.right(), 7.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_left_and_right(&mut self, left: N, right: N) { pub fn set_left_and_right(&mut self, left: N, right: N) {
assert!( assert!(
left < right, left != right,
"The left corner must be farther than the right corner." "The left corner must not be equal to the right corner."
); );
self.matrix[(0, 0)] = ::convert::<_, N>(2.0) / (right - left); self.matrix[(0, 0)] = ::convert::<_, N>(2.0) / (right - left);
self.matrix[(0, 3)] = -(right + left) / (right - left); self.matrix[(0, 3)] = -(right + left) / (right - left);
} }
/// Sets the view cuboid coordinates along the `y` axis. /// Sets the view cuboid offsets along the `y` axis.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom_and_top(7.0, 70.0);
/// assert_relative_eq!(proj.bottom(), 7.0, epsilon = 1.0e-6);
/// assert_relative_eq!(proj.top(), 70.0, epsilon = 1.0e-6);
///
/// // It is also OK to have `bottom > top`.
/// proj.set_bottom_and_top(70.0, 7.0);
/// assert_relative_eq!(proj.bottom(), 70.0, epsilon = 1.0e-6);
/// assert_relative_eq!(proj.top(), 7.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_bottom_and_top(&mut self, bottom: N, top: N) { pub fn set_bottom_and_top(&mut self, bottom: N, top: N) {
assert!( assert!(
bottom < top, bottom != top,
"The top corner must be higher than the bottom corner." "The top corner must not be equal to the bottom corner."
); );
self.matrix[(1, 1)] = ::convert::<_, N>(2.0) / (top - bottom); self.matrix[(1, 1)] = ::convert::<_, N>(2.0) / (top - bottom);
self.matrix[(1, 3)] = -(top + bottom) / (top - bottom); self.matrix[(1, 3)] = -(top + bottom) / (top - bottom);
} }
/// Sets the near and far plane offsets of the view cuboid. /// Sets the near and far plane offsets of the view cuboid.
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear_and_zfar(50.0, 5000.0);
/// assert_relative_eq!(proj.znear(), 50.0, epsilon = 1.0e-6);
/// assert_relative_eq!(proj.zfar(), 5000.0, epsilon = 1.0e-6);
///
/// // It is also OK to have `znear > zfar`.
/// proj.set_znear_and_zfar(5000.0, 0.5);
/// assert_relative_eq!(proj.znear(), 5000.0, epsilon = 1.0e-6);
/// assert_relative_eq!(proj.zfar(), 0.5, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) { pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
assert!( assert!(
!relative_eq!(zfar - znear, N::zero()), zfar != znear,
"The near-plane and far-plane must not be superimposed." "The near-plane and far-plane must not be superimposed."
); );
self.matrix[(2, 2)] = -::convert::<_, N>(2.0) / (zfar - znear); self.matrix[(2, 2)] = -::convert::<_, N>(2.0) / (zfar - znear);
@ -352,6 +712,6 @@ where Matrix4<N>: Send
impl<N: Real> From<Orthographic3<N>> for Matrix4<N> { impl<N: Real> From<Orthographic3<N>> for Matrix4<N> {
#[inline] #[inline]
fn from(orth: Orthographic3<N>) -> Self { fn from(orth: Orthographic3<N>) -> Self {
orth.unwrap() orth.into_inner()
} }
} }

View File

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

View File

@ -19,7 +19,7 @@ use base::{DefaultAllocator, Scalar, VectorN};
/// A point in a n-dimensional euclidean space. /// A point in a n-dimensional euclidean space.
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Point<N: Scalar, D: DimName> pub struct Point<N: Scalar, D: DimName>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
@ -44,17 +44,6 @@ where
{ {
} }
impl<N: Scalar, D: DimName> Clone for Point<N, D>
where
DefaultAllocator: Allocator<N, D>,
<DefaultAllocator as Allocator<N, D>>::Buffer: Clone,
{
#[inline]
fn clone(&self) -> Self {
Point::from_coordinates(self.coords.clone())
}
}
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<N: Scalar, D: DimName> Serialize for Point<N, D> impl<N: Scalar, D: DimName> Serialize for Point<N, D>
where where
@ -77,7 +66,7 @@ where
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let coords = VectorN::<N, D>::deserialize(deserializer)?; let coords = VectorN::<N, D>::deserialize(deserializer)?;
Ok(Point::from_coordinates(coords)) Ok(Point::from(coords))
} }
} }
@ -105,14 +94,21 @@ where
impl<N: Scalar, D: DimName> Point<N, D> impl<N: Scalar, D: DimName> Point<N, D>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
/// Clones this point into one that owns its data.
#[inline]
pub fn clone(&self) -> Point<N, D> {
Point::from_coordinates(self.coords.clone_owned())
}
/// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the
/// end of it. /// end of it.
///
/// This is the same as `.into()`.
///
/// # Example
/// ```
/// # use nalgebra::{Point2, Point3, Vector3, Vector4};
/// let p = Point2::new(10.0, 20.0);
/// assert_eq!(p.to_homogeneous(), Vector3::new(10.0, 20.0, 1.0));
///
/// // This works in any dimension.
/// let p = Point3::new(10.0, 20.0, 30.0);
/// assert_eq!(p.to_homogeneous(), Vector4::new(10.0, 20.0, 30.0, 1.0));
/// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> VectorN<N, DimNameSum<D, U1>> pub fn to_homogeneous(&self) -> VectorN<N, DimNameSum<D, U1>>
where where
@ -128,12 +124,24 @@ where DefaultAllocator: Allocator<N, D>
} }
/// Creates a new point with the given coordinates. /// Creates a new point with the given coordinates.
#[deprecated(note = "Use Point::from(vector) instead.")]
#[inline] #[inline]
pub fn from_coordinates(coords: VectorN<N, D>) -> Point<N, D> { pub fn from_coordinates(coords: VectorN<N, D>) -> Point<N, D> {
Point { coords: coords } Point { coords: coords }
} }
/// The dimension of this point. /// The dimension of this point.
///
/// # Example
/// ```
/// # use nalgebra::{Point2, Point3};
/// let p = Point2::new(1.0, 2.0);
/// assert_eq!(p.len(), 2);
///
/// // This works in any dimension.
/// let p = Point3::new(10.0, 20.0, 30.0);
/// assert_eq!(p.len(), 3);
/// ```
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.coords.len() self.coords.len()
@ -142,11 +150,23 @@ where DefaultAllocator: Allocator<N, D>
/// The stride of this point. This is the number of buffer element separating each component of /// The stride of this point. This is the number of buffer element separating each component of
/// this point. /// this point.
#[inline] #[inline]
#[deprecated(note = "This methods is no longer significant and will always return 1.")]
pub fn stride(&self) -> usize { pub fn stride(&self) -> usize {
self.coords.strides().0 self.coords.strides().0
} }
/// Iterates through this point coordinates. /// Iterates through this point coordinates.
///
/// # Example
/// ```
/// # use nalgebra::Point3;
/// let p = Point3::new(1.0, 2.0, 3.0);
/// let mut it = p.iter().cloned();
///
/// assert_eq!(it.next(), Some(1.0));
/// assert_eq!(it.next(), Some(2.0));
/// assert_eq!(it.next(), Some(3.0));
/// assert_eq!(it.next(), None);
#[inline] #[inline]
pub fn iter(&self) -> MatrixIter<N, D, U1, <DefaultAllocator as Allocator<N, D>>::Buffer> { pub fn iter(&self) -> MatrixIter<N, D, U1, <DefaultAllocator as Allocator<N, D>>::Buffer> {
self.coords.iter() self.coords.iter()
@ -159,6 +179,17 @@ where DefaultAllocator: Allocator<N, D>
} }
/// Mutably iterates through this point coordinates. /// Mutably iterates through this point coordinates.
///
/// # Example
/// ```
/// # use nalgebra::Point3;
/// let mut p = Point3::new(1.0, 2.0, 3.0);
///
/// for e in p.iter_mut() {
/// *e *= 10.0;
/// }
///
/// assert_eq!(p, Point3::new(10.0, 20.0, 30.0));
#[inline] #[inline]
pub fn iter_mut( pub fn iter_mut(
&mut self, &mut self,

View File

@ -33,7 +33,7 @@ where DefaultAllocator: Allocator<N, D>
#[inline] #[inline]
fn from_coordinates(coords: Self::Coordinates) -> Self { fn from_coordinates(coords: Self::Coordinates) -> Self {
Self::from_coordinates(coords) Self::from(coords)
} }
#[inline] #[inline]
@ -54,7 +54,7 @@ where
{ {
#[inline] #[inline]
fn meet(&self, other: &Self) -> Self { fn meet(&self, other: &Self) -> Self {
Point::from_coordinates(self.coords.meet(&other.coords)) Point::from(self.coords.meet(&other.coords))
} }
} }
@ -65,7 +65,7 @@ where
{ {
#[inline] #[inline]
fn join(&self, other: &Self) -> Self { fn join(&self, other: &Self) -> Self {
Point::from_coordinates(self.coords.join(&other.coords)) Point::from(self.coords.join(&other.coords))
} }
} }
@ -78,6 +78,6 @@ where
fn meet_join(&self, other: &Self) -> (Self, Self) { fn meet_join(&self, other: &Self) -> (Self, Self) {
let (meet, join) = self.coords.meet_join(&other.coords); let (meet, join) = self.coords.meet_join(&other.coords);
(Point::from_coordinates(meet), Point::from_coordinates(join)) (Point::from(meet), Point::from(join))
} }
} }

View File

@ -18,26 +18,79 @@ where DefaultAllocator: Allocator<N, D>
/// Creates a new point with uninitialized coordinates. /// Creates a new point with uninitialized coordinates.
#[inline] #[inline]
pub unsafe fn new_uninitialized() -> Self { pub unsafe fn new_uninitialized() -> Self {
Self::from_coordinates(VectorN::new_uninitialized()) Self::from(VectorN::new_uninitialized())
} }
/// Creates a new point with all coordinates equal to zero. /// Creates a new point with all coordinates equal to zero.
///
/// # Example
///
/// ```
/// # use nalgebra::{Point2, Point3};
/// // This works in any dimension.
/// // The explicit ::<f32> type annotation may not always be needed,
/// // depending on the context of type inference.
/// let pt = Point2::<f32>::origin();
/// assert!(pt.x == 0.0 && pt.y == 0.0);
///
/// let pt = Point3::<f32>::origin();
/// assert!(pt.x == 0.0 && pt.y == 0.0 && pt.z == 0.0);
/// ```
#[inline] #[inline]
pub fn origin() -> Self pub fn origin() -> Self
where N: Zero { where N: Zero {
Self::from_coordinates(VectorN::from_element(N::zero())) Self::from(VectorN::from_element(N::zero()))
} }
/// Creates a new point from a slice. /// Creates a new point from a slice.
///
/// # Example
///
/// ```
/// # use nalgebra::{Point2, Point3};
/// let data = [ 1.0, 2.0, 3.0 ];
///
/// let pt = Point2::from_slice(&data[..2]);
/// assert_eq!(pt, Point2::new(1.0, 2.0));
///
/// let pt = Point3::from_slice(&data);
/// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0));
/// ```
#[inline] #[inline]
pub fn from_slice(components: &[N]) -> Self { pub fn from_slice(components: &[N]) -> Self {
Self::from_coordinates(VectorN::from_row_slice(components)) Self::from(VectorN::from_row_slice(components))
} }
/// Creates a new point from its homogeneous vector representation. /// Creates a new point from its homogeneous vector representation.
/// ///
/// In practice, this builds a D-dimensional points with the same first D component as `v` /// In practice, this builds a D-dimensional points with the same first D component as `v`
/// divided by the last component of `v`. Returns `None` if this divisor is zero. /// divided by the last component of `v`. Returns `None` if this divisor is zero.
///
/// # Example
///
/// ```
/// # use nalgebra::{Point2, Point3, Vector3, Vector4};
///
/// let coords = Vector4::new(1.0, 2.0, 3.0, 1.0);
/// let pt = Point3::from_homogeneous(coords);
/// assert_eq!(pt, Some(Point3::new(1.0, 2.0, 3.0)));
///
/// // All component of the result will be divided by the
/// // last component of the vector, here 2.0.
/// let coords = Vector4::new(1.0, 2.0, 3.0, 2.0);
/// let pt = Point3::from_homogeneous(coords);
/// assert_eq!(pt, Some(Point3::new(0.5, 1.0, 1.5)));
///
/// // Fails because the last component is zero.
/// let coords = Vector4::new(1.0, 2.0, 3.0, 0.0);
/// let pt = Point3::from_homogeneous(coords);
/// assert!(pt.is_none());
///
/// // Works also in other dimensions.
/// let coords = Vector3::new(1.0, 2.0, 1.0);
/// let pt = Point2::from_homogeneous(coords);
/// assert_eq!(pt, Some(Point2::new(1.0, 2.0)));
/// ```
#[inline] #[inline]
pub fn from_homogeneous(v: VectorN<N, DimNameSum<D, U1>>) -> Option<Self> pub fn from_homogeneous(v: VectorN<N, DimNameSum<D, U1>>) -> Option<Self>
where where
@ -47,7 +100,7 @@ where DefaultAllocator: Allocator<N, D>
{ {
if !v[D::dim()].is_zero() { if !v[D::dim()].is_zero() {
let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()]; let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
Some(Self::from_coordinates(coords)) Some(Self::from(coords))
} else { } else {
None None
} }
@ -64,12 +117,12 @@ where DefaultAllocator: Allocator<N, D>
{ {
#[inline] #[inline]
fn max_value() -> Self { fn max_value() -> Self {
Self::from_coordinates(VectorN::max_value()) Self::from(VectorN::max_value())
} }
#[inline] #[inline]
fn min_value() -> Self { fn min_value() -> Self {
Self::from_coordinates(VectorN::min_value()) Self::from(VectorN::min_value())
} }
} }
@ -80,7 +133,7 @@ where
{ {
#[inline] #[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Point<N, D> { fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Point<N, D> {
Point::from_coordinates(rng.gen::<VectorN<N, D>>()) Point::from(rng.gen::<VectorN<N, D>>())
} }
} }
@ -92,7 +145,7 @@ where
{ {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
Point::from_coordinates(VectorN::arbitrary(g)) Point::from(VectorN::arbitrary(g))
} }
} }
@ -102,10 +155,13 @@ where
* *
*/ */
macro_rules! componentwise_constructors_impl( macro_rules! componentwise_constructors_impl(
($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$( ($($doc: expr; $D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<N: Scalar> Point<N, $D> impl<N: Scalar> Point<N, $D>
where DefaultAllocator: Allocator<N, $D> { where DefaultAllocator: Allocator<N, $D> {
/// Initializes this matrix from its components. #[doc = "Initializes this point from its components."]
#[doc = "# Example\n```"]
#[doc = $doc]
#[doc = "```"]
#[inline] #[inline]
pub fn new($($args: N),*) -> Point<N, $D> { pub fn new($($args: N),*) -> Point<N, $D> {
unsafe { unsafe {
@ -120,11 +176,17 @@ macro_rules! componentwise_constructors_impl(
); );
componentwise_constructors_impl!( componentwise_constructors_impl!(
"# use nalgebra::Point1;\nlet p = Point1::new(1.0);\nassert!(p.x == 1.0);";
U1, x:0; U1, x:0;
"# use nalgebra::Point2;\nlet p = Point2::new(1.0, 2.0);\nassert!(p.x == 1.0 && p.y == 2.0);";
U2, x:0, y:1; U2, x:0, y:1;
"# use nalgebra::Point3;\nlet p = Point3::new(1.0, 2.0, 3.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0);";
U3, x:0, y:1, z:2; U3, x:0, y:1, z:2;
"# use nalgebra::Point4;\nlet p = Point4::new(1.0, 2.0, 3.0, 4.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0);";
U4, x:0, y:1, z:2, w:3; U4, x:0, y:1, z:2, w:3;
"# use nalgebra::Point5;\nlet p = Point5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0);";
U5, x:0, y:1, z:2, w:3, a:4; U5, x:0, y:1, z:2, w:3, a:4;
"# use nalgebra::Point6;\nlet p = Point6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0 && p.b == 6.0);";
U6, x:0, y:1, z:2, w:3, a:4, b:5; U6, x:0, y:1, z:2, w:3, a:4, b:5;
); );
@ -132,7 +194,9 @@ macro_rules! from_array_impl(
($($D: ty, $len: expr);*) => {$( ($($D: ty, $len: expr);*) => {$(
impl <N: Scalar> From<[N; $len]> for Point<N, $D> { impl <N: Scalar> From<[N; $len]> for Point<N, $D> {
fn from (coords: [N; $len]) -> Self { fn from (coords: [N; $len]) -> Self {
Point::from_coordinates(coords.into()) Point {
coords: coords.into()
}
} }
} }
)*} )*}

View File

@ -33,7 +33,7 @@ where
{ {
#[inline] #[inline]
fn to_superset(&self) -> Point<N2, D> { fn to_superset(&self) -> Point<N2, D> {
Point::from_coordinates(self.coords.to_superset()) Point::from(self.coords.to_superset())
} }
#[inline] #[inline]
@ -45,7 +45,7 @@ where
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self { unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self {
Point::from_coordinates(Matrix::from_superset_unchecked(&m.coords)) Point::from(Matrix::from_superset_unchecked(&m.coords))
} }
} }
@ -73,7 +73,9 @@ where
#[inline] #[inline]
unsafe fn from_superset_unchecked(v: &VectorN<N2, DimNameSum<D, U1>>) -> Self { unsafe fn from_superset_unchecked(v: &VectorN<N2, DimNameSum<D, U1>>) -> Self {
let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()]; let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
Self::from_coordinates(::convert_unchecked(coords)) Self {
coords: ::convert_unchecked(coords)
}
} }
} }
@ -138,3 +140,15 @@ where
t.to_homogeneous() t.to_homogeneous()
} }
} }
impl<N: Scalar, D: DimName> From<VectorN<N, D>> for Point<N, D>
where
DefaultAllocator: Allocator<N, D>,
{
#[inline]
fn from(coords: VectorN<N, D>) -> Self {
Point {
coords
}
}
}

View File

@ -50,7 +50,7 @@ where DefaultAllocator: Allocator<N, D>
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Point::from_coordinates(-self.coords) Point::from(-self.coords)
} }
} }
@ -61,7 +61,7 @@ where DefaultAllocator: Allocator<N, D>
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Point::from_coordinates(-&self.coords) Point::from(-&self.coords)
} }
} }
@ -96,43 +96,43 @@ add_sub_impl!(Sub, sub, ClosedSub;
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>; self: &'a Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords - right); 'a, 'b); Self::Output::from(&self.coords - right); 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>; self: &'a Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords - &right); 'a); // FIXME: should not be a ref to `right`. Self::Output::from(&self.coords - &right); 'a); // FIXME: should not be a ref to `right`.
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>; self: Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords - right); 'b); Self::Output::from(self.coords - right); 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>; self: Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords - right); ); Self::Output::from(self.coords - right); );
// Point + Vector // Point + Vector
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>; self: &'a Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords + right); 'a, 'b); Self::Output::from(&self.coords + right); 'a, 'b);
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: &'a Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>; self: &'a Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(&self.coords + &right); 'a); // FIXME: should not be a ref to `right`. Self::Output::from(&self.coords + &right); 'a); // FIXME: should not be a ref to `right`.
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>; self: Point<N, D1>, right: &'b Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords + right); 'b); Self::Output::from(self.coords + right); 'b);
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>; (D1, U1), (D2, U1) -> (D1) for D1: DimName, D2: Dim, SB: Storage<N, D2>;
self: Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>; self: Point<N, D1>, right: Vector<N, D2, SB>, Output = Point<N, D1>;
Self::Output::from_coordinates(self.coords + right); ); Self::Output::from(self.coords + right); );
// XXX: replace by the shared macro: add_sub_assign_impl // XXX: replace by the shared macro: add_sub_assign_impl
macro_rules! op_assign_impl( macro_rules! op_assign_impl(
@ -178,10 +178,10 @@ md_impl_all!(
(R1, C1), (D2, U1) for R1: DimName, C1: Dim, D2: DimName, SA: Storage<N, R1, C1> (R1, C1), (D2, U1) for R1: DimName, C1: Dim, D2: DimName, SA: Storage<N, R1, C1>
where ShapeConstraint: AreMultipliable<R1, C1, D2, U1>; where ShapeConstraint: AreMultipliable<R1, C1, D2, U1>;
self: Matrix<N, R1, C1, SA>, right: Point<N, D2>, Output = Point<N, R1>; self: Matrix<N, R1, C1, SA>, right: Point<N, D2>, Output = Point<N, R1>;
[val val] => Point::from_coordinates(self * right.coords); [val val] => Point::from(self * right.coords);
[ref val] => Point::from_coordinates(self * right.coords); [ref val] => Point::from(self * right.coords);
[val ref] => Point::from_coordinates(self * &right.coords); [val ref] => Point::from(self * &right.coords);
[ref ref] => Point::from_coordinates(self * &right.coords); [ref ref] => Point::from(self * &right.coords);
); );
/* /*
@ -198,7 +198,7 @@ macro_rules! componentwise_scalarop_impl(
#[inline] #[inline]
fn $method(self, right: N) -> Self::Output { fn $method(self, right: N) -> Self::Output {
Point::from_coordinates(self.coords.$method(right)) Point::from(self.coords.$method(right))
} }
} }
@ -208,7 +208,7 @@ macro_rules! componentwise_scalarop_impl(
#[inline] #[inline]
fn $method(self, right: N) -> Self::Output { fn $method(self, right: N) -> Self::Output {
Point::from_coordinates((&self.coords).$method(right)) Point::from((&self.coords).$method(right))
} }
} }
@ -233,7 +233,7 @@ macro_rules! left_scalar_mul_impl(
#[inline] #[inline]
fn mul(self, right: Point<$T, D>) -> Self::Output { fn mul(self, right: Point<$T, D>) -> Self::Output {
Point::from_coordinates(self * right.coords) Point::from(self * right.coords)
} }
} }
@ -243,7 +243,7 @@ macro_rules! left_scalar_mul_impl(
#[inline] #[inline]
fn mul(self, right: &'b Point<$T, D>) -> Self::Output { fn mul(self, right: &'b Point<$T, D>) -> Self::Output {
Point::from_coordinates(self * &right.coords) Point::from(self * &right.coords)
} }
} }
)*} )*}

View File

@ -68,7 +68,7 @@ impl<N: Real> Copy for Quaternion<N> {}
impl<N: Real> Clone for Quaternion<N> { impl<N: Real> Clone for Quaternion<N> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Quaternion::from_vector(self.coords.clone()) Quaternion::from(self.coords.clone())
} }
} }
@ -90,7 +90,7 @@ where Owned<N, U4>: Deserialize<'a>
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let coords = Vector4::<N>::deserialize(deserializer)?; let coords = Vector4::<N>::deserialize(deserializer)?;
Ok(Quaternion::from_vector(coords)) Ok(Quaternion::from(coords))
} }
} }
@ -106,16 +106,33 @@ impl<N: Real> Quaternion<N> {
#[inline] #[inline]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")] #[deprecated(note = "This method is a no-op and will be removed in a future release.")]
pub fn clone_owned(&self) -> Quaternion<N> { pub fn clone_owned(&self) -> Quaternion<N> {
Quaternion::from_vector(self.coords.clone_owned()) Quaternion::from(self.coords.clone_owned())
} }
/// Normalizes this quaternion. /// Normalizes this quaternion.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let q_normalized = q.normalize();
/// relative_eq!(q_normalized.norm(), 1.0);
/// ```
#[inline] #[inline]
pub fn normalize(&self) -> Quaternion<N> { pub fn normalize(&self) -> Quaternion<N> {
Quaternion::from_vector(self.coords.normalize()) Quaternion::from(self.coords.normalize())
} }
/// Compute the conjugate of this quaternion. /// The conjugate of this quaternion.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let conj = q.conjugate();
/// assert!(conj.i == -2.0 && conj.j == -3.0 && conj.k == -4.0 && conj.w == 1.0);
/// ```
#[inline] #[inline]
pub fn conjugate(&self) -> Quaternion<N> { pub fn conjugate(&self) -> Quaternion<N> {
let v = Vector4::new( let v = Vector4::new(
@ -124,13 +141,30 @@ impl<N: Real> Quaternion<N> {
-self.coords[2], -self.coords[2],
self.coords[3], self.coords[3],
); );
Quaternion::from_vector(v) Quaternion::from(v)
} }
/// Inverts this quaternion if it is not zero. /// Inverts this quaternion if it is not zero.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let inv_q = q.try_inverse();
///
/// assert!(inv_q.is_some());
/// assert_relative_eq!(inv_q.unwrap() * q, Quaternion::identity());
///
/// //Non-invertible case
/// let q = Quaternion::new(0.0, 0.0, 0.0, 0.0);
/// let inv_q = q.try_inverse();
///
/// assert!(inv_q.is_none());
/// ```
#[inline] #[inline]
pub fn try_inverse(&self) -> Option<Quaternion<N>> { pub fn try_inverse(&self) -> Option<Quaternion<N>> {
let mut res = Quaternion::from_vector(self.coords.clone_owned()); let mut res = Quaternion::from(self.coords.clone_owned());
if res.try_inverse_mut() { if res.try_inverse_mut() {
Some(res) Some(res)
@ -140,30 +174,74 @@ impl<N: Real> Quaternion<N> {
} }
/// Linear interpolation between two quaternion. /// Linear interpolation between two quaternion.
///
/// Computes `self * (1 - t) + other * t`.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let q2 = Quaternion::new(10.0, 20.0, 30.0, 40.0);
///
/// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6));
/// ```
#[inline] #[inline]
pub fn lerp(&self, other: &Quaternion<N>, t: N) -> Quaternion<N> { pub fn lerp(&self, other: &Quaternion<N>, t: N) -> Quaternion<N> {
self * (N::one() - t) + other * t self * (N::one() - t) + other * t
} }
/// The vector part `(i, j, k)` of this quaternion. /// The vector part `(i, j, k)` of this quaternion.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_eq!(q.vector()[0], 2.0);
/// assert_eq!(q.vector()[1], 3.0);
/// assert_eq!(q.vector()[2], 4.0);
/// ```
#[inline] #[inline]
pub fn vector(&self) -> MatrixSlice<N, U3, U1, RStride<N, U4, U1>, CStride<N, U4, U1>> { pub fn vector(&self) -> MatrixSlice<N, U3, U1, RStride<N, U4, U1>, CStride<N, U4, U1>> {
self.coords.fixed_rows::<U3>(0) self.coords.fixed_rows::<U3>(0)
} }
/// The scalar part `w` of this quaternion. /// The scalar part `w` of this quaternion.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_eq!(q.scalar(), 1.0);
/// ```
#[inline] #[inline]
pub fn scalar(&self) -> N { pub fn scalar(&self) -> N {
self.coords[3] self.coords[3]
} }
/// Reinterprets this quaternion as a 4D vector. /// Reinterprets this quaternion as a 4D vector.
///
/// # Example
/// ```
/// # use nalgebra::{Vector4, Quaternion};
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// // Recall that the quaternion is stored internally as (i, j, k, w)
/// // while the ::new constructor takes the arguments as (w, i, j, k).
/// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0));
/// ```
#[inline] #[inline]
pub fn as_vector(&self) -> &Vector4<N> { pub fn as_vector(&self) -> &Vector4<N> {
&self.coords &self.coords
} }
/// The norm of this quaternion. /// The norm of this quaternion.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn norm(&self) -> N { pub fn norm(&self) -> N {
self.coords.norm() self.coords.norm()
@ -172,30 +250,58 @@ impl<N: Real> Quaternion<N> {
/// A synonym for the norm of this quaternion. /// A synonym for the norm of this quaternion.
/// ///
/// Aka the length. /// Aka the length.
/// This is the same as `.norm()`
/// ///
/// This function is simply implemented as a call to `norm()` /// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn magnitude(&self) -> N { pub fn magnitude(&self) -> N {
self.norm() self.norm()
} }
/// A synonym for the squared norm of this quaternion.
///
/// 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()
}
/// The squared norm of this quaternion. /// The squared norm of this quaternion.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_eq!(q.magnitude_squared(), 30.0);
/// ```
#[inline] #[inline]
pub fn norm_squared(&self) -> N { pub fn norm_squared(&self) -> N {
self.coords.norm_squared() self.coords.norm_squared()
} }
/// A synonym for the squared norm of this quaternion.
///
/// Aka the squared length.
/// This is the same as `.norm_squared()`
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_eq!(q.magnitude_squared(), 30.0);
/// ```
#[inline]
pub fn magnitude_squared(&self) -> N {
self.norm_squared()
}
/// The dot product of two quaternions. /// The dot product of two quaternions.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let q2 = Quaternion::new(5.0, 6.0, 7.0, 8.0);
/// assert_eq!(q1.dot(&q2), 70.0);
/// ```
#[inline] #[inline]
pub fn dot(&self, rhs: &Self) -> N { pub fn dot(&self, rhs: &Self) -> N {
self.coords.dot(&rhs.coords) self.coords.dot(&rhs.coords)
@ -205,6 +311,17 @@ impl<N: Real> Quaternion<N> {
/// ///
/// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation /// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation
/// axis. If the rotation angle is zero, the rotation axis is set to `None`. /// axis. If the rotation angle is zero, the rotation axis is set to `None`.
///
/// # Example
/// ```
/// # use std::f32;
/// # use nalgebra::{Vector3, Quaternion};
/// let q = Quaternion::new(0.0, 5.0, 0.0, 0.0);
/// let (norm, half_ang, axis) = q.polar_decomposition();
/// assert_eq!(norm, 5.0);
/// assert_eq!(half_ang, f32::consts::FRAC_PI_2);
/// assert_eq!(axis, Some(Vector3::x_axis()));
/// ```
pub fn polar_decomposition(&self) -> (N, N, Option<Unit<Vector3<N>>>) { pub fn polar_decomposition(&self) -> (N, N, Option<Unit<Vector3<N>>>) {
if let Some((q, n)) = Unit::try_new_and_get(*self, N::zero()) { if let Some((q, n)) = Unit::try_new_and_get(*self, N::zero()) {
if let Some(axis) = Unit::try_new(self.vector().clone_owned(), N::zero()) { if let Some(axis) = Unit::try_new(self.vector().clone_owned(), N::zero()) {
@ -219,13 +336,52 @@ impl<N: Real> Quaternion<N> {
} }
} }
/// Compute the natural logarithm of a quaternion.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0);
/// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6)
/// ```
#[inline]
pub fn ln(&self) -> Quaternion<N> {
let n = self.norm();
let v = self.vector();
let s = self.scalar();
Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos())
}
/// Compute the exponential of a quaternion. /// Compute the exponential of a quaternion.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
/// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5)
/// ```
#[inline] #[inline]
pub fn exp(&self) -> Quaternion<N> { pub fn exp(&self) -> Quaternion<N> {
self.exp_eps(N::default_epsilon()) self.exp_eps(N::default_epsilon())
} }
/// Compute the exponential of a quaternion. /// Compute the exponential of a quaternion. Returns the identity if the vector part of this quaternion
/// has a norm smaller than `eps`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
/// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5);
///
/// // Singular case.
/// let q = Quaternion::new(0.0000001, 0.0, 0.0, 0.0);
/// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity());
/// ```
#[inline] #[inline]
pub fn exp_eps(&self, eps: N) -> Quaternion<N> { pub fn exp_eps(&self, eps: N) -> Quaternion<N> {
let v = self.vector(); let v = self.vector();
@ -238,33 +394,52 @@ impl<N: Real> Quaternion<N> {
let n = nn.sqrt(); let n = nn.sqrt();
let nv = v * (w_exp * n.sin() / n); let nv = v * (w_exp * n.sin() / n);
Quaternion::from_parts(n.cos(), nv) Quaternion::from_parts(w_exp * n.cos(), nv)
} }
} }
/// Compute the natural logarithm of a quaternion.
#[inline]
pub fn ln(&self) -> Quaternion<N> {
let n = self.norm();
let v = self.vector();
let s = self.scalar();
Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos())
}
/// Raise the quaternion to a given floating power. /// Raise the quaternion to a given floating power.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Quaternion<N> { pub fn powf(&self, n: N) -> Quaternion<N> {
(self.ln() * n).exp() (self.ln() * n).exp()
} }
/// Transforms this quaternion into its 4D vector form (Vector part, Scalar part). /// Transforms this quaternion into its 4D vector form (Vector part, Scalar part).
///
/// # Example
/// ```
/// # use nalgebra::{Quaternion, Vector4};
/// let mut q = Quaternion::identity();
/// *q.as_vector_mut() = Vector4::new(1.0, 2.0, 3.0, 4.0);
/// assert!(q.i == 1.0 && q.j == 2.0 && q.k == 3.0 && q.w == 4.0);
/// ```
#[inline] #[inline]
pub fn as_vector_mut(&mut self) -> &mut Vector4<N> { pub fn as_vector_mut(&mut self) -> &mut Vector4<N> {
&mut self.coords &mut self.coords
} }
/// The mutable vector part `(i, j, k)` of this quaternion. /// The mutable vector part `(i, j, k)` of this quaternion.
///
/// # Example
/// ```
/// # use nalgebra::{Quaternion, Vector4};
/// let mut q = Quaternion::identity();
/// {
/// let mut v = q.vector_mut();
/// v[0] = 2.0;
/// v[1] = 3.0;
/// v[2] = 4.0;
/// }
/// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0);
/// ```
#[inline] #[inline]
pub fn vector_mut( pub fn vector_mut(
&mut self, &mut self,
@ -273,6 +448,14 @@ impl<N: Real> Quaternion<N> {
} }
/// Replaces this quaternion by its conjugate. /// Replaces this quaternion by its conjugate.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// q.conjugate_mut();
/// assert!(q.i == -2.0 && q.j == -3.0 && q.k == -4.0 && q.w == 1.0);
/// ```
#[inline] #[inline]
pub fn conjugate_mut(&mut self) { pub fn conjugate_mut(&mut self) {
self.coords[0] = -self.coords[0]; self.coords[0] = -self.coords[0];
@ -281,6 +464,20 @@ impl<N: Real> Quaternion<N> {
} }
/// Inverts this quaternion in-place if it is not zero. /// Inverts this quaternion in-place if it is not zero.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
///
/// assert!(q.try_inverse_mut());
/// assert_relative_eq!(q * Quaternion::new(1.0, 2.0, 3.0, 4.0), Quaternion::identity());
///
/// //Non-invertible case
/// let mut q = Quaternion::new(0.0, 0.0, 0.0, 0.0);
/// assert!(!q.try_inverse_mut());
/// ```
#[inline] #[inline]
pub fn try_inverse_mut(&mut self) -> bool { pub fn try_inverse_mut(&mut self) -> bool {
let norm_squared = self.norm_squared(); let norm_squared = self.norm_squared();
@ -296,6 +493,15 @@ impl<N: Real> Quaternion<N> {
} }
/// Normalizes this quaternion. /// Normalizes this quaternion.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// q.normalize_mut();
/// assert_relative_eq!(q.norm(), 1.0);
/// ```
#[inline] #[inline]
pub fn normalize_mut(&mut self) -> N { pub fn normalize_mut(&mut self) -> N {
self.coords.normalize_mut() self.coords.normalize_mut()
@ -368,19 +574,31 @@ pub type UnitQuaternion<N> = Unit<Quaternion<N>>;
impl<N: Real> UnitQuaternion<N> { impl<N: Real> UnitQuaternion<N> {
/// Moves this unit quaternion into one that owns its data. /// Moves this unit quaternion into one that owns its data.
#[inline] #[inline]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")] #[deprecated(
note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead."
)]
pub fn into_owned(self) -> UnitQuaternion<N> { pub fn into_owned(self) -> UnitQuaternion<N> {
self self
} }
/// Clones this unit quaternion into one that owns its data. /// Clones this unit quaternion into one that owns its data.
#[inline] #[inline]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")] #[deprecated(
note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead."
)]
pub fn clone_owned(&self) -> UnitQuaternion<N> { pub fn clone_owned(&self) -> UnitQuaternion<N> {
*self *self
} }
/// The rotation angle in [0; pi] of this unit quaternion. /// The rotation angle in [0; pi] of this unit quaternion.
///
/// # Example
/// ```
/// # use nalgebra::{Unit, UnitQuaternion, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78);
/// assert_eq!(rot.angle(), 1.78);
/// ```
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
let w = self.quaternion().scalar().abs(); let w = self.quaternion().scalar().abs();
@ -396,24 +614,59 @@ impl<N: Real> UnitQuaternion<N> {
/// The underlying quaternion. /// The underlying quaternion.
/// ///
/// Same as `self.as_ref()`. /// Same as `self.as_ref()`.
///
/// # Example
/// ```
/// # use nalgebra::{UnitQuaternion, Quaternion};
/// let axis = UnitQuaternion::identity();
/// assert_eq!(*axis.quaternion(), Quaternion::new(1.0, 0.0, 0.0, 0.0));
/// ```
#[inline] #[inline]
pub fn quaternion(&self) -> &Quaternion<N> { pub fn quaternion(&self) -> &Quaternion<N> {
self.as_ref() self.as_ref()
} }
/// Compute the conjugate of this unit quaternion. /// Compute the conjugate of this unit quaternion.
///
/// # Example
/// ```
/// # use nalgebra::{Unit, UnitQuaternion, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78);
/// let conj = rot.conjugate();
/// assert_eq!(conj, UnitQuaternion::from_axis_angle(&-axis, 1.78));
/// ```
#[inline] #[inline]
pub fn conjugate(&self) -> UnitQuaternion<N> { pub fn conjugate(&self) -> UnitQuaternion<N> {
UnitQuaternion::new_unchecked(self.as_ref().conjugate()) UnitQuaternion::new_unchecked(self.as_ref().conjugate())
} }
/// Inverts this quaternion if it is not zero. /// Inverts this quaternion if it is not zero.
///
/// # Example
/// ```
/// # use nalgebra::{Unit, UnitQuaternion, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78);
/// let inv = rot.inverse();
/// assert_eq!(rot * inv, UnitQuaternion::identity());
/// assert_eq!(inv * rot, UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn inverse(&self) -> UnitQuaternion<N> { pub fn inverse(&self) -> UnitQuaternion<N> {
self.conjugate() self.conjugate()
} }
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &UnitQuaternion<N>) -> N { pub fn angle_to(&self, other: &UnitQuaternion<N>) -> N {
let delta = self.rotation_to(other); let delta = self.rotation_to(other);
@ -423,6 +676,16 @@ impl<N: Real> UnitQuaternion<N> {
/// The unit quaternion needed to make `self` and `other` coincide. /// The unit quaternion needed to make `self` and `other` coincide.
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
/// let rot_to = rot1.rotation_to(&rot2);
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &UnitQuaternion<N>) -> UnitQuaternion<N> { pub fn rotation_to(&self, other: &UnitQuaternion<N>) -> UnitQuaternion<N> {
other / self other / self
@ -431,12 +694,30 @@ impl<N: Real> UnitQuaternion<N> {
/// Linear interpolation between two unit quaternions. /// Linear interpolation between two unit quaternions.
/// ///
/// The result is not normalized. /// The result is not normalized.
///
/// # Example
/// ```
/// # use nalgebra::{UnitQuaternion, Quaternion};
/// let q1 = UnitQuaternion::new_normalize(Quaternion::new(1.0, 0.0, 0.0, 0.0));
/// let q2 = UnitQuaternion::new_normalize(Quaternion::new(0.0, 1.0, 0.0, 0.0));
/// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(0.9, 0.1, 0.0, 0.0));
/// ```
#[inline] #[inline]
pub fn lerp(&self, other: &UnitQuaternion<N>, t: N) -> Quaternion<N> { pub fn lerp(&self, other: &UnitQuaternion<N>, t: N) -> Quaternion<N> {
self.as_ref().lerp(other.as_ref(), t) self.as_ref().lerp(other.as_ref(), t)
} }
/// Normalized linear interpolation between two unit quaternions. /// Normalized linear interpolation between two unit quaternions.
///
/// This is the same as `self.lerp` except that the result is normalized.
///
/// # Example
/// ```
/// # use nalgebra::{UnitQuaternion, Quaternion};
/// let q1 = UnitQuaternion::new_normalize(Quaternion::new(1.0, 0.0, 0.0, 0.0));
/// let q2 = UnitQuaternion::new_normalize(Quaternion::new(0.0, 1.0, 0.0, 0.0));
/// assert_eq!(q1.nlerp(&q2, 0.1), UnitQuaternion::new_normalize(Quaternion::new(0.9, 0.1, 0.0, 0.0)));
/// ```
#[inline] #[inline]
pub fn nlerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> { pub fn nlerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> {
let mut res = self.lerp(other, t); let mut res = self.lerp(other, t);
@ -448,13 +729,13 @@ impl<N: Real> UnitQuaternion<N> {
/// Spherical linear interpolation between two unit quaternions. /// Spherical linear interpolation between two unit quaternions.
/// ///
/// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation /// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation
/// is not well-defined). /// is not well-defined). Use `.try_slerp` instead to avoid the panic.
#[inline] #[inline]
pub fn slerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> { pub fn slerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> {
Unit::new_unchecked(Quaternion::from_vector( 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(),
)) ))
} }
@ -478,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_vector(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.
@ -488,12 +769,36 @@ impl<N: Real> UnitQuaternion<N> {
} }
/// Inverts this quaternion if it is not zero. /// Inverts this quaternion if it is not zero.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let mut rot = UnitQuaternion::new(axisangle);
/// rot.inverse_mut();
/// assert_relative_eq!(rot * UnitQuaternion::new(axisangle), UnitQuaternion::identity());
/// assert_relative_eq!(UnitQuaternion::new(axisangle) * rot, UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
self.as_mut_unchecked().conjugate_mut() self.as_mut_unchecked().conjugate_mut()
} }
/// The rotation axis of this unit quaternion or `None` if the rotation is zero. /// The rotation axis of this unit quaternion or `None` if the rotation is zero.
///
/// # Example
/// ```
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = UnitQuaternion::from_axis_angle(&axis, angle);
/// assert_eq!(rot.axis(), Some(axis));
///
/// // Case with a zero angle.
/// let rot = UnitQuaternion::from_axis_angle(&axis, 0.0);
/// assert!(rot.axis().is_none());
/// ```
#[inline] #[inline]
pub fn axis(&self) -> Option<Unit<Vector3<N>>> { pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
let v = if self.quaternion().scalar() >= N::zero() { let v = if self.quaternion().scalar() >= N::zero() {
@ -506,10 +811,19 @@ impl<N: Real> UnitQuaternion<N> {
} }
/// The rotation axis of this unit quaternion multiplied by the rotation angle. /// The rotation axis of this unit quaternion multiplied by the rotation angle.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = UnitQuaternion::new(axisangle);
/// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6);
/// ```
#[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()
} }
@ -518,6 +832,19 @@ impl<N: Real> UnitQuaternion<N> {
/// The rotation axis and angle in ]0, pi] of this unit quaternion. /// The rotation axis and angle in ]0, pi] of this unit quaternion.
/// ///
/// Returns `None` if the angle is zero. /// Returns `None` if the angle is zero.
///
/// # Example
/// ```
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = UnitQuaternion::from_axis_angle(&axis, angle);
/// assert_eq!(rot.axis_angle(), Some((axis, angle)));
///
/// // Case with a zero angle.
/// let rot = UnitQuaternion::from_axis_angle(&axis, 0.0);
/// assert!(rot.axis_angle().is_none());
/// ```
#[inline] #[inline]
pub fn axis_angle(&self) -> Option<(Unit<Vector3<N>>, N)> { pub fn axis_angle(&self) -> Option<(Unit<Vector3<N>>, N)> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
@ -540,10 +867,19 @@ impl<N: Real> UnitQuaternion<N> {
/// Note that this function yields a `Quaternion<N>` because it looses the unit property. /// Note that this function yields a `Quaternion<N>` because it looses the unit property.
/// The vector part of the return value corresponds to the axis-angle representation (divided /// The vector part of the return value corresponds to the axis-angle representation (divided
/// by 2.0) of this unit quaternion. /// by 2.0) of this unit quaternion.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector3, UnitQuaternion};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let q = UnitQuaternion::new(axisangle);
/// assert_relative_eq!(q.ln().vector().into_owned(), axisangle, epsilon = 1.0e-6);
/// ```
#[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()
} }
@ -553,6 +889,18 @@ impl<N: Real> UnitQuaternion<N> {
/// ///
/// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and /// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and
/// angle `self.angle() × n`. /// angle `self.angle() × n`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = UnitQuaternion::from_axis_angle(&axis, angle);
/// let pow = rot.powf(2.0);
/// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6);
/// assert_eq!(pow.angle(), 2.4);
/// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> UnitQuaternion<N> { pub fn powf(&self, n: N) -> UnitQuaternion<N> {
if let Some(v) = self.axis() { if let Some(v) = self.axis() {
@ -563,6 +911,21 @@ impl<N: Real> UnitQuaternion<N> {
} }
/// Builds a rotation matrix from this unit quaternion. /// Builds a rotation matrix from this unit quaternion.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix3};
/// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
/// let rot = q.to_rotation_matrix();
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0);
///
/// assert_relative_eq!(*rot.matrix(), expected, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn to_rotation_matrix(&self) -> Rotation<N, U3> { pub fn to_rotation_matrix(&self) -> Rotation<N, U3> {
let i = self.as_ref()[0]; let i = self.as_ref()[0];
@ -596,13 +959,48 @@ impl<N: Real> UnitQuaternion<N> {
/// Converts this unit quaternion into its equivalent Euler angles. /// Converts this unit quaternion into its equivalent Euler angles.
/// ///
/// The angles are produced in the form (roll, yaw, pitch). /// The angles are produced in the form (roll, pitch, yaw).
#[inline] #[inline]
#[deprecated(note = "This is renamed to use `.euler_angles()`.")]
pub fn to_euler_angles(&self) -> (N, N, N) { pub fn to_euler_angles(&self) -> (N, N, N) {
self.to_rotation_matrix().to_euler_angles() self.euler_angles()
}
/// Retrieves the euler angles corresponding to this unit quaternion.
///
/// The angles are produced in the form (roll, pitch, yaw).
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
/// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ```
#[inline]
pub fn euler_angles(&self) -> (N, N, N) {
self.to_rotation_matrix().euler_angles()
} }
/// Converts this unit quaternion into its equivalent homogeneous transformation matrix. /// Converts this unit quaternion into its equivalent homogeneous transformation matrix.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix4};
/// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
/// let expected = Matrix4::new(0.8660254, -0.5, 0.0, 0.0,
/// 0.5, 0.8660254, 0.0, 0.0,
/// 0.0, 0.0, 1.0, 0.0,
/// 0.0, 0.0, 0.0, 1.0);
///
/// assert_relative_eq!(rot.to_homogeneous(), expected, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, U4> { pub fn to_homogeneous(&self) -> MatrixN<N, U4> {
self.to_rotation_matrix().to_homogeneous() self.to_rotation_matrix().to_homogeneous()
@ -612,7 +1010,7 @@ impl<N: Real> UnitQuaternion<N> {
impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> { impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
let axis = axis.unwrap(); let axis = axis.into_inner();
write!( write!(
f, f,
"UnitQuaternion angle: {} axis: ({}, {}, {})", "UnitQuaternion angle: {} axis: ({}, {}, {})",

View File

@ -98,7 +98,7 @@ impl<N: Real> FiniteDimVectorSpace for Quaternion<N> {
#[inline] #[inline]
fn canonical_basis_element(i: usize) -> Self { fn canonical_basis_element(i: usize) -> Self {
Self::from_vector(Vector4::canonical_basis_element(i)) Self::from(Vector4::canonical_basis_element(i))
} }
#[inline] #[inline]
@ -131,7 +131,7 @@ impl<N: Real> NormedSpace for Quaternion<N> {
#[inline] #[inline]
fn normalize(&self) -> Self { fn normalize(&self) -> Self {
let v = self.coords.normalize(); let v = self.coords.normalize();
Self::from_vector(v) Self::from(v)
} }
#[inline] #[inline]
@ -142,7 +142,7 @@ impl<N: Real> NormedSpace for Quaternion<N> {
#[inline] #[inline]
fn try_normalize(&self, min_norm: N) -> Option<Self> { fn try_normalize(&self, min_norm: N) -> Option<Self> {
if let Some(v) = self.coords.try_normalize(min_norm) { if let Some(v) = self.coords.try_normalize(min_norm) {
Some(Self::from_vector(v)) Some(Self::from(v))
} else { } else {
None None
} }

View File

@ -23,6 +23,7 @@ impl<N: Real> Quaternion<N> {
/// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w` /// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w`
/// vector component. /// vector component.
#[inline] #[inline]
#[deprecated(note = "Use `::from` instead.")]
pub fn from_vector(vector: Vector4<N>) -> Self { pub fn from_vector(vector: Vector4<N>) -> Self {
Quaternion { coords: vector } Quaternion { coords: vector }
} }
@ -30,17 +31,36 @@ impl<N: Real> Quaternion<N> {
/// Creates a new quaternion from its individual components. Note that the arguments order does /// Creates a new quaternion from its individual components. Note that the arguments order does
/// **not** follow the storage order. /// **not** follow the storage order.
/// ///
/// The storage order is `[ x, y, z, w ]`. /// The storage order is `[ i, j, k, w ]` while the arguments for this functions are in the
/// order `(w, i, j, k)`.
///
/// # Example
/// ```
/// # use nalgebra::{Quaternion, Vector4};
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0);
/// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0));
/// ```
#[inline] #[inline]
pub fn new(w: N, x: N, y: N, z: N) -> Self { pub fn new(w: N, i: N, j: N, k: N) -> Self {
let v = Vector4::<N>::new(x, y, z, w); let v = Vector4::<N>::new(i, j, k, w);
Self::from_vector(v) Self::from(v)
} }
/// Creates a new quaternion from its scalar and vector parts. Note that the arguments order does /// Creates a new quaternion from its scalar and vector parts. Note that the arguments order does
/// **not** follow the storage order. /// **not** follow the storage order.
/// ///
/// The storage order is [ vector, scalar ]. /// The storage order is [ vector, scalar ].
///
/// # Example
/// ```
/// # use nalgebra::{Quaternion, Vector3, Vector4};
/// let w = 1.0;
/// let ijk = Vector3::new(2.0, 3.0, 4.0);
/// let q = Quaternion::from_parts(w, ijk);
/// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0);
/// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0));
/// ```
#[inline] #[inline]
// FIXME: take a reference to `vector`? // FIXME: take a reference to `vector`?
pub fn from_parts<SB>(scalar: N, vector: Vector<N, U3, SB>) -> Self pub fn from_parts<SB>(scalar: N, vector: Vector<N, U3, SB>) -> Self
@ -56,10 +76,20 @@ 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.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let q = Quaternion::identity();
/// let q2 = Quaternion::new(1.0, 2.0, 3.0, 4.0);
///
/// assert_eq!(q * q2, q2);
/// assert_eq!(q2 * q, q2);
/// ```
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::new(N::one(), N::zero(), N::zero(), N::zero()) Self::new(N::one(), N::zero(), N::zero(), N::zero())
@ -110,7 +140,21 @@ where Owned<N, U4>: Send
} }
impl<N: Real> UnitQuaternion<N> { impl<N: Real> UnitQuaternion<N> {
/// The quaternion multiplicative identity. /// The rotation identity.
///
/// # Example
/// ```
/// # use nalgebra::{UnitQuaternion, Vector3, Point3};
/// let q = UnitQuaternion::identity();
/// let q2 = UnitQuaternion::new(Vector3::new(1.0, 2.0, 3.0));
/// let v = Vector3::new_random();
/// let p = Point3::from(v);
///
/// assert_eq!(q * q2, q2);
/// assert_eq!(q2 * q, q2);
/// assert_eq!(q * v, v);
/// assert_eq!(q * p, p);
/// ```
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::new_unchecked(Quaternion::identity()) Self::new_unchecked(Quaternion::identity())
@ -118,6 +162,27 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates a new quaternion from a unit vector (the rotation axis) and an angle /// Creates a new quaternion from a unit vector (the rotation axis) and an angle
/// (the rotation angle). /// (the rotation angle).
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axis = Vector3::y_axis();
/// let angle = f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let q = UnitQuaternion::from_axis_angle(&axis, angle);
///
/// assert_eq!(q.axis().unwrap(), axis);
/// assert_eq!(q.angle(), angle);
/// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(UnitQuaternion::from_scaled_axis(Vector3::<f32>::zeros()), UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
@ -138,6 +203,17 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates a new unit quaternion from Euler angles. /// Creates a new unit quaternion from Euler angles.
/// ///
/// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw. /// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
/// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
let (sr, cr) = (roll * ::convert(0.5f64)).sin_cos(); let (sr, cr) = (roll * ::convert(0.5f64)).sin_cos();
@ -155,6 +231,19 @@ impl<N: Real> UnitQuaternion<N> {
} }
/// Builds an unit quaternion from a rotation matrix. /// Builds an unit quaternion from a rotation matrix.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, UnitQuaternion, Vector3};
/// let axis = Vector3::y_axis();
/// let angle = 0.1;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// let q = UnitQuaternion::from_rotation_matrix(&rot);
/// assert_relative_eq!(q.to_rotation_matrix(), rot, epsilon = 1.0e-6);
/// assert_relative_eq!(q.axis().unwrap(), rot.axis().unwrap(), epsilon = 1.0e-6);
/// assert_relative_eq!(q.angle(), rot.angle(), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn from_rotation_matrix(rotmat: &Rotation<N, U3>) -> Self { pub fn from_rotation_matrix(rotmat: &Rotation<N, U3>) -> Self {
// Robust matrix to quaternion transformation. // Robust matrix to quaternion transformation.
@ -206,6 +295,17 @@ impl<N: Real> UnitQuaternion<N> {
/// The unit quaternion needed to make `a` and `b` be collinear and point toward the same /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same
/// direction. /// direction.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
/// let q = UnitQuaternion::rotation_between(&a, &b).unwrap();
/// assert_relative_eq!(q * a, b);
/// assert_relative_eq!(q.inverse() * b, a);
/// ```
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self> pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
where where
@ -217,6 +317,18 @@ impl<N: Real> UnitQuaternion<N> {
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
/// let q2 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.2).unwrap();
/// let q5 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.5).unwrap();
/// assert_relative_eq!(q2 * q2 * q2 * q2 * q2 * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(q5 * q5 * a, b, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>( pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U3, SB>, a: &Vector<N, U3, SB>,
@ -240,6 +352,17 @@ impl<N: Real> UnitQuaternion<N> {
/// The unit quaternion needed to make `a` and `b` be collinear and point toward the same /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same
/// direction. /// direction.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
/// let q = UnitQuaternion::rotation_between(&a, &b).unwrap();
/// assert_relative_eq!(q * a, b);
/// assert_relative_eq!(q.inverse() * b, a);
/// ```
#[inline] #[inline]
pub fn rotation_between_axis<SB, SC>( pub fn rotation_between_axis<SB, SC>(
a: &Unit<Vector<N, U3, SB>>, a: &Unit<Vector<N, U3, SB>>,
@ -254,6 +377,18 @@ impl<N: Real> UnitQuaternion<N> {
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
/// let q2 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.2).unwrap();
/// let q5 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.5).unwrap();
/// assert_relative_eq!(q2 * q2 * q2 * q2 * q2 * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(q5 * q5 * a, b, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_rotation_between_axis<SB, SC>( pub fn scaled_rotation_between_axis<SB, SC>(
na: &Unit<Vector<N, U3, SB>>, na: &Unit<Vector<N, U3, SB>>,
@ -293,63 +428,127 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates an unit quaternion that corresponds to the local frame of an observer standing at the /// Creates an unit quaternion that corresponds to the local frame of an observer standing at the
/// origin and looking toward `dir`. /// origin and looking toward `dir`.
/// ///
/// It maps the view direction `dir` to the positive `z` axis. /// It maps the `z` axis to the direction `dir`.
/// ///
/// # Arguments /// # Arguments
/// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with. /// * dir - The look direction. It does not need to be normalized.
/// * up - The vertical direction. The only requirement of this parameter is to not be /// * up - The vertical direction. It does not need to be normalized.
/// collinear /// The only requirement of this parameter is to not be collinear to `dir`. Non-collinearity
/// to `dir`. Non-collinearity is not checked. /// is not checked.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let q = UnitQuaternion::face_towards(&dir, &up);
/// 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.
/// ///
/// It maps the view direction `dir` to the **negative** `z` axis.
/// This conforms to the common notion of right handed look-at matrix from the computer /// This conforms to the common notion of right handed look-at matrix from the computer
/// graphics community. /// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * eye - The eye position. /// * dir The view direction. It does not need to be normalized.
/// * target - The target position. /// * up - A vector approximately aligned with required the vertical axis. It does not need
/// * up - A vector approximately aligned with required the vertical axis. The only /// to be normalized. The only requirement of this parameter is to not be collinear to `dir`.
/// requirement of this parameter is to not be collinear to `target - eye`. ///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let q = UnitQuaternion::look_at_rh(&dir, &up);
/// assert_relative_eq!(q * dir.normalize(), -Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn look_at_rh<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::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.
/// ///
/// It maps the view direction `dir` to the **positive** `z` axis.
/// This conforms to the common notion of left handed look-at matrix from the computer /// This conforms to the common notion of left handed look-at matrix from the computer
/// graphics community. /// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * eye - The eye position. /// * dir The view direction. It does not need to be normalized.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `dir`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let q = UnitQuaternion::look_at_lh(&dir, &up);
/// assert_relative_eq!(q * dir.normalize(), Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn look_at_lh<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::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.
/// ///
/// If `axisangle` has a magnitude smaller than `N::default_epsilon()`, this returns the identity rotation. /// If `axisangle` has a magnitude smaller than `N::default_epsilon()`, this returns the identity rotation.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let q = UnitQuaternion::new(axisangle);
///
/// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(UnitQuaternion::new(Vector3::<f32>::zeros()), UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn new<SB>(axisangle: Vector<N, U3, SB>) -> Self pub fn new<SB>(axisangle: Vector<N, U3, SB>) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
@ -361,6 +560,24 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
/// ///
/// If `axisangle` has a magnitude smaller than `eps`, this returns the identity rotation. /// If `axisangle` has a magnitude smaller than `eps`, this returns the identity rotation.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let q = UnitQuaternion::new_eps(axisangle, 1.0e-6);
///
/// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // An almost zero vector yields an identity.
/// assert_eq!(UnitQuaternion::new_eps(Vector3::new(1.0e-8, 1.0e-9, 1.0e-7), 1.0e-6), UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn new_eps<SB>(axisangle: Vector<N, U3, SB>, eps: N) -> Self pub fn new_eps<SB>(axisangle: Vector<N, U3, SB>, eps: N) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
@ -373,6 +590,24 @@ impl<N: Real> UnitQuaternion<N> {
/// ///
/// If `axisangle` has a magnitude smaller than `N::default_epsilon()`, this returns the identity rotation. /// If `axisangle` has a magnitude smaller than `N::default_epsilon()`, this returns the identity rotation.
/// Same as `Self::new(axisangle)`. /// Same as `Self::new(axisangle)`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let q = UnitQuaternion::from_scaled_axis(axisangle);
///
/// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(UnitQuaternion::from_scaled_axis(Vector3::<f32>::zeros()), UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn from_scaled_axis<SB>(axisangle: Vector<N, U3, SB>) -> Self pub fn from_scaled_axis<SB>(axisangle: Vector<N, U3, SB>) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
@ -382,7 +617,25 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
/// ///
/// If `axisangle` has a magnitude smaller than `eps`, this returns the identity rotation. /// If `axisangle` has a magnitude smaller than `eps`, this returns the identity rotation.
/// Same as `Self::new(axisangle)`. /// Same as `Self::new_eps(axisangle, eps)`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let q = UnitQuaternion::from_scaled_axis_eps(axisangle, 1.0e-6);
///
/// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // An almost zero vector yields an identity.
/// assert_eq!(UnitQuaternion::from_scaled_axis_eps(Vector3::new(1.0e-8, 1.0e-9, 1.0e-7), 1.0e-6), UnitQuaternion::identity());
/// ```
#[inline] #[inline]
pub fn from_scaled_axis_eps<SB>(axisangle: Vector<N, U3, SB>, eps: N) -> Self pub fn from_scaled_axis_eps<SB>(axisangle: Vector<N, U3, SB>, eps: N) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
@ -436,15 +689,16 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate rand_xorshift;
use super::*; use super::*;
use rand::{self, SeedableRng}; use rand::SeedableRng;
#[test] #[test]
fn random_unit_quats_are_unit() { fn random_unit_quats_are_unit() {
let mut rng = rand::prng::XorShiftRng::from_seed([0xAB; 16]); let mut rng = rand_xorshift::XorShiftRng::from_seed([0xAB; 16]);
for _ in 0..1000 { for _ in 0..1000 {
let x = rng.gen::<UnitQuaternion<f32>>(); let x = rng.gen::<UnitQuaternion<f32>>();
assert!(relative_eq!(x.unwrap().norm(), 1.0)) assert!(relative_eq!(x.into_inner().norm(), 1.0))
} }
} }
} }

View File

@ -39,7 +39,7 @@ where
{ {
#[inline] #[inline]
fn to_superset(&self) -> Quaternion<N2> { fn to_superset(&self) -> Quaternion<N2> {
Quaternion::from_vector(self.coords.to_superset()) Quaternion::from(self.coords.to_superset())
} }
#[inline] #[inline]
@ -49,7 +49,9 @@ where
#[inline] #[inline]
unsafe fn from_superset_unchecked(q: &Quaternion<N2>) -> Self { unsafe fn from_superset_unchecked(q: &Quaternion<N2>) -> Self {
Self::from_vector(q.coords.to_subset_unchecked()) Self {
coords: q.coords.to_subset_unchecked(),
}
} }
} }
@ -226,6 +228,13 @@ 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()
}
}
impl<N: Real> From<Vector4<N>> for Quaternion<N> {
#[inline]
fn from(coords: Vector4<N>) -> Self {
Quaternion { coords }
} }
} }

View File

@ -103,28 +103,28 @@ quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>; self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(&self.coords + &rhs.coords); Quaternion::from(&self.coords + &rhs.coords);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>; self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(&self.coords + rhs.coords); Quaternion::from(&self.coords + rhs.coords);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>; self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords + &rhs.coords); Quaternion::from(self.coords + &rhs.coords);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Add, add; Add, add;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>; self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords + rhs.coords); Quaternion::from(self.coords + rhs.coords);
); );
// Quaternion - Quaternion // Quaternion - Quaternion
@ -132,28 +132,28 @@ quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>; self: &'a Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(&self.coords - &rhs.coords); Quaternion::from(&self.coords - &rhs.coords);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>; self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(&self.coords - rhs.coords); Quaternion::from(&self.coords - rhs.coords);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>; self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords - &rhs.coords); Quaternion::from(self.coords - &rhs.coords);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
Sub, sub; Sub, sub;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>; self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords - rhs.coords); Quaternion::from(self.coords - rhs.coords);
); );
// Quaternion × Quaternion // Quaternion × Quaternion
@ -428,7 +428,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: &'a UnitQuaternion<N>, rhs: &'b Point3<N>, self: &'a UnitQuaternion<N>, rhs: &'b Point3<N>,
Output = Point3<N> => U3, U4; Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * &rhs.coords); Point3::from(self * &rhs.coords);
'a, 'b); 'a, 'b);
quaternion_op_impl!( quaternion_op_impl!(
@ -436,7 +436,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: &'a UnitQuaternion<N>, rhs: Point3<N>, self: &'a UnitQuaternion<N>, rhs: Point3<N>,
Output = Point3<N> => U3, U4; Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * rhs.coords); Point3::from(self * rhs.coords);
'a); 'a);
quaternion_op_impl!( quaternion_op_impl!(
@ -444,7 +444,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternion<N>, rhs: &'b Point3<N>, self: UnitQuaternion<N>, rhs: &'b Point3<N>,
Output = Point3<N> => U3, U4; Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * &rhs.coords); Point3::from(self * &rhs.coords);
'b); 'b);
quaternion_op_impl!( quaternion_op_impl!(
@ -452,7 +452,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: UnitQuaternion<N>, rhs: Point3<N>, self: UnitQuaternion<N>, rhs: Point3<N>,
Output = Point3<N> => U3, U4; Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * rhs.coords); Point3::from(self * rhs.coords);
); );
// UnitQuaternion × Unit<Vector> // UnitQuaternion × Unit<Vector>
@ -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(
@ -495,7 +495,7 @@ macro_rules! scalar_op_impl(
#[inline] #[inline]
fn $op(self, n: N) -> Self::Output { fn $op(self, n: N) -> Self::Output {
Quaternion::from_vector(self.coords.$op(n)) Quaternion::from(self.coords.$op(n))
} }
} }
@ -504,7 +504,7 @@ macro_rules! scalar_op_impl(
#[inline] #[inline]
fn $op(self, n: N) -> Self::Output { fn $op(self, n: N) -> Self::Output {
Quaternion::from_vector((&self.coords).$op(n)) Quaternion::from((&self.coords).$op(n))
} }
} }
@ -530,7 +530,7 @@ macro_rules! left_scalar_mul_impl(
#[inline] #[inline]
fn mul(self, right: Quaternion<$T>) -> Self::Output { fn mul(self, right: Quaternion<$T>) -> Self::Output {
Quaternion::from_vector(self * right.coords) Quaternion::from(self * right.coords)
} }
} }
@ -539,7 +539,7 @@ macro_rules! left_scalar_mul_impl(
#[inline] #[inline]
fn mul(self, right: &'b Quaternion<$T>) -> Self::Output { fn mul(self, right: &'b Quaternion<$T>) -> Self::Output {
Quaternion::from_vector(self * &right.coords) Quaternion::from(self * &right.coords)
} }
} }
)*} )*}
@ -552,7 +552,7 @@ impl<N: Real> Neg for Quaternion<N> {
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Quaternion::from_vector(-self.coords) Quaternion::from(-self.coords)
} }
} }
@ -561,7 +561,7 @@ impl<'a, N: Real> Neg for &'a Quaternion<N> {
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Quaternion::from_vector(-&self.coords) Quaternion::from(-&self.coords)
} }
} }

View File

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

View File

@ -108,28 +108,100 @@ impl<N: Scalar, D: DimName> Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>
{ {
/// A reference to the underlying matrix representation of this rotation. /// A reference to the underlying matrix representation of this rotation.
///
/// # Example
/// ```
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3};
/// # use std::f32;
/// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(*rot.matrix(), expected);
///
///
/// let rot = Rotation2::new(f32::consts::FRAC_PI_6);
/// let expected = Matrix2::new(0.8660254, -0.5,
/// 0.5, 0.8660254);
/// assert_eq!(*rot.matrix(), expected);
/// ```
#[inline] #[inline]
pub fn matrix(&self) -> &MatrixN<N, D> { pub fn matrix(&self) -> &MatrixN<N, D> {
&self.matrix &self.matrix
} }
/// A mutable reference to the underlying matrix representation of this rotation. /// A mutable reference to the underlying matrix representation of this rotation.
///
/// This is unsafe because this allows the user to replace the matrix by another one that is
/// non-square, non-inversible, or non-orthonormal. If one of those properties is broken,
/// subsequent method calls may be UB.
#[inline] #[inline]
#[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")]
pub unsafe fn matrix_mut(&mut self) -> &mut MatrixN<N, D> { pub unsafe fn matrix_mut(&mut self) -> &mut MatrixN<N, D> {
&mut self.matrix &mut self.matrix
} }
/// A mutable reference to the underlying matrix representation of this rotation.
///
/// This is suffixed by "_unchecked" because this allows the user to replace the matrix by another one that is
/// non-square, non-inversible, or non-orthonormal. If one of those properties is broken,
/// subsequent method calls may be UB.
#[inline]
pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, D> {
&mut self.matrix
}
/// Unwraps the underlying matrix. /// Unwraps the underlying matrix.
///
/// # Example
/// ```
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3};
/// # use std::f32;
/// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
/// let mat = rot.into_inner();
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(mat, expected);
///
///
/// let rot = Rotation2::new(f32::consts::FRAC_PI_6);
/// let mat = rot.into_inner();
/// let expected = Matrix2::new(0.8660254, -0.5,
/// 0.5, 0.8660254);
/// assert_eq!(mat, expected);
/// ```
#[inline]
pub fn into_inner(self) -> MatrixN<N, D> {
self.matrix
}
/// Unwraps the underlying matrix.
/// Deprecated: Use [Rotation::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline] #[inline]
pub fn unwrap(self) -> MatrixN<N, D> { pub fn unwrap(self) -> MatrixN<N, D> {
self.matrix self.matrix
} }
/// Converts this rotation into its equivalent homogeneous transformation matrix. /// Converts this rotation into its equivalent homogeneous transformation matrix.
///
/// This is the same as `self.into()`.
///
/// # Example
/// ```
/// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix3, Matrix4};
/// # use std::f32;
/// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
/// let expected = Matrix4::new(0.8660254, -0.5, 0.0, 0.0,
/// 0.5, 0.8660254, 0.0, 0.0,
/// 0.0, 0.0, 1.0, 0.0,
/// 0.0, 0.0, 0.0, 1.0);
/// assert_eq!(rot.to_homogeneous(), expected);
///
///
/// let rot = Rotation2::new(f32::consts::FRAC_PI_6);
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(rot.to_homogeneous(), expected);
/// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where where
@ -137,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);
@ -146,6 +221,25 @@ where DefaultAllocator: Allocator<N, D, D>
/// Creates a new rotation from the given square matrix. /// Creates a new rotation from the given square matrix.
/// ///
/// The matrix squareness is checked but not its orthonormality. /// The matrix squareness is checked but not its orthonormality.
///
/// # Example
/// ```
/// # use nalgebra::{Rotation2, Rotation3, Matrix2, Matrix3};
/// # use std::f32;
/// let mat = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0);
/// let rot = Rotation3::from_matrix_unchecked(mat);
///
/// assert_eq!(*rot.matrix(), mat);
///
///
/// let mat = Matrix2::new(0.8660254, -0.5,
/// 0.5, 0.8660254);
/// let rot = Rotation2::from_matrix_unchecked(mat);
///
/// assert_eq!(*rot.matrix(), mat);
/// ```
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: MatrixN<N, D>) -> Rotation<N, D> { pub fn from_matrix_unchecked(matrix: MatrixN<N, D>) -> Rotation<N, D> {
assert!( assert!(
@ -157,24 +251,100 @@ where DefaultAllocator: Allocator<N, D, D>
} }
/// Transposes `self`. /// Transposes `self`.
///
/// Same as `.inverse()` because the inverse of a rotation matrix is its transform.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let tr_rot = rot.transpose();
/// assert_relative_eq!(rot * tr_rot, Rotation3::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(tr_rot * rot, Rotation3::identity(), epsilon = 1.0e-6);
///
/// let rot = Rotation2::new(1.2);
/// let tr_rot = rot.transpose();
/// assert_relative_eq!(rot * tr_rot, Rotation2::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn transpose(&self) -> Rotation<N, D> { pub fn transpose(&self) -> Rotation<N, D> {
Rotation::from_matrix_unchecked(self.matrix.transpose()) Rotation::from_matrix_unchecked(self.matrix.transpose())
} }
/// Inverts `self`. /// Inverts `self`.
///
/// Same as `.transpose()` because the inverse of a rotation matrix is its transform.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let inv = rot.inverse();
/// assert_relative_eq!(rot * inv, Rotation3::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(inv * rot, Rotation3::identity(), epsilon = 1.0e-6);
///
/// let rot = Rotation2::new(1.2);
/// let inv = rot.inverse();
/// assert_relative_eq!(rot * inv, Rotation2::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn inverse(&self) -> Rotation<N, D> { pub fn inverse(&self) -> Rotation<N, D> {
self.transpose() self.transpose()
} }
/// Transposes `self` in-place. /// Transposes `self` in-place.
///
/// Same as `.inverse_mut()` because the inverse of a rotation matrix is its transform.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// tr_rot.transpose_mut();
///
/// assert_relative_eq!(rot * tr_rot, Rotation3::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(tr_rot * rot, Rotation3::identity(), epsilon = 1.0e-6);
///
/// let rot = Rotation2::new(1.2);
/// let mut tr_rot = Rotation2::new(1.2);
/// tr_rot.transpose_mut();
///
/// assert_relative_eq!(rot * tr_rot, Rotation2::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn transpose_mut(&mut self) { pub fn transpose_mut(&mut self) {
self.matrix.transpose_mut() self.matrix.transpose_mut()
} }
/// Inverts `self` in-place. /// Inverts `self` in-place.
///
/// Same as `.transpose_mut()` because the inverse of a rotation matrix is its transform.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// inv.inverse_mut();
///
/// assert_relative_eq!(rot * inv, Rotation3::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(inv * rot, Rotation3::identity(), epsilon = 1.0e-6);
///
/// let rot = Rotation2::new(1.2);
/// let mut inv = Rotation2::new(1.2);
/// inv.inverse_mut();
///
/// assert_relative_eq!(rot * inv, Rotation2::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
self.transpose_mut() self.transpose_mut()

View File

@ -89,7 +89,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
{ {
#[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> {
Point::from_coordinates(self.inverse_transform_vector(&pt.coords)) Point::from(self.inverse_transform_vector(&pt.coords))
} }
#[inline] #[inline]

View File

@ -14,6 +14,16 @@ where
DefaultAllocator: Allocator<N, D, D>, DefaultAllocator: Allocator<N, D, D>,
{ {
/// Creates a new square identity rotation of the given `dimension`. /// Creates a new square identity rotation of the given `dimension`.
///
/// # Example
/// ```
/// # use nalgebra::Quaternion;
/// let rot1 = Quaternion::identity();
/// let rot2 = Quaternion::new(1.0, 2.0, 3.0, 4.0);
///
/// assert_eq!(rot1 * rot2, rot2);
/// assert_eq!(rot2 * rot1, rot2);
/// ```
#[inline] #[inline]
pub fn identity() -> Rotation<N, D> { pub fn identity() -> Rotation<N, D> {
Self::from_matrix_unchecked(MatrixN::<N, D>::identity()) Self::from_matrix_unchecked(MatrixN::<N, D>::identity())

View File

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

View File

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

View File

@ -22,6 +22,17 @@ use geometry::{Rotation2, Rotation3, UnitComplex};
*/ */
impl<N: Real> Rotation2<N> { impl<N: Real> Rotation2<N> {
/// Builds a 2 dimensional rotation matrix from an angle in radian. /// Builds a 2 dimensional rotation matrix from an angle in radian.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation2, Point2};
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
///
/// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
/// ```
pub fn new(angle: N) -> Self { pub fn new(angle: N) -> Self {
let (sia, coa) = angle.sin_cos(); let (sia, coa) = angle.sin_cos();
Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa)) Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa))
@ -29,7 +40,9 @@ impl<N: Real> Rotation2<N> {
/// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector. /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector.
/// ///
/// Equivalent to `Self::new(axisangle[0])`. ///
/// This is generally used in the context of generic programming. Using
/// the `::new(angle)` method instead is more common.
#[inline] #[inline]
pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self { pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self {
Self::new(axisangle[0]) Self::new(axisangle[0])
@ -38,6 +51,17 @@ impl<N: Real> Rotation2<N> {
/// 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.
/// ///
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
/// let rot = Rotation2::rotation_between(&a, &b);
/// assert_relative_eq!(rot * a, b);
/// assert_relative_eq!(rot.inverse() * b, a);
/// ```
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self
where where
@ -49,6 +73,18 @@ impl<N: Real> Rotation2<N> {
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0);
/// let rot2 = Rotation2::scaled_rotation_between(&a, &b, 0.2);
/// let rot5 = Rotation2::scaled_rotation_between(&a, &b, 0.5);
/// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>( pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U2, SB>, a: &Vector<N, U2, SB>,
@ -65,12 +101,29 @@ impl<N: Real> Rotation2<N> {
impl<N: Real> Rotation2<N> { impl<N: Real> Rotation2<N> {
/// The rotation angle. /// The rotation angle.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(1.78);
/// assert_relative_eq!(rot.angle(), 1.78);
/// ```
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)]) self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)])
} }
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
/// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &Rotation2<N>) -> N { pub fn angle_to(&self, other: &Rotation2<N>) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
@ -79,6 +132,18 @@ impl<N: Real> Rotation2<N> {
/// The rotation matrix needed to make `self` and `other` coincide. /// The rotation matrix needed to make `self` and `other` coincide.
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7);
/// let rot_to = rot1.rotation_to(&rot2);
///
/// assert_relative_eq!(rot_to * rot1, rot2);
/// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
/// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> { pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> {
other * self.inverse() other * self.inverse()
@ -86,12 +151,24 @@ impl<N: Real> Rotation2<N> {
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle
/// of `self` multiplied by `n`. /// of `self` multiplied by `n`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(0.78);
/// let pow = rot.powf(2.0);
/// 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> {
Self::new(self.angle() * n) Self::new(self.angle() * n)
} }
/// The rotation angle returned as a 1-dimensional vector. /// The rotation angle returned as a 1-dimensional vector.
///
/// This is generally used in the context of generic programming. Using
/// the `.angle()` method instead is more common.
#[inline] #[inline]
pub fn scaled_axis(&self) -> VectorN<N, U1> { pub fn scaled_axis(&self) -> VectorN<N, U1> {
Vector1::new(self.angle()) Vector1::new(self.angle())
@ -129,6 +206,24 @@ impl<N: Real> Rotation3<N> {
/// # Arguments /// # Arguments
/// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
/// in radian. Its direction is the axis of rotation. /// in radian. Its direction is the axis of rotation.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let rot = Rotation3::new(axisangle);
///
/// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(Rotation3::new(Vector3::<f32>::zeros()), Rotation3::identity());
/// ```
pub fn new<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self { pub fn new<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
let axisangle = axisangle.into_owned(); let axisangle = axisangle.into_owned();
let (axis, angle) = Unit::new_and_get(axisangle); let (axis, angle) = Unit::new_and_get(axisangle);
@ -136,11 +231,52 @@ impl<N: Real> Rotation3<N> {
} }
/// Builds a 3D rotation matrix from an axis scaled by the rotation angle. /// Builds a 3D rotation matrix from an axis scaled by the rotation angle.
///
/// This is the same as `Self::new(axisangle)`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let rot = Rotation3::new(axisangle);
///
/// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(Rotation3::from_scaled_axis(Vector3::<f32>::zeros()), Rotation3::identity());
/// ```
pub fn from_scaled_axis<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self { pub fn from_scaled_axis<SB: Storage<N, U3>>(axisangle: Vector<N, U3, SB>) -> Self {
Self::new(axisangle) Self::new(axisangle)
} }
/// Builds a 3D rotation matrix from an axis and a rotation angle. /// Builds a 3D rotation matrix from an axis and a rotation angle.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axis = Vector3::y_axis();
/// let angle = f32::consts::FRAC_PI_2;
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
/// let rot = Rotation3::from_axis_angle(&axis, angle);
///
/// assert_eq!(rot.axis().unwrap(), axis);
/// assert_eq!(rot.angle(), angle);
/// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
/// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
///
/// // A zero vector yields an identity.
/// assert_eq!(Rotation3::from_scaled_axis(Vector3::<f32>::zeros()), Rotation3::identity());
/// ```
pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
where SB: Storage<N, U3> { where SB: Storage<N, U3> {
if angle.is_zero() { if angle.is_zero() {
@ -172,6 +308,17 @@ impl<N: Real> Rotation3<N> {
/// Creates a new rotation from Euler angles. /// Creates a new rotation from Euler angles.
/// ///
/// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw. /// The primitive rotations are applied in order: 1 roll 2 pitch 3 yaw.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
/// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ```
pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
let (sr, cr) = roll.sin_cos(); let (sr, cr) = roll.sin_cos();
let (sp, cp) = pitch.sin_cos(); let (sp, cp) = pitch.sin_cos();
@ -192,16 +339,35 @@ impl<N: Real> Rotation3<N> {
/// Creates Euler angles from a rotation. /// Creates Euler angles from a rotation.
/// ///
/// The angles are produced in the form (roll, yaw, pitch). /// The angles are produced in the form (roll, pitch, yaw).
#[deprecated(note = "This is renamed to use `.euler_angles()`.")]
pub fn to_euler_angles(&self) -> (N, N, N) { pub fn to_euler_angles(&self) -> (N, N, N) {
self.euler_angles()
}
/// Euler angles corresponding to this rotation from a rotation.
///
/// The angles are produced in the form (roll, pitch, yaw).
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles();
/// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ```
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 {
( (
@ -215,15 +381,26 @@ impl<N: Real> Rotation3<N> {
/// Creates a rotation that corresponds to the local frame of an observer standing at the /// Creates a rotation that corresponds to the local frame of an observer standing at the
/// origin and looking toward `dir`. /// origin and looking toward `dir`.
/// ///
/// It maps the view direction `dir` to the positive `z` axis. /// It maps the `z` axis to the direction `dir`.
/// ///
/// # Arguments /// # Arguments
/// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with. /// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with.
/// * up - The vertical direction. The only requirement of this parameter is to not be /// * up - The vertical direction. The only requirement of this parameter is to not be
/// collinear /// collinear to `dir`. Non-collinearity is not checked.
/// to `dir`. Non-collinearity is not checked. ///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let rot = Rotation3::face_towards(&dir, &up);
/// 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>,
@ -237,47 +414,92 @@ 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.
/// This conforms to the common notion of right handed look-at matrix from the computer /// This conforms to the common notion of right handed look-at matrix from the computer
/// graphics community. /// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * eye - The eye position. /// * dir - The direction toward which the camera looks.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `dir`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let rot = Rotation3::look_at_rh(&dir, &up);
/// assert_relative_eq!(rot * dir.normalize(), -Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn look_at_rh<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::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.
/// ///
/// It maps the view direction `dir` to the **positive** `z` axis.
/// This conforms to the common notion of left handed look-at matrix from the computer /// This conforms to the common notion of left handed look-at matrix from the computer
/// graphics community. /// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * eye - The eye position. /// * dir - The direction toward which the camera looks.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `dir`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// let rot = Rotation3::look_at_lh(&dir, &up);
/// assert_relative_eq!(rot * dir.normalize(), Vector3::z());
/// ```
#[inline] #[inline]
pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn look_at_lh<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::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.
/// ///
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
/// let rot = Rotation3::rotation_between(&a, &b).unwrap();
/// assert_relative_eq!(rot * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(rot.inverse() * b, a, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self> pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
where where
@ -289,6 +511,18 @@ impl<N: Real> Rotation3<N> {
/// The smallest rotation needed to make `a` and `b` collinear and point toward the same /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
/// direction, raised to the power `s`. /// direction, raised to the power `s`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0);
/// let rot2 = Rotation3::scaled_rotation_between(&a, &b, 0.2).unwrap();
/// let rot5 = Rotation3::scaled_rotation_between(&a, &b, 0.5).unwrap();
/// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
/// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn scaled_rotation_between<SB, SC>( pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U3, SB>, a: &Vector<N, U3, SB>,
@ -320,7 +554,16 @@ impl<N: Real> Rotation3<N> {
Some(Self::identity()) Some(Self::identity())
} }
/// The rotation angle. /// The rotation angle in [0; pi].
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Unit, Rotation3, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = Rotation3::from_axis_angle(&axis, 1.78);
/// assert_relative_eq!(rot.angle(), 1.78);
/// ```
#[inline] #[inline]
pub fn angle(&self) -> N { pub fn angle(&self) -> N {
((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one())
@ -329,6 +572,20 @@ impl<N: Real> Rotation3<N> {
} }
/// The rotation axis. Returns `None` if the rotation angle is zero or PI. /// The rotation axis. Returns `None` if the rotation angle is zero or PI.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// assert_relative_eq!(rot.axis().unwrap(), axis);
///
/// // Case with a zero angle.
/// let rot = Rotation3::from_axis_angle(&axis, 0.0);
/// assert!(rot.axis().is_none());
/// ```
#[inline] #[inline]
pub fn axis(&self) -> Option<Unit<Vector3<N>>> { pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
let axis = VectorN::<N, U3>::new( let axis = VectorN::<N, U3>::new(
@ -341,16 +598,62 @@ impl<N: Real> Rotation3<N> {
} }
/// The rotation axis multiplied by the rotation angle. /// The rotation axis multiplied by the rotation angle.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = Rotation3::new(axisangle);
/// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6);
/// ```
#[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()
} }
} }
/// The rotation axis and angle in ]0, pi] of this unit quaternion.
///
/// Returns `None` if the angle is zero.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// let axis_angle = rot.axis_angle().unwrap();
/// assert_relative_eq!(axis_angle.0, axis);
/// assert_relative_eq!(axis_angle.1, angle);
///
/// // Case with a zero angle.
/// let rot = Rotation3::from_axis_angle(&axis, 0.0);
/// assert!(rot.axis_angle().is_none());
/// ```
#[inline]
pub fn axis_angle(&self) -> Option<(Unit<Vector3<N>>, N)> {
if let Some(axis) = self.axis() {
Some((axis, self.angle()))
} else {
None
}
}
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &Rotation3<N>) -> N { pub fn angle_to(&self, other: &Rotation3<N>) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
@ -359,6 +662,16 @@ impl<N: Real> Rotation3<N> {
/// The rotation matrix needed to make `self` and `other` coincide. /// The rotation matrix needed to make `self` and `other` coincide.
/// ///
/// The result is such that: `self.rotation_to(other) * self == other`. /// The result is such that: `self.rotation_to(other) * self == other`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
/// let rot_to = rot1.rotation_to(&rot2);
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> { pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> {
other * self.inverse() other * self.inverse()
@ -366,6 +679,18 @@ impl<N: Real> Rotation3<N> {
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the same /// Raise the quaternion to a given floating power, i.e., returns the rotation with the same
/// axis as `self` and an angle equal to `self.angle()` multiplied by `n`. /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2;
/// let rot = Rotation3::from_axis_angle(&axis, angle);
/// let pow = rot.powf(2.0);
/// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6);
/// assert_eq!(pow.angle(), 2.4);
/// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Rotation3<N> { pub fn powf(&self, n: N) -> Rotation3<N> {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {

View File

@ -25,17 +25,21 @@ use geometry::{Isometry, Point, Translation};
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(serialize = "N: Serialize, serde(bound(
serialize = "N: Serialize,
R: Serialize, R: Serialize,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Serialize")) Owned<N, D>: Serialize"
))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize", feature = "serde-serialize",
serde(bound(deserialize = "N: Deserialize<'de>, serde(bound(
deserialize = "N: Deserialize<'de>,
R: Deserialize<'de>, R: Deserialize<'de>,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Deserialize<'de>")) Owned<N, D>: Deserialize<'de>"
))
)] )]
pub struct Similarity<N: Real, D: DimName, R> pub struct Similarity<N: Real, D: DimName, R>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
@ -80,8 +84,7 @@ impl<N: Real, D: DimName + Copy, R: Rotation<Point<N, D>> + Copy> Copy for Simil
where where
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy, Owned<N, D>: Copy,
{ {}
}
impl<N: Real, D: DimName, R: Rotation<Point<N, D>> + Clone> Clone for Similarity<N, D, R> impl<N: Real, D: DimName, R: Rotation<Point<N, D>> + Clone> Clone for Similarity<N, D, R>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
@ -181,7 +184,7 @@ where
); );
Self::from_parts( Self::from_parts(
Translation::from_vector(&self.isometry.translation.vector * scaling), Translation::from(&self.isometry.translation.vector * scaling),
self.isometry.rotation.clone(), self.isometry.rotation.clone(),
self.scaling * scaling, self.scaling * scaling,
) )
@ -266,8 +269,7 @@ impl<N: Real, D: DimName, R> Eq for Similarity<N, D, R>
where where
R: Rotation<Point<N, D>> + Eq, R: Rotation<Point<N, D>> + Eq,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {}
}
impl<N: Real, D: DimName, R> PartialEq for Similarity<N, D, R> impl<N: Real, D: DimName, R> PartialEq for Similarity<N, D, R>
where where

View File

@ -25,6 +25,20 @@ where
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
/// Creates a new identity similarity. /// Creates a new identity similarity.
///
/// # Example
///
/// ```
/// # use nalgebra::{Similarity2, Point2, Similarity3, Point3};
///
/// let sim = Similarity2::identity();
/// let pt = Point2::new(1.0, 2.0);
/// assert_eq!(sim * pt, pt);
///
/// let sim = Similarity3::identity();
/// let pt = Point3::new(1.0, 2.0, 3.0);
/// assert_eq!(sim * pt, pt);
/// ```
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::from_isometry(Isometry::identity(), N::one()) Self::from_isometry(Isometry::identity(), N::one())
@ -67,10 +81,23 @@ where
{ {
/// The similarity that applies the scaling factor `scaling`, followed by the rotation `r` with /// The similarity that applies the scaling factor `scaling`, followed by the rotation `r` with
/// its axis passing through the point `p`. /// its axis passing through the point `p`.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Similarity2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let pt = Point2::new(3.0, 2.0);
/// let sim = Similarity2::rotation_wrt_point(rot, pt, 4.0);
///
/// assert_relative_eq!(sim * Point2::new(1.0, 2.0), Point2::new(-3.0, 3.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn rotation_wrt_point(r: R, p: Point<N, D>, scaling: N) -> Self { pub fn rotation_wrt_point(r: R, p: Point<N, D>, scaling: N) -> Self {
let shift = r.transform_vector(&-&p.coords); let shift = r.transform_vector(&-&p.coords);
Self::from_parts(Translation::from_vector(shift + p.coords), r, scaling) Self::from_parts(Translation::from(shift + p.coords), r, scaling)
} }
} }
@ -101,11 +128,22 @@ where
// 2D rotation. // 2D rotation.
impl<N: Real> Similarity<N, U2, Rotation2<N>> { impl<N: Real> Similarity<N, U2, Rotation2<N>> {
/// Creates a new similarity from a translation and a rotation angle. /// Creates a new similarity from a translation, a rotation, and an uniform scaling factor.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
/// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
///
/// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self { pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self {
Self::from_parts( Self::from_parts(
Translation::from_vector(translation), Translation::from(translation),
Rotation2::new(angle), Rotation2::new(angle),
scaling, scaling,
) )
@ -114,10 +152,21 @@ impl<N: Real> Similarity<N, U2, Rotation2<N>> {
impl<N: Real> Similarity<N, U2, UnitComplex<N>> { impl<N: Real> Similarity<N, U2, UnitComplex<N>> {
/// Creates a new similarity from a translation and a rotation angle. /// Creates a new similarity from a translation and a rotation angle.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Similarity2, Vector2, Point2};
/// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
///
/// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self { pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self {
Self::from_parts( Self::from_parts(
Translation::from_vector(translation), Translation::from(translation),
UnitComplex::new(angle), UnitComplex::new(angle),
scaling, scaling,
) )
@ -130,6 +179,29 @@ macro_rules! similarity_construction_impl(
impl<N: Real> Similarity<N, U3, $Rot> { impl<N: Real> Similarity<N, U3, $Rot> {
/// Creates a new similarity from a translation, rotation axis-angle, and scaling /// Creates a new similarity from a translation, rotation axis-angle, and scaling
/// factor. /// factor.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
/// let translation = Vector3::new(1.0, 2.0, 3.0);
/// // Point and vector being transformed in the tests.
/// let pt = Point3::new(4.0, 5.0, 6.0);
/// let vec = Vector3::new(4.0, 5.0, 6.0);
///
/// // Similarity with its rotation part represented as a UnitQuaternion
/// let sim = Similarity3::new(translation, axisangle, 3.0);
/// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
/// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
///
/// // Similarity with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
/// let sim = SimilarityMatrix3::new(translation, axisangle, 3.0);
/// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
/// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
/// ```
#[inline] #[inline]
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>, scaling: N) -> Self { pub fn new(translation: Vector3<N>, axisangle: Vector3<N>, scaling: N) -> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling) Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling)
@ -146,13 +218,44 @@ macro_rules! similarity_construction_impl(
/// * target - The target position. /// * target - The target position.
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear /// * up - Vertical direction. The only requirement of this parameter is to not be collinear
/// to `eye - at`. Non-collinearity is not checked. /// to `eye - at`. Non-collinearity is not checked.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
/// let target = Point3::new(2.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// // Similarity with its rotation part represented as a UnitQuaternion
/// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0);
/// assert_eq!(sim * Point3::origin(), eye);
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
///
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0);
/// assert_eq!(sim * Point3::origin(), eye);
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
/// ```
#[inline] #[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.
@ -165,6 +268,25 @@ macro_rules! similarity_construction_impl(
/// * target - The target position. /// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
/// let target = Point3::new(2.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// // Similarity with its rotation part represented as a UnitQuaternion
/// let iso = Similarity3::look_at_rh(&eye, &target, &up, 3.0);
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6);
///
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let iso = SimilarityMatrix3::look_at_rh(&eye, &target, &up, 3.0);
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn look_at_rh(eye: &Point3<N>, pub fn look_at_rh(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
@ -184,6 +306,25 @@ macro_rules! similarity_construction_impl(
/// * target - The target position. /// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only /// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`. /// requirement of this parameter is to not be collinear to `target - eye`.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0);
/// let target = Point3::new(2.0, 2.0, 3.0);
/// let up = Vector3::y();
///
/// // Similarity with its rotation part represented as a UnitQuaternion
/// let sim = Similarity3::look_at_lh(&eye, &target, &up, 3.0);
/// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6);
///
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let sim = SimilarityMatrix3::look_at_lh(&eye, &target, &up, 3.0);
/// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6);
/// ```
#[inline] #[inline]
pub fn look_at_lh(eye: &Point3<N>, pub fn look_at_lh(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,

View File

@ -155,7 +155,9 @@ where
} }
let t = m.fixed_slice::<D, U1>(0, D::dim()).into_owned(); let t = m.fixed_slice::<D, U1>(0, D::dim()).into_owned();
let t = Translation::from_vector(::convert_unchecked(t)); let t = Translation {
vector: ::convert_unchecked(t),
};
Self::from_parts(t, ::convert_unchecked(mm), ::convert_unchecked(scale)) Self::from_parts(t, ::convert_unchecked(mm), ::convert_unchecked(scale))
} }

View File

@ -269,7 +269,7 @@ similarity_binop_impl_all!(
[ref ref] => { [ref ref] => {
let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling();
Similarity::from_parts( Similarity::from_parts(
Translation::from_vector(&self.isometry.translation.vector + shift), Translation::from(&self.isometry.translation.vector + shift),
self.isometry.rotation.clone() * rhs.rotation.clone(), self.isometry.rotation.clone() * rhs.rotation.clone(),
self.scaling()) self.scaling())
}; };
@ -352,7 +352,7 @@ similarity_binop_impl_all!(
[ref ref] => { [ref ref] => {
let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling(); let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling();
Similarity::from_parts( Similarity::from_parts(
Translation::from_vector(&self.isometry.translation.vector + shift), Translation::from(&self.isometry.translation.vector + shift),
self.isometry.rotation.clone(), self.isometry.rotation.clone(),
self.scaling()) self.scaling())
}; };

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

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

View File

@ -1,3 +1,4 @@
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::Any; use std::any::Any;
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -14,7 +15,7 @@ use base::{DefaultAllocator, MatrixN};
/// Trait implemented by phantom types identifying the projective transformation type. /// Trait implemented by phantom types identifying the projective transformation type.
/// ///
/// NOTE: this trait is not intended to be implementable outside of the `nalgebra` crate. /// NOTE: this trait is not intended to be implemented outside of the `nalgebra` crate.
pub trait TCategory: Any + Debug + Copy + PartialEq + Send { pub trait TCategory: Any + Debug + Copy + PartialEq + Send {
/// Indicates whether a `Transform` with the category `Self` has a bottom-row different from /// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
/// `0 0 .. 1`. /// `0 0 .. 1`.
@ -237,13 +238,43 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
} }
} }
/// The underlying matrix. /// Retrieves the underlying matrix.
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.into_inner(), m);
/// ```
#[inline]
pub fn into_inner(self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix
}
/// Retrieves the underlying matrix.
/// Deprecated: Use [Transform::into_inner] instead.
#[deprecated(note="use `.into_inner()` instead")]
#[inline] #[inline]
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> { pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix self.matrix
} }
/// A reference to the underlying matrix. /// A reference to the underlying matrix.
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(*t.matrix(), m);
/// ```
#[inline] #[inline]
pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> { pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> {
&self.matrix &self.matrix
@ -253,6 +284,24 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// ///
/// It is `_unchecked` because direct modifications of this matrix may break invariants /// It is `_unchecked` because direct modifications of this matrix may break invariants
/// identified by this transformation category. /// identified by this transformation category.
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let mut t = Transform2::from_matrix_unchecked(m);
/// t.matrix_mut_unchecked().m12 = 42.0;
/// t.matrix_mut_unchecked().m23 = 90.0;
///
///
/// let expected = Matrix3::new(1.0, 42.0, 0.0,
/// 3.0, 4.0, 90.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(*t.matrix(), expected);
/// ```
#[inline] #[inline]
pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> { pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
&mut self.matrix &mut self.matrix
@ -271,19 +320,53 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// Clones this transform into one that owns its data. /// Clones this transform into one that owns its data.
#[inline] #[inline]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")] #[deprecated(
note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release."
)]
pub fn clone_owned(&self) -> Transform<N, D, C> { pub fn clone_owned(&self) -> Transform<N, D, C> {
Transform::from_matrix_unchecked(self.matrix.clone_owned()) Transform::from_matrix_unchecked(self.matrix.clone_owned())
} }
/// Converts this transform into its equivalent homogeneous transformation matrix. /// Converts this transform into its equivalent homogeneous transformation matrix.
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(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>> {
self.matrix().clone_owned() self.matrix().clone_owned()
} }
/// Attempts to invert this transformation. You may use `.inverse` instead of this /// Attempts to invert this transformation. You may use `.inverse` instead of this
/// transformation has a subcategory of `TProjective`. /// transformation has a subcategory of `TProjective` (i.e. if it is a `Projective{2,3}` or `Affine{2,3}`).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// let inv_t = t.try_inverse().unwrap();
/// assert_relative_eq!(t * inv_t, Transform2::identity());
/// assert_relative_eq!(inv_t * t, Transform2::identity());
///
/// // Non-invertible case.
/// let m = Matrix3::new(0.0, 2.0, 1.0,
/// 3.0, 0.0, 5.0,
/// 0.0, 0.0, 0.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert!(t.try_inverse().is_none());
/// ```
#[inline] #[inline]
pub fn try_inverse(self) -> Option<Transform<N, D, C>> { pub fn try_inverse(self) -> Option<Transform<N, D, C>> {
if let Some(m) = self.matrix.try_inverse() { if let Some(m) = self.matrix.try_inverse() {
@ -294,7 +377,21 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
} }
/// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral` /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
/// category (it may not be invertible). /// category (i.e., a `Transform{2,3}` may not be invertible).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Projective2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let proj = Projective2::from_matrix_unchecked(m);
/// let inv_t = proj.inverse();
/// assert_relative_eq!(proj * inv_t, Projective2::identity());
/// assert_relative_eq!(inv_t * proj, Projective2::identity());
/// ```
#[inline] #[inline]
pub fn inverse(self) -> Transform<N, D, C> pub fn inverse(self) -> Transform<N, D, C>
where C: SubTCategoryOf<TProjective> { where C: SubTCategoryOf<TProjective> {
@ -304,6 +401,28 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this /// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
/// transformation has a subcategory of `TProjective`. /// transformation has a subcategory of `TProjective`.
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// let mut inv_t = t;
/// assert!(inv_t.try_inverse_mut());
/// assert_relative_eq!(t * inv_t, Transform2::identity());
/// assert_relative_eq!(inv_t * t, Transform2::identity());
///
/// // Non-invertible case.
/// let m = Matrix3::new(0.0, 2.0, 1.0,
/// 3.0, 0.0, 5.0,
/// 0.0, 0.0, 0.0);
/// let mut t = Transform2::from_matrix_unchecked(m);
/// assert!(!t.try_inverse_mut());
/// ```
#[inline] #[inline]
pub fn try_inverse_mut(&mut self) -> bool { pub fn try_inverse_mut(&mut self) -> bool {
self.matrix.try_inverse_mut() self.matrix.try_inverse_mut()
@ -311,6 +430,21 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the /// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the
/// `TGeneral` category (it may not be invertible). /// `TGeneral` category (it may not be invertible).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Projective2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let proj = Projective2::from_matrix_unchecked(m);
/// let mut inv_t = proj;
/// inv_t.inverse_mut();
/// assert_relative_eq!(proj * inv_t, Projective2::identity());
/// assert_relative_eq!(inv_t * proj, Projective2::identity());
/// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) pub fn inverse_mut(&mut self)
where C: SubTCategoryOf<TProjective> { where C: SubTCategoryOf<TProjective> {
@ -329,6 +463,63 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
} }
} }
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> AbsDiffEq for Transform<N, D, C>
where
N::Epsilon: Copy,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{
type Epsilon = N::Epsilon;
#[inline]
fn default_epsilon() -> Self::Epsilon {
N::default_epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.matrix.abs_diff_eq(&other.matrix, epsilon)
}
}
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> RelativeEq for Transform<N, D, C>
where
N::Epsilon: Copy,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{
#[inline]
fn default_max_relative() -> Self::Epsilon {
N::default_max_relative()
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool
{
self.matrix
.relative_eq(&other.matrix, epsilon, max_relative)
}
}
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> UlpsEq for Transform<N, D, C>
where
N::Epsilon: Copy,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{
#[inline]
fn default_max_ulps() -> u32 {
N::default_max_ulps()
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.matrix.ulps_eq(&other.matrix, epsilon, max_ulps)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -2,16 +2,16 @@ use base::dimension::{U2, U3};
use geometry::{TAffine, TGeneral, TProjective, Transform}; use geometry::{TAffine, TGeneral, TProjective, Transform};
/// A 2D general transformation that may not be inversible. Stored as an homogeneous 3x3 matrix. /// A 2D general transformation that may not be invertible. Stored as an homogeneous 3x3 matrix.
pub type Transform2<N> = Transform<N, U2, TGeneral>; pub type Transform2<N> = Transform<N, U2, TGeneral>;
/// An inversible 2D general transformation. Stored as an homogeneous 3x3 matrix. /// An invertible 2D general transformation. Stored as an homogeneous 3x3 matrix.
pub type Projective2<N> = Transform<N, U2, TProjective>; pub type Projective2<N> = Transform<N, U2, TProjective>;
/// A 2D affine transformation. Stored as an homogeneous 3x3 matrix. /// A 2D affine transformation. Stored as an homogeneous 3x3 matrix.
pub type Affine2<N> = Transform<N, U2, TAffine>; pub type Affine2<N> = Transform<N, U2, TAffine>;
/// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix. /// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix.
pub type Transform3<N> = Transform<N, U3, TGeneral>; pub type Transform3<N> = Transform<N, U3, TGeneral>;
/// An inversible 3D general transformation. Stored as an homogeneous 4x4 matrix. /// An invertible 3D general transformation. Stored as an homogeneous 4x4 matrix.
pub type Projective3<N> = Transform<N, U3, TProjective>; pub type Projective3<N> = Transform<N, U3, TProjective>;
/// A 3D affine transformation. Stored as an homogeneous 4x4 matrix. /// A 3D affine transformation. Stored as an homogeneous 4x4 matrix.
pub type Affine3<N> = Transform<N, U3, TAffine>; pub type Affine3<N> = Transform<N, U3, TAffine>;

View File

@ -12,6 +12,33 @@ impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Transform<N, D, C>
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>> where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
{ {
/// Creates a new identity transform. /// Creates a new identity transform.
///
/// # Example
///
/// ```
/// # use nalgebra::{Transform2, Projective2, Affine2, Transform3, Projective3, Affine3, Point2, Point3};
///
/// let pt = Point2::new(1.0, 2.0);
/// let t = Projective2::identity();
/// assert_eq!(t * pt, pt);
///
/// let aff = Affine2::identity();
/// assert_eq!(aff * pt, pt);
///
/// let aff = Transform2::identity();
/// assert_eq!(aff * pt, pt);
///
/// // Also works in 3D.
/// let pt = Point3::new(1.0, 2.0, 3.0);
/// let t = Projective3::identity();
/// assert_eq!(t * pt, pt);
///
/// let aff = Affine3::identity();
/// assert_eq!(aff * pt, pt);
///
/// let aff = Transform3::identity();
/// assert_eq!(aff * pt, pt);
/// ```
#[inline] #[inline]
pub fn identity() -> Self { pub fn identity() -> Self {
Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity()) Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity())

View File

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

View File

@ -43,8 +43,7 @@ impl<N: Scalar, D: DimName> Copy for Translation<N, D>
where where
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy, Owned<N, D>: Copy,
{ {}
}
impl<N: Scalar, D: DimName> Clone for Translation<N, D> impl<N: Scalar, D: DimName> Clone for Translation<N, D>
where where
@ -53,7 +52,7 @@ where
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Translation::from_vector(self.vector.clone()) Translation::from(self.vector.clone())
} }
} }
@ -100,7 +99,7 @@ where
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let matrix = VectorN::<N, D>::deserialize(deserializer)?; let matrix = VectorN::<N, D>::deserialize(deserializer)?;
Ok(Translation::from_vector(matrix)) Ok(Translation::from(matrix))
} }
} }
@ -109,18 +108,49 @@ where DefaultAllocator: Allocator<N, D>
{ {
/// Creates a new translation from the given vector. /// Creates a new translation from the given vector.
#[inline] #[inline]
#[deprecated(note = "Use `::from` instead.")]
pub fn from_vector(vector: VectorN<N, D>) -> Translation<N, D> { pub fn from_vector(vector: VectorN<N, D>) -> Translation<N, D> {
Translation { vector: vector } Translation { vector: vector }
} }
/// Inverts `self`. /// Inverts `self`.
///
/// # Example
/// ```
/// # use nalgebra::{Translation2, Translation3};
/// let t = Translation3::new(1.0, 2.0, 3.0);
/// assert_eq!(t * t.inverse(), Translation3::identity());
/// assert_eq!(t.inverse() * t, Translation3::identity());
///
/// // Work in all dimensions.
/// let t = Translation2::new(1.0, 2.0);
/// assert_eq!(t * t.inverse(), Translation2::identity());
/// assert_eq!(t.inverse() * t, Translation2::identity());
/// ```
#[inline] #[inline]
pub fn inverse(&self) -> Translation<N, D> pub fn inverse(&self) -> Translation<N, D>
where N: ClosedNeg { where N: ClosedNeg {
Translation::from_vector(-&self.vector) Translation::from(-&self.vector)
} }
/// Converts this translation into its equivalent homogeneous transformation matrix. /// Converts this translation into its equivalent homogeneous transformation matrix.
///
/// # Example
/// ```
/// # use nalgebra::{Translation2, Translation3, Matrix3, Matrix4};
/// let t = Translation3::new(10.0, 20.0, 30.0);
/// let expected = Matrix4::new(1.0, 0.0, 0.0, 10.0,
/// 0.0, 1.0, 0.0, 20.0,
/// 0.0, 0.0, 1.0, 30.0,
/// 0.0, 0.0, 0.0, 1.0);
/// assert_eq!(t.to_homogeneous(), expected);
///
/// let t = Translation2::new(10.0, 20.0);
/// let expected = Matrix3::new(1.0, 0.0, 10.0,
/// 0.0, 1.0, 20.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(t.to_homogeneous(), expected);
/// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where where
@ -136,6 +166,23 @@ where DefaultAllocator: Allocator<N, D>
} }
/// Inverts `self` in-place. /// Inverts `self` in-place.
///
/// # Example
/// ```
/// # use nalgebra::{Translation2, Translation3};
/// let t = Translation3::new(1.0, 2.0, 3.0);
/// let mut inv_t = Translation3::new(1.0, 2.0, 3.0);
/// inv_t.inverse_mut();
/// assert_eq!(t * inv_t, Translation3::identity());
/// assert_eq!(inv_t * t, Translation3::identity());
///
/// // Work in all dimensions.
/// let t = Translation2::new(1.0, 2.0);
/// let mut inv_t = Translation2::new(1.0, 2.0);
/// inv_t.inverse_mut();
/// assert_eq!(t * inv_t, Translation2::identity());
/// assert_eq!(inv_t * t, Translation2::identity());
/// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) pub fn inverse_mut(&mut self)
where N: ClosedNeg { where N: ClosedNeg {

View File

@ -183,16 +183,16 @@ where DefaultAllocator: Allocator<N, D>
#[inline] #[inline]
fn from_vector(v: VectorN<N, D>) -> Option<Self> { fn from_vector(v: VectorN<N, D>) -> Option<Self> {
Some(Self::from_vector(v)) Some(Self::from(v))
} }
#[inline] #[inline]
fn powf(&self, n: N) -> Option<Self> { fn powf(&self, n: N) -> Option<Self> {
Some(Self::from_vector(&self.vector * n)) Some(Self::from(&self.vector * n))
} }
#[inline] #[inline]
fn translation_between(a: &Point<N, D>, b: &Point<N, D>) -> Option<Self> { fn translation_between(a: &Point<N, D>, b: &Point<N, D>) -> Option<Self> {
Some(Self::from_vector(b - a)) Some(Self::from(b - a))
} }
} }

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