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
### Added
* Add swizzling up to dimension 3. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.w)`.
* Add swizzling up to dimension 3 for vectors. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.y)`.
* Add swizzling up to dimension 3 for points. For example, you can do `p.zxy()` as an equivalent to `Point3::new(p.z, p.x, p.y)`.
* Add `.copy_from_slice` to copy matrix components from a slice in column-major order.
* Add `.dot` to quaternions.
* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them.
* 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
use them as `Projective3` structures.
* 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 `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.
* 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]
All dependencies have been updated to their latest versions.

View File

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

View File

@ -2,6 +2,9 @@
<img src="http://nalgebra.org/img/logo_nalgebra.svg" alt="crates.io">
</p>
<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">
<img src="https://travis-ci.org/rustsim/nalgebra.svg?branch=master" alt="Build status">
</a>

View File

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

View File

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

View File

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

View File

@ -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.
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.
let translation = Vector3::new(2.0, 3.0, 4.0);

View File

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

View File

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

View File

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

View File

@ -315,13 +315,151 @@ where DefaultAllocator: Alloc<f32, D> {
// 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]`.
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
}
/// 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.
///
/// 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::{
Qua, TMat, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3, TVec1,
TVec2, TVec3, TVec4,
};
use na::{Real, Scalar, U2, U3, U4};
#![cfg_attr(rustfmt, rustfmt_skip)]
use na::{Scalar, Real, U2, U3, U4};
use aliases::{TMat, Qua, TVec1, TVec2, TVec3, TVec4, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4,
TMat4, TMat4x2, TMat4x3};
/// 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)
}
/// Create a new 2x2 matrix.
pub fn mat2<N: Scalar>(m11: N, m12: N, m21: N, m22: N) -> TMat2<N> {
TMat::<N, U2, U2>::new(m11, m12, m21, m22)
pub fn mat2<N: Scalar>(m11: N, m12: N,
m21: N, m22: N) -> TMat2<N> {
TMat::<N, U2, U2>::new(
m11, m12,
m21, m22,
)
}
/// Create a new 2x2 matrix.
pub fn mat2x2<N: Scalar>(m11: N, m12: N, m21: N, m22: N) -> TMat2<N> {
TMat::<N, U2, U2>::new(m11, m12, m21, m22)
pub fn mat2x2<N: Scalar>(m11: N, m12: N,
m21: N, m22: N) -> TMat2<N> {
TMat::<N, U2, U2>::new(
m11, m12,
m21, m22,
)
}
/// Create a new 2x3 matrix.
pub fn mat2x3<N: Scalar>(m11: N, m12: N, m13: N, m21: N, m22: N, m23: N) -> TMat2x3<N> {
TMat::<N, U2, U3>::new(m11, m12, m13, m21, m22, m23)
pub fn mat2x3<N: Scalar>(m11: N, m12: N, m13: N,
m21: N, m22: N, m23: N) -> TMat2x3<N> {
TMat::<N, U2, U3>::new(
m11, m12, m13,
m21, m22, m23,
)
}
/// Create a new 2x4 matrix.
pub fn mat2x4<N: Scalar>(
m11: N,
m12: N,
m13: N,
m14: N,
m21: N,
m22: N,
m23: N,
m24: N,
) -> TMat2x4<N>
{
TMat::<N, U2, U4>::new(m11, m12, m13, m14, m21, m22, m23, m24)
pub fn mat2x4<N: Scalar>(m11: N, m12: N, m13: N, m14: N,
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.
pub fn mat3<N: Scalar>(
m11: N,
m12: N,
m13: N,
m21: N,
m22: N,
m23: N,
m31: N,
m32: N,
m33: N,
) -> TMat3<N>
{
TMat::<N, U3, U3>::new(m11, m12, m13, m21, m22, m23, m31, m32, m33)
pub fn mat3<N: Scalar>(m11: N, m12: N, m13: N,
m21: N, m22: N, m23: N,
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.
pub fn mat3x2<N: Scalar>(m11: N, m12: N, m21: N, m22: N, m31: N, m32: N) -> TMat3x2<N> {
TMat::<N, U3, U2>::new(m11, m12, m21, m22, m31, m32)
pub fn mat3x2<N: Scalar>(m11: N, m12: N,
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.
pub fn mat3x3<N: Scalar>(
m11: N,
m12: N,
m13: N,
m21: N,
m22: N,
m23: N,
m31: N,
m32: N,
m33: N,
) -> TMat3<N>
{
TMat::<N, U3, U3>::new(m11, m12, m13, m31, m32, m33, m21, m22, m23)
pub fn mat3x3<N: Scalar>(m11: N, m12: N, m13: N,
m21: N, m22: N, m23: N,
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.
pub fn mat3x4<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,
) -> TMat3x4<N>
{
TMat::<N, U3, U4>::new(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34)
pub fn mat3x4<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) -> TMat3x4<N> {
TMat::<N, U3, U4>::new(
m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
)
}
/// Create a new 4x2 matrix.
pub fn mat4x2<N: Scalar>(
m11: N,
m12: N,
m21: N,
m22: N,
m31: N,
m32: N,
m41: N,
m42: N,
) -> TMat4x2<N>
{
TMat::<N, U4, U2>::new(m11, m12, m21, m22, m31, m32, m41, m42)
pub fn mat4x2<N: Scalar>(m11: N, m12: N,
m21: N, m22: N,
m31: N, m32: N,
m41: N, m42: N) -> TMat4x2<N> {
TMat::<N, U4, U2>::new(
m11, m12,
m21, m22,
m31, m32,
m41, m42,
)
}
/// Create a new 4x3 matrix.
pub fn mat4x3<N: Scalar>(
m11: N,
m12: N,
m13: N,
m21: N,
m22: N,
m23: N,
m31: N,
m32: N,
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,
pub fn mat4x3<N: Scalar>(m11: N, m12: N, m13: N,
m21: N, m22: N, m23: N,
m31: N, m32: N, 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 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>
{
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,
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 na::{Orthographic3, Perspective3, Real};
use na::{Real};
//pub fn frustum<N: Real>(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
@ -53,119 +53,644 @@ use na::{Orthographic3, Perspective3, Real};
// unimplemented!()
//}
/// Creates a matrix for an orthographic parallel viewing volume, using the right handedness and OpenGL near and far clip planes definition.
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap()
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
//pub fn ortho_lh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_rh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_rh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_rh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn ortho_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
// unimplemented!()
//}
/// Creates a left hand matrix for a orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_lh_no(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a perspective-view frustum based on the right handedness and OpenGL near and far clip planes definition.
/// Creates a left hand matrix for a orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = -(right + left) / (right - left);
mat[(1, 1)] = two / (top-bottom);
mat[(1, 3)] = -(top + bottom) / (top - bottom);
mat[(2, 2)] = two / (zfar - znear);
mat[(2, 3)] = -(zfar + znear) / (zfar - znear);
mat
}
/// Creates a matrix for a left hand orthographic-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let one : N = N::one();
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = - (right + left) / (right - left);
mat[(1, 1)] = two / (top - bottom);
mat[(1, 3)] = - (top + bottom) / (top - bottom);
mat[(2, 2)] = one / (zfar - znear);
mat[(2, 3)] = - znear / (zfar - znear);
mat
}
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a right hand orthographic-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh_no<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = - (right + left) / (right - left);
mat[(1, 1)] = two/(top-bottom);
mat[(1, 3)] = - (top + bottom) / (top - bottom);
mat[(2, 2)] = - two / (zfar - znear);
mat[(2, 3)] = - (zfar + znear) / (zfar - znear);
mat
}
/// Creates a right hand matrix for a orthographic-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
let one : N = N::one();
let two : N = ::convert(2.0);
let mut mat : TMat4<N> = TMat4::<N>::identity();
mat[(0, 0)] = two / (right - left);
mat[(0, 3)] = - (right + left) / (right - left);
mat[(1, 1)] = two/(top-bottom);
mat[(1, 3)] = - (top + bottom) / (top - bottom);
mat[(2, 2)] = - one / (zfar - znear);
mat[(2, 3)] = - znear / (zfar - znear);
mat
}
/// Creates a right hand matrix for a orthographic-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `left` - Coordinate for left bound of matrix
/// * `right` - Coordinate for right bound of matrix
/// * `bottom` - Coordinate for bottom bound of matrix
/// * `top` - Coordinate for top bound of matrix
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_zo<N: Real>(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4<N> {
ortho_rh_zo(left, right, bottom, top, znear, zfar)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_no(fov, width, height, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_lh_no(fov, width, height, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = (far + near) / (far - near);
mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near);
mat[(3, 2)] = N::one();
mat
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = far / (far - near);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = N::one();
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_no(fov, width, height, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_no(fov, width, height, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = - (far + near) / (far - near);
mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near);
mat[(3, 2)] = -N::one();
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
assert!(
width > N::zero(),
"The width must be greater than zero"
);
assert!(
height > N::zero(),
"The height must be greater than zero."
);
assert!(
fov > N::zero(),
"The fov must be greater than zero"
);
let mut mat = TMat4::zeros();
let rad = fov;
let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin();
let w = h * height / width;
mat[(0, 0)] = w;
mat[(1, 1)] = h;
mat[(2, 2)] = far / (near - far);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = -N::one();
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fov` - Field of view, in radians
/// * `width` - Width of the viewport
/// * `height` - Height of the viewport
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
perspective_fov_rh_zo(fov, width, height, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
Perspective3::new(aspect, fovy, near, far).unwrap()
// TODO: Breaking change - revert back to proper glm conventions?
//
// Prior to changes to support configuring the behaviour of this function it was simply
// a wrapper around Perspective3::new(). The argument order for that function is different
// than the glm convention, but reordering the arguments would've caused pointlessly
// un-optimal code to be generated so they were rearranged so the function would just call
// straight through.
//
// Now this call to Perspective3::new() is no longer made so the functions can have their
// arguments reordered to the glm convention. Unfortunately this is a breaking change so
// can't be cleanly integrated into the existing library version without breaking other
// people's code. Reordering to glm isn't a huge deal but if it is done it will have to be
// in a major API breaking update.
//
perspective_rh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_lh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let one = N::one();
let two: N = ::convert( 2.0);
let mut mat : TMat4<N> = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = (far + near) / (far - near);
mat[(2, 3)] = -(two * far * near) / (far - near);
mat[(3, 2)] = one;
mat
}
/// Creates a matrix for a left hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let one = N::one();
let two: N = ::convert( 2.0);
let mut mat: TMat4<N> = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = far / (far - near);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = one;
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_rh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_rh_no(aspect, fovy, near, far)
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh_no<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let negone = -N::one();
let one = N::one();
let two: N = ::convert( 2.0);
let mut mat = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = - (far + near) / (far - near);
mat[(2, 3)] = -(two * far * near) / (far - near);
mat[(3, 2)] = negone;
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
assert!(
!relative_eq!(far - near, N::zero()),
"The near-plane and far-plane must not be superimposed."
);
assert!(
!relative_eq!(aspect, N::zero()),
"The apsect ratio must not be zero."
);
let negone = -N::one();
let one = N::one();
let two = ::convert( 2.0);
let mut mat = TMat4::zeros();
let tan_half_fovy = (fovy / two).tan();
mat[(0, 0)] = one / (aspect * tan_half_fovy);
mat[(1, 1)] = one / tan_half_fovy;
mat[(2, 2)] = far / (near - far);
mat[(2, 3)] = -(far * near) / (far - near);
mat[(3, 2)] = negone;
mat
}
/// Creates a matrix for a right hand perspective-view frustum with a depth range of 0 to 1
///
/// # Parameters
///
/// * `fovy` - Field of view, in radians
/// * `aspect` - Ratio of viewport width to height (width/height)
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_zo<N: Real>(aspect: N, fovy: N, near: N, far: N) -> TMat4<N> {
perspective_rh_zo(aspect, fovy, near, far)
}
//pub fn perspective_fov<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_lh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_lh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_lh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_rh<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_rh_no<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_rh_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_fov_zo<N: Real>(fov: N, width: N, height: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_lh<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_lh_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_lh_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_rh<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_rh_no<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_rh_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn perspective_zo<N: Real>(fovy: N, aspect: N, near: N, far: N) -> TMat4<N> {
// unimplemented!()
//}
//
//pub fn tweaked_infinite_perspective<N: Real>(fovy: N, aspect: N, near: N) -> TMat4<N> {
// unimplemented!()
//}

View File

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

View File

@ -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_rh`](fn.look_at_rh.html)
pub fn look_at_lh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
TMat::look_at_lh(
&Point3::from_coordinates(*eye),
&Point3::from_coordinates(*center),
up,
)
TMat::look_at_lh(&Point3::from(*eye), &Point3::from(*center), up)
}
/// 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_lh`](fn.look_at_lh.html)
pub fn look_at_rh<N: Real>(eye: &TVec3<N>, center: &TVec3<N>, up: &TVec3<N>) -> TMat4<N> {
TMat::look_at_rh(
&Point3::from_coordinates(*eye),
&Point3::from_coordinates(*center),
up,
)
TMat::look_at_rh(&Point3::from(*eye), &Point3::from(*center), up)
}
/// 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
pub use self::matrix_clip_space::{ortho, perspective};
pub use self::matrix_clip_space::{
ortho, ortho_lh, ortho_lh_no, ortho_lh_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo,
ortho_zo,
perspective, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no,
perspective_rh, perspective_rh_no, perspective_rh_zo, perspective_zo,
perspective_fov, perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo,
perspective_fov_no, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo,
perspective_fov_zo,
};
pub use self::matrix_projection::{
pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo,
};

View File

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

View File

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

View File

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

View File

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

View File

@ -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]`.
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.

View File

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

View File

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

View File

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

View File

@ -111,6 +111,7 @@
*/
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate num_traits as num;
#[macro_use]
@ -122,8 +123,9 @@ pub use aliases::*;
pub use common::{
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,
int_bits_to_float_vec, mix, modf, modf_vec, round, sign, smoothstep, step, step_scalar,
step_vec, trunc, uint_bits_to_float, uint_bits_to_float_scalar,
int_bits_to_float_vec, lerp, lerp_scalar, lerp_vec, mix, mix_scalar, mix_vec, modf, modf_vec,
round, sign, smoothstep, step, step_scalar, step_vec, trunc, uint_bits_to_float,
uint_bits_to_float_scalar,
};
pub use constructors::*;
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,
identity, look_at, look_at_lh, look_at_rh, max, max2, max3, max3_scalar, max4, max4_scalar,
min, min2, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps,
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, pi,
pick_matrix, project, project_no, project_zo, quat_angle, quat_angle_axis, quat_axis,
quat_conjugate, quat_cross, quat_dot, quat_equal, quat_equal_eps, quat_exp, quat_inverse,
quat_length, quat_lerp, quat_log, quat_magnitude, quat_normalize, quat_not_equal,
quat_not_equal_eps, quat_pow, quat_rotate, quat_slerp, rotate, rotate_x, rotate_y, rotate_z,
scale, translate, unproject, unproject_no, unproject_zo,
not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, perspective_fov,
perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo, perspective_fov_no,
perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, perspective_fov_zo,
perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, perspective_rh,
perspective_rh_no, perspective_rh_zo, perspective_zo, ortho_lh, ortho_lh_no, ortho_lh_zo,
ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, ortho_zo, pi, pick_matrix, project, project_no,
project_zo, quat_angle, quat_angle_axis, quat_axis, quat_conjugate, quat_cross, quat_dot,
quat_equal, quat_equal_eps, quat_exp, quat_inverse, quat_length, quat_lerp, quat_log,
quat_magnitude, quat_normalize, quat_not_equal, quat_not_equal_eps, quat_pow, quat_rotate,
quat_slerp, rotate, rotate_x, rotate_y, rotate_z, scale, translate, unproject, unproject_no,
unproject_zo,
};
pub use gtc::{
affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose,

View File

@ -17,8 +17,7 @@ pub trait Number:
impl<T: Scalar + Ring + Lattice + AbsDiffEq<Epsilon = Self> + Signed + FromPrimitive + Bounded>
Number for T
{
}
{}
#[doc(hidden)]
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<(usize, usize), R>
+ 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]
nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] }
quickcheck = "0.6"
quickcheck = "0.7"
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",
serde(bound(serialize = "DefaultAllocator: Allocator<N, D>,
MatrixN<N, D>: Serialize"))
serde(bound(
serialize = "DefaultAllocator: Allocator<N, D>,
MatrixN<N, D>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, D>,
MatrixN<N, D>: Deserialize<'de>"))
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D>,
MatrixN<N, D>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
pub struct Cholesky<N: Scalar, D: Dim>
@ -34,8 +38,7 @@ impl<N: Scalar, D: Dim> Copy for Cholesky<N, D>
where
DefaultAllocator: Allocator<N, D, D>,
MatrixN<N, D>: Copy,
{
}
{}
impl<N: CholeskyScalar + Zero, D: Dim> Cholesky<N, D>
where DefaultAllocator: Allocator<N, D, D>
@ -157,7 +160,7 @@ where DefaultAllocator: Allocator<N, D, D>
// Copy lower triangle to upper triangle.
for i in 0..dim {
for j in i + 1..dim {
unsafe { *self.l.get_unchecked_mut(i, j) = *self.l.get_unchecked(j, i) };
unsafe { *self.l.get_unchecked_mut((i, j)) = *self.l.get_unchecked((j, i)) };
}
}

View File

@ -18,19 +18,19 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde-serialize",
serde(
bound(serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
serde(bound(
serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize,
MatrixN<N, D>: Serialize")
)
MatrixN<N, D>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(
bound(deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize,
MatrixN<N, D>: Deserialize<'de>")
)
MatrixN<N, D>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
pub struct Eigen<N: Scalar, D: Dim>
@ -49,8 +49,7 @@ where
DefaultAllocator: Allocator<N, D> + Allocator<N, D, D>,
VectorN<N, D>: Copy,
MatrixN<N, D>: Copy,
{
}
{}
impl<N: EigenScalar + Real, D: Dim> Eigen<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",
serde(bound(serialize = "DefaultAllocator: Allocator<N, D, D> +
serde(bound(
serialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, DimDiff<D, U1>>,
MatrixN<N, D>: Serialize,
VectorN<N, DimDiff<D, U1>>: Serialize"))
VectorN<N, DimDiff<D, U1>>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, D, D> +
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, DimDiff<D, U1>>,
MatrixN<N, D>: Deserialize<'de>,
VectorN<N, DimDiff<D, U1>>: Deserialize<'de>"))
VectorN<N, DimDiff<D, U1>>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
pub struct Hessenberg<N: Scalar, D: DimSub<U1>>
@ -38,8 +42,7 @@ where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>,
MatrixN<N, D>: Copy,
VectorN<N, DimDiff<D, U1>>: Copy,
{
}
{}
impl<N: HessenbergScalar + Zero, D: DimSub<U1>> Hessenberg<N, D>
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",
serde(bound(serialize = "DefaultAllocator: Allocator<N, R, C> +
serde(bound(
serialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<i32, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Serialize,
PermutationSequence<DimMinimum<R, C>>: Serialize"))
PermutationSequence<DimMinimum<R, C>>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, R, C> +
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<i32, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Deserialize<'de>,
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"))
PermutationSequence<DimMinimum<R, C>>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
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>>,
MatrixMN<N, R, C>: Copy,
VectorN<i32, DimMinimum<R, C>>: Copy,
{
}
{}
impl<N: LUScalar, R: Dim, C: Dim> LU<N, R, C>
where

View File

@ -16,17 +16,21 @@ use lapack;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(serialize = "DefaultAllocator: Allocator<N, R, C> +
serde(bound(
serialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<N, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Serialize,
VectorN<N, DimMinimum<R, C>>: Serialize"))
VectorN<N, DimMinimum<R, C>>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, R, C> +
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, R, C> +
Allocator<N, DimMinimum<R, C>>,
MatrixMN<N, R, C>: Deserialize<'de>,
VectorN<N, DimMinimum<R, C>>: Deserialize<'de>"))
VectorN<N, DimMinimum<R, C>>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
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>>,
MatrixMN<N, R, C>: Copy,
VectorN<N, DimMinimum<R, C>>: Copy,
{
}
{}
impl<N: QRScalar + Zero, R: DimMin<C>, C: Dim> QR<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",
serde(
bound(serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
serde(bound(
serialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize,
MatrixN<N, D>: Serialize")
)
MatrixN<N, D>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(
bound(deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
VectorN<N, D>: Serialize,
MatrixN<N, D>: Deserialize<'de>")
)
MatrixN<N, D>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
pub struct RealSchur<N: Scalar, D: Dim>
@ -47,8 +47,7 @@ where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
MatrixN<N, D>: Copy,
VectorN<N, D>: Copy,
{
}
{}
impl<N: RealSchurScalar + Real, D: Dim> RealSchur<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",
serde(bound(serialize = "DefaultAllocator: Allocator<N, DimMinimum<R, C>> +
serde(bound(
serialize = "DefaultAllocator: Allocator<N, DimMinimum<R, C>> +
Allocator<N, R, R> +
Allocator<N, C, C>,
MatrixN<N, R>: Serialize,
MatrixN<N, C>: Serialize,
VectorN<N, DimMinimum<R, C>>: Serialize"))
VectorN<N, DimMinimum<R, C>>: Serialize"
))
)]
#[cfg_attr(
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, C, C>,
MatrixN<N, R>: Deserialize<'de>,
MatrixN<N, C>: Deserialize<'de>,
VectorN<N, DimMinimum<R, C>>: Deserialize<'de>"))
VectorN<N, DimMinimum<R, C>>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
pub struct SVD<N: Scalar, R: DimMin<C>, C: Dim>
@ -49,8 +53,7 @@ where
MatrixMN<N, R, R>: Copy,
MatrixMN<N, C, C>: Copy,
VectorN<N, DimMinimum<R, C>>: Copy,
{
}
{}
/// Trait implemented by floats (`f32`, `f64`) and complex floats (`Complex<f32>`, `Complex<f64>`)
/// 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",
serde(bound(serialize = "DefaultAllocator: Allocator<N, D, D> +
serde(bound(
serialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, D>,
VectorN<N, D>: Serialize,
MatrixN<N, D>: Serialize"))
MatrixN<N, D>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(deserialize = "DefaultAllocator: Allocator<N, D, D> +
serde(bound(
deserialize = "DefaultAllocator: Allocator<N, D, D> +
Allocator<N, D>,
VectorN<N, D>: Deserialize<'de>,
MatrixN<N, D>: Deserialize<'de>"))
MatrixN<N, D>: Deserialize<'de>"
))
)]
#[derive(Clone, Debug)]
pub struct SymmetricEigen<N: Scalar, D: Dim>
@ -46,8 +50,7 @@ where
DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>,
MatrixN<N, D>: Copy,
VectorN<N, D>: Copy,
{
}
{}
impl<N: SymmetricEigenScalar + Real, D: Dim> SymmetricEigen<N, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -115,13 +115,13 @@ impl<N: Real> Matrix4<N> {
/// Creates a new homogeneous matrix for an orthographic projection.
#[inline]
pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap()
Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner()
}
/// Creates a new homogeneous matrix for a perspective projection.
#[inline]
pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self {
Perspective3::new(aspect, fovy, znear, zfar).unwrap()
Perspective3::new(aspect, fovy, znear, zfar).into_inner()
}
/// Creates an isometry that corresponds to the local frame of an observer standing at the
@ -130,8 +130,14 @@ impl<N: Real> Matrix4<N> {
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
/// `eye`.
#[inline]
pub fn face_towards(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
}
/// Deprecated: Use [Matrix4::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous()
Matrix4::face_towards(eye, target, up)
}
/// Builds a right-handed look-at view matrix.
@ -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>
+ Allocator<N, DimNameDiff<D, U1>>
+ Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{
/// Transforms the given vector, assuming the matrix `self` uses homogeneous coordinates.
#[inline]
fn transform_vector(
pub fn transform_vector(
&self,
v: &VectorN<N, DimNameDiff<D, U1>>,
) -> VectorN<N, DimNameDiff<D, U1>>
@ -336,13 +343,18 @@ where DefaultAllocator: Allocator<N, D, D>
transform * v
}
/// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates.
#[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 translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
let n = normalizer.tr_dot(&pt.coords)
+ unsafe { *self.get_unchecked(D::dim() - 1, D::dim() - 1) };
+ unsafe { *self.get_unchecked((D::dim() - 1, D::dim() - 1)) };
if !n.is_zero() {
return transform * (pt / n) + translation;
@ -351,3 +363,23 @@ where DefaultAllocator: Allocator<N, D, D>
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::{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>;
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]
pub fn abs(&self) -> MatrixMN<N, R, C>
where
@ -52,7 +61,7 @@ macro_rules! component_binop_impl(
for j in 0 .. res.ncols() {
for i in 0 .. res.nrows() {
unsafe {
res.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
res.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j)));
}
}
}
@ -80,8 +89,8 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
*self.get_unchecked_mut(i, j) = res;
let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
*self.get_unchecked_mut((i, j)) = res;
}
}
}
@ -90,8 +99,8 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
let res = alpha * a.get_unchecked(i, j).$op(*b.get_unchecked(i, j));
*self.get_unchecked_mut(i, j) = beta * *self.get_unchecked(i, j) + res;
let res = alpha * a.get_unchecked((i, j)).$op(*b.get_unchecked((i, j)));
*self.get_unchecked_mut((i, j)) = beta * *self.get_unchecked((i, j)) + res;
}
}
}
@ -112,7 +121,7 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
self.get_unchecked_mut(i, j).$op_assign(*rhs.get_unchecked(i, j));
self.get_unchecked_mut((i, j)).$op_assign(*rhs.get_unchecked((i, j)));
}
}
}
@ -135,12 +144,94 @@ macro_rules! component_binop_impl(
component_binop_impl!(
component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign,
"Componentwise matrix multiplication.",
"Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.",
"Inplace componentwise matrix multiplication.";
r"
Componentwise matrix or vector 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,
"Componentwise matrix division.",
"Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.",
"Inplace componentwise matrix division.";
r"
Componentwise matrix or vector 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. ?
);

View File

@ -82,7 +82,7 @@ where DefaultAllocator: Allocator<N, R, C>
for i in 0..nrows.value() {
for j in 0..ncols.value() {
unsafe { *res.get_unchecked_mut(i, j) = *iter.next().unwrap() }
unsafe { *res.get_unchecked_mut((i, j)) = *iter.next().unwrap() }
}
}
@ -105,7 +105,7 @@ where DefaultAllocator: Allocator<N, R, C>
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe { *res.get_unchecked_mut(i, j) = f(i, j) }
unsafe { *res.get_unchecked_mut((i, j)) = f(i, j) }
}
}
@ -132,7 +132,7 @@ where DefaultAllocator: Allocator<N, R, C>
let mut res = Self::zeros_generic(nrows, ncols);
for i in 0..::min(nrows.value(), ncols.value()) {
unsafe { *res.get_unchecked_mut(i, i) = elt }
unsafe { *res.get_unchecked_mut((i, i)) = elt }
}
res
@ -152,7 +152,7 @@ where DefaultAllocator: Allocator<N, R, C>
);
for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut(i, i) = *elt }
unsafe { *res.get_unchecked_mut((i, i)) = *elt }
}
res
@ -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
/// 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]
pub fn from_rows<SB>(rows: &[Matrix<N, U1, C, SB>]) -> Self
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
/// 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]
pub fn from_columns<SB>(columns: &[Vector<N, R, SB>]) -> Self
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>(
nrows: R,
ncols: C,
distribution: &mut Distr,
distribution: &Distr,
rng: &mut G,
) -> Self
{
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>
@ -241,6 +288,23 @@ where
DefaultAllocator: Allocator<N, D, D>,
{
/// 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]
pub fn from_diagonal<SB: Storage<N, D>>(diag: &Vector<N, D, SB>) -> Self
where N: Zero {
@ -249,7 +313,7 @@ where
for i in 0..diag.len() {
unsafe {
*res.get_unchecked_mut(i, i) = *diag.vget_unchecked(i);
*res.get_unchecked_mut((i, i)) = *diag.vget_unchecked(i);
}
}
@ -267,60 +331,141 @@ macro_rules! impl_constructors(
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where DefaultAllocator: Allocator<N $(, $Dims)*> {
/// Creates a new uninitialized matrix.
/// Creates a new uninitialized matrix or vector.
#[inline]
pub unsafe fn new_uninitialized($($args: usize),*) -> Self {
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]
pub fn from_element($($args: usize,)* elem: N) -> Self {
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`.
///
/// # 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]
pub fn repeat($($args: usize,)* elem: N) -> Self {
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]
pub fn zeros($($args: usize),*) -> Self
where N: Zero {
Self::zeros_generic($($gargs),*)
}
/// Creates a matrix with all its elements filled by an iterator.
/// Creates a matrix 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]
pub fn from_iterator<I>($($args: usize,)* iter: I) -> Self
where I: IntoIterator<Item = N> {
Self::from_iterator_generic($($gargs, )* iter)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
#[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
/// Creates a matrix or vector filled with the results of a function applied to each of its
/// 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]
pub fn from_fn<F>($($args: usize,)* f: F) -> Self
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
/// submatrix (starting at the first row and column) is set to the identity while all
/// 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]
pub fn identity($($args: usize,)*) -> Self
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
/// 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]
pub fn from_diagonal_element($($args: usize,)* elt: N) -> Self
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.
///
/// 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]
pub fn from_partial_diagonal($($args: usize,)* elts: &[N]) -> Self
where N: Zero {
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]
pub fn from_distribution<Distr: Distribution<N> + ?Sized, G: Rng + ?Sized>(
$($args: usize,)*
distribution: &mut Distr,
distribution: &Distr,
rng: &mut G,
) -> Self {
Self::from_distribution_generic($($gargs, )* distribution, rng)
@ -401,6 +593,125 @@ impl_constructors!(Dynamic, Dynamic;
Dynamic::new(nrows), Dynamic::new(ncols);
nrows, ncols);
/*
*
* Constructors that don't necessarily require all dimensions
* to be specified whon one dimension is already known.
*
*/
macro_rules! impl_constructors_from_data(
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where DefaultAllocator: Allocator<N $(, $Dims)*> {
/// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_row_slice(&[0, 1, 2]);
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_row_slice($($args: usize,)* $data: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* $data)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_column_slice(&[0, 1, 2]);
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_column_slice($($args: usize,)* $data: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* $data)
}
/// Creates a matrix backed by a given `Vec`.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Matrix2x3};
///
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
///
///
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
#[cfg(feature = "std")]
pub fn from_vec($($args: usize,)* $data: Vec<N>) -> Self {
Self::from_vec_generic($($gargs, )* $data)
}
}
}
);
// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors_from_data!(data; R, C; // Arguments for Matrix<N, ..., S>
=> R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
R::name(), C::name(); // Arguments for `_generic` constructors.
); // Arguments for non-generic constructors.
impl_constructors_from_data!(data; R, Dynamic;
=> R: DimName;
R::name(), Dynamic::new(data.len() / R::dim());
);
impl_constructors_from_data!(data; Dynamic, C;
=> C: DimName;
Dynamic::new(data.len() / C::dim()), C::name();
);
impl_constructors_from_data!(data; Dynamic, Dynamic;
;
Dynamic::new(nrows), Dynamic::new(ncols);
nrows, ncols);
/*
*
* Zero, One, Rand traits.
@ -495,7 +806,7 @@ where
Unit::new_normalize(VectorN::from_distribution_generic(
D::name(),
U1,
&mut StandardNormal,
&StandardNormal,
rng,
))
}
@ -516,7 +827,7 @@ macro_rules! componentwise_constructors_impl(
pub fn new($($args: N),*) -> Self {
unsafe {
let mut res = Self::new_uninitialized();
$( *res.get_unchecked_mut($irow, $icol) = $args; )*
$( *res.get_unchecked_mut(($irow, $icol)) = $args; )*
res
}

View File

@ -17,8 +17,8 @@ use base::dimension::{
use base::iter::{MatrixIter, MatrixIterMut};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))]
use base::MatrixVec;
use base::{DefaultAllocator, Matrix, MatrixArray, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
use base::VecStorage;
use base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar};
// FIXME: too bad this won't work allo slice conversions.
impl<N1, N2, R1, C1, R2, C2> SubsetOf<MatrixMN<N2, R2, C2>> for MatrixMN<N1, R1, C1>
@ -42,7 +42,7 @@ where
let mut res = unsafe { MatrixMN::<N2, R2, C2>::new_uninitialized_generic(nrows2, ncols2) };
for i in 0..nrows {
for j in 0..ncols {
unsafe { *res.get_unchecked_mut(i, j) = N2::from_subset(self.get_unchecked(i, j)) }
unsafe { *res.get_unchecked_mut((i, j)) = N2::from_subset(self.get_unchecked((i, j))) }
}
}
@ -63,7 +63,7 @@ where
let mut res = Self::new_uninitialized_generic(nrows, ncols);
for i in 0..nrows2 {
for j in 0..ncols2 {
*res.get_unchecked_mut(i, j) = m.get_unchecked(i, j).to_subset_unchecked()
*res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked()
}
}
@ -336,7 +336,7 @@ impl_from_into_mint_2D!(
);
impl<'a, N, R, C, RStride, CStride> From<MatrixSlice<'a, N, R, C, RStride, CStride>>
for Matrix<N, R, C, MatrixArray<N, R, C>>
for Matrix<N, R, C, ArrayStorage<N, R, C>>
where
N: Scalar,
R: DimName,
@ -353,7 +353,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, C, RStride, CStride> From<MatrixSlice<'a, N, Dynamic, C, RStride, CStride>>
for Matrix<N, Dynamic, C, MatrixVec<N, Dynamic, C>>
for Matrix<N, Dynamic, C, VecStorage<N, Dynamic, C>>
where
N: Scalar,
C: Dim,
@ -367,7 +367,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, R, RStride, CStride> From<MatrixSlice<'a, N, R, Dynamic, RStride, CStride>>
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>>
for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
where
N: Scalar,
R: DimName,
@ -380,7 +380,7 @@ where
}
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
for Matrix<N, R, C, MatrixArray<N, R, C>>
for Matrix<N, R, C, ArrayStorage<N, R, C>>
where
N: Scalar,
R: DimName,
@ -397,7 +397,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, C, RStride, CStride> From<MatrixSliceMut<'a, N, Dynamic, C, RStride, CStride>>
for Matrix<N, Dynamic, C, MatrixVec<N, Dynamic, C>>
for Matrix<N, Dynamic, C, VecStorage<N, Dynamic, C>>
where
N: Scalar,
C: Dim,
@ -411,7 +411,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, N, R, RStride, CStride> From<MatrixSliceMut<'a, N, R, Dynamic, RStride, CStride>>
for Matrix<N, R, Dynamic, MatrixVec<N, R, Dynamic>>
for Matrix<N, R, Dynamic, VecStorage<N, R, Dynamic>>
where
N: Scalar,
R: DimName,

View File

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

View File

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

View File

@ -1,6 +1,7 @@
use num::{One, Zero};
use std::cmp;
use std::ptr;
use std::iter::ExactSizeIterator;
use std::mem;
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
}
/// Extracts the upper triangular part of this matrix (including the diagonal).
/// Extracts the lower triangular part of this matrix (including the diagonal).
#[inline]
pub fn lower_triangle(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
@ -33,6 +34,52 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res
}
/// Creates a new matrix by extracting the given set of rows from `self`.
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> {
@ -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);
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) {
assert!(i < self.nrows(), "Row index out of bounds.");
for j in 0..self.ncols() {
unsafe { *self.get_unchecked_mut(i, j) = val }
unsafe { *self.get_unchecked_mut((i, j)) = val }
}
}
@ -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) {
assert!(j < self.ncols(), "Row index out of bounds.");
for i in 0..self.nrows() {
unsafe { *self.get_unchecked_mut(i, j) = val }
unsafe { *self.get_unchecked_mut((i, j)) = val }
}
}
@ -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.");
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) {
for j in 0..self.ncols() {
for i in (j + shift)..self.nrows() {
unsafe { *self.get_unchecked_mut(i, j) = val }
unsafe { *self.get_unchecked_mut((i, j)) = val }
}
}
}
@ -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 ?
// (necessary for rectangular matrices)
for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
unsafe { *self.get_unchecked_mut(i, j) = val }
unsafe { *self.get_unchecked_mut((i, j)) = val }
}
}
}
@ -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 i in j + 1..dim {
unsafe {
*self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i);
*self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i));
}
}
}
@ -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 i in 0..j {
unsafe {
*self.get_unchecked_mut(i, j) = *self.get_unchecked(j, i);
*self.get_unchecked_mut((i, j)) = *self.get_unchecked((j, i));
}
}
}
@ -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::mem;
use base::dimension::Dim;
use base::dimension::{Dim, U1};
use base::storage::{Storage, StorageMut};
use base::Scalar;
use base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut};
macro_rules! iterator {
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
@ -96,3 +96,226 @@ macro_rules! iterator {
iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S);
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S);
/*
*
* Row iterators.
*
*/
#[derive(Clone)]
/// An iterator through the rows of a matrix.
pub struct RowIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
mat: &'a Matrix<N, R, C, S>,
curr: usize
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> RowIter<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
RowIter {
mat, curr: 0
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for RowIter<'a, N, R, C, S> {
type Item = MatrixSlice<'a, N, U1, C, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.mat.nrows() {
let res = self.mat.row(self.curr);
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.mat.nrows() - self.curr, Some(self.mat.nrows() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.mat.nrows() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for RowIter<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.mat.nrows() - self.curr
}
}
/// An iterator through the mutable rows of a matrix.
pub struct RowIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
mat: *mut Matrix<N, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> RowIterMut<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
RowIterMut {
mat,
curr: 0,
phantom: PhantomData
}
}
fn nrows(&self) -> usize {
unsafe {
(*self.mat).nrows()
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for RowIterMut<'a, N, R, C, S> {
type Item = MatrixSliceMut<'a, N, U1, C, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.nrows() {
let res = unsafe { (*self.mat).row_mut(self.curr) };
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.nrows() - self.curr, Some(self.nrows() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.nrows() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for RowIterMut<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.nrows() - self.curr
}
}
/*
*
* Column iterators.
*
*/
#[derive(Clone)]
/// An iterator through the columns of a matrix.
pub struct ColumnIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
mat: &'a Matrix<N, R, C, S>,
curr: usize
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ColumnIter<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
ColumnIter {
mat, curr: 0
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for ColumnIter<'a, N, R, C, S> {
type Item = MatrixSlice<'a, N, R, U1, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.mat.ncols() {
let res = self.mat.column(self.curr);
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.mat.ncols() - self.curr, Some(self.mat.ncols() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.mat.ncols() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for ColumnIter<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.mat.ncols() - self.curr
}
}
/// An iterator through the mutable columns of a matrix.
pub struct ColumnIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
mat: *mut Matrix<N, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ColumnIterMut<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
ColumnIterMut {
mat,
curr: 0,
phantom: PhantomData
}
}
fn ncols(&self) -> usize {
unsafe {
(*self.mat).ncols()
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for ColumnIterMut<'a, N, R, C, S> {
type Item = MatrixSliceMut<'a, N, R, U1, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.ncols() {
let res = unsafe { (*self.mat).column_mut(self.curr) };
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.ncols() - self.curr, Some(self.ncols() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.ncols() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for ColumnIterMut<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.ncols() - self.curr
}
}

View File

@ -1,4 +1,4 @@
use num::Zero;
use num::{One, Zero};
use num_complex::Complex;
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
@ -7,6 +7,7 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::TypeId;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
@ -16,12 +17,12 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "abomonation-serialize")]
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::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{Dim, DimAdd, DimSum, U1, U2, U3};
use base::iter::{MatrixIter, MatrixIterMut};
use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
use base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut};
use base::storage::{
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
};
@ -72,7 +73,7 @@ pub type MatrixCross<N, R1, C1, R2, C2> =
/// dynamically-sized column vector should be represented as a `Matrix<N, Dynamic, U1, S>` (given
/// some concrete types for `N` and a compatible data storage type `S`).
#[repr(C)]
#[derive(Hash, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
/// The data storage that contains all the matrix components and informations about its number
/// of rows and column (if needed).
@ -246,6 +247,37 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
MatrixIter::new(&self.data)
}
/// Iterate through the rows of this matrix.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, row) in a.row_iter().enumerate() {
/// assert_eq!(row, a.row(i))
/// }
/// ```
#[inline]
pub fn row_iter(&self) -> RowIter<N, R, C, S> {
RowIter::new(self)
}
/// Iterate through the columns of this matrix.
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, column) in a.column_iter().enumerate() {
/// assert_eq!(column, a.column(i))
/// }
/// ```
#[inline]
pub fn column_iter(&self) -> ColumnIter<N, R, C, S> {
ColumnIter::new(self)
}
/// Computes the row and column coordinates of the i-th element of this matrix seen as a
/// vector.
#[inline]
@ -263,17 +295,6 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
}
}
/// Gets a reference to the element of this matrix at row `irow` and column `icol` without
/// bound-checking.
#[inline]
pub unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &N {
debug_assert!(
irow < self.nrows() && icol < self.ncols(),
"Matrix index out of bounds."
);
self.data.get_unchecked(irow, icol)
}
/// Tests whether `self` and `rhs` are equal up to a given epsilon.
///
/// 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 i in 0..res.nrows() {
unsafe {
*res.get_unchecked_mut(i, j) = *self.get_unchecked(i, j);
*res.get_unchecked_mut((i, j)) = *self.get_unchecked((i, j));
}
}
}
@ -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`,
/// `f` also gets passed the row and column index, i.e. `f(value, row, col)`.
/// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
#[inline]
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
&self,
@ -503,6 +524,57 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res
}
/// Folds a function `f` on each entry of `self`.
#[inline]
pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, N) -> Acc) -> Acc {
let (nrows, ncols) = self.data.shape();
let mut res = init;
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = *self.data.get_unchecked(i, j);
res = f(res, a)
}
}
}
res
}
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
#[inline]
pub fn zip_fold<N2, R2, C2, S2, Acc>(&self, rhs: &Matrix<N2, R2, C2, S2>, init: Acc, mut f: impl FnMut(Acc, N, N2) -> Acc) -> Acc
where
N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>
{
let (nrows, ncols) = self.data.shape();
let mut res = init;
assert!(
(nrows.value(), ncols.value()) == rhs.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = *self.data.get_unchecked(i, j);
let b = *rhs.data.get_unchecked(i, j);
res = f(res, a, b)
}
}
}
res
}
/// Transposes `self` and store the result into `out`.
#[inline]
pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
@ -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 j in 0..ncols {
unsafe {
*out.get_unchecked_mut(j, i) = *self.get_unchecked(i, j);
*out.get_unchecked_mut((j, i)) = *self.get_unchecked((i, j));
}
}
}
@ -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)
}
/// Gets a mutable reference to the i-th element of this matrix.
/// Mutably iterates through this matrix rows.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, mut row) in a.row_iter_mut().enumerate() {
/// row *= (i + 1) * 10;
/// }
///
/// let expected = Matrix2x3::new(10, 20, 30,
/// 80, 100, 120);
/// assert_eq!(a, expected);
/// ```
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut N {
debug_assert!(
irow < self.nrows() && icol < self.ncols(),
"Matrix index out of bounds."
);
self.data.get_unchecked_mut(irow, icol)
pub fn row_iter_mut(&mut self) -> RowIterMut<N, R, C, S> {
RowIterMut::new(self)
}
/// Mutably iterates through this matrix columns.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, mut col) in a.column_iter_mut().enumerate() {
/// col *= (i + 1) * 10;
/// }
///
/// let expected = Matrix2x3::new(10, 40, 90,
/// 40, 100, 180);
/// assert_eq!(a, expected);
/// ```
#[inline]
pub fn column_iter_mut(&mut self) -> ColumnIterMut<N, R, C, S> {
ColumnIterMut::new(self)
}
/// Swaps two entries without bound-checking.
@ -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 i in 0..nrows {
unsafe {
*self.get_unchecked_mut(i, j) = *slice.get_unchecked(i + j * nrows);
*self.get_unchecked_mut((i, j)) = *slice.get_unchecked(i + j * nrows);
}
}
}
@ -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 i in 0..self.nrows() {
unsafe {
*self.get_unchecked_mut(i, j) = *other.get_unchecked(i, j);
*self.get_unchecked_mut((i, j)) = *other.get_unchecked((i, j));
}
}
}
@ -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 i in 0..nrows {
unsafe {
*self.get_unchecked_mut(i, j) = *other.get_unchecked(j, i);
*self.get_unchecked_mut((i, j)) = *other.get_unchecked((j, i));
}
}
}
@ -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.
#[inline]
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F)
where DefaultAllocator: Allocator<N, R, C> {
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) {
let (nrows, ncols) = self.shape();
for j in 0..ncols {
@ -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> {
@ -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 j in 0..ncols {
unsafe {
*out.get_unchecked_mut(j, i) = self.get_unchecked(i, j).conj();
*out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conj();
}
}
}
@ -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 j in 0..i {
unsafe {
let ref_ij = self.get_unchecked_mut(i, j) as *mut Complex<N>;
let ref_ji = self.get_unchecked_mut(j, i) as *mut Complex<N>;
let ref_ij = self.get_unchecked_mut((i, j)) as *mut Complex<N>;
let ref_ji = self.get_unchecked_mut((j, i)) as *mut Complex<N>;
let conj_ij = (*ref_ij).conj();
let conj_ji = (*ref_ji).conj();
*ref_ij = conj_ji;
@ -803,7 +969,7 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
for i in 0..dim.value() {
unsafe {
*res.vget_unchecked_mut(i) = *self.get_unchecked(i, i);
*res.vget_unchecked_mut(i) = *self.get_unchecked((i, i));
}
}
@ -823,27 +989,36 @@ impl<N: Scalar, D: Dim, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
let mut res = N::zero();
for i in 0..dim.value() {
res += unsafe { *self.get_unchecked(i, i) };
res += unsafe { *self.get_unchecked((i, i)) };
}
res
}
}
impl<N: Scalar + One + Zero, D: DimAdd<U1> + IsNotStaticOne, S: Storage<N, D, D>> Matrix<N, D, D, S> {
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
/// and setting the diagonal element to `1`.
#[inline]
pub fn to_homogeneous(&self) -> MatrixN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>, DimSum<D, U1>> {
assert!(self.is_square(), "Only square matrices can currently be transformed to homogeneous coordinates.");
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
let mut res = MatrixN::identity_generic(dim, dim);
res.generic_slice_mut::<D, D>((0, 0), self.data.shape()).copy_from(&self);
res
}
}
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
/// coordinates.
#[inline]
pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
let len = self.len();
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
res.generic_slice_mut((0, 0), self.data.shape())
.copy_from(self);
res[(len, 0)] = N::zero();
res
self.push(N::zero())
}
/// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
@ -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>
where
N: Scalar + AbsDiffEq,
@ -1019,8 +1210,7 @@ impl<N, R: Dim, C: Dim, S> Eq for Matrix<N, R, C, S>
where
N: Scalar + Eq,
S: Storage<N, R, C>,
{
}
{}
impl<N, R: Dim, C: Dim, S> PartialEq for Matrix<N, R, C, S>
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 ");
unsafe {
*self.get_unchecked(0, 0) * *b.get_unchecked(1, 0)
- *self.get_unchecked(1, 0) * *b.get_unchecked(0, 0)
*self.get_unchecked((0, 0)) * *b.get_unchecked((1, 0))
- *self.get_unchecked((1, 0)) * *b.get_unchecked((0, 0))
}
}
@ -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 mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let ax = *self.get_unchecked(0, 0);
let ay = *self.get_unchecked(1, 0);
let az = *self.get_unchecked(2, 0);
let ax = *self.get_unchecked((0, 0));
let ay = *self.get_unchecked((1, 0));
let az = *self.get_unchecked((2, 0));
let bx = *b.get_unchecked(0, 0);
let by = *b.get_unchecked(1, 0);
let bz = *b.get_unchecked(2, 0);
let bx = *b.get_unchecked((0, 0));
let by = *b.get_unchecked((1, 0));
let bz = *b.get_unchecked((2, 0));
*res.get_unchecked_mut(0, 0) = ay * bz - az * by;
*res.get_unchecked_mut(1, 0) = az * bx - ax * bz;
*res.get_unchecked_mut(2, 0) = ax * by - ay * bx;
*res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
*res.get_unchecked_mut((1, 0)) = az * bx - ax * bz;
*res.get_unchecked_mut((2, 0)) = ax * by - ay * bx;
res
}
@ -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 mut res = Matrix::new_uninitialized_generic(nrows, ncols);
let ax = *self.get_unchecked(0, 0);
let ay = *self.get_unchecked(0, 1);
let az = *self.get_unchecked(0, 2);
let ax = *self.get_unchecked((0, 0));
let ay = *self.get_unchecked((0, 1));
let az = *self.get_unchecked((0, 2));
let bx = *b.get_unchecked(0, 0);
let by = *b.get_unchecked(0, 1);
let bz = *b.get_unchecked(0, 2);
let bx = *b.get_unchecked((0, 0));
let by = *b.get_unchecked((0, 1));
let bz = *b.get_unchecked((0, 2));
*res.get_unchecked_mut(0, 0) = ay * bz - az * by;
*res.get_unchecked_mut(0, 1) = az * bx - ax * bz;
*res.get_unchecked_mut(0, 2) = ax * by - ay * bx;
*res.get_unchecked_mut((0, 0)) = ay * bz - az * by;
*res.get_unchecked_mut((0, 1)) = az * bx - ax * bz;
*res.get_unchecked_mut((0, 2)) = ax * by - ay * bx;
res
}
@ -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> {
/// 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)
}
impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
Vector<N, D, S>
{
/// Returns `self * (1.0 - t) + rhs * t`, 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::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
}
/// 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>> {
@ -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>>
where
N: Scalar + AbsDiffEq,
@ -1444,3 +1570,24 @@ where
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
}
}
impl<N, R, C, S> Hash for Matrix<N, R, C, S>
where
N: Scalar + Hash,
R: Dim,
C: Dim,
S: Storage<N, R, C>,
{
fn hash<H: Hasher>(&self, state: &mut H) {
let (nrows, ncols) = self.shape();
(nrows, ncols).hash(state);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
self.get_unchecked((i, j)).hash(state);
}
}
}
}
}

