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:
commit
fc24db8ff3
39
CHANGELOG.md
39
CHANGELOG.md
@ -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.
|
||||
|
13
Cargo.toml
13
Cargo.toml
@ -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" ]
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>();
|
||||
|
@ -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())
|
||||
}
|
||||
|
39
examples/linear_system_resolution.rs
Normal file
39
examples/linear_system_resolution.rs
Normal 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);
|
||||
}
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -1,7 +1,6 @@
|
||||
extern crate alga;
|
||||
extern crate nalgebra as na;
|
||||
|
||||
use alga::linear::Transformation;
|
||||
use na::{Matrix4, Point3, Vector3, Vector4};
|
||||
|
||||
fn main() {
|
||||
|
@ -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 }
|
||||
|
@ -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`.
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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!()
|
||||
//}
|
||||
|
@ -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:
|
||||
///
|
||||
|
@ -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`.
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -15,4 +15,4 @@
|
||||
//pub fn uround<N: Scalar, D: Dimension>(x: &TVec<N, D>) -> TVec<u32, D>
|
||||
// where DefaultAllocator: Alloc<N, D> {
|
||||
// unimplemented!()
|
||||
//}
|
||||
//}
|
||||
|
@ -288,4 +288,4 @@ pub fn unpackUnorm4x16(p: u64) -> Vec4 {
|
||||
|
||||
pub fn unpackUnorm4x4(p: u16) -> Vec4 {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
55
nalgebra-glm/tests/lib.rs
Normal 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);
|
||||
}
|
@ -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"
|
||||
|
@ -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)) };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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>;
|
||||
|
@ -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>;
|
||||
|
@ -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>,
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
@ -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,
|
128
src/base/blas.rs
128
src/base/blas.rs
@ -13,18 +13,18 @@ use base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
|
||||
use base::storage::{Storage, StorageMut};
|
||||
use base::{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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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. ?
|
||||
);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
);
|
||||
|
||||
|
@ -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
714
src/base/indexing.rs
Normal 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>],
|
||||
}
|
||||
}
|
227
src/base/iter.rs
227
src/base/iter.rs
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
238
src/base/norm.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
309
src/base/statistics.rs
Normal 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())
|
||||
})
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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];
|
||||
);
|
||||
|
@ -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]
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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, ¢er)
|
||||
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
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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)
|
||||
};
|
||||
);
|
||||
|
||||
|
@ -54,6 +54,8 @@ mod similarity_construction;
|
||||
mod similarity_conversion;
|
||||
mod similarity_ops;
|
||||
|
||||
mod swizzle;
|
||||
|
||||
mod transform;
|
||||
mod transform_alga;
|
||||
mod transform_alias;
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
)*}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
)*}
|
||||
|
@ -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: ({}, {}, {})",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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]
|
||||
|
@ -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())
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
);
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
65
src/geometry/swizzle.rs
Normal 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];
|
||||
);
|
@ -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::*;
|
||||
|
@ -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>;
|
||||
|
@ -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())
|
||||
|
@ -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();
|
||||
);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user