View File

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

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

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
#[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write};
use std::ops::Deref;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec;
@ -9,7 +8,8 @@ use base::allocator::Allocator;
use base::default_allocator::DefaultAllocator;
use base::dimension::{Dim, DimName, Dynamic, U1};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
use base::Scalar;
use base::{Scalar, Vector};
use base::constraint::{SameNumberOfRows, ShapeConstraint};
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
@ -23,21 +23,25 @@ use abomonation::Abomonation;
#[repr(C)]
#[derive(Eq, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct MatrixVec<N, R: Dim, C: Dim> {
pub struct VecStorage<N, R: Dim, C: Dim> {
data: Vec<N>,
nrows: R,
ncols: C,
}
impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
#[deprecated(note="renamed to `VecStorage`")]
/// Renamed to [VecStorage].
pub type MatrixVec<N, R, C> = VecStorage<N, R, C>;
impl<N, R: Dim, C: Dim> VecStorage<N, R, C> {
/// Creates a new dynamic matrix data storage from the given vector and shape.
#[inline]
pub fn new(nrows: R, ncols: C, data: Vec<N>) -> MatrixVec<N, R, C> {
pub fn new(nrows: R, ncols: C, data: Vec<N>) -> VecStorage<N, R, C> {
assert!(
nrows.value() * ncols.value() == data.len(),
"Data storage buffer dimension mismatch."
);
MatrixVec {
VecStorage {
data: data,
nrows: nrows,
ncols: ncols,
@ -46,15 +50,16 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
/// The underlying data storage.
#[inline]
pub fn data(&self) -> &Vec<N> {
pub fn as_vec(&self) -> &Vec<N> {
&self.data
}
/// The underlying mutable data storage.
///
/// This is unsafe because this may cause UB if the vector is modified by the user.
/// This is unsafe because this may cause UB if the size of the vector is changed
/// by the user.
#[inline]
pub unsafe fn data_mut(&mut self) -> &mut Vec<N> {
pub unsafe fn as_vec_mut(&mut self) -> &mut Vec<N> {
&mut self.data
}
@ -76,14 +81,18 @@ impl<N, R: Dim, C: Dim> MatrixVec<N, R, C> {
self.data
}
/// The number of elements on the underlying vector.
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
}
impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
type Target = Vec<N>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
impl<N, R: Dim, C: Dim> Into<Vec<N>> for VecStorage<N, R, C>
{
fn into(self) -> Vec<N> {
self.data
}
}
@ -93,7 +102,7 @@ impl<N, R: Dim, C: Dim> Deref for MatrixVec<N, R, C> {
* Dynamic Dynamic
*
*/
unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
unsafe impl<N: Scalar, C: Dim> Storage<N, Dynamic, C> for VecStorage<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
{
type RStride = U1;
@ -133,11 +142,11 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
&self.data
}
}
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
unsafe impl<N: Scalar, R: DimName> Storage<N, R, Dynamic> for VecStorage<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
{
type RStride = U1;
@ -177,7 +186,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
#[inline]
fn as_slice(&self) -> &[N] {
&self[..]
&self.data
}
}
@ -186,7 +195,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
* StorageMut, ContiguousStorage.
*
*/
unsafe impl<N: Scalar, C: Dim> StorageMut<N, Dynamic, C> for MatrixVec<N, Dynamic, C>
unsafe impl<N: Scalar, C: Dim> StorageMut<N, Dynamic, C> for VecStorage<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
{
#[inline]
@ -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>
{
#[inline]
@ -221,7 +230,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
}
#[cfg(feature = "abomonation-serialize")]
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for MatrixVec<N, R, C> {
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<N, R, C> {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
self.data.entomb(writer)
}
@ -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,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
use rand::Rng;
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
Self::new(D::from_usize(dim), || N::arbitrary(g))
}

View File

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

View File

@ -108,6 +108,19 @@ impl<N: Real, D: DimName, R: Rotation<Point<N, D>>> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D>
{
/// Creates a new isometry from its rotational and translational parts.
///
/// # 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]
pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> {
Isometry {
@ -118,6 +131,18 @@ where DefaultAllocator: Allocator<N, D>
}
/// 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]
pub fn inverse(&self) -> Isometry<N, D, R> {
let mut res = self.clone();
@ -125,7 +150,20 @@ where DefaultAllocator: Allocator<N, D>
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]
pub fn inverse_mut(&mut self) {
self.rotation.inverse_mut();
@ -134,12 +172,39 @@ where DefaultAllocator: Allocator<N, D>
}
/// 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]
pub fn append_translation_mut(&mut self, t: &Translation<N, D>) {
self.translation.vector += &t.vector
}
/// 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]
pub fn append_rotation_mut(&mut self, r: &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
/// 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]
pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point<N, D>) {
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
/// `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]
pub fn append_rotation_wrt_center_mut(&mut self, r: &R) {
let center = Point::from_coordinates(self.translation.vector.clone());
self.append_rotation_wrt_point_mut(r, &center)
self.rotation = self.rotation.append_rotation(r);
}
}
@ -172,6 +264,20 @@ impl<N: Real, D: DimName, R> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D>
{
/// 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]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where

View File

@ -143,10 +143,7 @@ where
#[inline]
fn append_rotation(&self, r: &Self::Rotation) -> Self {
let shift = r.transform_vector(&self.translation.vector);
Isometry::from_parts(
Translation::from_vector(shift),
r.clone() * self.rotation.clone(),
)
Isometry::from_parts(Translation::from(shift), r.clone() * self.rotation.clone())
}
#[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>
{
/// 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]
pub fn identity() -> Self {
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`.
/// 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]
pub fn rotation_wrt_point(r: R, p: Point<N, D>) -> Self {
let shift = r.transform_vector(&-&p.coords);
Self::from_parts(Translation::from_vector(shift + p.coords), r)
Self::from_parts(Translation::from(shift + p.coords), r)
}
}
@ -81,11 +109,23 @@ where
// 2D rotation.
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]
pub fn new(translation: Vector2<N>, angle: N) -> Self {
Self::from_parts(
Translation::from_vector(translation),
Translation::from(translation),
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>> {
/// 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]
pub fn new(translation: Vector2<N>, angle: N) -> Self {
Self::from_parts(
Translation::from_vector(translation),
Translation::from(translation),
UnitComplex::from_angle(angle),
)
}
@ -131,10 +183,33 @@ macro_rules! isometry_construction_impl(
($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => {
impl<N: Real> Isometry<N, U3, $RotId<$($RotParams),*>> {
/// 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]
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>) -> Self {
Self::from_parts(
Translation::from_vector(translation),
Translation::from(translation),
$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
/// point `eye` and looking toward `target`.
///
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
/// `eye`.
/// It maps the `z` axis to the view direction `target - eye`and the origin to the `eye`.
///
/// # Arguments
/// * eye - The observer position.
/// * target - The target position.
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear
/// 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]
pub fn new_observer_frame(eye: &Point3<N>,
pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>)
-> Self {
Self::from_parts(
Translation::from_vector(eye.coords.clone()),
$RotId::new_observer_frame(&(target - eye), up))
Translation::from(eye.coords.clone()),
$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.
///
/// This conforms to the common notion of right handed look-at matrix from the computer
/// graphics community.
/// It maps the view direction `target - eye` to the **negative** `z` axis to and the `eye` to the origin.
/// 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
/// * eye - The eye position.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// 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]
pub fn look_at_rh(eye: &Point3<N>,
target: &Point3<N>,
@ -189,19 +315,41 @@ macro_rules! isometry_construction_impl(
let rotation = $RotId::look_at_rh(&(target - eye), up);
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.
///
/// This conforms to the common notion of left handed look-at matrix from the computer
/// graphics community.
/// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin.
/// 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
/// * eye - The eye position.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// 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]
pub fn look_at_lh(eye: &Point3<N>,
target: &Point3<N>,
@ -210,7 +358,7 @@ macro_rules! isometry_construction_impl(
let rotation = $RotId::look_at_lh(&(target - eye), up);
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]
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 = Translation::from_vector(::convert_unchecked(t));
let t = Translation {
vector: ::convert_unchecked(t),
};
Self::from_parts(t, ::convert_unchecked(m.clone_owned()))
}

View File

@ -142,7 +142,7 @@ isometry_binop_impl_all!(
[ref ref] => {
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.
};
);
@ -267,7 +267,7 @@ isometry_binop_impl_all!(
[val ref] => &self * right;
[ref ref] => {
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;
(D, D), (D, U1) for D: DimName;
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);
[ref val] => Isometry::from_parts(Translation::from_vector(self * right.vector), self.clone());
[val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from_vector(self * &right.vector), self.clone());
[val val] => Isometry::from_parts(Translation::from(&self * right.vector), self);
[ref val] => Isometry::from_parts(Translation::from(self * right.vector), self.clone());
[val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from(self * &right.vector), self.clone());
);
// UnitQuaternion × Translation
@ -351,10 +351,10 @@ isometry_from_composition_impl_all!(
(U4, U1), (U3, U1);
self: UnitQuaternion<N>, right: Translation<N, U3>,
Output = Isometry<N, U3, UnitQuaternion<N>>;
[val val] => Isometry::from_parts(Translation::from_vector(&self * right.vector), self);
[ref val] => Isometry::from_parts(Translation::from_vector( self * right.vector), self.clone());
[val ref] => Isometry::from_parts(Translation::from_vector(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from_vector( self * &right.vector), self.clone());
[val val] => Isometry::from_parts(Translation::from(&self * right.vector), self);
[ref val] => Isometry::from_parts(Translation::from( self * right.vector), self.clone());
[val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from( self * &right.vector), self.clone());
);
// Rotation × Isometry
@ -368,7 +368,7 @@ isometry_from_composition_impl_all!(
[val ref] => &self * right;
[ref ref] => {
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;
[ref ref] => {
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_ops;
mod swizzle;
mod transform;
mod transform_alga;
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> {
/// 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]
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 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
/// 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]
pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self {
Orthographic3 { matrix: matrix }
@ -101,8 +142,8 @@ impl<N: Real> Orthographic3<N> {
#[inline]
pub fn from_fov(aspect: N, vfov: N, znear: N, zfar: N) -> Self {
assert!(
znear < zfar,
"The far plane must be farther than the near plane."
znear != zfar,
"The far plane must not be equal to the near plane."
);
assert!(
!relative_eq!(aspect, N::zero()),
@ -124,6 +165,22 @@ impl<N: Real> Orthographic3<N> {
}
/// 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]
pub fn inverse(&self) -> Matrix4<N> {
let mut res = self.to_homogeneous();
@ -144,66 +201,188 @@ impl<N: Real> Orthographic3<N> {
}
/// 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]
pub fn to_homogeneous(&self) -> Matrix4<N> {
self.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]
pub fn as_matrix(&self) -> &Matrix4<N> {
&self.matrix
}
/// 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]
pub fn as_projective(&self) -> &Projective3<N> {
unsafe { mem::transmute(self) }
}
/// 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]
pub fn to_projective(&self) -> Projective3<N> {
Projective3::from_matrix_unchecked(self.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]
pub fn unwrap(self) -> Matrix4<N> {
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]
pub fn left(&self) -> N {
(-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]
pub fn right(&self) -> N {
(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]
pub fn bottom(&self) -> N {
(-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]
pub fn top(&self) -> N {
(N::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)]
}
/// 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]
pub fn znear(&self) -> N {
(N::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)]
}
/// 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]
pub fn zfar(&self) -> N {
(-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.
/// 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]
pub fn project_point(&self, p: &Point3<N>) -> Point3<N> {
Point3::new(
@ -221,6 +425,31 @@ impl<N: Real> Orthographic3<N> {
}
/// 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]
pub fn unproject_point(&self, p: &Point3<N>) -> Point3<N> {
Point3::new(
@ -232,6 +461,23 @@ impl<N: Real> Orthographic3<N> {
// FIXME: when we get specialization, specialize the Mul impl instead.
/// 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]
pub fn project_vector<SB>(&self, p: &Vector<N, U3, SB>) -> Vector3<N>
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]
pub fn set_left(&mut self, left: N) {
let right = self.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]
pub fn set_right(&mut self, right: N) {
let left = self.left();
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]
pub fn set_bottom(&mut self, bottom: N) {
let top = self.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]
pub fn set_top(&mut self, top: N) {
let bottom = self.bottom();
@ -271,6 +565,18 @@ impl<N: Real> Orthographic3<N> {
}
/// 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]
pub fn set_znear(&mut self, znear: N) {
let zfar = self.zfar();
@ -278,39 +584,93 @@ impl<N: Real> Orthographic3<N> {
}
/// 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]
pub fn set_zfar(&mut self, zfar: N) {
let znear = self.znear();
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]
pub fn set_left_and_right(&mut self, left: N, right: N) {
assert!(
left < right,
"The left corner must be farther than the right corner."
left != right,
"The left corner must not be equal to the right corner."
);
self.matrix[(0, 0)] = ::convert::<_, N>(2.0) / (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]
pub fn set_bottom_and_top(&mut self, bottom: N, top: N) {
assert!(
bottom < top,
"The top corner must be higher than the bottom corner."
bottom != top,
"The top corner must not be equal to the bottom corner."
);
self.matrix[(1, 1)] = ::convert::<_, N>(2.0) / (top - bottom);
self.matrix[(1, 3)] = -(top + bottom) / (top - bottom);
}
/// 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]
pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
assert!(
!relative_eq!(zfar - znear, N::zero()),
zfar != znear,
"The near-plane and far-plane must not be superimposed."
);
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> {
#[inline]
fn from(orth: Orthographic3<N>) -> Self {
orth.unwrap()
orth.into_inner()
}
}

View File

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

View File

@ -19,7 +19,7 @@ use base::{DefaultAllocator, Scalar, VectorN};
/// A point in a n-dimensional euclidean space.
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Point<N: Scalar, D: DimName>
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")]
impl<N: Scalar, D: DimName> Serialize for Point<N, D>
where
@ -77,7 +66,7 @@ where
where Des: Deserializer<'a> {
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>
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
/// 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]
pub fn to_homogeneous(&self) -> VectorN<N, DimNameSum<D, U1>>
where
@ -128,12 +124,24 @@ where DefaultAllocator: Allocator<N, D>
}
/// Creates a new point with the given coordinates.
#[deprecated(note = "Use Point::from(vector) instead.")]
#[inline]
pub fn from_coordinates(coords: VectorN<N, D>) -> Point<N, D> {
Point { coords: coords }
}
/// 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]
pub fn len(&self) -> usize {
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
/// this point.
#[inline]
#[deprecated(note = "This methods is no longer significant and will always return 1.")]
pub fn stride(&self) -> usize {
self.coords.strides().0
}
/// 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]
pub fn iter(&self) -> MatrixIter<N, D, U1, <DefaultAllocator as Allocator<N, D>>::Buffer> {
self.coords.iter()
@ -159,6 +179,17 @@ where DefaultAllocator: Allocator<N, D>
}
/// 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]
pub fn iter_mut(
&mut self,

View File

@ -33,7 +33,7 @@ where DefaultAllocator: Allocator<N, D>
#[inline]
fn from_coordinates(coords: Self::Coordinates) -> Self {
Self::from_coordinates(coords)
Self::from(coords)
}
#[inline]
@ -54,7 +54,7 @@ where
{
#[inline]
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]
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) {
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.
#[inline]
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.
///
/// # 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]
pub fn origin() -> Self
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.
///
/// # 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]
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.
///
/// 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.
///
/// # 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]
pub fn from_homogeneous(v: VectorN<N, DimNameSum<D, U1>>) -> Option<Self>
where
@ -47,7 +100,7 @@ where DefaultAllocator: Allocator<N, D>
{
if !v[D::dim()].is_zero() {
let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
Some(Self::from_coordinates(coords))
Some(Self::from(coords))
} else {
None
}
@ -64,12 +117,12 @@ where DefaultAllocator: Allocator<N, D>
{
#[inline]
fn max_value() -> Self {
Self::from_coordinates(VectorN::max_value())
Self::from(VectorN::max_value())
}
#[inline]
fn min_value() -> Self {
Self::from_coordinates(VectorN::min_value())
Self::from(VectorN::min_value())
}
}
@ -80,7 +133,7 @@ where
{
#[inline]
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]
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(
($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
($($doc: expr; $D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<N: Scalar> Point<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]
pub fn new($($args: N),*) -> Point<N, $D> {
unsafe {
@ -120,11 +176,17 @@ macro_rules! componentwise_constructors_impl(
);
componentwise_constructors_impl!(
"# use nalgebra::Point1;\nlet p = Point1::new(1.0);\nassert!(p.x == 1.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;
"# 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;
"# 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;
"# 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;
"# 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;
);
@ -132,7 +194,9 @@ macro_rules! from_array_impl(
($($D: ty, $len: expr);*) => {$(
impl <N: Scalar> From<[N; $len]> for Point<N, $D> {
fn from (coords: [N; $len]) -> Self {
Point::from_coordinates(coords.into())
Point {
coords: coords.into()
}
}
}
)*}

View File

@ -33,7 +33,7 @@ where
{
#[inline]
fn to_superset(&self) -> Point<N2, D> {
Point::from_coordinates(self.coords.to_superset())
Point::from(self.coords.to_superset())
}
#[inline]
@ -45,7 +45,7 @@ where
#[inline]
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]
unsafe fn from_superset_unchecked(v: &VectorN<N2, DimNameSum<D, U1>>) -> Self {
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()
}
}
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]
fn neg(self) -> Self::Output {
Point::from_coordinates(-self.coords)
Point::from(-self.coords)
}
}
@ -61,7 +61,7 @@ where DefaultAllocator: Allocator<N, D>
#[inline]
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;
(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::Output::from_coordinates(&self.coords - right); 'a, 'b);
Self::Output::from(&self.coords - right); 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub;
(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::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;
(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::Output::from_coordinates(self.coords - right); 'b);
Self::Output::from(self.coords - right); 'b);
add_sub_impl!(Sub, sub, ClosedSub;
(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::Output::from_coordinates(self.coords - right); );
Self::Output::from(self.coords - right); );
// Point + Vector
add_sub_impl!(Add, add, ClosedAdd;
(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::Output::from_coordinates(&self.coords + right); 'a, 'b);
Self::Output::from(&self.coords + right); 'a, 'b);
add_sub_impl!(Add, add, ClosedAdd;
(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::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;
(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::Output::from_coordinates(self.coords + right); 'b);
Self::Output::from(self.coords + right); 'b);
add_sub_impl!(Add, add, ClosedAdd;
(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::Output::from_coordinates(self.coords + right); );
Self::Output::from(self.coords + right); );
// XXX: replace by the shared macro: add_sub_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>
where ShapeConstraint: AreMultipliable<R1, C1, D2, U1>;
self: Matrix<N, R1, C1, SA>, right: Point<N, D2>, Output = Point<N, R1>;
[val val] => Point::from_coordinates(self * right.coords);
[ref val] => Point::from_coordinates(self * right.coords);
[val ref] => Point::from_coordinates(self * &right.coords);
[ref ref] => Point::from_coordinates(self * &right.coords);
[val val] => Point::from(self * right.coords);
[ref val] => Point::from(self * right.coords);
[val ref] => Point::from(self * &right.coords);
[ref ref] => Point::from(self * &right.coords);
);
/*
@ -198,7 +198,7 @@ macro_rules! componentwise_scalarop_impl(
#[inline]
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]
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]
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]
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> {
#[inline]
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> {
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]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")]
pub fn clone_owned(&self) -> Quaternion<N> {
Quaternion::from_vector(self.coords.clone_owned())
Quaternion::from(self.coords.clone_owned())
}
/// 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]
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]
pub fn conjugate(&self) -> Quaternion<N> {
let v = Vector4::new(
@ -124,13 +141,30 @@ impl<N: Real> Quaternion<N> {
-self.coords[2],
self.coords[3],
);
Quaternion::from_vector(v)
Quaternion::from(v)
}
/// 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]
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() {
Some(res)
@ -140,30 +174,74 @@ impl<N: Real> Quaternion<N> {
}
/// 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]
pub fn lerp(&self, other: &Quaternion<N>, t: N) -> Quaternion<N> {
self * (N::one() - t) + other * t
}
/// The vector part `(i, j, k)` of this quaternion.
///
/// # 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]
pub fn vector(&self) -> MatrixSlice<N, U3, U1, RStride<N, U4, U1>, CStride<N, U4, U1>> {
self.coords.fixed_rows::<U3>(0)
}
/// 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]
pub fn scalar(&self) -> N {
self.coords[3]
}
/// 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]
pub fn as_vector(&self) -> &Vector4<N> {
&self.coords
}
/// 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]
pub fn norm(&self) -> N {
self.coords.norm()
@ -172,30 +250,58 @@ impl<N: Real> Quaternion<N> {
/// A synonym for the norm of this quaternion.
///
/// 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]
pub fn magnitude(&self) -> N {
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.
///
/// # 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 norm_squared(&self) -> N {
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.
///
/// # 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]
pub fn dot(&self, rhs: &Self) -> N {
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
/// 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>>>) {
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()) {
@ -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.
///
/// # 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]
pub fn exp(&self) -> Quaternion<N> {
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]
pub fn exp_eps(&self, eps: N) -> Quaternion<N> {
let v = self.vector();
@ -238,33 +394,52 @@ impl<N: Real> Quaternion<N> {
let n = nn.sqrt();
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.
///
/// # 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]
pub fn powf(&self, n: N) -> Quaternion<N> {
(self.ln() * n).exp()
}
/// 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]
pub fn as_vector_mut(&mut self) -> &mut Vector4<N> {
&mut self.coords
}
/// 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]
pub fn vector_mut(
&mut self,
@ -273,6 +448,14 @@ impl<N: Real> Quaternion<N> {
}
/// 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]
pub fn conjugate_mut(&mut self) {
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.
///
/// # 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]
pub fn try_inverse_mut(&mut self) -> bool {
let norm_squared = self.norm_squared();
@ -296,6 +493,15 @@ impl<N: Real> Quaternion<N> {
}
/// 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]
pub fn normalize_mut(&mut self) -> N {
self.coords.normalize_mut()
@ -368,19 +574,31 @@ pub type UnitQuaternion<N> = Unit<Quaternion<N>>;
impl<N: Real> UnitQuaternion<N> {
/// Moves this unit quaternion into one that owns its data.
#[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> {
self
}
/// Clones this unit quaternion into one that owns its data.
#[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> {
*self
}
/// 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]
pub fn angle(&self) -> N {
let w = self.quaternion().scalar().abs();
@ -396,24 +614,59 @@ impl<N: Real> UnitQuaternion<N> {
/// The underlying quaternion.
///
/// 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]
pub fn quaternion(&self) -> &Quaternion<N> {
self.as_ref()
}
/// 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]
pub fn conjugate(&self) -> UnitQuaternion<N> {
UnitQuaternion::new_unchecked(self.as_ref().conjugate())
}
/// 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]
pub fn inverse(&self) -> UnitQuaternion<N> {
self.conjugate()
}
/// 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]
pub fn angle_to(&self, other: &UnitQuaternion<N>) -> N {
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 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]
pub fn rotation_to(&self, other: &UnitQuaternion<N>) -> UnitQuaternion<N> {
other / self
@ -431,12 +694,30 @@ impl<N: Real> UnitQuaternion<N> {
/// Linear interpolation between two unit quaternions.
///
/// 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]
pub fn lerp(&self, other: &UnitQuaternion<N>, t: N) -> Quaternion<N> {
self.as_ref().lerp(other.as_ref(), t)
}
/// 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]
pub fn nlerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> {
let mut res = self.lerp(other, t);
@ -448,13 +729,13 @@ impl<N: Real> UnitQuaternion<N> {
/// Spherical linear interpolation between two unit quaternions.
///
/// 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]
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)
.slerp(&Unit::new_unchecked(other.coords), t)
.unwrap(),
.into_inner(),
))
}
@ -478,7 +759,7 @@ impl<N: Real> UnitQuaternion<N> {
{
Unit::new_unchecked(self.coords)
.try_slerp(&Unit::new_unchecked(other.coords), t, epsilon)
.map(|q| Unit::new_unchecked(Quaternion::from_vector(q.unwrap())))
.map(|q| Unit::new_unchecked(Quaternion::from(q.into_inner())))
}
/// 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.
///
/// # 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]
pub fn inverse_mut(&mut self) {
self.as_mut_unchecked().conjugate_mut()
}
/// 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]
pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
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.
///
/// # 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]
pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() {
axis.unwrap() * self.angle()
axis.into_inner() * self.angle()
} else {
Vector3::zero()
}
@ -518,6 +832,19 @@ impl<N: Real> UnitQuaternion<N> {
/// The rotation axis and angle in ]0, pi] of this unit quaternion.
///
/// 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]
pub fn axis_angle(&self) -> Option<(Unit<Vector3<N>>, N)> {
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.
/// The vector part of the return value corresponds to the axis-angle representation (divided
/// 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]
pub fn ln(&self) -> Quaternion<N> {
if let Some(v) = self.axis() {
Quaternion::from_parts(N::zero(), v.unwrap() * self.angle())
Quaternion::from_parts(N::zero(), v.into_inner() * self.angle())
} else {
Quaternion::zero()
}
@ -553,6 +889,18 @@ impl<N: Real> UnitQuaternion<N> {
///
/// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and
/// 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]
pub fn powf(&self, n: N) -> UnitQuaternion<N> {
if let Some(v) = self.axis() {
@ -563,6 +911,21 @@ impl<N: Real> UnitQuaternion<N> {
}
/// 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]
pub fn to_rotation_matrix(&self) -> Rotation<N, U3> {
let i = self.as_ref()[0];
@ -596,13 +959,48 @@ impl<N: Real> UnitQuaternion<N> {
/// 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]
#[deprecated(note = "This is renamed to use `.euler_angles()`.")]
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.
///
/// # 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]
pub fn to_homogeneous(&self) -> MatrixN<N, U4> {
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> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(axis) = self.axis() {
let axis = axis.unwrap();
let axis = axis.into_inner();
write!(
f,
"UnitQuaternion angle: {} axis: ({}, {}, {})",

View File

@ -98,7 +98,7 @@ impl<N: Real> FiniteDimVectorSpace for Quaternion<N> {
#[inline]
fn canonical_basis_element(i: usize) -> Self {
Self::from_vector(Vector4::canonical_basis_element(i))
Self::from(Vector4::canonical_basis_element(i))
}
#[inline]
@ -131,7 +131,7 @@ impl<N: Real> NormedSpace for Quaternion<N> {
#[inline]
fn normalize(&self) -> Self {
let v = self.coords.normalize();
Self::from_vector(v)
Self::from(v)
}
#[inline]
@ -142,7 +142,7 @@ impl<N: Real> NormedSpace for Quaternion<N> {
#[inline]
fn try_normalize(&self, min_norm: N) -> Option<Self> {
if let Some(v) = self.coords.try_normalize(min_norm) {
Some(Self::from_vector(v))
Some(Self::from(v))
} else {
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`
/// vector component.
#[inline]
#[deprecated(note = "Use `::from` instead.")]
pub fn from_vector(vector: Vector4<N>) -> Self {
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
/// **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]
pub fn new(w: N, x: N, y: N, z: N) -> Self {
let v = Vector4::<N>::new(x, y, z, w);
Self::from_vector(v)
pub fn new(w: N, i: N, j: N, k: N) -> Self {
let v = Vector4::<N>::new(i, j, k, w);
Self::from(v)
}
/// Creates a new quaternion from its scalar and vector parts. Note that the arguments order does
/// **not** follow the storage order.
///
/// 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]
// FIXME: take a reference to `vector`?
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> {
let rot = UnitQuaternion::<N>::from_axis_angle(&axis, theta * ::convert(2.0f64));
rot.unwrap() * scale
rot.into_inner() * scale
}
/// 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]
pub fn identity() -> Self {
Self::new(N::one(), N::zero(), N::zero(), N::zero())
@ -110,7 +140,21 @@ where Owned<N, U4>: Send
}
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]
pub fn identity() -> Self {
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
/// (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]
pub fn from_axis_angle<SB>(axis: &Unit<Vector<N, U3, SB>>, angle: N) -> Self
where SB: Storage<N, U3> {
@ -138,6 +203,17 @@ impl<N: Real> UnitQuaternion<N> {
/// Creates a new unit quaternion from Euler angles.
///
/// 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]
pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
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.
///
/// # 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]
pub fn from_rotation_matrix(rotmat: &Rotation<N, U3>) -> Self {
// 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
/// 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]
pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
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
/// 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]
pub fn scaled_rotation_between<SB, SC>(
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
/// 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]
pub fn rotation_between_axis<SB, SC>(
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
/// 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]
pub fn scaled_rotation_between_axis<SB, SC>(
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
/// 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
/// * 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
/// collinear
/// to `dir`. Non-collinearity is not checked.
/// * dir - The look direction. It does not need to be normalized.
/// * up - The vertical direction. It does not need to be normalized.
/// The only requirement of this parameter is to not be collinear to `dir`. Non-collinearity
/// 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]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::from_rotation_matrix(&Rotation::<N, U3>::new_observer_frame(dir, up))
Self::from_rotation_matrix(&Rotation::<N, U3>::face_towards(dir, up))
}
/// Deprecated: Use [UnitQuaternion::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::face_towards(dir, up)
}
/// Builds a right-handed look-at view matrix without translation.
///
/// 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
/// graphics community.
///
/// # Arguments
/// * eye - The eye position.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`.
/// * dir The view direction. It does not need to be normalized.
/// * up - A vector approximately aligned with required the vertical axis. It does not need
/// to be normalized. The only 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_rh(&dir, &up);
/// assert_relative_eq!(q * dir.normalize(), -Vector3::z());
/// ```
#[inline]
pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::new_observer_frame(&-dir, up).inverse()
Self::face_towards(&-dir, up).inverse()
}
/// Builds a left-handed look-at view matrix without translation.
///
/// 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
/// graphics community.
///
/// # Arguments
/// * eye - The eye position.
/// * target - The target position.
/// * dir The view direction. It does not need to be normalized.
/// * 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]
pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::new_observer_frame(dir, up).inverse()
Self::face_towards(dir, up).inverse()
}
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
///
/// 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]
pub fn new<SB>(axisangle: Vector<N, U3, SB>) -> Self
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.
///
/// 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]
pub fn new_eps<SB>(axisangle: Vector<N, U3, SB>, eps: N) -> Self
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.
/// 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]
pub fn from_scaled_axis<SB>(axisangle: Vector<N, U3, SB>) -> Self
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.
///
/// 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]
pub fn from_scaled_axis_eps<SB>(axisangle: Vector<N, U3, SB>, eps: N) -> Self
where SB: Storage<N, U3> {
@ -436,15 +689,16 @@ where
#[cfg(test)]
mod tests {
extern crate rand_xorshift;
use super::*;
use rand::{self, SeedableRng};
use rand::SeedableRng;
#[test]
fn random_unit_quats_are_unit() {
let mut rng = rand::prng::XorShiftRng::from_seed([0xAB; 16]);
let mut rng = rand_xorshift::XorShiftRng::from_seed([0xAB; 16]);
for _ in 0..1000 {
let x = rng.gen::<UnitQuaternion<f32>>();
assert!(relative_eq!(x.unwrap().norm(), 1.0))
assert!(relative_eq!(x.into_inner().norm(), 1.0))
}
}
}

View File

@ -39,7 +39,7 @@ where
{
#[inline]
fn to_superset(&self) -> Quaternion<N2> {
Quaternion::from_vector(self.coords.to_superset())
Quaternion::from(self.coords.to_superset())
}
#[inline]
@ -49,7 +49,9 @@ where
#[inline]
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> {
#[inline]
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;
(U4, U1), (U4, U1);
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);
quaternion_op_impl!(
Add, add;
(U4, U1), (U4, U1);
self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(&self.coords + rhs.coords);
Quaternion::from(&self.coords + rhs.coords);
'a);
quaternion_op_impl!(
Add, add;
(U4, U1), (U4, U1);
self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords + &rhs.coords);
Quaternion::from(self.coords + &rhs.coords);
'b);
quaternion_op_impl!(
Add, add;
(U4, U1), (U4, U1);
self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords + rhs.coords);
Quaternion::from(self.coords + rhs.coords);
);
// Quaternion - Quaternion
@ -132,28 +132,28 @@ quaternion_op_impl!(
Sub, sub;
(U4, U1), (U4, U1);
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);
quaternion_op_impl!(
Sub, sub;
(U4, U1), (U4, U1);
self: &'a Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(&self.coords - rhs.coords);
Quaternion::from(&self.coords - rhs.coords);
'a);
quaternion_op_impl!(
Sub, sub;
(U4, U1), (U4, U1);
self: Quaternion<N>, rhs: &'b Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords - &rhs.coords);
Quaternion::from(self.coords - &rhs.coords);
'b);
quaternion_op_impl!(
Sub, sub;
(U4, U1), (U4, U1);
self: Quaternion<N>, rhs: Quaternion<N>, Output = Quaternion<N>;
Quaternion::from_vector(self.coords - rhs.coords);
Quaternion::from(self.coords - rhs.coords);
);
// Quaternion × Quaternion
@ -428,7 +428,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1);
self: &'a UnitQuaternion<N>, rhs: &'b Point3<N>,
Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * &rhs.coords);
Point3::from(self * &rhs.coords);
'a, 'b);
quaternion_op_impl!(
@ -436,7 +436,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1);
self: &'a UnitQuaternion<N>, rhs: Point3<N>,
Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * rhs.coords);
Point3::from(self * rhs.coords);
'a);
quaternion_op_impl!(
@ -444,7 +444,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1);
self: UnitQuaternion<N>, rhs: &'b Point3<N>,
Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * &rhs.coords);
Point3::from(self * &rhs.coords);
'b);
quaternion_op_impl!(
@ -452,7 +452,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1);
self: UnitQuaternion<N>, rhs: Point3<N>,
Output = Point3<N> => U3, U4;
Point3::from_coordinates(self * rhs.coords);
Point3::from(self * rhs.coords);
);
// UnitQuaternion × Unit<Vector>
@ -469,7 +469,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: &'a UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap());
Unit::new_unchecked(self * rhs.into_inner());
'a);
quaternion_op_impl!(
@ -485,7 +485,7 @@ quaternion_op_impl!(
(U4, U1), (U3, U1) for SB: Storage<N, U3> ;
self: UnitQuaternion<N>, rhs: Unit<Vector<N, U3, SB>>,
Output = Unit<Vector3<N>> => U3, U4;
Unit::new_unchecked(self * rhs.unwrap());
Unit::new_unchecked(self * rhs.into_inner());
);
macro_rules! scalar_op_impl(
@ -495,7 +495,7 @@ macro_rules! scalar_op_impl(
#[inline]
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]
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]
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]
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]
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]
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.
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> {
Reflection {
axis: axis.unwrap(),
axis: axis.into_inner(),
bias: bias,
}
}

View File

@ -108,28 +108,100 @@ impl<N: Scalar, D: DimName> Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D>
{
/// 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]
pub fn matrix(&self) -> &MatrixN<N, D> {
&self.matrix
}
/// 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]
#[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")]
pub unsafe fn matrix_mut(&mut self) -> &mut MatrixN<N, D> {
&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.
///
/// # 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]
pub fn unwrap(self) -> MatrixN<N, D> {
self.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]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where
@ -137,6 +209,9 @@ where DefaultAllocator: Allocator<N, D, D>
D: DimNameAdd<U1>,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{
// We could use `MatrixN::to_homogeneous()` here, but that would imply
// adding the additional traits `DimAdd` and `IsNotStaticOne`. Maybe
// these things will get nicer once specialization lands in Rust.
let mut res = MatrixN::<N, DimNameSum<D, U1>>::identity();
res.fixed_slice_mut::<D, D>(0, 0).copy_from(&self.matrix);
@ -146,6 +221,25 @@ where DefaultAllocator: Allocator<N, D, D>
/// Creates a new rotation from the given square matrix.
///
/// 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]
pub fn from_matrix_unchecked(matrix: MatrixN<N, D>) -> Rotation<N, D> {
assert!(
@ -157,24 +251,100 @@ where DefaultAllocator: Allocator<N, D, D>
}
/// 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]
pub fn transpose(&self) -> Rotation<N, D> {
Rotation::from_matrix_unchecked(self.matrix.transpose())
}
/// 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]
pub fn inverse(&self) -> Rotation<N, D> {
self.transpose()
}
/// 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]
pub fn transpose_mut(&mut self) {
self.matrix.transpose_mut()
}
/// 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]
pub fn inverse_mut(&mut self) {
self.transpose_mut()

View File

@ -89,7 +89,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
{
#[inline]
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]

View File

@ -14,6 +14,16 @@ where
DefaultAllocator: Allocator<N, D, D>,
{
/// 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]
pub fn identity() -> Rotation<N, D> {
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> {
#[inline]
fn from(q: Rotation2<N>) -> Matrix2<N> {
q.unwrap()
q.into_inner()
}
}
@ -241,6 +241,6 @@ impl<N: Real> From<Rotation3<N>> for Matrix4<N> {
impl<N: Real> From<Rotation3<N>> for Matrix3<N> {
#[inline]
fn from(q: Rotation3<N>) -> Matrix3<N> {
q.unwrap()
q.into_inner()
}
}

View File

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

View File

@ -22,6 +22,17 @@ use geometry::{Rotation2, Rotation3, UnitComplex};
*/
impl<N: Real> Rotation2<N> {
/// 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 {
let (sia, coa) = angle.sin_cos();
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.
///
/// 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]
pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self {
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.
///
/// 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]
pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self
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
/// 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]
pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U2, SB>,
@ -65,12 +101,29 @@ impl<N: Real> Rotation2<N> {
impl<N: Real> Rotation2<N> {
/// 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]
pub fn angle(&self) -> N {
self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)])
}
/// 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]
pub fn angle_to(&self, other: &Rotation2<N>) -> N {
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 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]
pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> {
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
/// 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]
pub fn powf(&self, n: N) -> Rotation2<N> {
Self::new(self.angle() * n)
}
/// 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]
pub fn scaled_axis(&self) -> VectorN<N, U1> {
Vector1::new(self.angle())
@ -129,6 +206,24 @@ impl<N: Real> Rotation3<N> {
/// # Arguments
/// * `axisangle` - A vector representing the rotation. Its magnitude is the amount 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 {
let axisangle = axisangle.into_owned();
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.
///
/// 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 {
Self::new(axisangle)
}
/// 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
where SB: Storage<N, U3> {
if angle.is_zero() {
@ -172,6 +308,17 @@ impl<N: Real> Rotation3<N> {
/// Creates a new rotation from Euler angles.
///
/// 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 {
let (sr, cr) = roll.sin_cos();
let (sp, cp) = pitch.sin_cos();
@ -192,16 +339,35 @@ impl<N: Real> Rotation3<N> {
/// 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) {
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
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
if self[(2, 0)].abs() != N::one() {
if self[(2, 0)].abs() < N::one() {
let yaw = -self[(2, 0)].asin();
let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos());
let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos());
(roll, yaw, pitch)
} else if self[(2, 0)] == -N::one() {
} else if self[(2, 0)] <= -N::one() {
(self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero())
} else {
(
@ -215,15 +381,26 @@ impl<N: Real> Rotation3<N> {
/// Creates a rotation that corresponds to the local frame of an observer standing at the
/// 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
/// * 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
/// collinear
/// to `dir`. Non-collinearity is not checked.
/// collinear 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]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
@ -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.
///
/// 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
/// graphics community.
///
/// # Arguments
/// * eye - The eye position.
/// * target - The target position.
/// * dir - The direction toward which the camera looks.
/// * 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]
pub fn look_at_rh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::new_observer_frame(&dir.neg(), up).inverse()
Self::face_towards(&dir.neg(), up).inverse()
}
/// Builds a left-handed look-at view matrix without translation.
///
/// 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
/// graphics community.
///
/// # Arguments
/// * eye - The eye position.
/// * target - The target position.
/// * dir - The direction toward which the camera looks.
/// * 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]
pub fn look_at_lh<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::new_observer_frame(dir, up).inverse()
Self::face_towards(dir, up).inverse()
}
/// The rotation matrix required to align `a` and `b` but with its angle.
///
/// 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]
pub fn rotation_between<SB, SC>(a: &Vector<N, U3, SB>, b: &Vector<N, U3, SC>) -> Option<Self>
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
/// 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]
pub fn scaled_rotation_between<SB, SC>(
a: &Vector<N, U3, SB>,
@ -320,7 +554,16 @@ impl<N: Real> Rotation3<N> {
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]
pub fn angle(&self) -> N {
((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.
///
/// # 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]
pub fn axis(&self) -> Option<Unit<Vector3<N>>> {
let axis = VectorN::<N, U3>::new(
@ -341,16 +598,62 @@ impl<N: Real> Rotation3<N> {
}
/// 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]
pub fn scaled_axis(&self) -> Vector3<N> {
if let Some(axis) = self.axis() {
axis.unwrap() * self.angle()
axis.into_inner() * self.angle()
} else {
Vector::zero()
}
}
/// 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.
///
/// # 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]
pub fn angle_to(&self, other: &Rotation3<N>) -> N {
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 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]
pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> {
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
/// 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]
pub fn powf(&self, n: N) -> Rotation3<N> {
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",
serde(bound(serialize = "N: Serialize,
serde(bound(
serialize = "N: Serialize,
R: Serialize,
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Serialize"))
Owned<N, D>: Serialize"
))
)]
#[cfg_attr(
feature = "serde-serialize",
serde(bound(deserialize = "N: Deserialize<'de>,
serde(bound(
deserialize = "N: Deserialize<'de>,
R: Deserialize<'de>,
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Deserialize<'de>"))
Owned<N, D>: Deserialize<'de>"
))
)]
pub struct Similarity<N: Real, D: DimName, R>
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
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy,
{
}
{}
impl<N: Real, D: DimName, R: Rotation<Point<N, D>> + Clone> Clone for Similarity<N, D, R>
where DefaultAllocator: Allocator<N, D>
@ -181,7 +184,7 @@ where
);
Self::from_parts(
Translation::from_vector(&self.isometry.translation.vector * scaling),
Translation::from(&self.isometry.translation.vector * scaling),
self.isometry.rotation.clone(),
self.scaling * scaling,
)
@ -266,8 +269,7 @@ impl<N: Real, D: DimName, R> Eq for Similarity<N, D, R>
where
R: Rotation<Point<N, D>> + Eq,
DefaultAllocator: Allocator<N, D>,
{
}
{}
impl<N: Real, D: DimName, R> PartialEq for Similarity<N, D, R>
where

View File

@ -25,6 +25,20 @@ where
DefaultAllocator: Allocator<N, D>,
{
/// 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]
pub fn identity() -> Self {
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
/// 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]
pub fn rotation_wrt_point(r: R, p: Point<N, D>, scaling: N) -> Self {
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.
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]
pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self {
Self::from_parts(
Translation::from_vector(translation),
Translation::from(translation),
Rotation2::new(angle),
scaling,
)
@ -114,10 +152,21 @@ impl<N: Real> Similarity<N, U2, Rotation2<N>> {
impl<N: Real> Similarity<N, U2, UnitComplex<N>> {
/// 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]
pub fn new(translation: Vector2<N>, angle: N, scaling: N) -> Self {
Self::from_parts(
Translation::from_vector(translation),
Translation::from(translation),
UnitComplex::new(angle),
scaling,
)
@ -130,6 +179,29 @@ macro_rules! similarity_construction_impl(
impl<N: Real> Similarity<N, U3, $Rot> {
/// Creates a new similarity from a translation, rotation axis-angle, and scaling
/// 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]
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>, scaling: N) -> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling)
@ -146,13 +218,44 @@ macro_rules! similarity_construction_impl(
/// * target - The target position.
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear
/// 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]
pub fn new_observer_frame(eye: &Point3<N>,
pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>,
scaling: N)
-> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::new_observer_frame(eye, target, up), scaling)
Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling)
}
/// Deprecated: Use [SimilarityMatrix3::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>,
scaling: N)
-> Self {
Self::face_towards(eye, target, up, scaling)
}
/// Builds a right-handed look-at view matrix including scaling factor.
@ -165,6 +268,25 @@ macro_rules! similarity_construction_impl(
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// 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]
pub fn look_at_rh(eye: &Point3<N>,
target: &Point3<N>,
@ -184,6 +306,25 @@ macro_rules! similarity_construction_impl(
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// 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]
pub fn look_at_lh(eye: &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 = Translation::from_vector(::convert_unchecked(t));
let t = Translation {
vector: ::convert_unchecked(t),
};
Self::from_parts(t, ::convert_unchecked(mm), ::convert_unchecked(scale))
}

View File

@ -269,7 +269,7 @@ similarity_binop_impl_all!(
[ref ref] => {
let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling();
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.scaling())
};
@ -352,7 +352,7 @@ similarity_binop_impl_all!(
[ref ref] => {
let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling();
Similarity::from_parts(
Translation::from_vector(&self.isometry.translation.vector + shift),
Translation::from(&self.isometry.translation.vector + shift),
self.isometry.rotation.clone(),
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::fmt::Debug;
use std::marker::PhantomData;
@ -14,7 +15,7 @@ use base::{DefaultAllocator, MatrixN};
/// 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 {
/// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
/// `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]
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
self.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]
pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> {
&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
/// 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]
pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
&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.
#[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> {
Transform::from_matrix_unchecked(self.matrix.clone_owned())
}
/// 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]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
self.matrix().clone_owned()
}
/// 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]
pub fn try_inverse(self) -> Option<Transform<N, D, C>> {
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`
/// 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]
pub fn inverse(self) -> Transform<N, D, C>
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
/// 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]
pub fn try_inverse_mut(&mut self) -> bool {
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
/// `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]
pub fn inverse_mut(&mut self)
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)]
mod tests {
use super::*;

View File

@ -2,16 +2,16 @@ use base::dimension::{U2, U3};
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>;
/// 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>;
/// A 2D affine transformation. Stored as an homogeneous 3x3 matrix.
pub type Affine2<N> = Transform<N, U2, TAffine>;
/// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix.
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>;
/// A 3D affine transformation. Stored as an homogeneous 4x4 matrix.
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>>
{
/// 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]
pub fn identity() -> Self {
Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity())

View File

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

View File

@ -43,8 +43,7 @@ impl<N: Scalar, D: DimName> Copy for Translation<N, D>
where
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy,
{
}
{}
impl<N: Scalar, D: DimName> Clone for Translation<N, D>
where
@ -53,7 +52,7 @@ where
{
#[inline]
fn clone(&self) -> Self {
Translation::from_vector(self.vector.clone())
Translation::from(self.vector.clone())
}
}
@ -100,7 +99,7 @@ where
where Des: Deserializer<'a> {
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.
#[inline]
#[deprecated(note = "Use `::from` instead.")]
pub fn from_vector(vector: VectorN<N, D>) -> Translation<N, D> {
Translation { vector: vector }
}
/// 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]
pub fn inverse(&self) -> Translation<N, D>
where N: ClosedNeg {
Translation::from_vector(-&self.vector)
Translation::from(-&self.vector)
}
/// 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]
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>>
where
@ -136,6 +166,23 @@ where DefaultAllocator: Allocator<N, D>
}
/// 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]
pub fn inverse_mut(&mut self)
where N: ClosedNeg {

View File

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

View File

@ -1,9 +1,21 @@
use base::dimension::{U2, U3};
use base::dimension::{U1, U2, U3, U4, U5, U6};
use geometry::Translation;
/// A 1-dimensional translation.
pub type Translation1<N> = Translation<N, U1>;
/// A 2-dimensional translation.
pub type Translation2<N> = Translation<N, U2>;
/// A 3-dimensional translation.
pub type Translation3<N> = Translation<N, U3>;
/// A 4-dimensional translation.
pub type Translation4<N> = Translation<N, U4>;
/// A 5-dimensional translation.
pub type Translation5<N> = Translation<N, U5>;
/// A 6-dimensional translation.
pub type Translation6<N> = Translation<N, U6>;

View File

@ -18,10 +18,23 @@ use geometry::Translation;
impl<N: Scalar + Zero, D: DimName> Translation<N, D>
where DefaultAllocator: Allocator<N, D>
{
/// Creates a new square identity rotation of the given `dimension`.
/// Creates a new identity translation.
///
/// # Example
/// ```
/// # use nalgebra::{Point2, Point3, Translation2, Translation3};
/// let t = Translation2::identity();
/// let p = Point2::new(1.0, 2.0);
/// assert_eq!(t * p, p);
///
/// // Works in all dimensions.
/// let t = Translation3::identity();
/// let p = Point3::new(1.0, 2.0, 3.0);
/// assert_eq!(t * p, p);
/// ```
#[inline]
pub fn identity() -> Translation<N, D> {
Self::from_vector(VectorN::<N, D>::from_element(N::zero()))
Self::from(VectorN::<N, D>::from_element(N::zero()))
}
}
@ -41,7 +54,7 @@ where
{
#[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Translation<N, D> {
Translation::from_vector(rng.gen::<VectorN<N, D>>())
Translation::from(rng.gen::<VectorN<N, D>>())
}
}
@ -53,7 +66,8 @@ where
{
#[inline]
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
Self::from_vector(Arbitrary::arbitrary(rng))
let v: VectorN<N, D> = Arbitrary::arbitrary(rng);
Self::from(v)
}
}
@ -63,23 +77,32 @@ where
*
*/
macro_rules! componentwise_constructors_impl(
($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
($($doc: expr; $D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<N: Scalar> Translation<N, $D>
where DefaultAllocator: Allocator<N, $D> {
/// Initializes this matrix from its components.
#[doc = "Initializes this translation from its components."]
#[doc = "# Example\n```"]
#[doc = $doc]
#[doc = "```"]
#[inline]
pub fn new($($args: N),*) -> Self {
Self::from_vector(VectorN::<N, $D>::new($($args),*))
Self::from(VectorN::<N, $D>::new($($args),*))
}
}
)*}
);
componentwise_constructors_impl!(
"# use nalgebra::Translation1;\nlet t = Translation1::new(1.0);\nassert!(t.vector.x == 1.0);";
U1, x:0;
"# use nalgebra::Translation2;\nlet t = Translation2::new(1.0, 2.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0);";
U2, x:0, y:1;
"# use nalgebra::Translation3;\nlet t = Translation3::new(1.0, 2.0, 3.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0);";
U3, x:0, y:1, z:2;
"# use nalgebra::Translation4;\nlet t = Translation4::new(1.0, 2.0, 3.0, 4.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0);";
U4, x:0, y:1, z:2, w:3;
"# use nalgebra::Translation5;\nlet t = Translation5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0);";
U5, x:0, y:1, z:2, w:3, a:4;
"# use nalgebra::Translation6;\nlet t = Translation6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0 && t.vector.b == 6.0);";
U6, x:0, y:1, z:2, w:3, a:4, b:5;
);

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