Merge pull request #945 from dimforge/dev

Release v0.28.0
This commit is contained in:
Sébastien Crozet 2021-07-11 18:11:45 +02:00 committed by GitHub
commit 944afe24e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
129 changed files with 1732 additions and 804 deletions

View File

@ -4,6 +4,30 @@ documented here.
This project adheres to [Semantic Versioning](https://semver.org/). This project adheres to [Semantic Versioning](https://semver.org/).
## [0.28.0]
### Added
- Implement `Hash` for `Transform`.
- Implement `Borrow` and `BorrowMut` for contiguous slices.
### Modified
- The `OPoint<T, D>` type has been added. It takes the dimension number as a type-level integer (e.g. `Const<3>`) instead
of a const-generic. The type `Point<T, const D: usize>` is now an alias for `OPoint`. This changes doesn't affect any
of the existing code using `Point`. However, it will allow the use `OPoint` in a generic context where the dimension
cannot be easily expressed as a const-generic (because of the current limitation of const-generics in Rust).
- Several clippy warnings were fixed. This results in some method signature changes (e.g. taking `self` instead of `&self`)
but this should not have any practical infulances on existing codebase.
- The `Point::new` constructors are no longer const-fn. This is due to some limitations in const-fn
not allowing custom trait-bounds. Use the `point!` macro instead to build points in const environments.
- `Dynamic::new` and `Unit::new_unchecked` are now const-fn.
- Methods returning `Result<(), ()>` now return `bool` instead.
### Fixed
- Fixed a potential unsoundess issue when converting a mutable slice to a `&mut[T]`.
## [0.27.1]
### Fixed
- Fixed a bug in the conversion from `glam::Vec2` or `glam::DVec2` to `Isometry2`.
## [0.27.0] ## [0.27.0]
This removes the `convert-glam` and `convert-glam-unchecked` optional features. This removes the `convert-glam` and `convert-glam-unchecked` optional features.
Instead, this adds the `convert-glam013`, `convert-glam014`, and `convert-glam015` optional features for Instead, this adds the `convert-glam013`, `convert-glam014`, and `convert-glam015` optional features for
@ -34,7 +58,7 @@ conversions targeting the versions 0.13, 0.14, and 0.15 of `glam`.
Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized with `serde`. Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized with `serde`.
## [0.26.0] ## [0.26.0]
This releases integrates `min-const-generics` to nalgebra. See This release integrates `min-const-generics` to nalgebra. See
[our blog post](https://www.dimforge.com/blog/2021/04/12/integrating-const-generics-to-nalgebra) [our blog post](https://www.dimforge.com/blog/2021/04/12/integrating-const-generics-to-nalgebra)
for details about this release. for details about this release.
@ -74,7 +98,7 @@ for details about this release.
## [0.25.3] ## [0.25.3]
### Added ### Added
- The `Vector::simd_cap_magnitude` method to cap the magnitude of the a vector with - The `Vector::simd_cap_magnitude` method to cap the magnitude of the vector with
SIMD components. SIMD components.
## [0.25.2] ## [0.25.2]
@ -105,7 +129,7 @@ This updates all the dependencies of nalgebra to their latest version, including
### New crate: nalgebra-sparse ### New crate: nalgebra-sparse
Alongside this release of `nalgebra`, we are releasing `nalgebra-sparse`: a crate dedicated to sparse matrix Alongside this release of `nalgebra`, we are releasing `nalgebra-sparse`: a crate dedicated to sparse matrix
computation with `nalgebra`. The `sparse` module of `nalgebra`itself still exists for backward compatibility computation with `nalgebra`. The `sparse` module of `nalgebra`itself still exists for backward compatibility,
but it will be deprecated soon in favor of the `nalgebra-sparse` crate. but it will be deprecated soon in favor of the `nalgebra-sparse` crate.
### Added ### Added
@ -121,12 +145,12 @@ but it will be deprecated soon in favor of the `nalgebra-sparse` crate.
## [0.24.0] ## [0.24.0]
### Added ### Added
* The `DualQuaternion` type. It is still work-in-progress but the basics are here: * The `DualQuaternion` type. It is still work-in-progress, but the basics are here:
creation from its real and dual part, multiplication of two dual quaternions, creation from its real and dual part, multiplication of two dual quaternions,
and normalization. and normalization.
### Removed ### Removed
* There is no blanket `impl<T> PartialEq for Unit<T>` any more. Instead, it is * There is no blanket `impl<T> PartialEq for Unit<T>` anymore. Instead, it is
implemented specifically for `UnitComplex`, `UnitQuaternion` and `Unit<Vector>`. implemented specifically for `UnitComplex`, `UnitQuaternion` and `Unit<Vector>`.
## [0.23.2] ## [0.23.2]
@ -153,7 +177,7 @@ In this release we improved the documentation of the matrix and vector types by:
and `Vector.apply(f)`. and `Vector.apply(f)`.
* The `Quaternion::from([N; 4])` conversion to build a quaternion from an array of four elements. * The `Quaternion::from([N; 4])` conversion to build a quaternion from an array of four elements.
* The `Isometry::from(Translation)` conversion to build an isometry from a translation. * The `Isometry::from(Translation)` conversion to build an isometry from a translation.
* The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit<Vector3<f32>>` with its i-th component set to 1.0 and the * The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit<Vector3<f32>>` with its i-th component set to 1.0, and the
others set to zero. others set to zero.
* The `Isometry.lerp_slerp` and `Isometry.try_lerp_slerp` methods to interpolate between two isometries using linear * The `Isometry.lerp_slerp` and `Isometry.try_lerp_slerp` methods to interpolate between two isometries using linear
interpolation for the translational part, and spherical interpolation for the rotational part. interpolation for the translational part, and spherical interpolation for the rotational part.
@ -162,7 +186,7 @@ In this release we improved the documentation of the matrix and vector types by:
## [0.22.0] ## [0.22.0]
In this release, we are using the new version 0.2 of simba. One major change of that version is that the In this release, we are using the new version 0.2 of simba. One major change of that version is that the
use of `libm` is now opt-in when building targetting `no-std` environment. If you are using floating-point use of `libm` is now opt-in when building targeting `no-std` environment. If you are using floating-point
operations with nalgebra in a `no-std` environment, you will need to enable the new `libm` feature operations with nalgebra in a `no-std` environment, you will need to enable the new `libm` feature
of nalgebra for your code to compile again. of nalgebra for your code to compile again.
@ -170,7 +194,7 @@ of nalgebra for your code to compile again.
* The `libm` feature that enables `libm` when building for `no-std` environment. * The `libm` feature that enables `libm` when building for `no-std` environment.
* The `libm-force` feature that enables `libm` even when building for a not `no-std` environment. * The `libm-force` feature that enables `libm` even when building for a not `no-std` environment.
* `Cholesky::new_unchecked` which build a Cholesky decomposition without checking that its input is * `Cholesky::new_unchecked` which build a Cholesky decomposition without checking that its input is
positive-definite. It can be use with SIMD types. positive-definite. It can be used with SIMD types.
* The `Default` trait is now implemented for matrices, and quaternions. They are all filled with zeros, * The `Default` trait is now implemented for matrices, and quaternions. They are all filled with zeros,
except for `UnitQuaternion` which is initialized with the identity. except for `UnitQuaternion` which is initialized with the identity.
* Matrix exponential `matrix.exp()`. * Matrix exponential `matrix.exp()`.
@ -341,7 +365,7 @@ library (i.e. it supports `#![no_std]`). See the corresponding [documentation](h
* Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex` * Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex`
to compute the rotation matrix between two 2D **unit** vectors. to compute the rotation matrix between two 2D **unit** vectors.
* Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the * Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the
unit rotation axis and the rotation angle simultaneously. unit rotation axis, and the rotation angle simultaneously.
* Add functions to construct a random matrix with a user-defined distribution: `::from_distribution(...)`. * Add functions to construct a random matrix with a user-defined distribution: `::from_distribution(...)`.
## [0.14.0] ## [0.14.0]
@ -362,7 +386,7 @@ library (i.e. it supports `#![no_std]`). See the corresponding [documentation](h
the matrix `M` such that for all vector `v` we have the matrix `M` such that for all vector `v` we have
`M * v == self.cross(&v)`. `M * v == self.cross(&v)`.
* `.iamin()` that returns the index of the vector entry with * `.iamin()` that returns the index of the vector entry with
smallest absolute value. the smallest absolute value.
* The `mint` feature that can be enabled in order to allow conversions from * The `mint` feature that can be enabled in order to allow conversions from
and to types of the [mint](https://crates.io/crates/mint) crate. and to types of the [mint](https://crates.io/crates/mint) crate.
* Aliases for matrix and vector slices. Their are named by adding `Slice` * Aliases for matrix and vector slices. Their are named by adding `Slice`
@ -400,7 +424,7 @@ This adds support for serialization using the
* The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we * The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we
reordered M and N to be in alphabetical order). reordered M and N to be in alphabetical order).
* In-place componentwise multiplication and division * In-place componentwise multiplication and division
`.component_mul_mut(...)` and `.component_div_mut(...)` have bee deprecated `.component_mul_mut(...)` and `.component_div_mut(...)` have been deprecated
for a future renaming. Use `.component_mul_assign(...)` and for a future renaming. Use `.component_mul_assign(...)` and
`.component_div_assign(...)` instead. `.component_div_assign(...)` instead.
@ -502,7 +526,7 @@ This version is a major rewrite of the library. Major changes are:
All other mathematical traits, except `Axpy` have been removed from All other mathematical traits, except `Axpy` have been removed from
**nalgebra**. **nalgebra**.
* Methods are now preferred to free functions because they do not require any * Methods are now preferred to free functions because they do not require any
trait to be used any more. trait to be used anymore.
* Most algebraic entities can be parametrized by type-level integers * Most algebraic entities can be parametrized by type-level integers
to specify their dimensions. Using `Dynamic` instead of a type-level to specify their dimensions. Using `Dynamic` instead of a type-level
integer indicates that the dimension known at run-time only. integer indicates that the dimension known at run-time only.
@ -578,7 +602,7 @@ only:
* The free functions `::prepend_rotation`, `::append_rotation`, * The free functions `::prepend_rotation`, `::append_rotation`,
`::append_rotation_wrt_center`, `::append_rotation_wrt_point`, `::append_rotation_wrt_center`, `::append_rotation_wrt_point`,
`::append_transformation`, and `::append_translation ` have been removed. `::append_transformation`, and `::append_translation ` have been removed.
Instead create the rotation or translation object explicitly and use Instead, create the rotation or translation object explicitly and use
multiplication to compose it with anything else. multiplication to compose it with anything else.
* The free function `::outer` has been removed. Use column-vector × * The free function `::outer` has been removed. Use column-vector ×
@ -604,7 +628,7 @@ Binary operations are now allowed between references as well. For example
### Modified ### Modified
Removed unused parameters to methods from the `ApproxEq` trait. Those were Removed unused parameters to methods from the `ApproxEq` trait. Those were
required before rust 1.0 to help type inference. The are not needed any more required before rust 1.0 to help type inference. They are not needed any more
since it now allowed to write for a type `T` that implements `ApproxEq`: since it now allowed to write for a type `T` that implements `ApproxEq`:
`<T as ApproxEq>::approx_epsilon()`. This replaces the old form: `<T as ApproxEq>::approx_epsilon()`. This replaces the old form:
`ApproxEq::approx_epsilon(None::<T>)`. `ApproxEq::approx_epsilon(None::<T>)`.
@ -623,7 +647,7 @@ since it now allowed to write for a type `T` that implements `ApproxEq`:
`UnitQuaternion::from_axisangle`. The new `::new` method now requires a `UnitQuaternion::from_axisangle`. The new `::new` method now requires a
not-normalized quaternion. not-normalized quaternion.
Methods names starting with `new_with_` now start with `from_`. This is more Method names starting with `new_with_` now start with `from_`. This is more
idiomatic in Rust. idiomatic in Rust.
The `Norm` trait now uses an associated type instead of a type parameter. The `Norm` trait now uses an associated type instead of a type parameter.
@ -654,8 +678,8 @@ crate for vectors, rotations and points. To enable them, activate the
## [0.8.0] ## [0.8.0]
### Modified ### Modified
* Almost everything (types, methods, and traits) now use full names instead * Almost everything (types, methods, and traits) now use fulls names instead
of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are abvious. of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are obvious.
Note however that: Note however that:
- `::sqnorm` becomes `::norm_squared`. - `::sqnorm` becomes `::norm_squared`.
- `::sqdist` becomes `::distance_squared`. - `::sqdist` becomes `::distance_squared`.
@ -689,11 +713,11 @@ you [there](https://users.nphysics.org)!
### Removed ### Removed
* Removed zero-sized elements `Vector0`, `Point0`. * Removed zero-sized elements `Vector0`, `Point0`.
* Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation to incomplete to be useful). * Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation too incomplete to be useful).
### Modified ### Modified
* Vectors are now multipliable with isometries. This will result into a pure rotation (this is how * Vectors are now multipliable with isometries. This will result into a pure rotation (this is how
vectors differ from point semantically: they design directions so they are not translatable). vectors differ from point semantically: they design directions, so they are not translatable).
* `{Isometry3, Rotation3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree * `{Isometry3, Rotation3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree
with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh` with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh`
variant to build a view matrix that variant to build a view matrix that

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra" name = "nalgebra"
version = "0.27.0" version = "0.28.0"
authors = [ "Sébastien Crozet <developer@crozet.re>" ] authors = [ "Sébastien Crozet <developer@crozet.re>" ]
description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices."

View File

@ -4,7 +4,7 @@ version = "0.0.0"
authors = [ "You" ] authors = [ "You" ]
[dependencies] [dependencies]
nalgebra = "0.27.0" nalgebra = "0.28.0"
[[bin]] [[bin]]
name = "example" name = "example"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-glm" name = "nalgebra-glm"
version = "0.13.0" version = "0.14.0"
authors = ["sebcrozet <developer@crozet.re>"] authors = ["sebcrozet <developer@crozet.re>"]
description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library."
@ -27,4 +27,4 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
approx = { version = "0.5", default-features = false } approx = { version = "0.5", default-features = false }
simba = { version = "0.5", default-features = false } simba = { version = "0.5", default-features = false }
nalgebra = { path = "..", version = "0.27", default-features = false } nalgebra = { path = "..", version = "0.28", default-features = false }

View File

@ -21,7 +21,7 @@
**nalgebra-glm** using the module prefix `glm::`. For example you will write `glm::rotate(...)` instead **nalgebra-glm** using the module prefix `glm::`. For example you will write `glm::rotate(...)` instead
of the more verbose `nalgebra_glm::rotate(...)`: of the more verbose `nalgebra_glm::rotate(...)`:
```rust ```
extern crate nalgebra_glm as glm; extern crate nalgebra_glm as glm;
``` ```

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-lapack" name = "nalgebra-lapack"
version = "0.18.0" version = "0.19.0"
authors = [ "Sébastien Crozet <developer@crozet.re>", "Andrew Straw <strawman@astraw.com>" ] authors = [ "Sébastien Crozet <developer@crozet.re>", "Andrew Straw <strawman@astraw.com>" ]
description = "Matrix decompositions using nalgebra matrices and Lapack bindings." description = "Matrix decompositions using nalgebra matrices and Lapack bindings."
@ -29,7 +29,7 @@ accelerate = ["lapack-src/accelerate"]
intel-mkl = ["lapack-src/intel-mkl"] intel-mkl = ["lapack-src/intel-mkl"]
[dependencies] [dependencies]
nalgebra = { version = "0.27", path = ".." } nalgebra = { version = "0.28", path = ".." }
num-traits = "0.2" num-traits = "0.2"
num-complex = { version = "0.4", default-features = false } num-complex = { version = "0.4", default-features = false }
simba = "0.5" simba = "0.5"
@ -39,7 +39,7 @@ lapack-src = { version = "0.8", default-features = false }
# clippy = "*" # clippy = "*"
[dev-dependencies] [dev-dependencies]
nalgebra = { version = "0.27", features = [ "arbitrary", "rand" ], path = ".." } nalgebra = { version = "0.28", features = [ "arbitrary", "rand" ], path = ".." }
proptest = { version = "1", default-features = false, features = ["std"] } proptest = { version = "1", default-features = false, features = ["std"] }
quickcheck = "1" quickcheck = "1"
approx = "0.5" approx = "0.5"

View File

@ -80,6 +80,7 @@ where
} }
/// Retrieves the lower-triangular factor of the cholesky decomposition. /// Retrieves the lower-triangular factor of the cholesky decomposition.
#[must_use]
pub fn l(&self) -> OMatrix<T, D, D> { pub fn l(&self) -> OMatrix<T, D, D> {
let mut res = self.l.clone(); let mut res = self.l.clone();
res.fill_upper_triangle(Zero::zero(), 1); res.fill_upper_triangle(Zero::zero(), 1);
@ -91,6 +92,7 @@ where
/// ///
/// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular /// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular
/// part are garbage and should be ignored by further computations. /// part are garbage and should be ignored by further computations.
#[must_use]
pub fn l_dirty(&self) -> &OMatrix<T, D, D> { pub fn l_dirty(&self) -> &OMatrix<T, D, D> {
&self.l &self.l
} }

View File

@ -302,6 +302,7 @@ where
/// The determinant of the decomposed matrix. /// The determinant of the decomposed matrix.
#[inline] #[inline]
#[must_use]
pub fn determinant(&self) -> T { pub fn determinant(&self) -> T {
let mut det = T::one(); let mut det = T::one();
for e in self.eigenvalues.iter() { for e in self.eigenvalues.iter() {

View File

@ -89,6 +89,7 @@ where
/// Computes the hessenberg matrix of this decomposition. /// Computes the hessenberg matrix of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn h(&self) -> OMatrix<T, D, D> { pub fn h(&self) -> OMatrix<T, D, D> {
let mut h = self.h.clone_owned(); let mut h = self.h.clone_owned();
h.fill_lower_triangle(T::zero(), 2); h.fill_lower_triangle(T::zero(), 2);
@ -109,6 +110,7 @@ where
/// Computes the unitary matrix `Q` of this decomposition. /// Computes the unitary matrix `Q` of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn q(&self) -> OMatrix<T, D, D> { pub fn q(&self) -> OMatrix<T, D, D> {
let n = self.h.nrows() as i32; let n = self.h.nrows() as i32;
let mut q = self.h.clone_owned(); let mut q = self.h.clone_owned();

View File

@ -30,7 +30,7 @@
//! the system installation of netlib without LAPACKE (note the E) or //! the system installation of netlib without LAPACKE (note the E) or
//! CBLAS: //! CBLAS:
//! //!
//! ```.ignore //! ```ignore
//! sudo apt-get install gfortran libblas3gf liblapack3gf //! sudo apt-get install gfortran libblas3gf liblapack3gf
//! export CARGO_FEATURE_SYSTEM_NETLIB=1 //! export CARGO_FEATURE_SYSTEM_NETLIB=1
//! export CARGO_FEATURE_EXCLUDE_LAPACKE=1 //! export CARGO_FEATURE_EXCLUDE_LAPACKE=1
@ -44,7 +44,7 @@
//! //!
//! On macOS, do this to use Apple's Accelerate framework: //! On macOS, do this to use Apple's Accelerate framework:
//! //!
//! ```.ignore //! ```ignore
//! export CARGO_FEATURES="--no-default-features --features accelerate" //! export CARGO_FEATURES="--no-default-features --features accelerate"
//! cargo build ${CARGO_FEATURES} //! cargo build ${CARGO_FEATURES}
//! ``` //! ```

View File

@ -85,6 +85,7 @@ where
/// Gets the lower-triangular matrix part of the decomposition. /// Gets the lower-triangular matrix part of the decomposition.
#[inline] #[inline]
#[must_use]
pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> { pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.data.shape();
let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
@ -97,6 +98,7 @@ where
/// Gets the upper-triangular matrix part of the decomposition. /// Gets the upper-triangular matrix part of the decomposition.
#[inline] #[inline]
#[must_use]
pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> { pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
let (nrows, ncols) = self.lu.data.shape(); let (nrows, ncols) = self.lu.data.shape();
let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned(); let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned();
@ -111,6 +113,7 @@ where
/// Computing the permutation matrix explicitly is costly and usually not necessary. /// Computing the permutation matrix explicitly is costly and usually not necessary.
/// To permute rows of a matrix or vector, use the method `self.permute(...)` instead. /// To permute rows of a matrix or vector, use the method `self.permute(...)` instead.
#[inline] #[inline]
#[must_use]
pub fn p(&self) -> OMatrix<T, R, R> { pub fn p(&self) -> OMatrix<T, R, R> {
let (dim, _) = self.lu.data.shape(); let (dim, _) = self.lu.data.shape();
let mut id = Matrix::identity_generic(dim, dim); let mut id = Matrix::identity_generic(dim, dim);
@ -124,6 +127,7 @@ where
/// Gets the LAPACK permutation indices. /// Gets the LAPACK permutation indices.
#[inline] #[inline]
#[must_use]
pub fn permutation_indices(&self) -> &OVector<i32, DimMinimum<R, C>> { pub fn permutation_indices(&self) -> &OVector<i32, DimMinimum<R, C>> {
&self.p &self.p
} }

View File

@ -92,6 +92,7 @@ where
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition. /// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> { pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.data.shape();
self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle() self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle()
@ -117,6 +118,7 @@ where
/// Computes the orthogonal matrix `Q` of this decomposition. /// Computes the orthogonal matrix `Q` of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> { pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
let (nrows, ncols) = self.qr.data.shape(); let (nrows, ncols) = self.qr.data.shape();
let min_nrows_ncols = nrows.min(ncols); let min_nrows_ncols = nrows.min(ncols);

View File

@ -138,6 +138,7 @@ where
/// Computes the real eigenvalues of the decomposed matrix. /// Computes the real eigenvalues of the decomposed matrix.
/// ///
/// Return `None` if some eigenvalues are complex. /// Return `None` if some eigenvalues are complex.
#[must_use]
pub fn eigenvalues(&self) -> Option<OVector<T, D>> { pub fn eigenvalues(&self) -> Option<OVector<T, D>> {
if self.im.iter().all(|e| e.is_zero()) { if self.im.iter().all(|e| e.is_zero()) {
Some(self.re.clone()) Some(self.re.clone())
@ -147,6 +148,7 @@ where
} }
/// Computes the complex eigenvalues of the decomposed matrix. /// Computes the complex eigenvalues of the decomposed matrix.
#[must_use]
pub fn complex_eigenvalues(&self) -> OVector<Complex<T>, D> pub fn complex_eigenvalues(&self) -> OVector<Complex<T>, D>
where where
DefaultAllocator: Allocator<Complex<T>, D>, DefaultAllocator: Allocator<Complex<T>, D>,

View File

@ -175,6 +175,7 @@ macro_rules! svd_impl(
/// ///
/// All singular value below epsilon will be set to zero instead of being inverted. /// All singular value below epsilon will be set to zero instead of being inverted.
#[inline] #[inline]
#[must_use]
pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> { pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> {
let nrows = self.u.data.shape().0; let nrows = self.u.data.shape().0;
let ncols = self.vt.data.shape().1; let ncols = self.vt.data.shape().1;
@ -207,6 +208,7 @@ macro_rules! svd_impl(
/// This is the number of singular values that are not too small (i.e. greater than /// This is the number of singular values that are not too small (i.e. greater than
/// the given `epsilon`). /// the given `epsilon`).
#[inline] #[inline]
#[must_use]
pub fn rank(&self, epsilon: $t) -> usize { pub fn rank(&self, epsilon: $t) -> usize {
let mut i = 0; let mut i = 0;

View File

@ -138,6 +138,7 @@ where
/// The determinant of the decomposed matrix. /// The determinant of the decomposed matrix.
#[inline] #[inline]
#[must_use]
pub fn determinant(&self) -> T { pub fn determinant(&self) -> T {
let mut det = T::one(); let mut det = T::one();
for e in self.eigenvalues.iter() { for e in self.eigenvalues.iter() {
@ -150,6 +151,7 @@ where
/// Rebuild the original matrix. /// Rebuild the original matrix.
/// ///
/// This is useful if some of the eigenvalues have been manually modified. /// This is useful if some of the eigenvalues have been manually modified.
#[must_use]
pub fn recompose(&self) -> OMatrix<T, D, D> { pub fn recompose(&self) -> OMatrix<T, D, D> {
let mut u_t = self.eigenvectors.clone(); let mut u_t = self.eigenvectors.clone();
for i in 0..self.eigenvalues.len() { for i in 0..self.eigenvalues.len() {

View File

@ -21,5 +21,5 @@ quote = "1.0"
proc-macro2 = "1.0" proc-macro2 = "1.0"
[dev-dependencies] [dev-dependencies]
nalgebra = { version = "0.27.0", path = ".." } nalgebra = { version = "0.28.0", path = ".." }
trybuild = "1.0.42" trybuild = "1.0.42"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-sparse" name = "nalgebra-sparse"
version = "0.3.0" version = "0.4.0"
authors = [ "Andreas Longva", "Sébastien Crozet <developer@crozet.re>" ] authors = [ "Andreas Longva", "Sébastien Crozet <developer@crozet.re>" ]
edition = "2018" edition = "2018"
description = "Sparse matrix computation based on nalgebra." description = "Sparse matrix computation based on nalgebra."
@ -20,7 +20,7 @@ compare = [ "matrixcompare-core" ]
slow-tests = [] slow-tests = []
[dependencies] [dependencies]
nalgebra = { version="0.27", path = "../" } nalgebra = { version="0.28", path = "../" }
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
proptest = { version = "1.0", optional = true } proptest = { version = "1.0", optional = true }
matrixcompare-core = { version = "0.1.0", optional = true } matrixcompare-core = { version = "0.1.0", optional = true }
@ -28,7 +28,7 @@ matrixcompare-core = { version = "0.1.0", optional = true }
[dev-dependencies] [dev-dependencies]
itertools = "0.10" itertools = "0.10"
matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] } matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] }
nalgebra = { version="0.27", path = "../", features = ["compare"] } nalgebra = { version="0.28", path = "../", features = ["compare"] }
[package.metadata.docs.rs] [package.metadata.docs.rs]
# Enable certain features when building docs for docs.rs # Enable certain features when building docs for docs.rs

View File

@ -7,7 +7,7 @@
//! The following example illustrates how to convert between matrix formats with the `From` //! The following example illustrates how to convert between matrix formats with the `From`
//! implementations. //! implementations.
//! //!
//! ```rust //! ```
//! use nalgebra_sparse::{csr::CsrMatrix, csc::CscMatrix, coo::CooMatrix}; //! use nalgebra_sparse::{csr::CsrMatrix, csc::CscMatrix, coo::CooMatrix};
//! use nalgebra::DMatrix; //! use nalgebra::DMatrix;
//! //!

View File

@ -20,7 +20,7 @@ use crate::SparseFormatError;
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```
/// use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix, csc::CscMatrix}; /// use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix, csc::CscMatrix};
/// ///
/// // Initialize a matrix with all zeros (no explicitly stored entries). /// // Initialize a matrix with all zeros (no explicitly stored entries).
@ -45,6 +45,43 @@ pub struct CooMatrix<T> {
values: Vec<T>, values: Vec<T>,
} }
impl<T: na::Scalar> CooMatrix<T> {
/// Pushes a dense matrix into the sparse one.
///
/// This adds the dense matrix `m` starting at the `r`th row and `c`th column
/// to the matrix.
///
/// Panics
/// ------
///
/// Panics if any part of the dense matrix is out of bounds of the sparse matrix
/// when inserted at `(r, c)`.
#[inline]
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::Storage<T, R, C>>(
&mut self,
r: usize,
c: usize,
m: &na::Matrix<T, R, C, S>,
) {
let block_nrows = m.nrows();
let block_ncols = m.ncols();
let max_row_with_block = r + block_nrows - 1;
let max_col_with_block = c + block_ncols - 1;
assert!(max_row_with_block < self.nrows);
assert!(max_col_with_block < self.ncols);
self.reserve(block_ncols * block_nrows);
for (col_idx, col) in m.column_iter().enumerate() {
for (row_idx, v) in col.iter().enumerate() {
self.row_indices.push(r + row_idx);
self.col_indices.push(c + col_idx);
self.values.push(v.clone());
}
}
}
}
impl<T> CooMatrix<T> { impl<T> CooMatrix<T> {
/// Construct a zero COO matrix of the given dimensions. /// Construct a zero COO matrix of the given dimensions.
/// ///
@ -173,12 +210,14 @@ impl<T> CooMatrix<T> {
/// The number of rows in the matrix. /// The number of rows in the matrix.
#[inline] #[inline]
#[must_use]
pub fn nrows(&self) -> usize { pub fn nrows(&self) -> usize {
self.nrows self.nrows
} }
/// The number of columns in the matrix. /// The number of columns in the matrix.
#[inline] #[inline]
#[must_use]
pub fn ncols(&self) -> usize { pub fn ncols(&self) -> usize {
self.ncols self.ncols
} }
@ -189,21 +228,25 @@ impl<T> CooMatrix<T> {
/// entries, then it may have a different number of non-zeros as reported by `nnz()` compared /// entries, then it may have a different number of non-zeros as reported by `nnz()` compared
/// to its CSR representation. /// to its CSR representation.
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.values.len() self.values.len()
} }
/// The row indices of the explicitly stored entries. /// The row indices of the explicitly stored entries.
#[must_use]
pub fn row_indices(&self) -> &[usize] { pub fn row_indices(&self) -> &[usize] {
&self.row_indices &self.row_indices
} }
/// The column indices of the explicitly stored entries. /// The column indices of the explicitly stored entries.
#[must_use]
pub fn col_indices(&self) -> &[usize] { pub fn col_indices(&self) -> &[usize] {
&self.col_indices &self.col_indices
} }
/// The values of the explicitly stored entries. /// The values of the explicitly stored entries.
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
&self.values &self.values
} }

View File

@ -32,11 +32,13 @@ impl<T> CsMatrix<T> {
} }
#[inline] #[inline]
#[must_use]
pub fn pattern(&self) -> &SparsityPattern { pub fn pattern(&self) -> &SparsityPattern {
&self.sparsity_pattern &self.sparsity_pattern
} }
#[inline] #[inline]
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
&self.values &self.values
} }
@ -48,6 +50,7 @@ impl<T> CsMatrix<T> {
/// Returns the raw data represented as a tuple `(major_offsets, minor_indices, values)`. /// Returns the raw data represented as a tuple `(major_offsets, minor_indices, values)`.
#[inline] #[inline]
#[must_use]
pub fn cs_data(&self) -> (&[usize], &[usize], &[T]) { pub fn cs_data(&self) -> (&[usize], &[usize], &[T]) {
let pattern = self.pattern(); let pattern = self.pattern();
( (
@ -88,6 +91,7 @@ impl<T> CsMatrix<T> {
/// Internal method for simplifying access to a lane's data /// Internal method for simplifying access to a lane's data
#[inline] #[inline]
#[must_use]
pub fn get_index_range(&self, row_index: usize) -> Option<Range<usize>> { pub fn get_index_range(&self, row_index: usize) -> Option<Range<usize>> {
let row_begin = *self.sparsity_pattern.major_offsets().get(row_index)?; let row_begin = *self.sparsity_pattern.major_offsets().get(row_index)?;
let row_end = *self.sparsity_pattern.major_offsets().get(row_index + 1)?; let row_end = *self.sparsity_pattern.major_offsets().get(row_index + 1)?;
@ -111,6 +115,7 @@ impl<T> CsMatrix<T> {
/// Returns an entry for the given major/minor indices, or `None` if the indices are out /// Returns an entry for the given major/minor indices, or `None` if the indices are out
/// of bounds. /// of bounds.
#[must_use]
pub fn get_entry(&self, major_index: usize, minor_index: usize) -> Option<SparseEntry<T>> { pub fn get_entry(&self, major_index: usize, minor_index: usize) -> Option<SparseEntry<T>> {
let row_range = self.get_index_range(major_index)?; let row_range = self.get_index_range(major_index)?;
let (_, minor_indices, values) = self.cs_data(); let (_, minor_indices, values) = self.cs_data();
@ -139,6 +144,7 @@ impl<T> CsMatrix<T> {
get_mut_entry_from_slices(minor_dim, minor_indices, values, minor_index) get_mut_entry_from_slices(minor_dim, minor_indices, values, minor_index)
} }
#[must_use]
pub fn get_lane(&self, index: usize) -> Option<CsLane<T>> { pub fn get_lane(&self, index: usize) -> Option<CsLane<T>> {
let range = self.get_index_range(index)?; let range = self.get_index_range(index)?;
let (_, minor_indices, values) = self.cs_data(); let (_, minor_indices, values) = self.cs_data();
@ -150,6 +156,7 @@ impl<T> CsMatrix<T> {
} }
#[inline] #[inline]
#[must_use]
pub fn get_lane_mut(&mut self, index: usize) -> Option<CsLaneMut<T>> { pub fn get_lane_mut(&mut self, index: usize) -> Option<CsLaneMut<T>> {
let range = self.get_index_range(index)?; let range = self.get_index_range(index)?;
let minor_dim = self.pattern().minor_dim(); let minor_dim = self.pattern().minor_dim();
@ -172,6 +179,7 @@ impl<T> CsMatrix<T> {
} }
#[inline] #[inline]
#[must_use]
pub fn filter<P>(&self, predicate: P) -> Self pub fn filter<P>(&self, predicate: P) -> Self
where where
T: Clone, T: Clone,
@ -207,6 +215,7 @@ impl<T> CsMatrix<T> {
} }
/// Returns the diagonal of the matrix as a sparse matrix. /// Returns the diagonal of the matrix as a sparse matrix.
#[must_use]
pub fn diagonal_as_matrix(&self) -> Self pub fn diagonal_as_matrix(&self) -> Self
where where
T: Clone, T: Clone,
@ -372,26 +381,31 @@ macro_rules! impl_cs_lane_common_methods {
($name:ty) => { ($name:ty) => {
impl<'a, T> $name { impl<'a, T> $name {
#[inline] #[inline]
#[must_use]
pub fn minor_dim(&self) -> usize { pub fn minor_dim(&self) -> usize {
self.minor_dim self.minor_dim
} }
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.minor_indices.len() self.minor_indices.len()
} }
#[inline] #[inline]
#[must_use]
pub fn minor_indices(&self) -> &[usize] { pub fn minor_indices(&self) -> &[usize] {
self.minor_indices self.minor_indices
} }
#[inline] #[inline]
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
self.values self.values
} }
#[inline] #[inline]
#[must_use]
pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<T>> { pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<T>> {
get_entry_from_slices( get_entry_from_slices(
self.minor_dim, self.minor_dim,
@ -416,6 +430,7 @@ impl<'a, T> CsLaneMut<'a, T> {
(self.minor_indices, self.values) (self.minor_indices, self.values)
} }
#[must_use]
pub fn get_entry_mut(&mut self, global_minor_index: usize) -> Option<SparseEntryMut<T>> { pub fn get_entry_mut(&mut self, global_minor_index: usize) -> Option<SparseEntryMut<T>> {
get_mut_entry_from_slices( get_mut_entry_from_slices(
self.minor_dim, self.minor_dim,

View File

@ -19,7 +19,7 @@ use std::slice::{Iter, IterMut};
/// ///
/// # Usage /// # Usage
/// ///
/// ```rust /// ```
/// use nalgebra_sparse::csc::CscMatrix; /// use nalgebra_sparse::csc::CscMatrix;
/// use nalgebra::{DMatrix, Matrix3x4}; /// use nalgebra::{DMatrix, Matrix3x4};
/// use matrixcompare::assert_matrix_eq; /// use matrixcompare::assert_matrix_eq;
@ -97,7 +97,7 @@ use std::slice::{Iter, IterMut};
/// represents the matrix in a column-by-column fashion. The entries associated with column `j` are /// represents the matrix in a column-by-column fashion. The entries associated with column `j` are
/// determined as follows: /// determined as follows:
/// ///
/// ```rust /// ```
/// # let col_offsets: Vec<usize> = vec![0, 0]; /// # let col_offsets: Vec<usize> = vec![0, 0];
/// # let row_indices: Vec<usize> = vec![]; /// # let row_indices: Vec<usize> = vec![];
/// # let values: Vec<i32> = vec![]; /// # let values: Vec<i32> = vec![];
@ -192,12 +192,14 @@ impl<T> CscMatrix<T> {
/// The number of rows in the matrix. /// The number of rows in the matrix.
#[inline] #[inline]
#[must_use]
pub fn nrows(&self) -> usize { pub fn nrows(&self) -> usize {
self.cs.pattern().minor_dim() self.cs.pattern().minor_dim()
} }
/// The number of columns in the matrix. /// The number of columns in the matrix.
#[inline] #[inline]
#[must_use]
pub fn ncols(&self) -> usize { pub fn ncols(&self) -> usize {
self.cs.pattern().major_dim() self.cs.pattern().major_dim()
} }
@ -208,24 +210,28 @@ impl<T> CscMatrix<T> {
/// number of algebraically zero entries in the matrix. Explicitly stored entries can still /// number of algebraically zero entries in the matrix. Explicitly stored entries can still
/// be zero. Corresponds to the number of entries in the sparsity pattern. /// be zero. Corresponds to the number of entries in the sparsity pattern.
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.pattern().nnz() self.pattern().nnz()
} }
/// The column offsets defining part of the CSC format. /// The column offsets defining part of the CSC format.
#[inline] #[inline]
#[must_use]
pub fn col_offsets(&self) -> &[usize] { pub fn col_offsets(&self) -> &[usize] {
self.pattern().major_offsets() self.pattern().major_offsets()
} }
/// The row indices defining part of the CSC format. /// The row indices defining part of the CSC format.
#[inline] #[inline]
#[must_use]
pub fn row_indices(&self) -> &[usize] { pub fn row_indices(&self) -> &[usize] {
self.pattern().minor_indices() self.pattern().minor_indices()
} }
/// The non-zero values defining part of the CSC format. /// The non-zero values defining part of the CSC format.
#[inline] #[inline]
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
self.cs.values() self.cs.values()
} }
@ -298,6 +304,7 @@ impl<T> CscMatrix<T> {
/// ------ /// ------
/// Panics if column index is out of bounds. /// Panics if column index is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn col(&self, index: usize) -> CscCol<T> { pub fn col(&self, index: usize) -> CscCol<T> {
self.get_col(index).expect("Row index must be in bounds") self.get_col(index).expect("Row index must be in bounds")
} }
@ -315,12 +322,14 @@ impl<T> CscMatrix<T> {
/// Return the column at the given column index, or `None` if out of bounds. /// Return the column at the given column index, or `None` if out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get_col(&self, index: usize) -> Option<CscCol<T>> { pub fn get_col(&self, index: usize) -> Option<CscCol<T>> {
self.cs.get_lane(index).map(|lane| CscCol { lane }) self.cs.get_lane(index).map(|lane| CscCol { lane })
} }
/// Mutable column access for the given column index, or `None` if out of bounds. /// Mutable column access for the given column index, or `None` if out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get_col_mut(&mut self, index: usize) -> Option<CscColMut<T>> { pub fn get_col_mut(&mut self, index: usize) -> Option<CscColMut<T>> {
self.cs.get_lane_mut(index).map(|lane| CscColMut { lane }) self.cs.get_lane_mut(index).map(|lane| CscColMut { lane })
} }
@ -381,6 +390,7 @@ impl<T> CscMatrix<T> {
} }
/// Returns a reference to the underlying sparsity pattern. /// Returns a reference to the underlying sparsity pattern.
#[must_use]
pub fn pattern(&self) -> &SparsityPattern { pub fn pattern(&self) -> &SparsityPattern {
self.cs.pattern() self.cs.pattern()
} }
@ -397,6 +407,7 @@ impl<T> CscMatrix<T> {
/// ///
/// Each call to this function incurs the cost of a binary search among the explicitly /// Each call to this function incurs the cost of a binary search among the explicitly
/// stored row entries for the given column. /// stored row entries for the given column.
#[must_use]
pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<T>> { pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<T>> {
self.cs.get_entry(col_index, row_index) self.cs.get_entry(col_index, row_index)
} }
@ -422,6 +433,7 @@ impl<T> CscMatrix<T> {
/// Panics /// Panics
/// ------ /// ------
/// Panics if `row_index` or `col_index` is out of bounds. /// Panics if `row_index` or `col_index` is out of bounds.
#[must_use]
pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<T> { pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<T> {
self.get_entry(row_index, col_index) self.get_entry(row_index, col_index)
.expect("Out of bounds matrix indices encountered") .expect("Out of bounds matrix indices encountered")
@ -441,6 +453,7 @@ impl<T> CscMatrix<T> {
} }
/// Returns a triplet of slices `(col_offsets, row_indices, values)` that make up the CSC data. /// Returns a triplet of slices `(col_offsets, row_indices, values)` that make up the CSC data.
#[must_use]
pub fn csc_data(&self) -> (&[usize], &[usize], &[T]) { pub fn csc_data(&self) -> (&[usize], &[usize], &[T]) {
self.cs.cs_data() self.cs.cs_data()
} }
@ -453,6 +466,7 @@ impl<T> CscMatrix<T> {
/// Creates a sparse matrix that contains only the explicit entries decided by the /// Creates a sparse matrix that contains only the explicit entries decided by the
/// given predicate. /// given predicate.
#[must_use]
pub fn filter<P>(&self, predicate: P) -> Self pub fn filter<P>(&self, predicate: P) -> Self
where where
T: Clone, T: Clone,
@ -470,6 +484,7 @@ impl<T> CscMatrix<T> {
/// Returns a new matrix representing the upper triangular part of this matrix. /// Returns a new matrix representing the upper triangular part of this matrix.
/// ///
/// The result includes the diagonal of the matrix. /// The result includes the diagonal of the matrix.
#[must_use]
pub fn upper_triangle(&self) -> Self pub fn upper_triangle(&self) -> Self
where where
T: Clone, T: Clone,
@ -480,6 +495,7 @@ impl<T> CscMatrix<T> {
/// Returns a new matrix representing the lower triangular part of this matrix. /// Returns a new matrix representing the lower triangular part of this matrix.
/// ///
/// The result includes the diagonal of the matrix. /// The result includes the diagonal of the matrix.
#[must_use]
pub fn lower_triangle(&self) -> Self pub fn lower_triangle(&self) -> Self
where where
T: Clone, T: Clone,
@ -488,6 +504,7 @@ impl<T> CscMatrix<T> {
} }
/// Returns the diagonal of the matrix as a sparse matrix. /// Returns the diagonal of the matrix as a sparse matrix.
#[must_use]
pub fn diagonal_as_csc(&self) -> Self pub fn diagonal_as_csc(&self) -> Self
where where
T: Clone, T: Clone,
@ -498,6 +515,7 @@ impl<T> CscMatrix<T> {
} }
/// Compute the transpose of the matrix. /// Compute the transpose of the matrix.
#[must_use]
pub fn transpose(&self) -> CscMatrix<T> pub fn transpose(&self) -> CscMatrix<T>
where where
T: Scalar, T: Scalar,
@ -617,24 +635,28 @@ macro_rules! impl_csc_col_common_methods {
impl<'a, T> $name { impl<'a, T> $name {
/// The number of global rows in the column. /// The number of global rows in the column.
#[inline] #[inline]
#[must_use]
pub fn nrows(&self) -> usize { pub fn nrows(&self) -> usize {
self.lane.minor_dim() self.lane.minor_dim()
} }
/// The number of non-zeros in this column. /// The number of non-zeros in this column.
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.lane.nnz() self.lane.nnz()
} }
/// The row indices corresponding to explicitly stored entries in this column. /// The row indices corresponding to explicitly stored entries in this column.
#[inline] #[inline]
#[must_use]
pub fn row_indices(&self) -> &[usize] { pub fn row_indices(&self) -> &[usize] {
self.lane.minor_indices() self.lane.minor_indices()
} }
/// The values corresponding to explicitly stored entries in this column. /// The values corresponding to explicitly stored entries in this column.
#[inline] #[inline]
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
self.lane.values() self.lane.values()
} }
@ -643,6 +665,7 @@ macro_rules! impl_csc_col_common_methods {
/// ///
/// Each call to this function incurs the cost of a binary search among the explicitly /// Each call to this function incurs the cost of a binary search among the explicitly
/// stored row entries. /// stored row entries.
#[must_use]
pub fn get_entry(&self, global_row_index: usize) -> Option<SparseEntry<T>> { pub fn get_entry(&self, global_row_index: usize) -> Option<SparseEntry<T>> {
self.lane.get_entry(global_row_index) self.lane.get_entry(global_row_index)
} }
@ -669,6 +692,7 @@ impl<'a, T> CscColMut<'a, T> {
} }
/// Returns a mutable entry for the given global row index. /// Returns a mutable entry for the given global row index.
#[must_use]
pub fn get_entry_mut(&mut self, global_row_index: usize) -> Option<SparseEntryMut<T>> { pub fn get_entry_mut(&mut self, global_row_index: usize) -> Option<SparseEntryMut<T>> {
self.lane.get_entry_mut(global_row_index) self.lane.get_entry_mut(global_row_index)
} }

View File

@ -19,7 +19,7 @@ use std::slice::{Iter, IterMut};
/// ///
/// # Usage /// # Usage
/// ///
/// ```rust /// ```
/// use nalgebra_sparse::csr::CsrMatrix; /// use nalgebra_sparse::csr::CsrMatrix;
/// use nalgebra::{DMatrix, Matrix3x4}; /// use nalgebra::{DMatrix, Matrix3x4};
/// use matrixcompare::assert_matrix_eq; /// use matrixcompare::assert_matrix_eq;
@ -97,7 +97,7 @@ use std::slice::{Iter, IterMut};
/// represents the matrix in a row-by-row fashion. The entries associated with row `i` are /// represents the matrix in a row-by-row fashion. The entries associated with row `i` are
/// determined as follows: /// determined as follows:
/// ///
/// ```rust /// ```
/// # let row_offsets: Vec<usize> = vec![0, 0]; /// # let row_offsets: Vec<usize> = vec![0, 0];
/// # let col_indices: Vec<usize> = vec![]; /// # let col_indices: Vec<usize> = vec![];
/// # let values: Vec<i32> = vec![]; /// # let values: Vec<i32> = vec![];
@ -192,12 +192,14 @@ impl<T> CsrMatrix<T> {
/// The number of rows in the matrix. /// The number of rows in the matrix.
#[inline] #[inline]
#[must_use]
pub fn nrows(&self) -> usize { pub fn nrows(&self) -> usize {
self.cs.pattern().major_dim() self.cs.pattern().major_dim()
} }
/// The number of columns in the matrix. /// The number of columns in the matrix.
#[inline] #[inline]
#[must_use]
pub fn ncols(&self) -> usize { pub fn ncols(&self) -> usize {
self.cs.pattern().minor_dim() self.cs.pattern().minor_dim()
} }
@ -208,12 +210,14 @@ impl<T> CsrMatrix<T> {
/// number of algebraically zero entries in the matrix. Explicitly stored entries can still /// number of algebraically zero entries in the matrix. Explicitly stored entries can still
/// be zero. Corresponds to the number of entries in the sparsity pattern. /// be zero. Corresponds to the number of entries in the sparsity pattern.
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.cs.pattern().nnz() self.cs.pattern().nnz()
} }
/// The row offsets defining part of the CSR format. /// The row offsets defining part of the CSR format.
#[inline] #[inline]
#[must_use]
pub fn row_offsets(&self) -> &[usize] { pub fn row_offsets(&self) -> &[usize] {
let (offsets, _, _) = self.cs.cs_data(); let (offsets, _, _) = self.cs.cs_data();
offsets offsets
@ -221,6 +225,7 @@ impl<T> CsrMatrix<T> {
/// The column indices defining part of the CSR format. /// The column indices defining part of the CSR format.
#[inline] #[inline]
#[must_use]
pub fn col_indices(&self) -> &[usize] { pub fn col_indices(&self) -> &[usize] {
let (_, indices, _) = self.cs.cs_data(); let (_, indices, _) = self.cs.cs_data();
indices indices
@ -228,6 +233,7 @@ impl<T> CsrMatrix<T> {
/// The non-zero values defining part of the CSR format. /// The non-zero values defining part of the CSR format.
#[inline] #[inline]
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
self.cs.values() self.cs.values()
} }
@ -300,6 +306,7 @@ impl<T> CsrMatrix<T> {
/// ------ /// ------
/// Panics if row index is out of bounds. /// Panics if row index is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn row(&self, index: usize) -> CsrRow<T> { pub fn row(&self, index: usize) -> CsrRow<T> {
self.get_row(index).expect("Row index must be in bounds") self.get_row(index).expect("Row index must be in bounds")
} }
@ -317,12 +324,14 @@ impl<T> CsrMatrix<T> {
/// Return the row at the given row index, or `None` if out of bounds. /// Return the row at the given row index, or `None` if out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get_row(&self, index: usize) -> Option<CsrRow<T>> { pub fn get_row(&self, index: usize) -> Option<CsrRow<T>> {
self.cs.get_lane(index).map(|lane| CsrRow { lane }) self.cs.get_lane(index).map(|lane| CsrRow { lane })
} }
/// Mutable row access for the given row index, or `None` if out of bounds. /// Mutable row access for the given row index, or `None` if out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get_row_mut(&mut self, index: usize) -> Option<CsrRowMut<T>> { pub fn get_row_mut(&mut self, index: usize) -> Option<CsrRowMut<T>> {
self.cs.get_lane_mut(index).map(|lane| CsrRowMut { lane }) self.cs.get_lane_mut(index).map(|lane| CsrRowMut { lane })
} }
@ -383,6 +392,7 @@ impl<T> CsrMatrix<T> {
} }
/// Returns a reference to the underlying sparsity pattern. /// Returns a reference to the underlying sparsity pattern.
#[must_use]
pub fn pattern(&self) -> &SparsityPattern { pub fn pattern(&self) -> &SparsityPattern {
self.cs.pattern() self.cs.pattern()
} }
@ -399,6 +409,7 @@ impl<T> CsrMatrix<T> {
/// ///
/// Each call to this function incurs the cost of a binary search among the explicitly /// Each call to this function incurs the cost of a binary search among the explicitly
/// stored column entries for the given row. /// stored column entries for the given row.
#[must_use]
pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<T>> { pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<T>> {
self.cs.get_entry(row_index, col_index) self.cs.get_entry(row_index, col_index)
} }
@ -424,6 +435,7 @@ impl<T> CsrMatrix<T> {
/// Panics /// Panics
/// ------ /// ------
/// Panics if `row_index` or `col_index` is out of bounds. /// Panics if `row_index` or `col_index` is out of bounds.
#[must_use]
pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<T> { pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<T> {
self.get_entry(row_index, col_index) self.get_entry(row_index, col_index)
.expect("Out of bounds matrix indices encountered") .expect("Out of bounds matrix indices encountered")
@ -443,6 +455,7 @@ impl<T> CsrMatrix<T> {
} }
/// Returns a triplet of slices `(row_offsets, col_indices, values)` that make up the CSR data. /// Returns a triplet of slices `(row_offsets, col_indices, values)` that make up the CSR data.
#[must_use]
pub fn csr_data(&self) -> (&[usize], &[usize], &[T]) { pub fn csr_data(&self) -> (&[usize], &[usize], &[T]) {
self.cs.cs_data() self.cs.cs_data()
} }
@ -455,6 +468,7 @@ impl<T> CsrMatrix<T> {
/// Creates a sparse matrix that contains only the explicit entries decided by the /// Creates a sparse matrix that contains only the explicit entries decided by the
/// given predicate. /// given predicate.
#[must_use]
pub fn filter<P>(&self, predicate: P) -> Self pub fn filter<P>(&self, predicate: P) -> Self
where where
T: Clone, T: Clone,
@ -470,6 +484,7 @@ impl<T> CsrMatrix<T> {
/// Returns a new matrix representing the upper triangular part of this matrix. /// Returns a new matrix representing the upper triangular part of this matrix.
/// ///
/// The result includes the diagonal of the matrix. /// The result includes the diagonal of the matrix.
#[must_use]
pub fn upper_triangle(&self) -> Self pub fn upper_triangle(&self) -> Self
where where
T: Clone, T: Clone,
@ -480,6 +495,7 @@ impl<T> CsrMatrix<T> {
/// Returns a new matrix representing the lower triangular part of this matrix. /// Returns a new matrix representing the lower triangular part of this matrix.
/// ///
/// The result includes the diagonal of the matrix. /// The result includes the diagonal of the matrix.
#[must_use]
pub fn lower_triangle(&self) -> Self pub fn lower_triangle(&self) -> Self
where where
T: Clone, T: Clone,
@ -488,6 +504,7 @@ impl<T> CsrMatrix<T> {
} }
/// Returns the diagonal of the matrix as a sparse matrix. /// Returns the diagonal of the matrix as a sparse matrix.
#[must_use]
pub fn diagonal_as_csr(&self) -> Self pub fn diagonal_as_csr(&self) -> Self
where where
T: Clone, T: Clone,
@ -498,6 +515,7 @@ impl<T> CsrMatrix<T> {
} }
/// Compute the transpose of the matrix. /// Compute the transpose of the matrix.
#[must_use]
pub fn transpose(&self) -> CsrMatrix<T> pub fn transpose(&self) -> CsrMatrix<T>
where where
T: Scalar, T: Scalar,
@ -617,24 +635,28 @@ macro_rules! impl_csr_row_common_methods {
impl<'a, T> $name { impl<'a, T> $name {
/// The number of global columns in the row. /// The number of global columns in the row.
#[inline] #[inline]
#[must_use]
pub fn ncols(&self) -> usize { pub fn ncols(&self) -> usize {
self.lane.minor_dim() self.lane.minor_dim()
} }
/// The number of non-zeros in this row. /// The number of non-zeros in this row.
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.lane.nnz() self.lane.nnz()
} }
/// The column indices corresponding to explicitly stored entries in this row. /// The column indices corresponding to explicitly stored entries in this row.
#[inline] #[inline]
#[must_use]
pub fn col_indices(&self) -> &[usize] { pub fn col_indices(&self) -> &[usize] {
self.lane.minor_indices() self.lane.minor_indices()
} }
/// The values corresponding to explicitly stored entries in this row. /// The values corresponding to explicitly stored entries in this row.
#[inline] #[inline]
#[must_use]
pub fn values(&self) -> &[T] { pub fn values(&self) -> &[T] {
self.lane.values() self.lane.values()
} }
@ -644,6 +666,7 @@ macro_rules! impl_csr_row_common_methods {
/// Each call to this function incurs the cost of a binary search among the explicitly /// Each call to this function incurs the cost of a binary search among the explicitly
/// stored column entries. /// stored column entries.
#[inline] #[inline]
#[must_use]
pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<T>> { pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<T>> {
self.lane.get_entry(global_col_index) self.lane.get_entry(global_col_index)
} }
@ -673,6 +696,7 @@ impl<'a, T> CsrRowMut<'a, T> {
/// Returns a mutable entry for the given global column index. /// Returns a mutable entry for the given global column index.
#[inline] #[inline]
#[must_use]
pub fn get_entry_mut(&mut self, global_col_index: usize) -> Option<SparseEntryMut<T>> { pub fn get_entry_mut(&mut self, global_col_index: usize) -> Option<SparseEntryMut<T>> {
self.lane.get_entry_mut(global_col_index) self.lane.get_entry_mut(global_col_index)
} }

View File

@ -42,6 +42,7 @@ impl CscSymbolicCholesky {
} }
/// The pattern of the Cholesky factor `L`. /// The pattern of the Cholesky factor `L`.
#[must_use]
pub fn l_pattern(&self) -> &SparsityPattern { pub fn l_pattern(&self) -> &SparsityPattern {
&self.l_pattern &self.l_pattern
} }
@ -171,6 +172,7 @@ impl<T: RealField> CscCholesky<T> {
} }
/// Returns a reference to the Cholesky factor `L`. /// Returns a reference to the Cholesky factor `L`.
#[must_use]
pub fn l(&self) -> &CscMatrix<T> { pub fn l(&self) -> &CscMatrix<T> {
&self.l_factor &self.l_factor
} }
@ -260,6 +262,7 @@ impl<T: RealField> CscCholesky<T> {
/// # Panics /// # Panics
/// ///
/// Panics if `B` is not square. /// Panics if `B` is not square.
#[must_use = "Did you mean to use solve_mut()?"]
pub fn solve<'a>(&'a self, b: impl Into<DMatrixSlice<'a, T>>) -> DMatrix<T> { pub fn solve<'a>(&'a self, b: impl Into<DMatrixSlice<'a, T>>) -> DMatrix<T> {
let b = b.into(); let b = b.into();
let mut output = b.clone_owned(); let mut output = b.clone_owned();

View File

@ -73,7 +73,7 @@
//! //!
//! # Example: COO -> CSR -> matrix-vector product //! # Example: COO -> CSR -> matrix-vector product
//! //!
//! ```rust //! ```
//! use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix}; //! use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix};
//! use nalgebra::{DMatrix, DVector}; //! use nalgebra::{DMatrix, DVector};
//! use matrixcompare::assert_matrix_eq; //! use matrixcompare::assert_matrix_eq;
@ -93,6 +93,9 @@
//! coo.push(1, 2, 1.3); //! coo.push(1, 2, 1.3);
//! coo.push(2, 2, 4.1); //! coo.push(2, 2, 4.1);
//! //!
//! // ... or add entire dense matrices like so:
//! // coo.push_matrix(0, 0, &dense);
//!
//! // The simplest way to construct a CSR matrix is to first construct a COO matrix, and //! // The simplest way to construct a CSR matrix is to first construct a COO matrix, and
//! // then convert it to CSR. The `From` trait is implemented for conversions between different //! // then convert it to CSR. The `From` trait is implemented for conversions between different
//! // sparse matrix types. //! // sparse matrix types.
@ -170,6 +173,7 @@ pub struct SparseFormatError {
impl SparseFormatError { impl SparseFormatError {
/// The type of error. /// The type of error.
#[must_use]
pub fn kind(&self) -> &SparseFormatErrorKind { pub fn kind(&self) -> &SparseFormatErrorKind {
&self.kind &self.kind
} }

View File

@ -90,7 +90,7 @@
//! `C <- 3.0 * C + 2.0 * A^T * B`, where `A`, `B`, `C` are matrices and `A^T` is the transpose //! `C <- 3.0 * C + 2.0 * A^T * B`, where `A`, `B`, `C` are matrices and `A^T` is the transpose
//! of `A`. The simplest way to write this is: //! of `A`. The simplest way to write this is:
//! //!
//! ```rust //! ```
//! # use nalgebra_sparse::csr::CsrMatrix; //! # use nalgebra_sparse::csr::CsrMatrix;
//! # let a = CsrMatrix::identity(10); let b = CsrMatrix::identity(10); //! # let a = CsrMatrix::identity(10); let b = CsrMatrix::identity(10);
//! # let mut c = CsrMatrix::identity(10); //! # let mut c = CsrMatrix::identity(10);
@ -109,7 +109,7 @@
//! //!
//! An alternative way to implement this expression (here using CSR matrices) is: //! An alternative way to implement this expression (here using CSR matrices) is:
//! //!
//! ```rust //! ```
//! # use nalgebra_sparse::csr::CsrMatrix; //! # use nalgebra_sparse::csr::CsrMatrix;
//! # let a = CsrMatrix::identity(10); let b = CsrMatrix::identity(10); //! # let a = CsrMatrix::identity(10); let b = CsrMatrix::identity(10);
//! # let mut c = CsrMatrix::identity(10); //! # let mut c = CsrMatrix::identity(10);
@ -140,11 +140,13 @@ pub enum Op<T> {
impl<T> Op<T> { impl<T> Op<T> {
/// Returns a reference to the inner value that the operation applies to. /// Returns a reference to the inner value that the operation applies to.
#[must_use]
pub fn inner_ref(&self) -> &T { pub fn inner_ref(&self) -> &T {
self.as_ref().into_inner() self.as_ref().into_inner()
} }
/// Returns an `Op` applied to a reference of the inner value. /// Returns an `Op` applied to a reference of the inner value.
#[must_use]
pub fn as_ref(&self) -> Op<&T> { pub fn as_ref(&self) -> Op<&T> {
match self { match self {
Op::NoOp(obj) => Op::NoOp(&obj), Op::NoOp(obj) => Op::NoOp(&obj),

View File

@ -96,11 +96,13 @@ impl OperationError {
} }
/// The operation error kind. /// The operation error kind.
#[must_use]
pub fn kind(&self) -> &OperationErrorKind { pub fn kind(&self) -> &OperationErrorKind {
&self.error_kind &self.error_kind
} }
/// The underlying error message. /// The underlying error message.
#[must_use]
pub fn message(&self) -> &str { pub fn message(&self) -> &str {
self.message.as_str() self.message.as_str()
} }

View File

@ -60,18 +60,21 @@ impl SparsityPattern {
/// The offsets for the major dimension. /// The offsets for the major dimension.
#[inline] #[inline]
#[must_use]
pub fn major_offsets(&self) -> &[usize] { pub fn major_offsets(&self) -> &[usize] {
&self.major_offsets &self.major_offsets
} }
/// The indices for the minor dimension. /// The indices for the minor dimension.
#[inline] #[inline]
#[must_use]
pub fn minor_indices(&self) -> &[usize] { pub fn minor_indices(&self) -> &[usize] {
&self.minor_indices &self.minor_indices
} }
/// The number of major lanes in the pattern. /// The number of major lanes in the pattern.
#[inline] #[inline]
#[must_use]
pub fn major_dim(&self) -> usize { pub fn major_dim(&self) -> usize {
assert!(self.major_offsets.len() > 0); assert!(self.major_offsets.len() > 0);
self.major_offsets.len() - 1 self.major_offsets.len() - 1
@ -79,12 +82,14 @@ impl SparsityPattern {
/// The number of minor lanes in the pattern. /// The number of minor lanes in the pattern.
#[inline] #[inline]
#[must_use]
pub fn minor_dim(&self) -> usize { pub fn minor_dim(&self) -> usize {
self.minor_dim self.minor_dim
} }
/// The number of "non-zeros", i.e. explicitly stored entries in the pattern. /// The number of "non-zeros", i.e. explicitly stored entries in the pattern.
#[inline] #[inline]
#[must_use]
pub fn nnz(&self) -> usize { pub fn nnz(&self) -> usize {
self.minor_indices.len() self.minor_indices.len()
} }
@ -96,12 +101,14 @@ impl SparsityPattern {
/// ///
/// Panics if `major_index` is out of bounds. /// Panics if `major_index` is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn lane(&self, major_index: usize) -> &[usize] { pub fn lane(&self, major_index: usize) -> &[usize] {
self.get_lane(major_index).unwrap() self.get_lane(major_index).unwrap()
} }
/// Get the lane at the given index, or `None` if out of bounds. /// Get the lane at the given index, or `None` if out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get_lane(&self, major_index: usize) -> Option<&[usize]> { pub fn get_lane(&self, major_index: usize) -> Option<&[usize]> {
let offset_begin = *self.major_offsets().get(major_index)?; let offset_begin = *self.major_offsets().get(major_index)?;
let offset_end = *self.major_offsets().get(major_index + 1)?; let offset_end = *self.major_offsets().get(major_index + 1)?;
@ -197,6 +204,7 @@ impl SparsityPattern {
/// assert_eq!(entries, vec![(0, 0), (0, 2), (1, 1), (2, 0)]); /// assert_eq!(entries, vec![(0, 0), (0, 2), (1, 1), (2, 0)]);
/// ``` /// ```
/// ///
#[must_use]
pub fn entries(&self) -> SparsityPatternIter { pub fn entries(&self) -> SparsityPatternIter {
SparsityPatternIter::from_pattern(self) SparsityPatternIter::from_pattern(self)
} }
@ -228,6 +236,7 @@ impl SparsityPattern {
/// ///
/// This is analogous to matrix transposition, i.e. an entry `(i, j)` becomes `(j, i)` in the /// This is analogous to matrix transposition, i.e. an entry `(i, j)` becomes `(j, i)` in the
/// new pattern. /// new pattern.
#[must_use]
pub fn transpose(&self) -> Self { pub fn transpose(&self) -> Self {
// By using unit () values, we can use the same routines as for CSR/CSC matrices // By using unit () values, we can use the same routines as for CSR/CSC matrices
let values = vec![(); self.nnz()]; let values = vec![(); self.nnz()];

View File

@ -252,3 +252,95 @@ fn coo_push_out_of_bounds_entries() {
assert_panics!(coo.clone().push(3, 2, 1)); assert_panics!(coo.clone().push(3, 2, 1));
} }
} }
#[test]
fn coo_push_matrix_valid_entries() {
let mut coo = CooMatrix::new(3, 3);
// Works with static
{
// new is row-major...
let inserted = nalgebra::SMatrix::<i32, 2, 2>::new(1, 2, 3, 4);
coo.push_matrix(1, 1, &inserted);
// insert happens column-major, so expect transposition when read this way
assert_eq!(
coo.triplet_iter().collect::<Vec<_>>(),
vec![(1, 1, &1), (2, 1, &3), (1, 2, &2), (2, 2, &4)]
);
}
// Works with owned dynamic
{
let inserted = nalgebra::DMatrix::<i32>::repeat(1, 2, 5);
coo.push_matrix(0, 0, &inserted);
assert_eq!(
coo.triplet_iter().collect::<Vec<_>>(),
vec![
(1, 1, &1),
(2, 1, &3),
(1, 2, &2),
(2, 2, &4),
(0, 0, &5),
(0, 1, &5)
]
);
}
// Works with sliced
{
let source = nalgebra::SMatrix::<i32, 2, 2>::new(6, 7, 8, 9);
let sliced = source.fixed_slice::<2, 1>(0, 0);
coo.push_matrix(1, 0, &sliced);
assert_eq!(
coo.triplet_iter().collect::<Vec<_>>(),
vec![
(1, 1, &1),
(2, 1, &3),
(1, 2, &2),
(2, 2, &4),
(0, 0, &5),
(0, 1, &5),
(1, 0, &6),
(2, 0, &8)
]
);
}
}
#[test]
fn coo_push_matrix_out_of_bounds_entries() {
// 0x0
{
let inserted = nalgebra::SMatrix::<i32, 1, 1>::new(1);
assert_panics!(CooMatrix::new(0, 0).push_matrix(0, 0, &inserted));
}
// 0x1
{
let inserted = nalgebra::SMatrix::<i32, 1, 1>::new(1);
assert_panics!(CooMatrix::new(1, 0).push_matrix(0, 0, &inserted));
}
// 1x0
{
let inserted = nalgebra::SMatrix::<i32, 1, 1>::new(1);
assert_panics!(CooMatrix::new(0, 1).push_matrix(0, 0, &inserted));
}
// 3x3 exceeds col-dim
{
let inserted = nalgebra::SMatrix::<i32, 1, 2>::repeat(1);
assert_panics!(CooMatrix::new(3, 3).push_matrix(0, 2, &inserted));
}
// 3x3 exceeds row-dim
{
let inserted = nalgebra::SMatrix::<i32, 2, 1>::repeat(1);
assert_panics!(CooMatrix::new(3, 3).push_matrix(2, 0, &inserted));
}
// 3x3 exceeds row-dim and row-dim
{
let inserted = nalgebra::SMatrix::<i32, 2, 2>::repeat(1);
assert_panics!(CooMatrix::new(3, 3).push_matrix(2, 2, &inserted));
}
}

View File

@ -40,6 +40,7 @@ pub trait Reallocator<T: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
/// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer /// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer
/// `buf`. Data stored by `buf` are linearly copied to the output: /// `buf`. Data stored by `buf` are linearly copied to the output:
/// ///
/// # Safety
/// * The copy is performed as if both were just arrays (without a matrix structure). /// * The copy is performed as if both were just arrays (without a matrix structure).
/// * If `buf` is larger than the output size, then extra elements of `buf` are truncated. /// * If `buf` is larger than the output size, then extra elements of `buf` are truncated.
/// * If `buf` is smaller than the output size, then extra elements of the output are left /// * If `buf` is smaller than the output size, then extra elements of the output are left

View File

@ -101,8 +101,8 @@ where
} }
#[inline] #[inline]
fn as_slice(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(self.ptr(), R * C) } std::slice::from_raw_parts(self.ptr(), R * C)
} }
} }
@ -118,8 +118,8 @@ where
} }
#[inline] #[inline]
fn as_mut_slice(&mut self) -> &mut [T] { unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
unsafe { std::slice::from_raw_parts_mut(self.ptr_mut(), R * C) } std::slice::from_raw_parts_mut(self.ptr_mut(), R * C)
} }
} }
@ -286,11 +286,7 @@ where
unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
for element in self.as_mut_slice() { for element in self.as_mut_slice() {
let temp = bytes; let temp = bytes;
bytes = if let Some(remainder) = element.exhume(temp) { bytes = element.exhume(temp)?
remainder
} else {
return None;
}
} }
Some(bytes) Some(bytes)
} }
@ -327,7 +323,7 @@ mod rkyv_impl {
for ArrayStorage<T, R, C> for ArrayStorage<T, R, C>
{ {
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> { fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
Ok(self.0.serialize(serializer)?) self.0.serialize(serializer)
} }
} }

View File

@ -193,6 +193,7 @@ where
/// ``` /// ```
/// ///
#[inline] #[inline]
#[must_use]
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
@ -221,6 +222,7 @@ where
/// assert_ne!(vec1.dotc(&vec2), vec1.dot(&vec2)); /// assert_ne!(vec1.dotc(&vec2), vec1.dot(&vec2));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where where
T: SimdComplexField, T: SimdComplexField,
@ -248,6 +250,7 @@ where
/// assert_eq!(mat1.tr_dot(&mat2), 9.1); /// assert_eq!(mat1.tr_dot(&mat2), 9.1);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
@ -275,6 +278,7 @@ where
} }
} }
#[allow(clippy::too_many_arguments)]
fn array_axcpy<T>( fn array_axcpy<T>(
y: &mut [T], y: &mut [T],
a: T, a: T,
@ -331,6 +335,7 @@ where
/// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0)); /// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0));
/// ``` /// ```
#[inline] #[inline]
#[allow(clippy::many_single_char_names)]
pub fn axcpy<D2: Dim, SB>(&mut self, a: T, x: &Vector<T, D2, SB>, c: T, b: T) pub fn axcpy<D2: Dim, SB>(&mut self, a: T, x: &Vector<T, D2, SB>, c: T, b: T)
where where
SB: Storage<T, D2>, SB: Storage<T, D2>,
@ -341,13 +346,17 @@ where
let rstride1 = self.strides().0; let rstride1 = self.strides().0;
let rstride2 = x.strides().0; let rstride2 = x.strides().0;
let y = self.data.as_mut_slice(); unsafe {
let x = x.data.as_slice(); // SAFETY: the conversion to slices is OK because we access the
// elements taking the strides into account.
let y = self.data.as_mut_slice_unchecked();
let x = x.data.as_slice_unchecked();
if !b.is_zero() { if !b.is_zero() {
array_axcpy(y, a, x, c, b, rstride1, rstride2, x.len()); array_axcpy(y, a, x, c, b, rstride1, rstride2, x.len());
} else { } else {
array_axc(y, a, x, c, rstride1, rstride2, x.len()); array_axc(y, a, x, c, rstride1, rstride2, x.len());
}
} }
} }
@ -1379,12 +1388,12 @@ where
{ {
work.gemv(T::one(), mid, &rhs.column(0), T::zero()); work.gemv(T::one(), mid, &rhs.column(0), T::zero());
self.column_mut(0) self.column_mut(0)
.gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); .gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
for j in 1..rhs.ncols() { for j in 1..rhs.ncols() {
work.gemv(T::one(), mid, &rhs.column(j), T::zero()); work.gemv(T::one(), mid, &rhs.column(j), T::zero());
self.column_mut(j) self.column_mut(j)
.gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); .gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
} }
} }

View File

@ -386,7 +386,7 @@ impl<T: Scalar + Zero + One + ClosedMul + ClosedAdd, D: DimName, S: Storage<T, D
(D::dim() - 1, 0), (D::dim() - 1, 0),
(Const::<1>, DimNameDiff::<D, U1>::name()), (Const::<1>, DimNameDiff::<D, U1>::name()),
) )
.tr_dot(&shift); .tr_dot(shift);
let post_translation = self.generic_slice( let post_translation = self.generic_slice(
(0, 0), (0, 0),
(DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()), (DimNameDiff::<D, U1>::name(), DimNameDiff::<D, U1>::name()),
@ -423,7 +423,7 @@ where
(D::dim() - 1, 0), (D::dim() - 1, 0),
(Const::<1>, DimNameDiff::<D, U1>::name()), (Const::<1>, DimNameDiff::<D, U1>::name()),
); );
let n = normalizer.tr_dot(&v); let n = normalizer.tr_dot(v);
if !n.is_zero() { if !n.is_zero() {
return transform * (v / n); return transform * (v / n);

View File

@ -28,6 +28,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0)) /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0))
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn abs(&self) -> OMatrix<T, R, C> pub fn abs(&self) -> OMatrix<T, R, C>
where where
T: Signed, T: Signed,
@ -49,6 +50,7 @@ macro_rules! component_binop_impl(
($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$( ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$(
#[doc = $desc] #[doc = $desc]
#[inline] #[inline]
#[must_use]
pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> MatrixComponentOp<T, R1, C1, R2, C2> pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> MatrixComponentOp<T, R1, C1, R2, C2>
where T: $Trait, where T: $Trait,
R2: Dim, C2: Dim, R2: Dim, C2: Dim,
@ -251,6 +253,7 @@ impl<T: Scalar, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
/// assert_eq!(u.inf(&v), expected) /// assert_eq!(u.inf(&v), expected)
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inf(&self, other: &Self) -> OMatrix<T, R1, C1> pub fn inf(&self, other: &Self) -> OMatrix<T, R1, C1>
where where
T: SimdPartialOrd, T: SimdPartialOrd,
@ -271,6 +274,7 @@ impl<T: Scalar, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
/// assert_eq!(u.sup(&v), expected) /// assert_eq!(u.sup(&v), expected)
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn sup(&self, other: &Self) -> OMatrix<T, R1, C1> pub fn sup(&self, other: &Self) -> OMatrix<T, R1, C1>
where where
T: SimdPartialOrd, T: SimdPartialOrd,
@ -291,6 +295,7 @@ impl<T: Scalar, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
/// assert_eq!(u.inf_sup(&v), expected) /// assert_eq!(u.inf_sup(&v), expected)
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inf_sup(&self, other: &Self) -> (OMatrix<T, R1, C1>, OMatrix<T, R1, C1>) pub fn inf_sup(&self, other: &Self) -> (OMatrix<T, R1, C1>, OMatrix<T, R1, C1>)
where where
T: SimdPartialOrd, T: SimdPartialOrd,

View File

@ -53,7 +53,10 @@ impl<T: Scalar, R: Dim, C: Dim> OMatrix<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
{ {
/// Creates a new uninitialized matrix. If the matrix has a compile-time dimension, this panics /// Creates a new uninitialized matrix.
///
/// # Safety
/// If the matrix has a compile-time dimension, this panics
/// if `nrows != R::to_usize()` or `ncols != C::to_usize()`. /// if `nrows != R::to_usize()` or `ncols != C::to_usize()`.
#[inline] #[inline]
pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> mem::MaybeUninit<Self> { pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> mem::MaybeUninit<Self> {
@ -827,7 +830,7 @@ where
Standard: Distribution<T>, Standard: Distribution<T>,
{ {
#[inline] #[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> OMatrix<T, R, C> { fn sample<G: Rng + ?Sized>(&self, rng: &mut G) -> OMatrix<T, R, C> {
let nrows = R::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10)); let nrows = R::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10));
let ncols = C::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10)); let ncols = C::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10));
@ -864,7 +867,7 @@ where
{ {
/// Generate a uniformly distributed random unit vector. /// Generate a uniformly distributed random unit vector.
#[inline] #[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Unit<OVector<T, D>> { fn sample<G: Rng + ?Sized>(&self, rng: &mut G) -> Unit<OVector<T, D>> {
Unit::new_normalize(OVector::from_distribution_generic( Unit::new_normalize(OVector::from_distribution_generic(
D::name(), D::name(),
Const::<1>, Const::<1>,
@ -906,6 +909,7 @@ macro_rules! componentwise_constructors_impl(
impl<T> Matrix<T, Const<$R>, Const<$C>, ArrayStorage<T, $R, $C>> { impl<T> Matrix<T, Const<$R>, Const<$C>, ArrayStorage<T, $R, $C>> {
/// Initializes this matrix from its components. /// Initializes this matrix from its components.
#[inline] #[inline]
#[allow(clippy::too_many_arguments)]
pub const fn new($($($args: T),*),*) -> Self { pub const fn new($($($args: T),*),*) -> Self {
unsafe { unsafe {
Self::from_data_statically_unchecked( Self::from_data_statically_unchecked(

View File

@ -10,6 +10,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
{ {
/// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances. /// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances.
/// ///
/// # Safety
/// This method is unsafe because the input data array is not checked to contain enough elements. /// This method is unsafe because the input data array is not checked to contain enough elements.
/// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
#[inline] #[inline]
@ -59,6 +60,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> { impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> {
/// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances. /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances.
/// ///
/// # Safety
/// This method is unsafe because the input data array is not checked to contain enough elements. /// This method is unsafe because the input data array is not checked to contain enough elements.
/// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
#[inline] #[inline]
@ -146,6 +148,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
{ {
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances. /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
/// ///
/// # Safety
/// This method is unsafe because the input data array is not checked to contain enough elements. /// This method is unsafe because the input data array is not checked to contain enough elements.
/// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
#[inline] #[inline]
@ -217,6 +220,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> { impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
/// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances. /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
/// ///
/// # Safety
/// This method is unsafe because the input data array is not checked to contain enough elements. /// This method is unsafe because the input data array is not checked to contain enough elements.
/// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
#[inline] #[inline]

View File

@ -1,8 +1,8 @@
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
use simba::scalar::{SubsetOf, SupersetOf}; use simba::scalar::{SubsetOf, SupersetOf};
use std::borrow::{Borrow, BorrowMut};
use std::convert::{AsMut, AsRef, From, Into}; use std::convert::{AsMut, AsRef, From, Into};
use std::mem;
use simba::simd::{PrimitiveSimdValue, SimdValue}; use simba::simd::{PrimitiveSimdValue, SimdValue};
@ -110,11 +110,11 @@ impl<T: Scalar, const D: usize> From<[T; D]> for SVector<T, D> {
} }
} }
impl<T: Scalar, const D: usize> Into<[T; D]> for SVector<T, D> { impl<T: Scalar, const D: usize> From<SVector<T, D>> for [T; D] {
#[inline] #[inline]
fn into(self) -> [T; D] { fn from(vec: SVector<T, D>) -> Self {
// TODO: unfortunately, we must clone because we can move out of an array. // TODO: unfortunately, we must clone because we can move out of an array.
self.data.0[0].clone() vec.data.0[0].clone()
} }
} }
@ -128,13 +128,13 @@ where
} }
} }
impl<T: Scalar, const D: usize> Into<[T; D]> for RowSVector<T, D> impl<T: Scalar, const D: usize> From<RowSVector<T, D>> for [T; D]
where where
Const<D>: IsNotStaticOne, Const<D>: IsNotStaticOne,
{ {
#[inline] #[inline]
fn into(self) -> [T; D] { fn from(vec: RowSVector<T, D>) -> [T; D] {
self.transpose().into() vec.transpose().into()
} }
} }
@ -146,7 +146,7 @@ macro_rules! impl_from_into_asref_1D(
#[inline] #[inline]
fn as_ref(&self) -> &[T; $SZ] { fn as_ref(&self) -> &[T; $SZ] {
unsafe { unsafe {
mem::transmute(self.data.ptr()) &*(self.data.ptr() as *const [T; $SZ])
} }
} }
} }
@ -157,7 +157,7 @@ macro_rules! impl_from_into_asref_1D(
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [T; $SZ] { fn as_mut(&mut self) -> &mut [T; $SZ] {
unsafe { unsafe {
mem::transmute(self.data.ptr_mut()) &mut *(self.data.ptr_mut() as *mut [T; $SZ])
} }
} }
} }
@ -186,39 +186,54 @@ impl<T: Scalar, const R: usize, const C: usize> From<[[T; R]; C]> for SMatrix<T,
} }
} }
impl<T: Scalar, const R: usize, const C: usize> Into<[[T; R]; C]> for SMatrix<T, R, C> { impl<T: Scalar, const R: usize, const C: usize> From<SMatrix<T, R, C>> for [[T; R]; C] {
#[inline] #[inline]
fn into(self) -> [[T; R]; C] { fn from(vec: SMatrix<T, R, C>) -> Self {
self.data.0 vec.data.0
} }
} }
macro_rules! impl_from_into_asref_2D( macro_rules! impl_from_into_asref_borrow_2D(
($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$(
impl<T: Scalar, S> AsRef<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S> //does the impls on one case for either AsRef/AsMut and Borrow/BorrowMut
(
($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr);
$Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
) => {
impl<T: Scalar, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorage<T, $NRows, $NCols> { where S: ContiguousStorage<T, $NRows, $NCols> {
#[inline] #[inline]
fn as_ref(&self) -> &[[T; $SZRows]; $SZCols] { fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
unsafe { unsafe {
mem::transmute(self.data.ptr()) &*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
} }
} }
} }
impl<T: Scalar, S> AsMut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S> impl<T: Scalar, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorageMut<T, $NRows, $NCols> { where S: ContiguousStorageMut<T, $NRows, $NCols> {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] { fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
unsafe { unsafe {
mem::transmute(self.data.ptr_mut()) &mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols])
} }
} }
} }
};
//collects the mappings from typenum pairs to consts
($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$(
impl_from_into_asref_borrow_2D!(
($NRows, $NCols) => ($SZRows, $SZCols); AsRef.as_ref(), AsMut.as_mut()
);
impl_from_into_asref_borrow_2D!(
($NRows, $NCols) => ($SZRows, $SZCols); Borrow.borrow(), BorrowMut.borrow_mut()
);
)*} )*}
); );
// Implement for matrices with shape 2x2 .. 6x6. // Implement for matrices with shape 2x2 .. 6x6.
impl_from_into_asref_2D!( impl_from_into_asref_borrow_2D!(
(U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6); (U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6);
(U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6); (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6);
(U4, U2) => (4, 2); (U4, U3) => (4, 3); (U4, U4) => (4, 4); (U4, U5) => (4, 5); (U4, U6) => (4, 6); (U4, U2) => (4, 2); (U4, U3) => (4, 3); (U4, U4) => (4, 4); (U4, U5) => (4, 5); (U4, U6) => (4, 6);
@ -427,21 +442,21 @@ impl<'a, T: Scalar> From<Vec<T>> for DVector<T> {
} }
} }
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> Into<&'a [T]> impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>>
for &'a Matrix<T, R, C, S> From<&'a Matrix<T, R, C, S>> for &'a [T]
{ {
#[inline] #[inline]
fn into(self) -> &'a [T] { fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
self.as_slice() matrix.as_slice()
} }
} }
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> Into<&'a mut [T]> impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>>
for &'a mut Matrix<T, R, C, S> From<&'a mut Matrix<T, R, C, S>> for &'a mut [T]
{ {
#[inline] #[inline]
fn into(self) -> &'a mut [T] { fn from(matrix: &'a mut Matrix<T, R, C, S>) -> Self {
self.as_mut_slice() matrix.as_mut_slice()
} }
} }
@ -452,6 +467,12 @@ impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorSlice<'a, T> {
} }
} }
impl<'a, T: Scalar> From<DVectorSlice<'a, T>> for &'a [T] {
fn from(vec: DVectorSlice<'a, T>) -> &'a [T] {
vec.data.into_slice()
}
}
impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> { impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> {
#[inline] #[inline]
fn from(slice: &'a mut [T]) -> Self { fn from(slice: &'a mut [T]) -> Self {
@ -459,6 +480,12 @@ impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> {
} }
} }
impl<'a, T: Scalar> From<DVectorSliceMut<'a, T>> for &'a mut [T] {
fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] {
vec.data.into_slice_mut()
}
}
impl<T: Scalar + PrimitiveSimdValue, R: Dim, C: Dim> From<[OMatrix<T::Element, R, C>; 2]> impl<T: Scalar + PrimitiveSimdValue, R: Dim, C: Dim> From<[OMatrix<T::Element, R, C>; 2]>
for OMatrix<T, R, C> for OMatrix<T, R, C>
where where

View File

@ -4,7 +4,6 @@
//! components using their names. For example, if `v` is a 3D vector, one can write `v.z` instead //! components using their names. For example, if `v` is a 3D vector, one can write `v.z` instead
//! of `v[2]`. //! of `v[2]`.
use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
@ -38,7 +37,7 @@ macro_rules! deref_impl(
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self.data.ptr()) } unsafe { &*(self.data.ptr() as *const Self::Target) }
} }
} }
@ -46,7 +45,7 @@ macro_rules! deref_impl(
where S: ContiguousStorageMut<T, $R, $C> { where S: ContiguousStorageMut<T, $R, $C> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self.data.ptr_mut()) } unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) }
} }
} }
} }

View File

@ -16,7 +16,7 @@ use crate::base::array_storage::ArrayStorage;
#[cfg(any(feature = "alloc", feature = "std"))] #[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic; use crate::base::dimension::Dynamic;
use crate::base::dimension::{Dim, DimName}; use crate::base::dimension::{Dim, DimName};
use crate::base::storage::{Storage, StorageMut}; use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::vec_storage::VecStorage; use crate::base::vec_storage::VecStorage;
use crate::base::Scalar; use crate::base::Scalar;

View File

@ -20,7 +20,7 @@ pub struct Dynamic {
impl Dynamic { impl Dynamic {
/// A dynamic size equal to `value`. /// A dynamic size equal to `value`.
#[inline] #[inline]
pub fn new(value: usize) -> Self { pub const fn new(value: usize) -> Self {
Self { value } Self { value }
} }
} }

View File

@ -11,13 +11,14 @@ use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, Shap
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::dimension::Dynamic; use crate::base::dimension::Dynamic;
use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1}; use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1};
use crate::base::storage::{ReshapableStorage, Storage, StorageMut}; use crate::base::storage::{ContiguousStorageMut, ReshapableStorage, Storage, StorageMut};
use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector}; use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector};
/// # Rows and columns extraction /// # Rows and columns extraction
impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Extracts the upper triangular part of this matrix (including the diagonal). /// Extracts the upper triangular part of this matrix (including the diagonal).
#[inline] #[inline]
#[must_use]
pub fn upper_triangle(&self) -> OMatrix<T, R, C> pub fn upper_triangle(&self) -> OMatrix<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
@ -30,6 +31,7 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Extracts the lower triangular part of this matrix (including the diagonal). /// Extracts the lower triangular part of this matrix (including the diagonal).
#[inline] #[inline]
#[must_use]
pub fn lower_triangle(&self) -> OMatrix<T, R, C> pub fn lower_triangle(&self) -> OMatrix<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
@ -42,6 +44,7 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Creates a new matrix by extracting the given set of rows from `self`. /// Creates a new matrix by extracting the given set of rows from `self`.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
#[must_use]
pub fn select_rows<'a, I>(&self, irows: I) -> OMatrix<T, Dynamic, C> pub fn select_rows<'a, I>(&self, irows: I) -> OMatrix<T, Dynamic, C>
where where
I: IntoIterator<Item = &'a usize>, I: IntoIterator<Item = &'a usize>,
@ -78,6 +81,7 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Creates a new matrix by extracting the given set of columns from `self`. /// Creates a new matrix by extracting the given set of columns from `self`.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
#[must_use]
pub fn select_columns<'a, I>(&self, icols: I) -> OMatrix<T, R, Dynamic> pub fn select_columns<'a, I>(&self, icols: I) -> OMatrix<T, R, Dynamic>
where where
I: IntoIterator<Item = &'a usize>, I: IntoIterator<Item = &'a usize>,
@ -583,6 +587,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix. /// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix.
/// ///
/// # Safety
/// The added column values are not initialized. /// The added column values are not initialized.
#[inline] #[inline]
pub unsafe fn insert_columns_generic_uninitialized<D>( pub unsafe fn insert_columns_generic_uninitialized<D>(
@ -664,6 +669,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Inserts `ninsert.value()` rows at the `i-th` place of this matrix. /// Inserts `ninsert.value()` rows at the `i-th` place of this matrix.
/// ///
/// # Safety
/// The added rows values are not initialized. /// The added rows values are not initialized.
/// This is the generic implementation of `.insert_rows(...)` and /// This is the generic implementation of `.insert_rows(...)` and
/// `.insert_fixed_rows(...)` which have nicer API interfaces. /// `.insert_fixed_rows(...)` which have nicer API interfaces.

View File

@ -44,7 +44,7 @@ impl<D: Dim> DimRange<D> for usize {
#[test] #[test]
fn dimrange_usize() { fn dimrange_usize() {
assert_eq!(DimRange::contained_by(&0, Const::<0>), false); assert_eq!(DimRange::contained_by(&0, Const::<0>), false);
assert_eq!(DimRange::contained_by(&0, Const::<1>), true); assert!(DimRange::contained_by(&0, Const::<1>));
} }
impl<D: Dim> DimRange<D> for ops::Range<usize> { impl<D: Dim> DimRange<D> for ops::Range<usize> {
@ -68,24 +68,23 @@ impl<D: Dim> DimRange<D> for ops::Range<usize> {
#[test] #[test]
fn dimrange_range_usize() { fn dimrange_range_usize() {
use std::usize::MAX;
assert_eq!(DimRange::contained_by(&(0..0), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..0), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(0..1), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..1), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(0..1), Const::<1>), true); assert!(DimRange::contained_by(&(0..1), Const::<1>));
assert!(DimRange::contained_by(
&((usize::MAX - 1)..usize::MAX),
Dynamic::new(usize::MAX)
));
assert_eq!( assert_eq!(
DimRange::contained_by(&((MAX - 1)..MAX), Dynamic::new(MAX)), DimRange::length(&((usize::MAX - 1)..usize::MAX), Dynamic::new(usize::MAX)),
true
);
assert_eq!(
DimRange::length(&((MAX - 1)..MAX), Dynamic::new(MAX)),
Dynamic::new(1) Dynamic::new(1)
); );
assert_eq!( assert_eq!(
DimRange::length(&(MAX..(MAX - 1)), Dynamic::new(MAX)), DimRange::length(&(usize::MAX..(usize::MAX - 1)), Dynamic::new(usize::MAX)),
Dynamic::new(0) Dynamic::new(0)
); );
assert_eq!( assert_eq!(
DimRange::length(&(MAX..MAX), Dynamic::new(MAX)), DimRange::length(&(usize::MAX..usize::MAX), Dynamic::new(usize::MAX)),
Dynamic::new(0) Dynamic::new(0)
); );
} }
@ -111,20 +110,19 @@ impl<D: Dim> DimRange<D> for ops::RangeFrom<usize> {
#[test] #[test]
fn dimrange_rangefrom_usize() { fn dimrange_rangefrom_usize() {
use std::usize::MAX;
assert_eq!(DimRange::contained_by(&(0..), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(0..), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(0..), Const::<1>), true); assert!(DimRange::contained_by(&(0..), Const::<1>));
assert!(DimRange::contained_by(
&((usize::MAX - 1)..),
Dynamic::new(usize::MAX)
));
assert_eq!( assert_eq!(
DimRange::contained_by(&((MAX - 1)..), Dynamic::new(MAX)), DimRange::length(&((usize::MAX - 1)..), Dynamic::new(usize::MAX)),
true
);
assert_eq!(
DimRange::length(&((MAX - 1)..), Dynamic::new(MAX)),
Dynamic::new(1) Dynamic::new(1)
); );
assert_eq!( assert_eq!(
DimRange::length(&(MAX..), Dynamic::new(MAX)), DimRange::length(&(usize::MAX..), Dynamic::new(usize::MAX)),
Dynamic::new(0) Dynamic::new(0)
); );
} }
@ -177,7 +175,7 @@ impl<D: Dim> DimRange<D> for ops::RangeFull {
#[test] #[test]
fn dimrange_rangefull() { fn dimrange_rangefull() {
assert_eq!(DimRange::contained_by(&(..), Const::<0>), true); assert!(DimRange::contained_by(&(..), Const::<0>));
assert_eq!(DimRange::length(&(..), Const::<1>), Const::<1>); assert_eq!(DimRange::length(&(..), Const::<1>), Const::<1>);
} }
@ -206,32 +204,31 @@ impl<D: Dim> DimRange<D> for ops::RangeInclusive<usize> {
#[test] #[test]
fn dimrange_rangeinclusive_usize() { fn dimrange_rangeinclusive_usize() {
use std::usize::MAX;
assert_eq!(DimRange::contained_by(&(0..=0), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..=0), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(0..=0), Const::<1>), true); assert!(DimRange::contained_by(&(0..=0), Const::<1>));
assert_eq!( assert_eq!(
DimRange::contained_by(&(MAX..=MAX), Dynamic::new(MAX)), DimRange::contained_by(&(usize::MAX..=usize::MAX), Dynamic::new(usize::MAX)),
false false
); );
assert_eq!( assert_eq!(
DimRange::contained_by(&((MAX - 1)..=MAX), Dynamic::new(MAX)), DimRange::contained_by(&((usize::MAX - 1)..=usize::MAX), Dynamic::new(usize::MAX)),
false false
); );
assert_eq!( assert!(DimRange::contained_by(
DimRange::contained_by(&((MAX - 1)..=(MAX - 1)), Dynamic::new(MAX)), &((usize::MAX - 1)..=(usize::MAX - 1)),
true Dynamic::new(usize::MAX)
); ));
assert_eq!(DimRange::length(&(0..=0), Const::<1>), Dynamic::new(1)); assert_eq!(DimRange::length(&(0..=0), Const::<1>), Dynamic::new(1));
assert_eq!( assert_eq!(
DimRange::length(&((MAX - 1)..=MAX), Dynamic::new(MAX)), DimRange::length(&((usize::MAX - 1)..=usize::MAX), Dynamic::new(usize::MAX)),
Dynamic::new(2) Dynamic::new(2)
); );
assert_eq!( assert_eq!(
DimRange::length(&(MAX..=(MAX - 1)), Dynamic::new(MAX)), DimRange::length(&(usize::MAX..=(usize::MAX - 1)), Dynamic::new(usize::MAX)),
Dynamic::new(0) Dynamic::new(0)
); );
assert_eq!( assert_eq!(
DimRange::length(&(MAX..=MAX), Dynamic::new(MAX)), DimRange::length(&(usize::MAX..=usize::MAX), Dynamic::new(usize::MAX)),
Dynamic::new(1) Dynamic::new(1)
); );
} }
@ -257,21 +254,20 @@ impl<D: Dim> DimRange<D> for ops::RangeTo<usize> {
#[test] #[test]
fn dimrange_rangeto_usize() { fn dimrange_rangeto_usize() {
use std::usize::MAX; assert!(DimRange::contained_by(&(..0), Const::<0>));
assert_eq!(DimRange::contained_by(&(..0), Const::<0>), true);
assert_eq!(DimRange::contained_by(&(..1), Const::<0>), false); assert_eq!(DimRange::contained_by(&(..1), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(..0), Const::<1>), true); assert!(DimRange::contained_by(&(..0), Const::<1>));
assert!(DimRange::contained_by(
&(..(usize::MAX - 1)),
Dynamic::new(usize::MAX)
));
assert_eq!( assert_eq!(
DimRange::contained_by(&(..(MAX - 1)), Dynamic::new(MAX)), DimRange::length(&(..(usize::MAX - 1)), Dynamic::new(usize::MAX)),
true Dynamic::new(usize::MAX - 1)
); );
assert_eq!( assert_eq!(
DimRange::length(&(..(MAX - 1)), Dynamic::new(MAX)), DimRange::length(&(..usize::MAX), Dynamic::new(usize::MAX)),
Dynamic::new(MAX - 1) Dynamic::new(usize::MAX)
);
assert_eq!(
DimRange::length(&(..MAX), Dynamic::new(MAX)),
Dynamic::new(MAX)
); );
} }
@ -296,21 +292,20 @@ impl<D: Dim> DimRange<D> for ops::RangeToInclusive<usize> {
#[test] #[test]
fn dimrange_rangetoinclusive_usize() { fn dimrange_rangetoinclusive_usize() {
use std::usize::MAX;
assert_eq!(DimRange::contained_by(&(..=0), Const::<0>), false); assert_eq!(DimRange::contained_by(&(..=0), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(..=1), Const::<0>), false); assert_eq!(DimRange::contained_by(&(..=1), Const::<0>), false);
assert_eq!(DimRange::contained_by(&(..=0), Const::<1>), true); assert!(DimRange::contained_by(&(..=0), Const::<1>));
assert_eq!( assert_eq!(
DimRange::contained_by(&(..=(MAX)), Dynamic::new(MAX)), DimRange::contained_by(&(..=(usize::MAX)), Dynamic::new(usize::MAX)),
false false
); );
assert!(DimRange::contained_by(
&(..=(usize::MAX - 1)),
Dynamic::new(usize::MAX)
));
assert_eq!( assert_eq!(
DimRange::contained_by(&(..=(MAX - 1)), Dynamic::new(MAX)), DimRange::length(&(..=(usize::MAX - 1)), Dynamic::new(usize::MAX)),
true Dynamic::new(usize::MAX)
);
assert_eq!(
DimRange::length(&(..=(MAX - 1)), Dynamic::new(MAX)),
Dynamic::new(MAX)
); );
} }
@ -485,6 +480,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Produces a view of the data at the given index, or /// Produces a view of the data at the given index, or
/// `None` if the index is out of bounds. /// `None` if the index is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get<'a, I>(&'a self, index: I) -> Option<I::Output> pub fn get<'a, I>(&'a self, index: I) -> Option<I::Output>
where where
I: MatrixIndex<'a, T, R, C, S>, I: MatrixIndex<'a, T, R, C, S>,
@ -495,6 +491,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Produces a mutable view of the data at the given index, or /// Produces a mutable view of the data at the given index, or
/// `None` if the index is out of bounds. /// `None` if the index is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut> pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
where where
S: StorageMut<T, R, C>, S: StorageMut<T, R, C>,
@ -506,6 +503,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Produces a view of the data at the given index, or /// Produces a view of the data at the given index, or
/// panics if the index is out of bounds. /// panics if the index is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn index<'a, I>(&'a self, index: I) -> I::Output pub fn index<'a, I>(&'a self, index: I) -> I::Output
where where
I: MatrixIndex<'a, T, R, C, S>, I: MatrixIndex<'a, T, R, C, S>,
@ -527,6 +525,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Produces a view of the data at the given index, without doing /// Produces a view of the data at the given index, without doing
/// any bounds checking. /// any bounds checking.
#[inline] #[inline]
#[must_use]
pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::Output pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::Output
where where
I: MatrixIndex<'a, T, R, C, S>, I: MatrixIndex<'a, T, R, C, S>,
@ -537,6 +536,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a mutable view of the data at the given index, without doing /// Returns a mutable view of the data at the given index, without doing
/// any bounds checking. /// any bounds checking.
#[inline] #[inline]
#[must_use]
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where where
S: StorageMut<T, R, C>, S: StorageMut<T, R, C>,

View File

@ -20,6 +20,7 @@ impl<T: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Stor
/// let y = Vector3::new(10.0, 20.0, 30.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)); /// assert_eq!(x.lerp(&y, 0.1), Vector3::new(1.9, 3.8, 5.7));
/// ``` /// ```
#[must_use]
pub fn lerp<S2: Storage<T, D>>(&self, rhs: &Vector<T, D, S2>, t: T) -> OVector<T, D> pub fn lerp<S2: Storage<T, D>>(&self, rhs: &Vector<T, D, S2>, t: T) -> OVector<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -45,6 +46,7 @@ impl<T: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Stor
/// ///
/// assert_eq!(v, v2.normalize()); /// assert_eq!(v, v2.normalize());
/// ``` /// ```
#[must_use]
pub fn slerp<S2: Storage<T, D>>(&self, rhs: &Vector<T, D, S2>, t: T) -> OVector<T, D> pub fn slerp<S2: Storage<T, D>>(&self, rhs: &Vector<T, D, S2>, t: T) -> OVector<T, D>
where where
T: RealField, T: RealField,
@ -72,6 +74,7 @@ impl<T: RealField, D: Dim, S: Storage<T, D>> Unit<Vector<T, D, S>> {
/// ///
/// assert_eq!(v, v2); /// assert_eq!(v, v2);
/// ``` /// ```
#[must_use]
pub fn slerp<S2: Storage<T, D>>( pub fn slerp<S2: Storage<T, D>>(
&self, &self,
rhs: &Unit<Vector<T, D, S2>>, rhs: &Unit<Vector<T, D, S2>>,
@ -89,6 +92,7 @@ impl<T: RealField, D: Dim, S: Storage<T, D>> Unit<Vector<T, D, S>> {
/// ///
/// Returns `None` if the two vectors are almost collinear and with opposite direction /// Returns `None` if the two vectors are almost collinear and with opposite direction
/// (in this case, there is an infinity of possible results). /// (in this case, there is an infinity of possible results).
#[must_use]
pub fn try_slerp<S2: Storage<T, D>>( pub fn try_slerp<S2: Storage<T, D>>(
&self, &self,
rhs: &Unit<Vector<T, D, S2>>, rhs: &Unit<Vector<T, D, S2>>,

View File

@ -96,6 +96,10 @@ macro_rules! iterator {
let stride = self.strides.0.value(); let stride = self.strides.0.value();
self.ptr = self.ptr.add(stride); self.ptr = self.ptr.add(stride);
} }
// We want either `& *last` or `&mut *last` here, depending
// on the mutability of `$Ref`.
#[allow(clippy::transmute_ptr_to_ref)]
Some(mem::transmute(old)) Some(mem::transmute(old))
} }
} }
@ -139,13 +143,13 @@ macro_rules! iterator {
let inner_remaining = self.size % inner_size; let inner_remaining = self.size % inner_size;
// Compute pointer to last element // Compute pointer to last element
let last = self.ptr.offset( let last = self
(outer_remaining * outer_stride + inner_remaining * inner_stride) .ptr
as isize, .add((outer_remaining * outer_stride + inner_remaining * inner_stride));
);
// We want either `& *last` or `&mut *last` here, depending // We want either `& *last` or `&mut *last` here, depending
// on the mutability of `$Ref`. // on the mutability of `$Ref`.
#[allow(clippy::transmute_ptr_to_ref)]
Some(mem::transmute(last)) Some(mem::transmute(last))
} }
} }

View File

@ -336,7 +336,7 @@ mod rkyv_impl {
for Matrix<T, R, C, S> for Matrix<T, R, C, S>
{ {
fn serialize(&self, serializer: &mut _S) -> Result<Self::Resolver, _S::Error> { fn serialize(&self, serializer: &mut _S) -> Result<Self::Resolver, _S::Error> {
Ok(self.data.serialize(serializer)?) self.data.serialize(serializer)
} }
} }
@ -441,6 +441,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// let mat = Matrix3x4::<f32>::zeros(); /// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.shape(), (3, 4)); /// assert_eq!(mat.shape(), (3, 4));
#[inline] #[inline]
#[must_use]
pub fn shape(&self) -> (usize, usize) { pub fn shape(&self) -> (usize, usize) {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.data.shape();
(nrows.value(), ncols.value()) (nrows.value(), ncols.value())
@ -455,6 +456,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// let mat = Matrix3x4::<f32>::zeros(); /// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.nrows(), 3); /// assert_eq!(mat.nrows(), 3);
#[inline] #[inline]
#[must_use]
pub fn nrows(&self) -> usize { pub fn nrows(&self) -> usize {
self.shape().0 self.shape().0
} }
@ -468,6 +470,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// let mat = Matrix3x4::<f32>::zeros(); /// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.ncols(), 4); /// assert_eq!(mat.ncols(), 4);
#[inline] #[inline]
#[must_use]
pub fn ncols(&self) -> usize { pub fn ncols(&self) -> usize {
self.shape().1 self.shape().1
} }
@ -483,6 +486,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// // The column strides is the number of steps (here 2) multiplied by the corresponding dimension. /// // The column strides is the number of steps (here 2) multiplied by the corresponding dimension.
/// assert_eq!(mat.strides(), (1, 10)); /// assert_eq!(mat.strides(), (1, 10));
#[inline] #[inline]
#[must_use]
pub fn strides(&self) -> (usize, usize) { pub fn strides(&self) -> (usize, usize) {
let (srows, scols) = self.data.strides(); let (srows, scols) = self.data.strides();
(srows.value(), scols.value()) (srows.value(), scols.value())
@ -501,6 +505,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m[i], m[3]); /// assert_eq!(m[i], m[3]);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn vector_to_matrix_index(&self, i: usize) -> (usize, usize) { pub fn vector_to_matrix_index(&self, i: usize) -> (usize, usize) {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
@ -529,6 +534,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(unsafe { *ptr }, m[0]); /// assert_eq!(unsafe { *ptr }, m[0]);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn as_ptr(&self) -> *const T { pub fn as_ptr(&self) -> *const T {
self.data.ptr() self.data.ptr()
} }
@ -537,6 +543,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// ///
/// See `relative_eq` from the `RelativeEq` trait for more details. /// See `relative_eq` from the `RelativeEq` trait for more details.
#[inline] #[inline]
#[must_use]
pub fn relative_eq<R2, C2, SB>( pub fn relative_eq<R2, C2, SB>(
&self, &self,
other: &Matrix<T, R2, C2, SB>, other: &Matrix<T, R2, C2, SB>,
@ -559,6 +566,8 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Tests whether `self` and `rhs` are exactly equal. /// Tests whether `self` and `rhs` are exactly equal.
#[inline] #[inline]
#[must_use]
#[allow(clippy::should_implement_trait)]
pub fn eq<R2, C2, SB>(&self, other: &Matrix<T, R2, C2, SB>) -> bool pub fn eq<R2, C2, SB>(&self, other: &Matrix<T, R2, C2, SB>) -> bool
where where
T: PartialEq, T: PartialEq,
@ -609,6 +618,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Clones this matrix to one that owns its data. /// Clones this matrix to one that owns its data.
#[inline] #[inline]
#[must_use]
pub fn clone_owned(&self) -> OMatrix<T, R, C> pub fn clone_owned(&self) -> OMatrix<T, R, C>
where where
DefaultAllocator: Allocator<T, R, C>, DefaultAllocator: Allocator<T, R, C>,
@ -619,6 +629,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Clones this matrix into one that owns its data. The actual type of the result depends on /// Clones this matrix into one that owns its data. The actual type of the result depends on
/// matrix storage combination rules for addition. /// matrix storage combination rules for addition.
#[inline] #[inline]
#[must_use]
pub fn clone_owned_sum<R2, C2>(&self) -> MatrixSum<T, R, C, R2, C2> pub fn clone_owned_sum<R2, C2>(&self) -> MatrixSum<T, R, C, R2, C2>
where where
R2: Dim, R2: Dim,
@ -692,6 +703,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each of its entries. /// Returns a matrix containing the result of `f` applied to each of its entries.
#[inline] #[inline]
#[must_use]
pub fn map<T2: Scalar, F: FnMut(T) -> T2>(&self, mut f: F) -> OMatrix<T2, R, C> pub fn map<T2: Scalar, F: FnMut(T) -> T2>(&self, mut f: F) -> OMatrix<T2, R, C>
where where
DefaultAllocator: Allocator<T2, R, C>, DefaultAllocator: Allocator<T2, R, C>,
@ -738,6 +750,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// - If the matrix has has least one component, then `init_f` is called with the first component /// - If the matrix has has least one component, then `init_f` is called with the first component
/// to compute the initial value. Folding then continues on all the remaining components of the matrix. /// to compute the initial value. Folding then continues on all the remaining components of the matrix.
#[inline] #[inline]
#[must_use]
pub fn fold_with<T2>( pub fn fold_with<T2>(
&self, &self,
init_f: impl FnOnce(Option<&T>) -> T2, init_f: impl FnOnce(Option<&T>) -> T2,
@ -751,6 +764,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`, /// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
/// `f` also gets passed the row and column index, i.e. `f(row, col, value)`. /// `f` also gets passed the row and column index, i.e. `f(row, col, value)`.
#[inline] #[inline]
#[must_use]
pub fn map_with_location<T2: Scalar, F: FnMut(usize, usize, T) -> T2>( pub fn map_with_location<T2: Scalar, F: FnMut(usize, usize, T) -> T2>(
&self, &self,
mut f: F, mut f: F,
@ -778,6 +792,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each entries of `self` and /// Returns a matrix containing the result of `f` applied to each entries of `self` and
/// `rhs`. /// `rhs`.
#[inline] #[inline]
#[must_use]
pub fn zip_map<T2, N3, S2, F>(&self, rhs: &Matrix<T2, R, C, S2>, mut f: F) -> OMatrix<N3, R, C> pub fn zip_map<T2, N3, S2, F>(&self, rhs: &Matrix<T2, R, C, S2>, mut f: F) -> OMatrix<N3, R, C>
where where
T2: Scalar, T2: Scalar,
@ -813,6 +828,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each entries of `self` and /// Returns a matrix containing the result of `f` applied to each entries of `self` and
/// `b`, and `c`. /// `b`, and `c`.
#[inline] #[inline]
#[must_use]
pub fn zip_zip_map<T2, N3, N4, S2, S3, F>( pub fn zip_zip_map<T2, N3, N4, S2, S3, F>(
&self, &self,
b: &Matrix<T2, R, C, S2>, b: &Matrix<T2, R, C, S2>,
@ -860,6 +876,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Folds a function `f` on each entry of `self`. /// Folds a function `f` on each entry of `self`.
#[inline] #[inline]
#[must_use]
pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, T) -> Acc) -> Acc { pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, T) -> Acc) -> Acc {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.data.shape();
@ -879,6 +896,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Folds a function `f` on each pairs of entries from `self` and `rhs`. /// Folds a function `f` on each pairs of entries from `self` and `rhs`.
#[inline] #[inline]
#[must_use]
pub fn zip_fold<T2, R2, C2, S2, Acc>( pub fn zip_fold<T2, R2, C2, S2, Acc>(
&self, &self,
rhs: &Matrix<T2, R2, C2, S2>, rhs: &Matrix<T2, R2, C2, S2>,
@ -1238,6 +1256,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> { impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// Gets a reference to the i-th element of this column vector without bound checking. /// Gets a reference to the i-th element of this column vector without bound checking.
#[inline] #[inline]
#[must_use]
pub unsafe fn vget_unchecked(&self, i: usize) -> &T { pub unsafe fn vget_unchecked(&self, i: usize) -> &T {
debug_assert!(i < self.nrows(), "Vector index out of bounds."); debug_assert!(i < self.nrows(), "Vector index out of bounds.");
let i = i * self.strides().0; let i = i * self.strides().0;
@ -1248,6 +1267,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
impl<T: Scalar, D: Dim, S: StorageMut<T, D>> Vector<T, D, S> { impl<T: Scalar, D: Dim, S: StorageMut<T, D>> Vector<T, D, S> {
/// Gets a mutable reference to the i-th element of this column vector without bound checking. /// Gets a mutable reference to the i-th element of this column vector without bound checking.
#[inline] #[inline]
#[must_use]
pub unsafe fn vget_unchecked_mut(&mut self, i: usize) -> &mut T { pub unsafe fn vget_unchecked_mut(&mut self, i: usize) -> &mut T {
debug_assert!(i < self.nrows(), "Vector index out of bounds."); debug_assert!(i < self.nrows(), "Vector index out of bounds.");
let i = i * self.strides().0; let i = i * self.strides().0;
@ -1258,6 +1278,7 @@ impl<T: Scalar, D: Dim, S: StorageMut<T, D>> Vector<T, D, S> {
impl<T: Scalar, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> Matrix<T, R, C, S> {
/// Extracts a slice containing the entire matrix entries ordered column-by-columns. /// Extracts a slice containing the entire matrix entries ordered column-by-columns.
#[inline] #[inline]
#[must_use]
pub fn as_slice(&self) -> &[T] { pub fn as_slice(&self) -> &[T] {
self.data.as_slice() self.data.as_slice()
} }
@ -1266,6 +1287,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>> Matrix<T, R, C, S
impl<T: Scalar, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Extracts a mutable slice containing the entire matrix entries ordered column-by-columns. /// Extracts a mutable slice containing the entire matrix entries ordered column-by-columns.
#[inline] #[inline]
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] { pub fn as_mut_slice(&mut self) -> &mut [T] {
self.data.as_mut_slice() self.data.as_mut_slice()
} }
@ -1446,6 +1468,7 @@ impl<T: SimdComplexField, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
impl<T: Scalar, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> { impl<T: Scalar, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
/// The diagonal of this matrix. /// The diagonal of this matrix.
#[inline] #[inline]
#[must_use]
pub fn diagonal(&self) -> OVector<T, D> pub fn diagonal(&self) -> OVector<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -1457,6 +1480,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
/// ///
/// This is a more efficient version of `self.diagonal().map(f)` since this /// This is a more efficient version of `self.diagonal().map(f)` since this
/// allocates only once. /// allocates only once.
#[must_use]
pub fn map_diagonal<T2: Scalar>(&self, mut f: impl FnMut(T) -> T2) -> OVector<T2, D> pub fn map_diagonal<T2: Scalar>(&self, mut f: impl FnMut(T) -> T2) -> OVector<T2, D>
where where
DefaultAllocator: Allocator<T2, D>, DefaultAllocator: Allocator<T2, D>,
@ -1481,6 +1505,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
/// Computes a trace of a square matrix, i.e., the sum of its diagonal elements. /// Computes a trace of a square matrix, i.e., the sum of its diagonal elements.
#[inline] #[inline]
#[must_use]
pub fn trace(&self) -> T pub fn trace(&self) -> T
where where
T: Scalar + Zero + ClosedAdd, T: Scalar + Zero + ClosedAdd,
@ -1504,6 +1529,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
impl<T: SimdComplexField, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> { impl<T: SimdComplexField, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
/// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`. /// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`.
#[inline] #[inline]
#[must_use]
pub fn symmetric_part(&self) -> OMatrix<T, D, D> pub fn symmetric_part(&self) -> OMatrix<T, D, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
@ -1520,6 +1546,7 @@ impl<T: SimdComplexField, D: Dim, S: Storage<T, D, D>> SquareMatrix<T, D, S> {
/// The hermitian part of `self`, i.e., `0.5 * (self + self.adjoint())`. /// The hermitian part of `self`, i.e., `0.5 * (self + self.adjoint())`.
#[inline] #[inline]
#[must_use]
pub fn hermitian_part(&self) -> OMatrix<T, D, D> pub fn hermitian_part(&self) -> OMatrix<T, D, D>
where where
DefaultAllocator: Allocator<T, D, D>, DefaultAllocator: Allocator<T, D, D>,
@ -1542,6 +1569,7 @@ impl<T: Scalar + Zero + One, D: DimAdd<U1> + IsNotStaticOne, S: Storage<T, D, D>
/// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and /// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and
/// and setting the diagonal element to `1`. /// and setting the diagonal element to `1`.
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimSum<D, U1>, DimSum<D, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimSum<D, U1>, DimSum<D, U1>>
where where
DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>>, DefaultAllocator: Allocator<T, DimSum<D, U1>, DimSum<D, U1>>,
@ -1553,7 +1581,7 @@ impl<T: Scalar + Zero + One, D: DimAdd<U1> + IsNotStaticOne, S: Storage<T, D, D>
let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1); let dim = DimSum::<D, U1>::from_usize(self.nrows() + 1);
let mut res = OMatrix::identity_generic(dim, dim); let mut res = OMatrix::identity_generic(dim, dim);
res.generic_slice_mut::<D, D>((0, 0), self.data.shape()) res.generic_slice_mut::<D, D>((0, 0), self.data.shape())
.copy_from(&self); .copy_from(self);
res res
} }
} }
@ -1562,6 +1590,7 @@ impl<T: Scalar + Zero, D: DimAdd<U1>, S: Storage<T, D>> Vector<T, D, S> {
/// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its /// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its
/// coordinates. /// coordinates.
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OVector<T, DimSum<D, U1>> pub fn to_homogeneous(&self) -> OVector<T, DimSum<D, U1>>
where where
DefaultAllocator: Allocator<T, DimSum<D, U1>>, DefaultAllocator: Allocator<T, DimSum<D, U1>>,
@ -1589,6 +1618,7 @@ impl<T: Scalar + Zero, D: DimAdd<U1>, S: Storage<T, D>> Vector<T, D, S> {
impl<T: Scalar + Zero, D: DimAdd<U1>, S: Storage<T, D>> Vector<T, D, S> { impl<T: Scalar + Zero, D: DimAdd<U1>, S: Storage<T, D>> Vector<T, D, S> {
/// Constructs a new vector of higher dimension by appending `element` to the end of `self`. /// Constructs a new vector of higher dimension by appending `element` to the end of `self`.
#[inline] #[inline]
#[must_use]
pub fn push(&self, element: T) -> OVector<T, DimSum<D, U1>> pub fn push(&self, element: T) -> OVector<T, DimSum<D, U1>>
where where
DefaultAllocator: Allocator<T, DimSum<D, U1>>, DefaultAllocator: Allocator<T, DimSum<D, U1>>,
@ -1789,7 +1819,6 @@ macro_rules! impl_fmt {
where where
T: Scalar + $trait, T: Scalar + $trait,
S: Storage<T, R, C>, S: Storage<T, R, C>,
DefaultAllocator: Allocator<usize, R, C>,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -1807,20 +1836,17 @@ macro_rules! impl_fmt {
4 4
} }
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.shape();
if nrows.value() == 0 || ncols.value() == 0 { if nrows == 0 || ncols == 0 {
return write!(f, "[ ]"); return write!(f, "[ ]");
} }
let mut max_length = 0; let mut max_length = 0;
let mut lengths: OMatrix<usize, R, C> = Matrix::zeros_generic(nrows, ncols);
let (nrows, ncols) = self.shape();
for i in 0..nrows { for i in 0..nrows {
for j in 0..ncols { for j in 0..ncols {
lengths[(i, j)] = val_width(&self[(i, j)], f); max_length = crate::max(max_length, val_width(&self[(i, j)], f));
max_length = crate::max(max_length, lengths[(i, j)]);
} }
} }
@ -1837,7 +1863,7 @@ macro_rules! impl_fmt {
for i in 0..nrows { for i in 0..nrows {
write!(f, "")?; write!(f, "")?;
for j in 0..ncols { for j in 0..ncols {
let number_length = lengths[(i, j)] + 1; let number_length = val_width(&self[(i, j)], f) + 1;
let pad = max_length_with_space - number_length; let pad = max_length_with_space - number_length;
write!(f, " {:>thepad$}", "", thepad = pad)?; write!(f, " {:>thepad$}", "", thepad = pad)?;
match f.precision() { match f.precision() {
@ -1870,19 +1896,29 @@ impl_fmt!(fmt::UpperHex, "{:X}", "{:1$X}");
impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}"); impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}");
impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}");
#[test] #[cfg(test)]
fn lower_exp() { mod tests {
let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.); #[test]
assert_eq!( fn empty_display() {
format!("{:e}", test), let vec: Vec<f64> = Vec::new();
r" let dvector = crate::DVector::from_vec(vec);
assert_eq!(format!("{}", dvector), "[ ]")
}
#[test]
fn lower_exp() {
let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.);
assert_eq!(
format!("{:e}", test),
r"
1e6 2e5 1e6 2e5
2e-5 1e0 2e-5 1e0
" "
) )
}
} }
/// # Cross product /// # Cross product
@ -1891,6 +1927,7 @@ impl<T: Scalar + ClosedAdd + ClosedSub + ClosedMul, R: Dim, C: Dim, S: Storage<T
{ {
/// The perpendicular product between two 2D column vectors, i.e. `a.x * b.y - a.y * b.x`. /// The perpendicular product between two 2D column vectors, i.e. `a.x * b.y - a.y * b.x`.
#[inline] #[inline]
#[must_use]
pub fn perp<R2, C2, SB>(&self, b: &Matrix<T, R2, C2, SB>) -> T pub fn perp<R2, C2, SB>(&self, b: &Matrix<T, R2, C2, SB>) -> T
where where
R2: Dim, R2: Dim,
@ -1920,6 +1957,7 @@ impl<T: Scalar + ClosedAdd + ClosedSub + ClosedMul, R: Dim, C: Dim, S: Storage<T
/// Panics if the shape is not 3D vector. In the future, this will be implemented only for /// Panics if the shape is not 3D vector. In the future, this will be implemented only for
/// dynamically-sized matrices and statically-sized 3D matrices. /// dynamically-sized matrices and statically-sized 3D matrices.
#[inline] #[inline]
#[must_use]
pub fn cross<R2, C2, SB>(&self, b: &Matrix<T, R2, C2, SB>) -> MatrixCross<T, R, C, R2, C2> pub fn cross<R2, C2, SB>(&self, b: &Matrix<T, R2, C2, SB>) -> MatrixCross<T, R, C, R2, C2>
where where
R2: Dim, R2: Dim,
@ -1993,6 +2031,7 @@ impl<T: Scalar + ClosedAdd + ClosedSub + ClosedMul, R: Dim, C: Dim, S: Storage<T
impl<T: Scalar + Field, S: Storage<T, U3>> Vector<T, U3, S> { impl<T: Scalar + Field, S: Storage<T, U3>> Vector<T, U3, S> {
/// Computes the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`. /// Computes the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`.
#[inline] #[inline]
#[must_use]
pub fn cross_matrix(&self) -> OMatrix<T, U3, U3> { pub fn cross_matrix(&self) -> OMatrix<T, U3, U3> {
OMatrix::<T, U3, U3>::new( OMatrix::<T, U3, U3>::new(
T::zero(), T::zero(),
@ -2011,6 +2050,7 @@ impl<T: Scalar + Field, S: Storage<T, U3>> Vector<T, U3, S> {
impl<T: SimdComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: SimdComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// The smallest angle between two vectors. /// The smallest angle between two vectors.
#[inline] #[inline]
#[must_use]
pub fn angle<R2: Dim, C2: Dim, SB>(&self, other: &Matrix<T, R2, C2, SB>) -> T::SimdRealField pub fn angle<R2: Dim, C2: Dim, SB>(&self, other: &Matrix<T, R2, C2, SB>) -> T::SimdRealField
where where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,

View File

@ -1,5 +1,5 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Range, RangeFrom, RangeFull, RangeTo}; use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
use std::slice; use std::slice;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
@ -77,6 +77,23 @@ macro_rules! slice_storage_impl(
$T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides) $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides)
} }
} }
impl <'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
$T<'a, T, R, C, RStride, CStride>
where
Self: ContiguousStorage<T, R, C>
{
/// Extracts the original slice from this storage
pub fn into_slice(self) -> &'a [T] {
let (nrows, ncols) = self.shape();
if nrows.value() != 0 && ncols.value() != 0 {
let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
unsafe { slice::from_raw_parts(self.ptr, sz + 1) }
} else {
unsafe { slice::from_raw_parts(self.ptr, 0) }
}
}
}
} }
); );
@ -108,6 +125,23 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
} }
} }
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
SliceStorageMut<'a, T, R, C, RStride, CStride>
where
Self: ContiguousStorageMut<T, R, C>,
{
/// Extracts the original slice from this storage
pub fn into_slice_mut(self) -> &'a mut [T] {
let (nrows, ncols) = self.shape();
if nrows.value() != 0 && ncols.value() != 0 {
let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) }
} else {
unsafe { slice::from_raw_parts_mut(self.ptr, 0) }
}
}
}
macro_rules! storage_impl( macro_rules! storage_impl(
($($T: ident),* $(,)*) => {$( ($($T: ident),* $(,)*) => {$(
unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C> unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C>
@ -162,14 +196,14 @@ macro_rules! storage_impl(
} }
#[inline] #[inline]
fn as_slice(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
if nrows.value() != 0 && ncols.value() != 0 { if nrows.value() != 0 && ncols.value() != 0 {
let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
unsafe { slice::from_raw_parts(self.ptr, sz + 1) } slice::from_raw_parts(self.ptr, sz + 1)
} }
else { else {
unsafe { slice::from_raw_parts(self.ptr, 0) } slice::from_raw_parts(self.ptr, 0)
} }
} }
} }
@ -187,13 +221,13 @@ unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMu
} }
#[inline] #[inline]
fn as_mut_slice(&mut self) -> &mut [T] { unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
if nrows.value() != 0 && ncols.value() != 0 { if nrows.value() != 0 && ncols.value() != 0 {
let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) } slice::from_raw_parts_mut(self.ptr, sz + 1)
} else { } else {
unsafe { slice::from_raw_parts_mut(self.ptr, 0) } slice::from_raw_parts_mut(self.ptr, 0)
} }
} }
} }
@ -806,12 +840,32 @@ impl<D: Dim> SliceRange<D> for RangeFull {
} }
} }
impl<D: Dim> SliceRange<D> for RangeInclusive<usize> {
type Size = Dynamic;
#[inline(always)]
fn begin(&self, _: D) -> usize {
*self.start()
}
#[inline(always)]
fn end(&self, _: D) -> usize {
*self.end() + 1
}
#[inline(always)]
fn size(&self, _: D) -> Self::Size {
Dynamic::new(*self.end() + 1 - *self.start())
}
}
// TODO: see how much of this overlaps with the general indexing // TODO: see how much of this overlaps with the general indexing
// methods from indexing.rs. // methods from indexing.rs.
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed
/// by the range `cols`. /// by the range `cols`.
#[inline] #[inline]
#[must_use]
pub fn slice_range<RowRange, ColRange>( pub fn slice_range<RowRange, ColRange>(
&self, &self,
rows: RowRange, rows: RowRange,
@ -830,6 +884,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Slice containing all the rows indexed by the range `rows`. /// Slice containing all the rows indexed by the range `rows`.
#[inline] #[inline]
#[must_use]
pub fn rows_range<RowRange: SliceRange<R>>( pub fn rows_range<RowRange: SliceRange<R>>(
&self, &self,
rows: RowRange, rows: RowRange,
@ -839,6 +894,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Slice containing all the columns indexed by the range `rows`. /// Slice containing all the columns indexed by the range `rows`.
#[inline] #[inline]
#[must_use]
pub fn columns_range<ColRange: SliceRange<C>>( pub fn columns_range<ColRange: SliceRange<C>>(
&self, &self,
cols: ColRange, cols: ColRange,

View File

@ -13,6 +13,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0); /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn amax(&self) -> T pub fn amax(&self) -> T
where where
T: Zero + SimdSigned + SimdPartialOrd, T: Zero + SimdSigned + SimdPartialOrd,
@ -33,6 +34,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Complex::new(1.0, 3.0)).camax(), 5.0); /// Complex::new(1.0, 3.0)).camax(), 5.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn camax(&self) -> T::SimdRealField pub fn camax(&self) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -52,6 +54,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(Vector3::new(5u32, 2, 3).max(), 5); /// assert_eq!(Vector3::new(5u32, 2, 3).max(), 5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn max(&self) -> T pub fn max(&self) -> T
where where
T: SimdPartialOrd + Zero, T: SimdPartialOrd + Zero,
@ -70,6 +73,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0); /// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn amin(&self) -> T pub fn amin(&self) -> T
where where
T: Zero + SimdPartialOrd + SimdSigned, T: Zero + SimdPartialOrd + SimdSigned,
@ -90,6 +94,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Complex::new(1.0, 3.0)).camin(), 3.0); /// Complex::new(1.0, 3.0)).camin(), 3.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn camin(&self) -> T::SimdRealField pub fn camin(&self) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -112,6 +117,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(Vector3::new(5u32, 2, 3).min(), 2); /// assert_eq!(Vector3::new(5u32, 2, 3).min(), 2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn min(&self) -> T pub fn min(&self) -> T
where where
T: SimdPartialOrd + Zero, T: SimdPartialOrd + Zero,
@ -136,6 +142,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(mat.icamax_full(), (1, 0)); /// assert_eq!(mat.icamax_full(), (1, 0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn icamax_full(&self) -> (usize, usize) pub fn icamax_full(&self) -> (usize, usize)
where where
T: ComplexField, T: ComplexField,
@ -172,6 +179,7 @@ impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matri
/// assert_eq!(mat.iamax_full(), (1, 2)); /// assert_eq!(mat.iamax_full(), (1, 2));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn iamax_full(&self) -> (usize, usize) { pub fn iamax_full(&self) -> (usize, usize) {
assert!(!self.is_empty(), "The input matrix must not be empty."); assert!(!self.is_empty(), "The input matrix must not be empty.");
@ -209,6 +217,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.icamax(), 2); /// assert_eq!(vec.icamax(), 2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn icamax(&self) -> usize pub fn icamax(&self) -> usize
where where
T: ComplexField, T: ComplexField,
@ -240,6 +249,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.argmax(), (2, 13)); /// assert_eq!(vec.argmax(), (2, 13));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn argmax(&self) -> (usize, T) pub fn argmax(&self) -> (usize, T)
where where
T: PartialOrd, T: PartialOrd,
@ -271,6 +281,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.imax(), 2); /// assert_eq!(vec.imax(), 2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn imax(&self) -> usize pub fn imax(&self) -> usize
where where
T: PartialOrd, T: PartialOrd,
@ -288,6 +299,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.iamax(), 1); /// assert_eq!(vec.iamax(), 1);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn iamax(&self) -> usize pub fn iamax(&self) -> usize
where where
T: PartialOrd + Signed, T: PartialOrd + Signed,
@ -319,6 +331,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.argmin(), (1, -15)); /// assert_eq!(vec.argmin(), (1, -15));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn argmin(&self) -> (usize, T) pub fn argmin(&self) -> (usize, T)
where where
T: PartialOrd, T: PartialOrd,
@ -350,6 +363,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.imin(), 1); /// assert_eq!(vec.imin(), 1);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn imin(&self) -> usize pub fn imin(&self) -> usize
where where
T: PartialOrd, T: PartialOrd,
@ -367,6 +381,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
/// assert_eq!(vec.iamin(), 0); /// assert_eq!(vec.iamin(), 0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn iamin(&self) -> usize pub fn iamin(&self) -> usize
where where
T: PartialOrd + Signed, T: PartialOrd + Signed,

View File

@ -158,6 +158,7 @@ impl<T: SimdComplexField> Norm<T> for UniformNorm {
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> { impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// The squared L2 norm of this vector. /// The squared L2 norm of this vector.
#[inline] #[inline]
#[must_use]
pub fn norm_squared(&self) -> T::SimdRealField pub fn norm_squared(&self) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -176,6 +177,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// ///
/// Use `.apply_norm` to apply a custom norm. /// Use `.apply_norm` to apply a custom norm.
#[inline] #[inline]
#[must_use]
pub fn norm(&self) -> T::SimdRealField pub fn norm(&self) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -187,6 +189,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// ///
/// Use `.apply_metric_distance` to apply a custom norm. /// Use `.apply_metric_distance` to apply a custom norm.
#[inline] #[inline]
#[must_use]
pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<T, R2, C2, S2>) -> T::SimdRealField pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<T, R2, C2, S2>) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -211,6 +214,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm()); /// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn apply_norm(&self, norm: &impl Norm<T>) -> T::SimdRealField pub fn apply_norm(&self, norm: &impl Norm<T>) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -233,6 +237,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm()); /// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn apply_metric_distance<R2, C2, S2>( pub fn apply_metric_distance<R2, C2, S2>(
&self, &self,
rhs: &Matrix<T, R2, C2, S2>, rhs: &Matrix<T, R2, C2, S2>,
@ -254,6 +259,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// ///
/// This function is simply implemented as a call to `norm()` /// This function is simply implemented as a call to `norm()`
#[inline] #[inline]
#[must_use]
pub fn magnitude(&self) -> T::SimdRealField pub fn magnitude(&self) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -267,6 +273,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// ///
/// This function is simply implemented as a call to `norm_squared()` /// This function is simply implemented as a call to `norm_squared()`
#[inline] #[inline]
#[must_use]
pub fn magnitude_squared(&self) -> T::SimdRealField pub fn magnitude_squared(&self) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -298,6 +305,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// The Lp norm of this matrix. /// The Lp norm of this matrix.
#[inline] #[inline]
#[must_use]
pub fn lp_norm(&self, p: i32) -> T::SimdRealField pub fn lp_norm(&self, p: i32) -> T::SimdRealField
where where
T: SimdComplexField, T: SimdComplexField,
@ -341,6 +349,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a new vector with the same magnitude as `self` clamped between `0.0` and `max`. /// Returns a new vector with the same magnitude as `self` clamped between `0.0` and `max`.
#[inline] #[inline]
#[must_use]
pub fn cap_magnitude(&self, max: T::RealField) -> OMatrix<T, R, C> pub fn cap_magnitude(&self, max: T::RealField) -> OMatrix<T, R, C>
where where
T: ComplexField, T: ComplexField,
@ -357,6 +366,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a new vector with the same magnitude as `self` clamped between `0.0` and `max`. /// Returns a new vector with the same magnitude as `self` clamped between `0.0` and `max`.
#[inline] #[inline]
#[must_use]
pub fn simd_cap_magnitude(&self, max: T::SimdRealField) -> OMatrix<T, R, C> pub fn simd_cap_magnitude(&self, max: T::SimdRealField) -> OMatrix<T, R, C>
where where
T: SimdComplexField, T: SimdComplexField,

View File

@ -158,20 +158,17 @@ macro_rules! componentwise_binop_impl(
// This is the most common case and should be deduced at compile-time. // This is the most common case and should be deduced at compile-time.
// TODO: use specialization instead? // TODO: use specialization instead?
if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() { unsafe {
let arr1 = self.data.as_slice(); if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() {
let arr2 = rhs.data.as_slice(); let arr1 = self.data.as_slice_unchecked();
let out = out.data.as_mut_slice(); let arr2 = rhs.data.as_slice_unchecked();
for i in 0 .. arr1.len() { let out = out.data.as_mut_slice_unchecked();
unsafe { for i in 0 .. arr1.len() {
*out.get_unchecked_mut(i) = arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()); *out.get_unchecked_mut(i) = arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone());
} }
} } else {
} for j in 0 .. self.ncols() {
else { for i in 0 .. self.nrows() {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
let val = self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone()); let val = self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone());
*out.get_unchecked_mut((i, j)) = val; *out.get_unchecked_mut((i, j)) = val;
} }
@ -191,19 +188,17 @@ macro_rules! componentwise_binop_impl(
// This is the most common case and should be deduced at compile-time. // This is the most common case and should be deduced at compile-time.
// TODO: use specialization instead? // TODO: use specialization instead?
if self.data.is_contiguous() && rhs.data.is_contiguous() { unsafe {
let arr1 = self.data.as_mut_slice(); if self.data.is_contiguous() && rhs.data.is_contiguous() {
let arr2 = rhs.data.as_slice(); let arr1 = self.data.as_mut_slice_unchecked();
for i in 0 .. arr2.len() { let arr2 = rhs.data.as_slice_unchecked();
unsafe {
for i in 0 .. arr2.len() {
arr1.get_unchecked_mut(i).$method_assign(arr2.get_unchecked(i).inlined_clone()); arr1.get_unchecked_mut(i).$method_assign(arr2.get_unchecked(i).inlined_clone());
} }
} } else {
} for j in 0 .. rhs.ncols() {
else { for i in 0 .. rhs.nrows() {
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)).inlined_clone()) self.get_unchecked_mut((i, j)).$method_assign(rhs.get_unchecked((i, j)).inlined_clone())
} }
} }
@ -221,20 +216,18 @@ macro_rules! componentwise_binop_impl(
// This is the most common case and should be deduced at compile-time. // This is the most common case and should be deduced at compile-time.
// TODO: use specialization instead? // TODO: use specialization instead?
if self.data.is_contiguous() && rhs.data.is_contiguous() { unsafe {
let arr1 = self.data.as_slice(); if self.data.is_contiguous() && rhs.data.is_contiguous() {
let arr2 = rhs.data.as_mut_slice(); let arr1 = self.data.as_slice_unchecked();
for i in 0 .. arr1.len() { let arr2 = rhs.data.as_mut_slice_unchecked();
unsafe {
for i in 0 .. arr1.len() {
let res = arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone()); let res = arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone());
*arr2.get_unchecked_mut(i) = res; *arr2.get_unchecked_mut(i) = res;
} }
} } else {
} for j in 0 .. self.ncols() {
else { for i in 0 .. self.nrows() {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
let r = rhs.get_unchecked_mut((i, j)); let r = rhs.get_unchecked_mut((i, j));
*r = self.get_unchecked((i, j)).inlined_clone().$method(r.inlined_clone()) *r = self.get_unchecked((i, j)).inlined_clone().$method(r.inlined_clone())
} }
@ -536,7 +529,7 @@ macro_rules! left_scalar_mul_impl(
// for rhs in res.iter_mut() { // for rhs in res.iter_mut() {
for rhs in res.as_mut_slice().iter_mut() { for rhs in res.as_mut_slice().iter_mut() {
*rhs = self * *rhs *rhs *= self
} }
res res
@ -676,6 +669,7 @@ where
{ {
/// Equivalent to `self.transpose() * rhs`. /// Equivalent to `self.transpose() * rhs`.
#[inline] #[inline]
#[must_use]
pub fn tr_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> OMatrix<T, C1, C2> pub fn tr_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> OMatrix<T, C1, C2>
where where
SB: Storage<T, R2, C2>, SB: Storage<T, R2, C2>,
@ -692,6 +686,7 @@ where
/// Equivalent to `self.adjoint() * rhs`. /// Equivalent to `self.adjoint() * rhs`.
#[inline] #[inline]
#[must_use]
pub fn ad_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> OMatrix<T, C1, C2> pub fn ad_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> OMatrix<T, C1, C2>
where where
T: SimdComplexField, T: SimdComplexField,
@ -801,6 +796,7 @@ where
/// The kronecker product of two matrices (aka. tensor product of the corresponding linear /// The kronecker product of two matrices (aka. tensor product of the corresponding linear
/// maps). /// maps).
#[must_use]
pub fn kronecker<R2: Dim, C2: Dim, SB>( pub fn kronecker<R2: Dim, C2: Dim, SB>(
&self, &self,
rhs: &Matrix<T, R2, C2, SB>, rhs: &Matrix<T, R2, C2, SB>,

View File

@ -20,6 +20,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(mat.len(), 12); /// assert_eq!(mat.len(), 12);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
nrows * ncols nrows * ncols
@ -35,12 +36,14 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert!(!mat.is_empty()); /// assert!(!mat.is_empty());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }
/// Indicates if this is a square matrix. /// Indicates if this is a square matrix.
#[inline] #[inline]
#[must_use]
pub fn is_square(&self) -> bool { pub fn is_square(&self) -> bool {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
nrows == ncols nrows == ncols
@ -52,6 +55,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// If the matrix is diagonal, this checks that diagonal elements (i.e. at coordinates `(i, i)` /// If the matrix is diagonal, this checks that diagonal elements (i.e. at coordinates `(i, i)`
/// for i from `0` to `min(R, C)`) are equal one; and that all other elements are zero. /// for i from `0` to `min(R, C)`) are equal one; and that all other elements are zero.
#[inline] #[inline]
#[must_use]
pub fn is_identity(&self, eps: T::Epsilon) -> bool pub fn is_identity(&self, eps: T::Epsilon) -> bool
where where
T: Zero + One + RelativeEq, T: Zero + One + RelativeEq,
@ -112,6 +116,7 @@ impl<T: ComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// In this definition `Id` is approximately equal to the identity matrix with a relative error /// In this definition `Id` is approximately equal to the identity matrix with a relative error
/// equal to `eps`. /// equal to `eps`.
#[inline] #[inline]
#[must_use]
pub fn is_orthogonal(&self, eps: T::Epsilon) -> bool pub fn is_orthogonal(&self, eps: T::Epsilon) -> bool
where where
T: Zero + One + ClosedAdd + ClosedMul + RelativeEq, T: Zero + One + ClosedAdd + ClosedMul + RelativeEq,
@ -129,6 +134,7 @@ where
{ {
/// Checks that this matrix is orthogonal and has a determinant equal to 1. /// Checks that this matrix is orthogonal and has a determinant equal to 1.
#[inline] #[inline]
#[must_use]
pub fn is_special_orthogonal(&self, eps: T) -> bool pub fn is_special_orthogonal(&self, eps: T) -> bool
where where
D: DimMin<D, Output = D>, D: DimMin<D, Output = D>,
@ -139,6 +145,7 @@ where
/// Returns `true` if this matrix is invertible. /// Returns `true` if this matrix is invertible.
#[inline] #[inline]
#[must_use]
pub fn is_invertible(&self) -> bool { pub fn is_invertible(&self) -> bool {
// TODO: improve this? // TODO: improve this?
self.clone_owned().try_inverse().is_some() self.clone_owned().try_inverse().is_some()

View File

@ -9,6 +9,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a row vector where each element is the result of the application of `f` on the /// Returns a row vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix. /// corresponding column of the original matrix.
#[inline] #[inline]
#[must_use]
pub fn compress_rows( pub fn compress_rows(
&self, &self,
f: impl Fn(VectorSlice<T, R, S::RStride, S::CStride>) -> T, f: impl Fn(VectorSlice<T, R, S::RStride, S::CStride>) -> T,
@ -35,6 +36,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// ///
/// This is the same as `self.compress_rows(f).transpose()`. /// This is the same as `self.compress_rows(f).transpose()`.
#[inline] #[inline]
#[must_use]
pub fn compress_rows_tr( pub fn compress_rows_tr(
&self, &self,
f: impl Fn(VectorSlice<T, R, S::RStride, S::CStride>) -> T, f: impl Fn(VectorSlice<T, R, S::RStride, S::CStride>) -> T,
@ -58,6 +60,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a column vector resulting from the folding of `f` on each column of this matrix. /// Returns a column vector resulting from the folding of `f` on each column of this matrix.
#[inline] #[inline]
#[must_use]
pub fn compress_columns( pub fn compress_columns(
&self, &self,
init: OVector<T, R>, init: OVector<T, R>,
@ -95,6 +98,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.sum(), 21.0); /// assert_eq!(m.sum(), 21.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn sum(&self) -> T pub fn sum(&self) -> T
where where
T: ClosedAdd + Zero, T: ClosedAdd + Zero,
@ -120,6 +124,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(mint.row_sum(), RowVector2::new(9,12)); /// assert_eq!(mint.row_sum(), RowVector2::new(9,12));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn row_sum(&self) -> RowOVector<T, C> pub fn row_sum(&self) -> RowOVector<T, C>
where where
T: ClosedAdd + Zero, T: ClosedAdd + Zero,
@ -144,6 +149,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(mint.row_sum_tr(), Vector2::new(9,12)); /// assert_eq!(mint.row_sum_tr(), Vector2::new(9,12));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn row_sum_tr(&self) -> OVector<T, C> pub fn row_sum_tr(&self) -> OVector<T, C>
where where
T: ClosedAdd + Zero, T: ClosedAdd + Zero,
@ -168,6 +174,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(mint.column_sum(), Vector3::new(3,7,11)); /// assert_eq!(mint.column_sum(), Vector3::new(3,7,11));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn column_sum(&self) -> OVector<T, R> pub fn column_sum(&self) -> OVector<T, R>
where where
T: ClosedAdd + Zero, T: ClosedAdd + Zero,
@ -197,6 +204,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_relative_eq!(m.variance(), 35.0 / 12.0, epsilon = 1.0e-8); /// assert_relative_eq!(m.variance(), 35.0 / 12.0, epsilon = 1.0e-8);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn variance(&self) -> T pub fn variance(&self) -> T
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -226,6 +234,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.row_variance(), RowVector3::new(2.25, 2.25, 2.25)); /// assert_eq!(m.row_variance(), RowVector3::new(2.25, 2.25, 2.25));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn row_variance(&self) -> RowOVector<T, C> pub fn row_variance(&self) -> RowOVector<T, C>
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -246,6 +255,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.row_variance_tr(), Vector3::new(2.25, 2.25, 2.25)); /// assert_eq!(m.row_variance_tr(), Vector3::new(2.25, 2.25, 2.25));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn row_variance_tr(&self) -> OVector<T, C> pub fn row_variance_tr(&self) -> OVector<T, C>
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -267,6 +277,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_relative_eq!(m.column_variance(), Vector2::new(2.0 / 3.0, 2.0 / 3.0), epsilon = 1.0e-8); /// assert_relative_eq!(m.column_variance(), Vector2::new(2.0 / 3.0, 2.0 / 3.0), epsilon = 1.0e-8);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn column_variance(&self) -> OVector<T, R> pub fn column_variance(&self) -> OVector<T, R>
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -306,6 +317,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.mean(), 3.5); /// assert_eq!(m.mean(), 3.5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn mean(&self) -> T pub fn mean(&self) -> T
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -331,6 +343,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.row_mean(), RowVector3::new(2.5, 3.5, 4.5)); /// assert_eq!(m.row_mean(), RowVector3::new(2.5, 3.5, 4.5));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn row_mean(&self) -> RowOVector<T, C> pub fn row_mean(&self) -> RowOVector<T, C>
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -351,6 +364,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.row_mean_tr(), Vector3::new(2.5, 3.5, 4.5)); /// assert_eq!(m.row_mean_tr(), Vector3::new(2.5, 3.5, 4.5));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn row_mean_tr(&self) -> OVector<T, C> pub fn row_mean_tr(&self) -> OVector<T, C>
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,
@ -371,6 +385,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// assert_eq!(m.column_mean(), Vector2::new(2.0, 5.0)); /// assert_eq!(m.column_mean(), Vector2::new(2.0, 5.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn column_mean(&self) -> OVector<T, R> pub fn column_mean(&self) -> OVector<T, R>
where where
T: Field + SupersetOf<f64>, T: Field + SupersetOf<f64>,

View File

@ -1,7 +1,7 @@
//! Abstract definition of a matrix data storage. //! Abstract definition of a matrix data storage.
use std::fmt::Debug; use std::fmt::Debug;
use std::mem; use std::ptr;
use crate::base::allocator::{Allocator, SameShapeC, SameShapeR}; use crate::base::allocator::{Allocator, SameShapeC, SameShapeR};
use crate::base::default_allocator::DefaultAllocator; use crate::base::default_allocator::DefaultAllocator;
@ -58,7 +58,7 @@ pub unsafe trait Storage<T: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
/// Compute the index corresponding to the irow-th row and icol-th column of this matrix. The /// Compute the index corresponding to the irow-th row and icol-th column of this matrix. The
/// index must be such that the following holds: /// index must be such that the following holds:
/// ///
/// ```.ignore /// ```ignore
/// let lindex = self.linear_index(irow, icol); /// let lindex = self.linear_index(irow, icol);
/// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex)) /// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex))
/// ``` /// ```
@ -70,36 +70,57 @@ pub unsafe trait Storage<T: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
} }
/// Gets the address of the i-th matrix component without performing bound-checking. /// Gets the address of the i-th matrix component without performing bound-checking.
///
/// # Safety
/// If the index is out of bounds, dereferencing the result will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_address_unchecked_linear(&self, i: usize) -> *const T { fn get_address_unchecked_linear(&self, i: usize) -> *const T {
self.ptr().wrapping_add(i) self.ptr().wrapping_add(i)
} }
/// Gets the address of the i-th matrix component without performing bound-checking. /// Gets the address of the i-th matrix component without performing bound-checking.
///
/// # Safety
/// If the index is out of bounds, dereferencing the result will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_address_unchecked(&self, irow: usize, icol: usize) -> *const T { fn get_address_unchecked(&self, irow: usize, icol: usize) -> *const T {
self.get_address_unchecked_linear(self.linear_index(irow, icol)) self.get_address_unchecked_linear(self.linear_index(irow, icol))
} }
/// Retrieves a reference to the i-th element without bound-checking. /// Retrieves a reference to the i-th element without bound-checking.
///
/// # Safety
/// If the index is out of bounds, the method will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_unchecked_linear(&self, i: usize) -> &T { unsafe fn get_unchecked_linear(&self, i: usize) -> &T {
&*self.get_address_unchecked_linear(i) &*self.get_address_unchecked_linear(i)
} }
/// Retrieves a reference to the i-th element without bound-checking. /// Retrieves a reference to the i-th element without bound-checking.
///
/// # Safety
/// If the index is out of bounds, the method will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &T { unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &T {
self.get_unchecked_linear(self.linear_index(irow, icol)) self.get_unchecked_linear(self.linear_index(irow, icol))
} }
/// Indicates whether this data buffer stores its elements contiguously. /// Indicates whether this data buffer stores its elements contiguously.
///
/// # Safety
/// This function must not return `true` if the underlying storage is not contiguous,
/// or undefined behaviour will occur.
fn is_contiguous(&self) -> bool; fn is_contiguous(&self) -> bool;
/// Retrieves the data buffer as a contiguous slice. /// Retrieves the data buffer as a contiguous slice.
/// ///
/// # Safety
/// The matrix components may not be stored in a contiguous way, depending on the strides. /// The matrix components may not be stored in a contiguous way, depending on the strides.
fn as_slice(&self) -> &[T]; /// This method is unsafe because this can yield to invalid aliasing when called on some pairs
/// of matrix slices originating from the same matrix with strides.
///
/// Call the safe alternative `matrix.as_slice()` instead.
unsafe fn as_slice_unchecked(&self) -> &[T];
/// Builds a matrix data storage that does not contain any reference. /// Builds a matrix data storage that does not contain any reference.
fn into_owned(self) -> Owned<T, R, C> fn into_owned(self) -> Owned<T, R, C>
@ -122,39 +143,57 @@ pub unsafe trait StorageMut<T: Scalar, R: Dim, C: Dim = U1>: Storage<T, R, C> {
fn ptr_mut(&mut self) -> *mut T; fn ptr_mut(&mut self) -> *mut T;
/// Gets the mutable address of the i-th matrix component without performing bound-checking. /// Gets the mutable address of the i-th matrix component without performing bound-checking.
///
/// # Safety
/// If the index is out of bounds, dereferencing the result will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_address_unchecked_linear_mut(&mut self, i: usize) -> *mut T { fn get_address_unchecked_linear_mut(&mut self, i: usize) -> *mut T {
self.ptr_mut().wrapping_add(i) self.ptr_mut().wrapping_add(i)
} }
/// Gets the mutable address of the i-th matrix component without performing bound-checking. /// Gets the mutable address of the i-th matrix component without performing bound-checking.
///
/// # Safety
/// If the index is out of bounds, dereferencing the result will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_address_unchecked_mut(&mut self, irow: usize, icol: usize) -> *mut T { fn get_address_unchecked_mut(&mut self, irow: usize, icol: usize) -> *mut T {
let lid = self.linear_index(irow, icol); let lid = self.linear_index(irow, icol);
self.get_address_unchecked_linear_mut(lid) self.get_address_unchecked_linear_mut(lid)
} }
/// Retrieves a mutable reference to the i-th element without bound-checking. /// Retrieves a mutable reference to the i-th element without bound-checking.
///
/// # Safety
/// If the index is out of bounds, the method will cause undefined behavior.
unsafe fn get_unchecked_linear_mut(&mut self, i: usize) -> &mut T { unsafe fn get_unchecked_linear_mut(&mut self, i: usize) -> &mut T {
&mut *self.get_address_unchecked_linear_mut(i) &mut *self.get_address_unchecked_linear_mut(i)
} }
/// Retrieves a mutable reference to the element at `(irow, icol)` without bound-checking. /// Retrieves a mutable reference to the element at `(irow, icol)` without bound-checking.
///
/// # Safety
/// If the index is out of bounds, the method will cause undefined behavior.
#[inline] #[inline]
unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut T { unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut T {
&mut *self.get_address_unchecked_mut(irow, icol) &mut *self.get_address_unchecked_mut(irow, icol)
} }
/// Swaps two elements using their linear index without bound-checking. /// Swaps two elements using their linear index without bound-checking.
///
/// # Safety
/// If the indices are out of bounds, the method will cause undefined behavior.
#[inline] #[inline]
unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) { unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) {
let a = self.get_address_unchecked_linear_mut(i1); let a = self.get_address_unchecked_linear_mut(i1);
let b = self.get_address_unchecked_linear_mut(i2); let b = self.get_address_unchecked_linear_mut(i2);
mem::swap(&mut *a, &mut *b); ptr::swap(a, b);
} }
/// Swaps two elements without bound-checking. /// Swaps two elements without bound-checking.
///
/// # Safety
/// If the indices are out of bounds, the method will cause undefined behavior.
#[inline] #[inline]
unsafe fn swap_unchecked(&mut self, row_col1: (usize, usize), row_col2: (usize, usize)) { unsafe fn swap_unchecked(&mut self, row_col1: (usize, usize), row_col2: (usize, usize)) {
let lid1 = self.linear_index(row_col1.0, row_col1.1); let lid1 = self.linear_index(row_col1.0, row_col1.1);
@ -165,8 +204,13 @@ pub unsafe trait StorageMut<T: Scalar, R: Dim, C: Dim = U1>: Storage<T, R, C> {
/// Retrieves the mutable data buffer as a contiguous slice. /// Retrieves the mutable data buffer as a contiguous slice.
/// ///
/// Matrix components may not be contiguous, depending on its strides. /// Matrix components may not be contiguous, depending on its strides.
fn as_mut_slice(&mut self) -> &mut [T]; ///
/// # Safety
/// The matrix components may not be stored in a contiguous way, depending on the strides.
/// This method is unsafe because this can yield to invalid aliasing when called on some pairs
/// of matrix slices originating from the same matrix with strides.
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T];
} }
/// A matrix storage that is stored contiguously in memory. /// A matrix storage that is stored contiguously in memory.
@ -177,6 +221,12 @@ pub unsafe trait StorageMut<T: Scalar, R: Dim, C: Dim = U1>: Storage<T, R, C> {
pub unsafe trait ContiguousStorage<T: Scalar, R: Dim, C: Dim = U1>: pub unsafe trait ContiguousStorage<T: Scalar, R: Dim, C: Dim = U1>:
Storage<T, R, C> Storage<T, R, C>
{ {
/// Converts this data storage to a contiguous slice.
fn as_slice(&self) -> &[T] {
// SAFETY: this is safe because this trait guarantees the fact
// that the data is stored contiguously.
unsafe { self.as_slice_unchecked() }
}
} }
/// A mutable matrix storage that is stored contiguously in memory. /// A mutable matrix storage that is stored contiguously in memory.
@ -187,6 +237,12 @@ pub unsafe trait ContiguousStorage<T: Scalar, R: Dim, C: Dim = U1>:
pub unsafe trait ContiguousStorageMut<T: Scalar, R: Dim, C: Dim = U1>: pub unsafe trait ContiguousStorageMut<T: Scalar, R: Dim, C: Dim = U1>:
ContiguousStorage<T, R, C> + StorageMut<T, R, C> ContiguousStorage<T, R, C> + StorageMut<T, R, C>
{ {
/// Converts this data storage to a contiguous mutable slice.
fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: this is safe because this trait guarantees the fact
// that the data is stored contiguously.
unsafe { self.as_mut_slice_unchecked() }
}
} }
/// A matrix storage that can be reshaped in-place. /// A matrix storage that can be reshaped in-place.

View File

@ -8,6 +8,7 @@ macro_rules! impl_swizzle {
$( $(
/// Builds a new vector from components of `self`. /// Builds a new vector from components of `self`.
#[inline] #[inline]
#[must_use]
pub fn $name(&self) -> $Result<T> pub fn $name(&self) -> $Result<T>
where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> { where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> {
$Result::new($(self[$i].inlined_clone()),*) $Result::new($(self[$i].inlined_clone()),*)

View File

@ -1,6 +1,5 @@
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
use std::mem;
use std::ops::Deref; use std::ops::Deref;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
@ -96,7 +95,7 @@ mod rkyv_impl {
impl<T: Serialize<S>, S: Fallible + ?Sized> Serialize<S> for Unit<T> { impl<T: Serialize<S>, S: Fallible + ?Sized> Serialize<S> for Unit<T> {
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> { fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
Ok(self.value.serialize(serializer)?) self.value.serialize(serializer)
} }
} }
@ -222,14 +221,14 @@ impl<T: Normed> Unit<T> {
impl<T> Unit<T> { impl<T> Unit<T> {
/// Wraps the given value, assuming it is already normalized. /// Wraps the given value, assuming it is already normalized.
#[inline] #[inline]
pub fn new_unchecked(value: T) -> Self { pub const fn new_unchecked(value: T) -> Self {
Unit { value } Unit { value }
} }
/// Wraps the given reference, assuming it is already normalized. /// Wraps the given reference, assuming it is already normalized.
#[inline] #[inline]
pub fn from_ref_unchecked<'a>(value: &'a T) -> &'a Self { pub fn from_ref_unchecked(value: &T) -> &Self {
unsafe { mem::transmute(value) } unsafe { &*(value as *const T as *const Self) }
} }
/// Retrieves the underlying value. /// Retrieves the underlying value.
@ -332,7 +331,7 @@ impl<T> Deref for Unit<T> {
#[inline] #[inline]
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { mem::transmute(self) } unsafe { &*(self as *const Self as *const T) }
} }
} }

View File

@ -95,12 +95,14 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
/// The underlying data storage. /// The underlying data storage.
#[inline] #[inline]
#[must_use]
pub fn as_vec(&self) -> &Vec<T> { pub fn as_vec(&self) -> &Vec<T> {
&self.data &self.data
} }
/// The underlying mutable data storage. /// The underlying mutable data storage.
/// ///
/// # Safety
/// This is unsafe because this may cause UB if the size of the vector is changed /// This is unsafe because this may cause UB if the size of the vector is changed
/// by the user. /// by the user.
#[inline] #[inline]
@ -110,6 +112,7 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
/// Resizes the underlying mutable data storage and unwraps it. /// Resizes the underlying mutable data storage and unwraps it.
/// ///
/// # Safety
/// If `sz` is larger than the current size, additional elements are uninitialized. /// If `sz` is larger than the current size, additional elements are uninitialized.
/// If `sz` is smaller than the current size, additional elements are truncated. /// If `sz` is smaller than the current size, additional elements are truncated.
#[inline] #[inline]
@ -129,20 +132,22 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
/// The number of elements on the underlying vector. /// The number of elements on the underlying vector.
#[inline] #[inline]
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.data.len() self.data.len()
} }
/// Returns true if the underlying vector contains no elements. /// Returns true if the underlying vector contains no elements.
#[inline] #[inline]
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }
} }
impl<T, R: Dim, C: Dim> Into<Vec<T>> for VecStorage<T, R, C> { impl<T, R: Dim, C: Dim> From<VecStorage<T, R, C>> for Vec<T> {
fn into(self) -> Vec<T> { fn from(vec: VecStorage<T, R, C>) -> Self {
self.data vec.data
} }
} }
@ -196,7 +201,7 @@ where
} }
#[inline] #[inline]
fn as_slice(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
&self.data &self.data
} }
} }
@ -245,7 +250,7 @@ where
} }
#[inline] #[inline]
fn as_slice(&self) -> &[T] { unsafe fn as_slice_unchecked(&self) -> &[T] {
&self.data &self.data
} }
} }
@ -265,7 +270,7 @@ where
} }
#[inline] #[inline]
fn as_mut_slice(&mut self) -> &mut [T] { unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
&mut self.data[..] &mut self.data[..]
} }
} }
@ -326,7 +331,7 @@ where
} }
#[inline] #[inline]
fn as_mut_slice(&mut self) -> &mut [T] { unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
&mut self.data[..] &mut self.data[..]
} }
} }

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
use crate::{ use crate::{
Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3, Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3,
Unit, UnitQuaternion, Vector3, Zero, U8, Unit, UnitQuaternion, Vector3, Zero, U8,
@ -35,14 +38,23 @@ use simba::scalar::{ClosedNeg, RealField};
/// If a feature that you need is missing, feel free to open an issue or a PR. /// If a feature that you need is missing, feel free to open an issue or a PR.
/// See https://github.com/dimforge/nalgebra/issues/487 /// See https://github.com/dimforge/nalgebra/issues/487
#[repr(C)] #[repr(C)]
#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct DualQuaternion<T: Scalar> { pub struct DualQuaternion<T> {
/// The real component of the quaternion /// The real component of the quaternion
pub real: Quaternion<T>, pub real: Quaternion<T>,
/// The dual component of the quaternion /// The dual component of the quaternion
pub dual: Quaternion<T>, pub dual: Quaternion<T>,
} }
impl<T: Scalar + Eq> Eq for DualQuaternion<T> {}
impl<T: Scalar> PartialEq for DualQuaternion<T> {
#[inline]
fn eq(&self, right: &Self) -> bool {
self.real == right.real && self.dual == right.dual
}
}
impl<T: Scalar + Zero> Default for DualQuaternion<T> { impl<T: Scalar + Zero> Default for DualQuaternion<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -232,6 +244,7 @@ where
/// )); /// ));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp(&self, other: &Self, t: T) -> Self { pub fn lerp(&self, other: &Self, t: T) -> Self {
self * (T::one() - t) + other * t self * (T::one() - t) + other * t
} }
@ -271,8 +284,8 @@ where
} }
impl<T: RealField> DualQuaternion<T> { impl<T: RealField> DualQuaternion<T> {
fn to_vector(&self) -> OVector<T, U8> { fn to_vector(self) -> OVector<T, U8> {
self.as_ref().clone().into() (*self.as_ref()).into()
} }
} }
@ -381,6 +394,7 @@ where
/// )); /// ));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn dual_quaternion(&self) -> &DualQuaternion<T> { pub fn dual_quaternion(&self) -> &DualQuaternion<T> {
self.as_ref() self.as_ref()
} }
@ -463,7 +477,6 @@ where
/// assert_relative_eq!(inv * unit, UnitDualQuaternion::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(inv * unit, UnitDualQuaternion::identity(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use = "Did you mean to use inverse_mut()?"]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
let quat = self.as_mut_unchecked(); let quat = self.as_mut_unchecked();
quat.real = Unit::new_unchecked(quat.real).inverse().into_inner(); quat.real = Unit::new_unchecked(quat.real).inverse().into_inner();
@ -486,6 +499,7 @@ where
/// assert_relative_eq!(dq_to * dq1, dq2, epsilon = 1.0e-6); /// assert_relative_eq!(dq_to * dq1, dq2, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn isometry_to(&self, other: &Self) -> Self { pub fn isometry_to(&self, other: &Self) -> Self {
other / self other / self
} }
@ -518,6 +532,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp(&self, other: &Self, t: T) -> DualQuaternion<T> { pub fn lerp(&self, other: &Self, t: T) -> DualQuaternion<T> {
self.as_ref().lerp(other.as_ref(), t) self.as_ref().lerp(other.as_ref(), t)
} }
@ -546,6 +561,7 @@ where
/// ), epsilon = 1.0e-6); /// ), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn nlerp(&self, other: &Self, t: T) -> Self { pub fn nlerp(&self, other: &Self, t: T) -> Self {
let mut res = self.lerp(other, t); let mut res = self.lerp(other, t);
let _ = res.normalize_mut(); let _ = res.normalize_mut();
@ -581,6 +597,7 @@ where
/// ); /// );
/// assert_relative_eq!(dq.translation().vector.y, 3.0, epsilon = 1.0e-6); /// assert_relative_eq!(dq.translation().vector.y, 3.0, epsilon = 1.0e-6);
#[inline] #[inline]
#[must_use]
pub fn sclerp(&self, other: &Self, t: T) -> Self pub fn sclerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,
@ -600,6 +617,7 @@ where
/// * `epsilon`: the value below which the sinus of the angle separating both quaternion /// * `epsilon`: the value below which the sinus of the angle separating both quaternion
/// must be to return `None`. /// must be to return `None`.
#[inline] #[inline]
#[must_use]
pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self> pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
where where
T: RealField, T: RealField,
@ -612,9 +630,9 @@ where
let other = { let other = {
let dot_product = self.as_ref().real.coords.dot(&other.as_ref().real.coords); let dot_product = self.as_ref().real.coords.dot(&other.as_ref().real.coords);
if dot_product < T::zero() { if dot_product < T::zero() {
-other.clone() -*other
} else { } else {
other.clone() *other
} }
}; };
@ -667,6 +685,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn rotation(&self) -> UnitQuaternion<T> { pub fn rotation(&self) -> UnitQuaternion<T> {
Unit::new_unchecked(self.as_ref().real) Unit::new_unchecked(self.as_ref().real)
} }
@ -686,6 +705,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn translation(&self) -> Translation3<T> { pub fn translation(&self) -> Translation3<T> {
let two = T::one() + T::one(); let two = T::one() + T::one();
Translation3::from( Translation3::from(
@ -712,7 +732,8 @@ where
/// assert_relative_eq!(iso.translation.vector, translation, epsilon = 1.0e-6); /// assert_relative_eq!(iso.translation.vector, translation, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn to_isometry(&self) -> Isometry3<T> { #[must_use]
pub fn to_isometry(self) -> Isometry3<T> {
Isometry3::from_parts(self.translation(), self.rotation()) Isometry3::from_parts(self.translation(), self.rotation())
} }
@ -735,6 +756,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point3<T>) -> Point3<T> { pub fn transform_point(&self, pt: &Point3<T>) -> Point3<T> {
self * pt self * pt
} }
@ -758,6 +780,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &Vector3<T>) -> Vector3<T> { pub fn transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
self * v self * v
} }
@ -781,6 +804,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point3<T>) -> Point3<T> { pub fn inverse_transform_point(&self, pt: &Point3<T>) -> Point3<T> {
self.inverse() * pt self.inverse() * pt
} }
@ -805,6 +829,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &Vector3<T>) -> Vector3<T> { pub fn inverse_transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
self.inverse() * v self.inverse() * v
} }
@ -830,6 +855,7 @@ where
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector3<T>>) -> Unit<Vector3<T>> { pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector3<T>>) -> Unit<Vector3<T>> {
self.inverse() * v self.inverse() * v
} }
@ -857,7 +883,8 @@ where
/// assert_relative_eq!(dq.to_homogeneous(), expected, epsilon = 1.0e-6); /// assert_relative_eq!(dq.to_homogeneous(), expected, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> Matrix4<T> { #[must_use]
pub fn to_homogeneous(self) -> Matrix4<T> {
self.to_isometry().to_homogeneous() self.to_isometry().to_homogeneous()
} }
} }

View File

@ -186,9 +186,9 @@ where
pub fn from_parts(translation: Translation3<T>, rotation: UnitQuaternion<T>) -> Self { pub fn from_parts(translation: Translation3<T>, rotation: UnitQuaternion<T>) -> Self {
let half: T = crate::convert(0.5f64); let half: T = crate::convert(0.5f64);
UnitDualQuaternion::new_unchecked(DualQuaternion { UnitDualQuaternion::new_unchecked(DualQuaternion {
real: rotation.clone().into_inner(), real: rotation.into_inner(),
dual: Quaternion::from_parts(T::zero(), translation.vector) dual: Quaternion::from_parts(T::zero(), translation.vector)
* rotation.clone().into_inner() * rotation.into_inner()
* half, * half,
}) })
} }

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
/* /*
* This file provides: * This file provides:
* *
@ -49,7 +52,6 @@ use crate::{
DualQuaternion, Isometry3, Point, Point3, Quaternion, SimdRealField, Translation3, Unit, DualQuaternion, Isometry3, Point, Point3, Quaternion, SimdRealField, Translation3, Unit,
UnitDualQuaternion, UnitQuaternion, Vector, Vector3, U3, UnitDualQuaternion, UnitQuaternion, Vector, Vector3, U3,
}; };
use std::mem;
use std::ops::{ use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
}; };
@ -57,14 +59,14 @@ use std::ops::{
impl<T: SimdRealField> AsRef<[T; 8]> for DualQuaternion<T> { impl<T: SimdRealField> AsRef<[T; 8]> for DualQuaternion<T> {
#[inline] #[inline]
fn as_ref(&self) -> &[T; 8] { fn as_ref(&self) -> &[T; 8] {
unsafe { mem::transmute(self) } unsafe { &*(self as *const Self as *const [T; 8]) }
} }
} }
impl<T: SimdRealField> AsMut<[T; 8]> for DualQuaternion<T> { impl<T: SimdRealField> AsMut<[T; 8]> for DualQuaternion<T> {
#[inline] #[inline]
fn as_mut(&mut self) -> &mut [T; 8] { fn as_mut(&mut self) -> &mut [T; 8] {
unsafe { mem::transmute(self) } unsafe { &mut *(self as *mut Self as *mut [T; 8]) }
} }
} }
@ -564,7 +566,7 @@ dual_quaternion_op_impl!(
(U4, U1), (U3, U1); (U4, U1), (U3, U1);
self: &'a UnitDualQuaternion<T>, rhs: &'b Translation3<T>, self: &'a UnitDualQuaternion<T>, rhs: &'b Translation3<T>,
Output = UnitDualQuaternion<T> => U3, U1; Output = UnitDualQuaternion<T> => U3, U1;
self * UnitDualQuaternion::<T>::from_parts(rhs.clone(), UnitQuaternion::identity()); self * UnitDualQuaternion::<T>::from_parts(*rhs, UnitQuaternion::identity());
'a, 'b); 'a, 'b);
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -580,7 +582,7 @@ dual_quaternion_op_impl!(
(U4, U1), (U3, U3); (U4, U1), (U3, U3);
self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>, self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>,
Output = UnitDualQuaternion<T> => U3, U1; Output = UnitDualQuaternion<T> => U3, U1;
self * UnitDualQuaternion::<T>::from_parts(rhs.clone(), UnitQuaternion::identity()); self * UnitDualQuaternion::<T>::from_parts(*rhs, UnitQuaternion::identity());
'b); 'b);
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -632,7 +634,7 @@ dual_quaternion_op_impl!(
(U3, U1), (U4, U1); (U3, U1), (U4, U1);
self: &'b Translation3<T>, rhs: &'a UnitDualQuaternion<T>, self: &'b Translation3<T>, rhs: &'a UnitDualQuaternion<T>,
Output = UnitDualQuaternion<T> => U3, U1; Output = UnitDualQuaternion<T> => U3, U1;
UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) * rhs; UnitDualQuaternion::<T>::from_parts(*self, UnitQuaternion::identity()) * rhs;
'a, 'b); 'a, 'b);
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -640,7 +642,7 @@ dual_quaternion_op_impl!(
(U3, U1), (U4, U1); (U3, U1), (U4, U1);
self: &'a Translation3<T>, rhs: UnitDualQuaternion<T>, self: &'a Translation3<T>, rhs: UnitDualQuaternion<T>,
Output = UnitDualQuaternion<T> => U3, U1; Output = UnitDualQuaternion<T> => U3, U1;
UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) * rhs; UnitDualQuaternion::<T>::from_parts(*self, UnitQuaternion::identity()) * rhs;
'a); 'a);
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -664,7 +666,7 @@ dual_quaternion_op_impl!(
(U3, U1), (U4, U1); (U3, U1), (U4, U1);
self: &'b Translation3<T>, rhs: &'a UnitDualQuaternion<T>, self: &'b Translation3<T>, rhs: &'a UnitDualQuaternion<T>,
Output = UnitDualQuaternion<T> => U3, U1; Output = UnitDualQuaternion<T> => U3, U1;
UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) / rhs; UnitDualQuaternion::<T>::from_parts(*self, UnitQuaternion::identity()) / rhs;
'a, 'b); 'a, 'b);
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -672,7 +674,7 @@ dual_quaternion_op_impl!(
(U3, U1), (U4, U1); (U3, U1), (U4, U1);
self: &'a Translation3<T>, rhs: UnitDualQuaternion<T>, self: &'a Translation3<T>, rhs: UnitDualQuaternion<T>,
Output = UnitDualQuaternion<T> => U3, U1; Output = UnitDualQuaternion<T> => U3, U1;
UnitDualQuaternion::<T>::from_parts(self.clone(), UnitQuaternion::identity()) / rhs; UnitDualQuaternion::<T>::from_parts(*self, UnitQuaternion::identity()) / rhs;
'a); 'a);
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -860,7 +862,7 @@ dual_quaternion_op_impl!(
Output = Point3<T> => U3, U1; Output = Point3<T> => U3, U1;
{ {
let two: T = crate::convert(2.0f64); let two: T = crate::convert(2.0f64);
let q_point = Quaternion::from_parts(T::zero(), rhs.coords.clone()); let q_point = Quaternion::from_parts(T::zero(), rhs.coords);
Point::from( Point::from(
((self.as_ref().real * q_point + self.as_ref().dual * two) * self.as_ref().real.conjugate()) ((self.as_ref().real * q_point + self.as_ref().dual * two) * self.as_ref().real.conjugate())
.vector() .vector()
@ -1115,7 +1117,7 @@ dual_quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>; self: UnitDualQuaternion<T>, rhs: &'b UnitQuaternion<T>;
*self *= rhs.clone(); 'b); *self *= *rhs; 'b);
// UnitDualQuaternion ÷= UnitQuaternion // UnitDualQuaternion ÷= UnitQuaternion
dual_quaternion_op_impl!( dual_quaternion_op_impl!(
@ -1151,7 +1153,7 @@ dual_quaternion_op_impl!(
MulAssign, mul_assign; MulAssign, mul_assign;
(U4, U1), (U4, U1); (U4, U1), (U4, U1);
self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>; self: UnitDualQuaternion<T>, rhs: &'b Translation3<T>;
*self *= rhs.clone(); 'b); *self *= *rhs; 'b);
// UnitDualQuaternion ÷= Translation3 // UnitDualQuaternion ÷= Translation3
dual_quaternion_op_impl!( dual_quaternion_op_impl!(

View File

@ -60,15 +60,17 @@ use crate::geometry::{AbstractRotation, Point, Translation};
feature = "serde-serialize-no-std", feature = "serde-serialize-no-std",
serde(bound(serialize = "R: Serialize, serde(bound(serialize = "R: Serialize,
DefaultAllocator: Allocator<T, Const<D>>, DefaultAllocator: Allocator<T, Const<D>>,
Owned<T, Const<D>>: Serialize")) Owned<T, Const<D>>: Serialize,
T: Scalar"))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize-no-std", feature = "serde-serialize-no-std",
serde(bound(deserialize = "R: Deserialize<'de>, serde(bound(deserialize = "R: Deserialize<'de>,
DefaultAllocator: Allocator<T, Const<D>>, DefaultAllocator: Allocator<T, Const<D>>,
Owned<T, Const<D>>: Deserialize<'de>")) Owned<T, Const<D>>: Deserialize<'de>,
T: Scalar"))
)] )]
pub struct Isometry<T: Scalar, R, const D: usize> { pub struct Isometry<T, R, const D: usize> {
/// The pure rotational part of this isometry. /// The pure rotational part of this isometry.
pub rotation: R, pub rotation: R,
/// The pure translational part of this isometry. /// The pure translational part of this isometry.
@ -267,9 +269,10 @@ where
/// assert_eq!(iso1.inverse() * iso2, iso1.inv_mul(&iso2)); /// assert_eq!(iso1.inverse() * iso2, iso1.inv_mul(&iso2));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inv_mul(&self, rhs: &Isometry<T, R, D>) -> Self { pub fn inv_mul(&self, rhs: &Isometry<T, R, D>) -> Self {
let inv_rot1 = self.rotation.inverse(); let inv_rot1 = self.rotation.inverse();
let tr_12 = rhs.translation.vector.clone() - self.translation.vector.clone(); let tr_12 = rhs.translation.vector - self.translation.vector;
Isometry::from_parts( Isometry::from_parts(
inv_rot1.transform_vector(&tr_12).into(), inv_rot1.transform_vector(&tr_12).into(),
inv_rot1 * rhs.rotation.clone(), inv_rot1 * rhs.rotation.clone(),
@ -384,6 +387,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, 2.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, 2.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self * pt self * pt
} }
@ -407,6 +411,7 @@ where
/// assert_relative_eq!(transformed_point, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self * v self * v
} }
@ -429,9 +434,10 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(0.0, 2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point3::new(0.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self.rotation self.rotation
.inverse_transform_point(&(pt - &self.translation.vector)) .inverse_transform_point(&(pt - self.translation.vector))
} }
/// Transform the given vector by the inverse of this isometry, ignoring the /// Transform the given vector by the inverse of this isometry, ignoring the
@ -453,6 +459,7 @@ where
/// assert_relative_eq!(transformed_point, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self.rotation.inverse_transform_vector(v) self.rotation.inverse_transform_vector(v)
} }
@ -476,6 +483,7 @@ where
/// assert_relative_eq!(transformed_point, -Vector3::y_axis(), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, -Vector3::y_axis(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_unit_vector(&self, v: &Unit<SVector<T, D>>) -> Unit<SVector<T, D>> { pub fn inverse_transform_unit_vector(&self, v: &Unit<SVector<T, D>>) -> Unit<SVector<T, D>> {
self.rotation.inverse_transform_unit_vector(v) self.rotation.inverse_transform_unit_vector(v)
} }
@ -505,6 +513,7 @@ impl<T: SimdRealField, R, const D: usize> Isometry<T, R, D> {
/// assert_relative_eq!(iso.to_homogeneous(), expected, epsilon = 1.0e-6); /// assert_relative_eq!(iso.to_homogeneous(), expected, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,
@ -536,6 +545,7 @@ impl<T: SimdRealField, R, const D: usize> Isometry<T, R, D> {
/// assert_relative_eq!(iso.to_matrix(), expected, epsilon = 1.0e-6); /// assert_relative_eq!(iso.to_matrix(), expected, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn to_matrix(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_matrix(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,

View File

@ -86,7 +86,7 @@ where
Standard: Distribution<T> + Distribution<R>, Standard: Distribution<T> + Distribution<R>,
{ {
#[inline] #[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Isometry<T, R, D> { fn sample<G: Rng + ?Sized>(&self, rng: &mut G) -> Isometry<T, R, D> {
Isometry::from_parts(rng.gen(), rng.gen()) Isometry::from_parts(rng.gen(), rng.gen())
} }
} }

View File

@ -239,7 +239,7 @@ where
{ {
#[inline] #[inline]
fn from(arr: [Isometry<T::Element, R::Element, D>; 2]) -> Self { fn from(arr: [Isometry<T::Element, R::Element, D>; 2]) -> Self {
let tra = Translation::from([arr[0].translation.clone(), arr[1].translation.clone()]); let tra = Translation::from([arr[0].translation, arr[1].translation]);
let rot = R::from([arr[0].rotation, arr[0].rotation]); let rot = R::from([arr[0].rotation, arr[0].rotation]);
Self::from_parts(tra, rot) Self::from_parts(tra, rot)
@ -258,10 +258,10 @@ where
#[inline] #[inline]
fn from(arr: [Isometry<T::Element, R::Element, D>; 4]) -> Self { fn from(arr: [Isometry<T::Element, R::Element, D>; 4]) -> Self {
let tra = Translation::from([ let tra = Translation::from([
arr[0].translation.clone(), arr[0].translation,
arr[1].translation.clone(), arr[1].translation,
arr[2].translation.clone(), arr[2].translation,
arr[3].translation.clone(), arr[3].translation,
]); ]);
let rot = R::from([ let rot = R::from([
arr[0].rotation, arr[0].rotation,
@ -286,14 +286,14 @@ where
#[inline] #[inline]
fn from(arr: [Isometry<T::Element, R::Element, D>; 8]) -> Self { fn from(arr: [Isometry<T::Element, R::Element, D>; 8]) -> Self {
let tra = Translation::from([ let tra = Translation::from([
arr[0].translation.clone(), arr[0].translation,
arr[1].translation.clone(), arr[1].translation,
arr[2].translation.clone(), arr[2].translation,
arr[3].translation.clone(), arr[3].translation,
arr[4].translation.clone(), arr[4].translation,
arr[5].translation.clone(), arr[5].translation,
arr[6].translation.clone(), arr[6].translation,
arr[7].translation.clone(), arr[7].translation,
]); ]);
let rot = R::from([ let rot = R::from([
arr[0].rotation, arr[0].rotation,
@ -322,22 +322,22 @@ where
#[inline] #[inline]
fn from(arr: [Isometry<T::Element, R::Element, D>; 16]) -> Self { fn from(arr: [Isometry<T::Element, R::Element, D>; 16]) -> Self {
let tra = Translation::from([ let tra = Translation::from([
arr[0].translation.clone(), arr[0].translation,
arr[1].translation.clone(), arr[1].translation,
arr[2].translation.clone(), arr[2].translation,
arr[3].translation.clone(), arr[3].translation,
arr[4].translation.clone(), arr[4].translation,
arr[5].translation.clone(), arr[5].translation,
arr[6].translation.clone(), arr[6].translation,
arr[7].translation.clone(), arr[7].translation,
arr[8].translation.clone(), arr[8].translation,
arr[9].translation.clone(), arr[9].translation,
arr[10].translation.clone(), arr[10].translation,
arr[11].translation.clone(), arr[11].translation,
arr[12].translation.clone(), arr[12].translation,
arr[13].translation.clone(), arr[13].translation,
arr[14].translation.clone(), arr[14].translation,
arr[15].translation.clone(), arr[15].translation,
]); ]);
let rot = R::from([ let rot = R::from([
arr[0].rotation, arr[0].rotation,

View File

@ -26,6 +26,7 @@ impl<T: SimdRealField> Isometry3<T> {
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp_slerp(&self, other: &Self, t: T) -> Self pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,
@ -59,6 +60,7 @@ impl<T: SimdRealField> Isometry3<T> {
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self> pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
where where
T: RealField, T: RealField,
@ -94,6 +96,7 @@ impl<T: SimdRealField> IsometryMatrix3<T> {
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp_slerp(&self, other: &Self, t: T) -> Self pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,
@ -127,6 +130,7 @@ impl<T: SimdRealField> IsometryMatrix3<T> {
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self> pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
where where
T: RealField, T: RealField,
@ -163,6 +167,7 @@ impl<T: SimdRealField> Isometry2<T> {
/// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2); /// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp_slerp(&self, other: &Self, t: T) -> Self pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,
@ -199,6 +204,7 @@ impl<T: SimdRealField> IsometryMatrix2<T> {
/// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2); /// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp_slerp(&self, other: &Self, t: T) -> Self pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
use num::{One, Zero}; use num::{One, Zero};
use std::ops::{Div, DivAssign, Mul, MulAssign}; use std::ops::{Div, DivAssign, Mul, MulAssign};
@ -198,7 +201,7 @@ md_assign_impl_all!(
const D; for; where; const D; for; where;
self: Isometry<T, Rotation<T, D>, D>, rhs: Rotation<T, D>; self: Isometry<T, Rotation<T, D>, D>, rhs: Rotation<T, D>;
[val] => self.rotation *= rhs; [val] => self.rotation *= rhs;
[ref] => self.rotation *= rhs.clone(); [ref] => self.rotation *= *rhs;
); );
md_assign_impl_all!( md_assign_impl_all!(
@ -365,9 +368,9 @@ isometry_from_composition_impl_all!(
D; D;
self: Rotation<T, D>, right: Translation<T, D>, Output = Isometry<T, Rotation<T, D>, D>; self: Rotation<T, D>, right: Translation<T, D>, Output = Isometry<T, Rotation<T, D>, D>;
[val val] => Isometry::from_parts(Translation::from(&self * right.vector), self); [val val] => Isometry::from_parts(Translation::from(&self * right.vector), self);
[ref val] => Isometry::from_parts(Translation::from(self * right.vector), self.clone()); [ref val] => Isometry::from_parts(Translation::from(self * right.vector), *self);
[val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self); [val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self);
[ref ref] => Isometry::from_parts(Translation::from(self * &right.vector), self.clone()); [ref ref] => Isometry::from_parts(Translation::from(self * &right.vector), *self);
); );
// UnitQuaternion × Translation // UnitQuaternion × Translation
@ -389,9 +392,9 @@ isometry_from_composition_impl_all!(
self: Isometry<T, Rotation<T, D>, D>, rhs: Rotation<T, D>, self: Isometry<T, Rotation<T, D>, D>, rhs: Rotation<T, D>,
Output = Isometry<T, Rotation<T, D>, D>; Output = Isometry<T, Rotation<T, D>, D>;
[val val] => Isometry::from_parts(self.translation, self.rotation * rhs); [val val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // TODO: do not clone. [ref val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); [val ref] => Isometry::from_parts(self.translation, self.rotation * *rhs);
[ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); [ref ref] => Isometry::from_parts(self.translation, self.rotation * *rhs);
); );
// Rotation × Isometry // Rotation × Isometry
@ -416,9 +419,9 @@ isometry_from_composition_impl_all!(
self: Isometry<T, Rotation<T, D>, D>, rhs: Rotation<T, D>, self: Isometry<T, Rotation<T, D>, D>, rhs: Rotation<T, D>,
Output = Isometry<T, Rotation<T, D>, D>; Output = Isometry<T, Rotation<T, D>, D>;
[val val] => Isometry::from_parts(self.translation, self.rotation / rhs); [val val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // TODO: do not clone. [ref val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); [val ref] => Isometry::from_parts(self.translation, self.rotation / *rhs);
[ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); [ref ref] => Isometry::from_parts(self.translation, self.rotation / *rhs);
); );
// Rotation ÷ Isometry // Rotation ÷ Isometry
@ -441,9 +444,9 @@ isometry_from_composition_impl_all!(
self: Isometry<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>, self: Isometry<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>,
Output = Isometry<T, UnitQuaternion<T>, 3>; Output = Isometry<T, UnitQuaternion<T>, 3>;
[val val] => Isometry::from_parts(self.translation, self.rotation * rhs); [val val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[ref val] => Isometry::from_parts(self.translation.clone(), self.rotation * rhs); // TODO: do not clone. [ref val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[val ref] => Isometry::from_parts(self.translation, self.rotation * *rhs); [val ref] => Isometry::from_parts(self.translation, self.rotation * *rhs);
[ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation * *rhs); [ref ref] => Isometry::from_parts(self.translation, self.rotation * *rhs);
); );
// UnitQuaternion × Isometry // UnitQuaternion × Isometry
@ -468,9 +471,9 @@ isometry_from_composition_impl_all!(
self: Isometry<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>, self: Isometry<T, UnitQuaternion<T>, 3>, rhs: UnitQuaternion<T>,
Output = Isometry<T, UnitQuaternion<T>, 3>; Output = Isometry<T, UnitQuaternion<T>, 3>;
[val val] => Isometry::from_parts(self.translation, self.rotation / rhs); [val val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[ref val] => Isometry::from_parts(self.translation.clone(), self.rotation / rhs); // TODO: do not clone. [ref val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[val ref] => Isometry::from_parts(self.translation, self.rotation / *rhs); [val ref] => Isometry::from_parts(self.translation, self.rotation / *rhs);
[ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation / *rhs); [ref ref] => Isometry::from_parts(self.translation, self.rotation / *rhs);
); );
// UnitQuaternion ÷ Isometry // UnitQuaternion ÷ Isometry
@ -492,9 +495,9 @@ isometry_from_composition_impl_all!(
D; D;
self: Translation<T, D>, right: Rotation<T, D>, Output = Isometry<T, Rotation<T, D>, D>; self: Translation<T, D>, right: Rotation<T, D>, Output = Isometry<T, Rotation<T, D>, D>;
[val val] => Isometry::from_parts(self, right); [val val] => Isometry::from_parts(self, right);
[ref val] => Isometry::from_parts(self.clone(), right); [ref val] => Isometry::from_parts(*self, right);
[val ref] => Isometry::from_parts(self, right.clone()); [val ref] => Isometry::from_parts(self, *right);
[ref ref] => Isometry::from_parts(self.clone(), right.clone()); [ref ref] => Isometry::from_parts(*self, *right);
); );
// Translation × UnitQuaternion // Translation × UnitQuaternion
@ -503,9 +506,9 @@ isometry_from_composition_impl_all!(
; ;
self: Translation<T, 3>, right: UnitQuaternion<T>, Output = Isometry<T, UnitQuaternion<T>, 3>; self: Translation<T, 3>, right: UnitQuaternion<T>, Output = Isometry<T, UnitQuaternion<T>, 3>;
[val val] => Isometry::from_parts(self, right); [val val] => Isometry::from_parts(self, right);
[ref val] => Isometry::from_parts(self.clone(), right); [ref val] => Isometry::from_parts(*self, right);
[val ref] => Isometry::from_parts(self, *right); [val ref] => Isometry::from_parts(self, *right);
[ref ref] => Isometry::from_parts(self.clone(), *right); [ref ref] => Isometry::from_parts(*self, *right);
); );
// Isometry × UnitComplex // Isometry × UnitComplex
@ -515,9 +518,9 @@ isometry_from_composition_impl_all!(
self: Isometry<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>, self: Isometry<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>,
Output = Isometry<T, UnitComplex<T>, 2>; Output = Isometry<T, UnitComplex<T>, 2>;
[val val] => Isometry::from_parts(self.translation, self.rotation * rhs); [val val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[ref val] => Isometry::from_parts(self.translation.clone(), self.rotation * rhs); // TODO: do not clone. [ref val] => Isometry::from_parts(self.translation, self.rotation * rhs);
[val ref] => Isometry::from_parts(self.translation, self.rotation * *rhs); [val ref] => Isometry::from_parts(self.translation, self.rotation * *rhs);
[ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation * *rhs); [ref ref] => Isometry::from_parts(self.translation, self.rotation * *rhs);
); );
// Isometry ÷ UnitComplex // Isometry ÷ UnitComplex
@ -527,7 +530,7 @@ isometry_from_composition_impl_all!(
self: Isometry<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>, self: Isometry<T, UnitComplex<T>, 2>, rhs: UnitComplex<T>,
Output = Isometry<T, UnitComplex<T>, 2>; Output = Isometry<T, UnitComplex<T>, 2>;
[val val] => Isometry::from_parts(self.translation, self.rotation / rhs); [val val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[ref val] => Isometry::from_parts(self.translation.clone(), self.rotation / rhs); // TODO: do not clone. [ref val] => Isometry::from_parts(self.translation, self.rotation / rhs);
[val ref] => Isometry::from_parts(self.translation, self.rotation / *rhs); [val ref] => Isometry::from_parts(self.translation, self.rotation / *rhs);
[ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation / *rhs); [ref ref] => Isometry::from_parts(self.translation, self.rotation / *rhs);
); );

View File

@ -8,7 +8,6 @@ use rand::{
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt; use std::fmt;
use std::mem;
use simba::scalar::RealField; use simba::scalar::RealField;
@ -19,7 +18,7 @@ use crate::base::{Matrix4, Vector, Vector3};
use crate::geometry::{Point3, Projective3}; use crate::geometry::{Point3, Projective3};
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix. /// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
pub struct Orthographic3<T: RealField> { pub struct Orthographic3<T> {
matrix: Matrix4<T>, matrix: Matrix4<T>,
} }
@ -188,6 +187,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity()); /// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse(&self) -> Matrix4<T> { pub fn inverse(&self) -> Matrix4<T> {
let mut res = self.to_homogeneous(); let mut res = self.to_homogeneous();
@ -221,7 +221,8 @@ impl<T: RealField> Orthographic3<T> {
/// assert_eq!(proj.to_homogeneous(), expected); /// assert_eq!(proj.to_homogeneous(), expected);
/// ``` /// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> Matrix4<T> { #[must_use]
pub fn to_homogeneous(self) -> Matrix4<T> {
self.matrix self.matrix
} }
@ -240,6 +241,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_eq!(*proj.as_matrix(), expected); /// assert_eq!(*proj.as_matrix(), expected);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn as_matrix(&self) -> &Matrix4<T> { pub fn as_matrix(&self) -> &Matrix4<T> {
&self.matrix &self.matrix
} }
@ -253,8 +255,9 @@ impl<T: RealField> Orthographic3<T> {
/// assert_eq!(proj.as_projective().to_homogeneous(), proj.to_homogeneous()); /// assert_eq!(proj.as_projective().to_homogeneous(), proj.to_homogeneous());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn as_projective(&self) -> &Projective3<T> { pub fn as_projective(&self) -> &Projective3<T> {
unsafe { mem::transmute(self) } unsafe { &*(self as *const Orthographic3<T> as *const Projective3<T>) }
} }
/// This transformation seen as a `Projective3`. /// This transformation seen as a `Projective3`.
@ -266,7 +269,8 @@ impl<T: RealField> Orthographic3<T> {
/// assert_eq!(proj.to_projective().to_homogeneous(), proj.to_homogeneous()); /// assert_eq!(proj.to_projective().to_homogeneous(), proj.to_homogeneous());
/// ``` /// ```
#[inline] #[inline]
pub fn to_projective(&self) -> Projective3<T> { #[must_use]
pub fn to_projective(self) -> Projective3<T> {
Projective3::from_matrix_unchecked(self.matrix) Projective3::from_matrix_unchecked(self.matrix)
} }
@ -310,6 +314,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.left(), 10.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.left(), 10.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn left(&self) -> T { pub fn left(&self) -> T {
(-T::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)] (-T::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)]
} }
@ -326,6 +331,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.right(), 1.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.right(), 1.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn right(&self) -> T { pub fn right(&self) -> T {
(T::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)] (T::one() - self.matrix[(0, 3)]) / self.matrix[(0, 0)]
} }
@ -342,6 +348,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.bottom(), 20.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.bottom(), 20.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn bottom(&self) -> T { pub fn bottom(&self) -> T {
(-T::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)] (-T::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)]
} }
@ -358,6 +365,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.top(), 2.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.top(), 2.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn top(&self) -> T { pub fn top(&self) -> T {
(T::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)] (T::one() - self.matrix[(1, 3)]) / self.matrix[(1, 1)]
} }
@ -374,6 +382,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.znear(), 1000.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.znear(), 1000.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn znear(&self) -> T { pub fn znear(&self) -> T {
(T::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)] (T::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)]
} }
@ -390,6 +399,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.zfar(), 0.1, epsilon = 1.0e-6); /// assert_relative_eq!(proj.zfar(), 0.1, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn zfar(&self) -> T { pub fn zfar(&self) -> T {
(-T::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)] (-T::one() + self.matrix[(2, 3)]) / self.matrix[(2, 2)]
} }
@ -422,6 +432,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0)); /// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn project_point(&self, p: &Point3<T>) -> Point3<T> { pub fn project_point(&self, p: &Point3<T>) -> Point3<T> {
Point3::new( Point3::new(
self.matrix[(0, 0)] * p[0] + self.matrix[(0, 3)], self.matrix[(0, 0)] * p[0] + self.matrix[(0, 3)],
@ -457,6 +468,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.unproject_point(&p8), Point3::new(10.0, 20.0, -1000.0), epsilon = 1.0e-6); /// assert_relative_eq!(proj.unproject_point(&p8), Point3::new(10.0, 20.0, -1000.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn unproject_point(&self, p: &Point3<T>) -> Point3<T> { pub fn unproject_point(&self, p: &Point3<T>) -> Point3<T> {
Point3::new( Point3::new(
(p[0] - self.matrix[(0, 3)]) / self.matrix[(0, 0)], (p[0] - self.matrix[(0, 3)]) / self.matrix[(0, 0)],
@ -485,6 +497,7 @@ impl<T: RealField> Orthographic3<T> {
/// assert_relative_eq!(proj.project_vector(&v3), Vector3::z() * -2.0 / 999.9); /// assert_relative_eq!(proj.project_vector(&v3), Vector3::z() * -2.0 / 999.9);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn project_vector<SB>(&self, p: &Vector<T, U3, SB>) -> Vector3<T> pub fn project_vector<SB>(&self, p: &Vector<T, U3, SB>) -> Vector3<T>
where where
SB: Storage<T, U3>, SB: Storage<T, U3>,

View File

@ -9,18 +9,17 @@ use rand::{
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt; use std::fmt;
use std::mem;
use simba::scalar::RealField; use simba::scalar::RealField;
use crate::base::dimension::U3; use crate::base::dimension::U3;
use crate::base::storage::Storage; use crate::base::storage::Storage;
use crate::base::{Matrix4, Scalar, Vector, Vector3}; use crate::base::{Matrix4, Vector, Vector3};
use crate::geometry::{Point3, Projective3}; use crate::geometry::{Point3, Projective3};
/// A 3D perspective projection stored as a homogeneous 4x4 matrix. /// A 3D perspective projection stored as a homogeneous 4x4 matrix.
pub struct Perspective3<T: Scalar> { pub struct Perspective3<T> {
matrix: Matrix4<T>, matrix: Matrix4<T>,
} }
@ -104,6 +103,7 @@ impl<T: RealField> Perspective3<T> {
/// Retrieves the inverse of the underlying homogeneous matrix. /// Retrieves the inverse of the underlying homogeneous matrix.
#[inline] #[inline]
#[must_use]
pub fn inverse(&self) -> Matrix4<T> { pub fn inverse(&self) -> Matrix4<T> {
let mut res = self.to_homogeneous(); let mut res = self.to_homogeneous();
@ -123,25 +123,29 @@ impl<T: RealField> Perspective3<T> {
/// Computes the corresponding homogeneous matrix. /// Computes the corresponding homogeneous matrix.
#[inline] #[inline]
pub fn to_homogeneous(&self) -> Matrix4<T> { #[must_use]
pub fn to_homogeneous(self) -> Matrix4<T> {
self.matrix.clone_owned() self.matrix.clone_owned()
} }
/// A reference to the underlying homogeneous transformation matrix. /// A reference to the underlying homogeneous transformation matrix.
#[inline] #[inline]
#[must_use]
pub fn as_matrix(&self) -> &Matrix4<T> { pub fn as_matrix(&self) -> &Matrix4<T> {
&self.matrix &self.matrix
} }
/// A reference to this transformation seen as a `Projective3`. /// A reference to this transformation seen as a `Projective3`.
#[inline] #[inline]
#[must_use]
pub fn as_projective(&self) -> &Projective3<T> { pub fn as_projective(&self) -> &Projective3<T> {
unsafe { mem::transmute(self) } unsafe { &*(self as *const Perspective3<T> as *const Projective3<T>) }
} }
/// This transformation seen as a `Projective3`. /// This transformation seen as a `Projective3`.
#[inline] #[inline]
pub fn to_projective(&self) -> Projective3<T> { #[must_use]
pub fn to_projective(self) -> Projective3<T> {
Projective3::from_matrix_unchecked(self.matrix) Projective3::from_matrix_unchecked(self.matrix)
} }
@ -161,18 +165,21 @@ impl<T: RealField> Perspective3<T> {
/// Gets the `width / height` aspect ratio of the view frustum. /// Gets the `width / height` aspect ratio of the view frustum.
#[inline] #[inline]
#[must_use]
pub fn aspect(&self) -> T { pub fn aspect(&self) -> T {
self.matrix[(1, 1)] / self.matrix[(0, 0)] self.matrix[(1, 1)] / self.matrix[(0, 0)]
} }
/// Gets the y field of view of the view frustum. /// Gets the y field of view of the view frustum.
#[inline] #[inline]
#[must_use]
pub fn fovy(&self) -> T { pub fn fovy(&self) -> T {
(T::one() / self.matrix[(1, 1)]).atan() * crate::convert(2.0) (T::one() / self.matrix[(1, 1)]).atan() * crate::convert(2.0)
} }
/// Gets the near plane offset of the view frustum. /// Gets the near plane offset of the view frustum.
#[inline] #[inline]
#[must_use]
pub fn znear(&self) -> T { pub fn znear(&self) -> T {
let ratio = (-self.matrix[(2, 2)] + T::one()) / (-self.matrix[(2, 2)] - T::one()); let ratio = (-self.matrix[(2, 2)] + T::one()) / (-self.matrix[(2, 2)] - T::one());
@ -182,6 +189,7 @@ impl<T: RealField> Perspective3<T> {
/// Gets the far plane offset of the view frustum. /// Gets the far plane offset of the view frustum.
#[inline] #[inline]
#[must_use]
pub fn zfar(&self) -> T { pub fn zfar(&self) -> T {
let ratio = (-self.matrix[(2, 2)] + T::one()) / (-self.matrix[(2, 2)] - T::one()); let ratio = (-self.matrix[(2, 2)] + T::one()) / (-self.matrix[(2, 2)] - T::one());
@ -193,6 +201,7 @@ impl<T: RealField> Perspective3<T> {
// TODO: when we get specialization, specialize the Mul impl instead. // TODO: when we get specialization, specialize the Mul impl instead.
/// Projects a point. Faster than matrix multiplication. /// Projects a point. Faster than matrix multiplication.
#[inline] #[inline]
#[must_use]
pub fn project_point(&self, p: &Point3<T>) -> Point3<T> { pub fn project_point(&self, p: &Point3<T>) -> Point3<T> {
let inverse_denom = -T::one() / p[2]; let inverse_denom = -T::one() / p[2];
Point3::new( Point3::new(
@ -204,6 +213,7 @@ impl<T: RealField> Perspective3<T> {
/// Un-projects a point. Faster than multiplication by the matrix inverse. /// Un-projects a point. Faster than multiplication by the matrix inverse.
#[inline] #[inline]
#[must_use]
pub fn unproject_point(&self, p: &Point3<T>) -> Point3<T> { pub fn unproject_point(&self, p: &Point3<T>) -> Point3<T> {
let inverse_denom = self.matrix[(2, 3)] / (p[2] + self.matrix[(2, 2)]); let inverse_denom = self.matrix[(2, 3)] / (p[2] + self.matrix[(2, 2)]);
@ -217,6 +227,7 @@ impl<T: RealField> Perspective3<T> {
// TODO: when we get specialization, specialize the Mul impl instead. // TODO: when we get specialization, specialize the Mul impl instead.
/// Projects a vector. Faster than matrix multiplication. /// Projects a vector. Faster than matrix multiplication.
#[inline] #[inline]
#[must_use]
pub fn project_vector<SB>(&self, p: &Vector<T, U3, SB>) -> Vector3<T> pub fn project_vector<SB>(&self, p: &Vector<T, U3, SB>) -> Vector3<T>
where where
SB: Storage<T, U3>, SB: Storage<T, U3>,
@ -244,8 +255,9 @@ impl<T: RealField> Perspective3<T> {
#[inline] #[inline]
pub fn set_fovy(&mut self, fovy: T) { pub fn set_fovy(&mut self, fovy: T) {
let old_m22 = self.matrix[(1, 1)]; let old_m22 = self.matrix[(1, 1)];
self.matrix[(1, 1)] = T::one() / (fovy / crate::convert(2.0)).tan(); let new_m22 = T::one() / (fovy / crate::convert(2.0)).tan();
self.matrix[(0, 0)] = self.matrix[(0, 0)] * (self.matrix[(1, 1)] / old_m22); self.matrix[(1, 1)] = new_m22;
self.matrix[(0, 0)] *= new_m22 / old_m22;
} }
/// Updates this perspective matrix with a new near plane offset of the view frustum. /// Updates this perspective matrix with a new near plane offset of the view frustum.
@ -276,7 +288,7 @@ where
Standard: Distribution<T>, Standard: Distribution<T>,
{ {
/// Generate an arbitrary random variate for testing purposes. /// Generate an arbitrary random variate for testing purposes.
fn sample<'a, R: Rng + ?Sized>(&self, r: &'a mut R) -> Perspective3<T> { fn sample<R: Rng + ?Sized>(&self, r: &mut R) -> Perspective3<T> {
use crate::base::helper; use crate::base::helper;
let znear = r.gen(); let znear = r.gen();
let zfar = helper::reject_rand(r, |&x: &T| !(x - znear).is_zero()); let zfar = helper::reject_rand(r, |&x: &T| !(x - znear).is_zero());

View File

@ -17,7 +17,7 @@ use simba::simd::SimdPartialOrd;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use crate::base::iter::{MatrixIter, MatrixIterMut}; use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::{Const, DefaultAllocator, OVector, SVector, Scalar}; use crate::base::{Const, DefaultAllocator, OVector, Scalar};
/// A point in an euclidean space. /// A point in an euclidean space.
/// ///
@ -40,35 +40,53 @@ use crate::base::{Const, DefaultAllocator, OVector, SVector, Scalar};
/// of said transformations for details. /// of said transformations for details.
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Point<T, const D: usize> { pub struct OPoint<T: Scalar, D: DimName>
where
DefaultAllocator: Allocator<T, D>,
{
/// The coordinates of this point, i.e., the shift from the origin. /// The coordinates of this point, i.e., the shift from the origin.
pub coords: SVector<T, D>, pub coords: OVector<T, D>,
} }
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Point<T, D> { impl<T: Scalar + hash::Hash, D: DimName> hash::Hash for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.coords.hash(state) self.coords.hash(state)
} }
} }
impl<T: Scalar + Copy, const D: usize> Copy for Point<T, D> {} impl<T: Scalar + Copy, D: DimName> Copy for OPoint<T, D>
where
#[cfg(feature = "bytemuck")] DefaultAllocator: Allocator<T, D>,
unsafe impl<T: Scalar, const D: usize> bytemuck::Zeroable for Point<T, D> where OVector<T, D>: Copy,
SVector<T, D>: bytemuck::Zeroable
{ {
} }
#[cfg(feature = "bytemuck")] #[cfg(feature = "bytemuck")]
unsafe impl<T: Scalar, const D: usize> bytemuck::Pod for Point<T, D> unsafe impl<T: Scalar, D: DimName> bytemuck::Zeroable for OPoint<T, D>
where
OVector<T, D>: bytemuck::Zeroable,
DefaultAllocator: Allocator<T, D>,
{
}
#[cfg(feature = "bytemuck")]
unsafe impl<T: Scalar, D: DimName> bytemuck::Pod for OPoint<T, D>
where where
T: Copy, T: Copy,
SVector<T, D>: bytemuck::Pod, OVector<T, D>: bytemuck::Pod,
DefaultAllocator: Allocator<T, D>,
{ {
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<T: Scalar + Serialize, const D: usize> Serialize for Point<T, D> { impl<T: Scalar + Serialize, D: DimName> Serialize for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
<DefaultAllocator as Allocator<T, D>>::Buffer: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
@ -78,22 +96,27 @@ impl<T: Scalar + Serialize, const D: usize> Serialize for Point<T, D> {
} }
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
impl<'a, T: Scalar + Deserialize<'a>, const D: usize> Deserialize<'a> for Point<T, D> { impl<'a, T: Scalar + Deserialize<'a>, D: DimName> Deserialize<'a> for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
<DefaultAllocator as Allocator<T, D>>::Buffer: Deserialize<'a>,
{
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where where
Des: Deserializer<'a>, Des: Deserializer<'a>,
{ {
let coords = SVector::<T, D>::deserialize(deserializer)?; let coords = OVector::<T, D>::deserialize(deserializer)?;
Ok(Self::from(coords)) Ok(Self::from(coords))
} }
} }
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
impl<T, const D: usize> Abomonation for Point<T, D> impl<T, D: DimName> Abomonation for OPoint<T, D>
where where
T: Scalar, T: Scalar,
SVector<T, D>: Abomonation, OVector<T, D>: Abomonation,
DefaultAllocator: Allocator<T, D>,
{ {
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> { unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
self.coords.entomb(writer) self.coords.entomb(writer)
@ -108,7 +131,10 @@ where
} }
} }
impl<T: Scalar, const D: usize> Point<T, D> { impl<T: Scalar, D: DimName> OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
/// Returns a point containing the result of `f` applied to each of its entries. /// Returns a point containing the result of `f` applied to each of its entries.
/// ///
/// # Example /// # Example
@ -122,7 +148,11 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// assert_eq!(p.map(|e| e as u32), Point3::new(1, 2, 3)); /// assert_eq!(p.map(|e| e as u32), Point3::new(1, 2, 3));
/// ``` /// ```
#[inline] #[inline]
pub fn map<T2: Scalar, F: FnMut(T) -> T2>(&self, f: F) -> Point<T2, D> { #[must_use]
pub fn map<T2: Scalar, F: FnMut(T) -> T2>(&self, f: F) -> OPoint<T2, D>
where
DefaultAllocator: Allocator<T2, D>,
{
self.coords.map(f).into() self.coords.map(f).into()
} }
@ -161,20 +191,22 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// assert_eq!(p.to_homogeneous(), Vector4::new(10.0, 20.0, 30.0, 1.0)); /// assert_eq!(p.to_homogeneous(), Vector4::new(10.0, 20.0, 30.0, 1.0));
/// ``` /// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> OVector<T, DimNameSum<Const<D>, U1>> #[must_use]
pub fn to_homogeneous(&self) -> OVector<T, DimNameSum<D, U1>>
where where
T: One, T: One,
Const<D>: DimNameAdd<U1>, D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
{ {
let mut res = unsafe { let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!( crate::unimplemented_or_uninitialized_generic!(
<DimNameSum<Const<D>, U1> as DimName>::name(), <DimNameSum<D, U1> as DimName>::name(),
Const::<1> Const::<1>
) )
}; };
res.fixed_slice_mut::<D, 1>(0, 0).copy_from(&self.coords); res.generic_slice_mut((0, 0), (D::name(), Const::<1>))
res[(D, 0)] = T::one(); .copy_from(&self.coords);
res[(D::dim(), 0)] = T::one();
res res
} }
@ -182,7 +214,7 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// Creates a new point with the given coordinates. /// Creates a new point with the given coordinates.
#[deprecated(note = "Use Point::from(vector) instead.")] #[deprecated(note = "Use Point::from(vector) instead.")]
#[inline] #[inline]
pub fn from_coordinates(coords: SVector<T, D>) -> Self { pub fn from_coordinates(coords: OVector<T, D>) -> Self {
Self { coords } Self { coords }
} }
@ -199,6 +231,7 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// assert_eq!(p.len(), 3); /// assert_eq!(p.len(), 3);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.coords.len() self.coords.len()
} }
@ -212,6 +245,7 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// assert!(!p.is_empty()); /// assert!(!p.is_empty());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }
@ -239,13 +273,13 @@ impl<T: Scalar, const D: usize> Point<T, D> {
#[inline] #[inline]
pub fn iter( pub fn iter(
&self, &self,
) -> MatrixIter<T, Const<D>, Const<1>, <DefaultAllocator as Allocator<T, Const<D>>>::Buffer> ) -> MatrixIter<T, D, Const<1>, <DefaultAllocator as Allocator<T, D>>::Buffer> {
{
self.coords.iter() self.coords.iter()
} }
/// Gets a reference to i-th element of this point without bound-checking. /// Gets a reference to i-th element of this point without bound-checking.
#[inline] #[inline]
#[must_use]
pub unsafe fn get_unchecked(&self, i: usize) -> &T { pub unsafe fn get_unchecked(&self, i: usize) -> &T {
self.coords.vget_unchecked(i) self.coords.vget_unchecked(i)
} }
@ -265,13 +299,13 @@ impl<T: Scalar, const D: usize> Point<T, D> {
#[inline] #[inline]
pub fn iter_mut( pub fn iter_mut(
&mut self, &mut self,
) -> MatrixIterMut<T, Const<D>, Const<1>, <DefaultAllocator as Allocator<T, Const<D>>>::Buffer> ) -> MatrixIterMut<T, D, Const<1>, <DefaultAllocator as Allocator<T, D>>::Buffer> {
{
self.coords.iter_mut() self.coords.iter_mut()
} }
/// Gets a mutable reference to i-th element of this point without bound-checking. /// Gets a mutable reference to i-th element of this point without bound-checking.
#[inline] #[inline]
#[must_use]
pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut T { pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut T {
self.coords.vget_unchecked_mut(i) self.coords.vget_unchecked_mut(i)
} }
@ -283,9 +317,10 @@ impl<T: Scalar, const D: usize> Point<T, D> {
} }
} }
impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Point<T, D> impl<T: Scalar + AbsDiffEq, D: DimName> AbsDiffEq for OPoint<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D>,
{ {
type Epsilon = T::Epsilon; type Epsilon = T::Epsilon;
@ -300,9 +335,10 @@ where
} }
} }
impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Point<T, D> impl<T: Scalar + RelativeEq, D: DimName> RelativeEq for OPoint<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D>,
{ {
#[inline] #[inline]
fn default_max_relative() -> Self::Epsilon { fn default_max_relative() -> Self::Epsilon {
@ -321,9 +357,10 @@ where
} }
} }
impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Point<T, D> impl<T: Scalar + UlpsEq, D: DimName> UlpsEq for OPoint<T, D>
where where
T::Epsilon: Copy, T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D>,
{ {
#[inline] #[inline]
fn default_max_ulps() -> u32 { fn default_max_ulps() -> u32 {
@ -336,16 +373,22 @@ where
} }
} }
impl<T: Scalar + Eq, const D: usize> Eq for Point<T, D> {} impl<T: Scalar + Eq, D: DimName> Eq for OPoint<T, D> where DefaultAllocator: Allocator<T, D> {}
impl<T: Scalar, const D: usize> PartialEq for Point<T, D> { impl<T: Scalar, D: DimName> PartialEq for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
#[inline] #[inline]
fn eq(&self, right: &Self) -> bool { fn eq(&self, right: &Self) -> bool {
self.coords == right.coords self.coords == right.coords
} }
} }
impl<T: Scalar + PartialOrd, const D: usize> PartialOrd for Point<T, D> { impl<T: Scalar + PartialOrd, D: DimName> PartialOrd for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
#[inline] #[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.coords.partial_cmp(&other.coords) self.coords.partial_cmp(&other.coords)
@ -375,22 +418,28 @@ impl<T: Scalar + PartialOrd, const D: usize> PartialOrd for Point<T, D> {
/* /*
* inf/sup * inf/sup
*/ */
impl<T: Scalar + SimdPartialOrd, const D: usize> Point<T, D> { impl<T: Scalar + SimdPartialOrd, D: DimName> OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
/// Computes the infimum (aka. componentwise min) of two points. /// Computes the infimum (aka. componentwise min) of two points.
#[inline] #[inline]
pub fn inf(&self, other: &Self) -> Point<T, D> { #[must_use]
pub fn inf(&self, other: &Self) -> OPoint<T, D> {
self.coords.inf(&other.coords).into() self.coords.inf(&other.coords).into()
} }
/// Computes the supremum (aka. componentwise max) of two points. /// Computes the supremum (aka. componentwise max) of two points.
#[inline] #[inline]
pub fn sup(&self, other: &Self) -> Point<T, D> { #[must_use]
pub fn sup(&self, other: &Self) -> OPoint<T, D> {
self.coords.sup(&other.coords).into() self.coords.sup(&other.coords).into()
} }
/// Computes the (infimum, supremum) of two points. /// Computes the (infimum, supremum) of two points.
#[inline] #[inline]
pub fn inf_sup(&self, other: &Self) -> (Point<T, D>, Point<T, D>) { #[must_use]
pub fn inf_sup(&self, other: &Self) -> (OPoint<T, D>, OPoint<T, D>) {
let (inf, sup) = self.coords.inf_sup(&other.coords); let (inf, sup) = self.coords.inf_sup(&other.coords);
(inf.into(), sup.into()) (inf.into(), sup.into())
} }
@ -401,7 +450,10 @@ impl<T: Scalar + SimdPartialOrd, const D: usize> Point<T, D> {
* Display * Display
* *
*/ */
impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Point<T, D> { impl<T: Scalar + fmt::Display, D: DimName> fmt::Display for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{")?; write!(f, "{{")?;

View File

@ -1,4 +1,8 @@
use crate::geometry::Point; use crate::geometry::OPoint;
use crate::Const;
/// A point with `D` elements.
pub type Point<T, const D: usize> = OPoint<T, Const<D>>;
/// A statically sized 1-dimensional column point. /// A statically sized 1-dimensional column point.
/// ///

View File

@ -10,22 +10,26 @@ use rand::{
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{DefaultAllocator, SVector, Scalar}; use crate::base::{DefaultAllocator, Scalar};
use crate::{ use crate::{
Const, OVector, Point1, Point2, Point3, Point4, Point5, Point6, Vector1, Vector2, Vector3, Const, DimName, OPoint, OVector, Point1, Point2, Point3, Point4, Point5, Point6, Vector1,
Vector4, Vector5, Vector6, Vector2, Vector3, Vector4, Vector5, Vector6,
}; };
use simba::scalar::{ClosedDiv, SupersetOf}; use simba::scalar::{ClosedDiv, SupersetOf};
use crate::geometry::Point; use crate::geometry::Point;
/// # Other construction methods /// # Other construction methods
impl<T: Scalar, const D: usize> Point<T, D> { impl<T: Scalar, D: DimName> OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
/// Creates a new point with uninitialized coordinates. /// Creates a new point with uninitialized coordinates.
#[inline] #[inline]
pub unsafe fn new_uninitialized() -> Self { pub unsafe fn new_uninitialized() -> Self {
Self::from(crate::unimplemented_or_uninitialized_generic!( Self::from(crate::unimplemented_or_uninitialized_generic!(
Const::<D>, Const::<1> D::name(),
Const::<1>
)) ))
} }
@ -49,7 +53,7 @@ impl<T: Scalar, const D: usize> Point<T, D> {
where where
T: Zero, T: Zero,
{ {
Self::from(SVector::from_element(T::zero())) Self::from(OVector::from_element(T::zero()))
} }
/// Creates a new point from a slice. /// Creates a new point from a slice.
@ -68,7 +72,7 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// ``` /// ```
#[inline] #[inline]
pub fn from_slice(components: &[T]) -> Self { pub fn from_slice(components: &[T]) -> Self {
Self::from(SVector::from_row_slice(components)) Self::from(OVector::from_row_slice(components))
} }
/// Creates a new point from its homogeneous vector representation. /// Creates a new point from its homogeneous vector representation.
@ -102,14 +106,15 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// assert_eq!(pt, Some(Point2::new(1.0, 2.0))); /// assert_eq!(pt, Some(Point2::new(1.0, 2.0)));
/// ``` /// ```
#[inline] #[inline]
pub fn from_homogeneous(v: OVector<T, DimNameSum<Const<D>, U1>>) -> Option<Self> pub fn from_homogeneous(v: OVector<T, DimNameSum<D, U1>>) -> Option<Self>
where where
T: Scalar + Zero + One + ClosedDiv, T: Scalar + Zero + One + ClosedDiv,
Const<D>: DimNameAdd<U1>, D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<D, U1>>,
{ {
if !v[D].is_zero() { if !v[D::dim()].is_zero() {
let coords = v.fixed_slice::<D, 1>(0, 0) / v[D].inlined_clone(); let coords =
v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].inlined_clone();
Some(Self::from(coords)) Some(Self::from(coords))
} else { } else {
None None
@ -125,9 +130,10 @@ impl<T: Scalar, const D: usize> Point<T, D> {
/// let pt2 = pt.cast::<f32>(); /// let pt2 = pt.cast::<f32>();
/// assert_eq!(pt2, Point2::new(1.0f32, 2.0)); /// assert_eq!(pt2, Point2::new(1.0f32, 2.0));
/// ``` /// ```
pub fn cast<To: Scalar>(self) -> Point<To, D> pub fn cast<To: Scalar>(self) -> OPoint<To, D>
where where
Point<To, D>: SupersetOf<Self>, OPoint<To, D>: SupersetOf<Self>,
DefaultAllocator: Allocator<To, D>,
{ {
crate::convert(self) crate::convert(self)
} }
@ -138,38 +144,43 @@ impl<T: Scalar, const D: usize> Point<T, D> {
* Traits that build points. * Traits that build points.
* *
*/ */
impl<T: Scalar + Bounded, const D: usize> Bounded for Point<T, D> { impl<T: Scalar + Bounded, D: DimName> Bounded for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
#[inline] #[inline]
fn max_value() -> Self { fn max_value() -> Self {
Self::from(SVector::max_value()) Self::from(OVector::max_value())
} }
#[inline] #[inline]
fn min_value() -> Self { fn min_value() -> Self {
Self::from(SVector::min_value()) Self::from(OVector::min_value())
} }
} }
#[cfg(feature = "rand-no-std")] #[cfg(feature = "rand-no-std")]
impl<T: Scalar, const D: usize> Distribution<Point<T, D>> for Standard impl<T: Scalar, D: DimName> Distribution<OPoint<T, D>> for Standard
where where
Standard: Distribution<T>, Standard: Distribution<T>,
DefaultAllocator: Allocator<T, D>,
{ {
/// Generate a `Point` where each coordinate is an independent variate from `[0, 1)`. /// Generate a `Point` where each coordinate is an independent variate from `[0, 1)`.
#[inline] #[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Point<T, D> { fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> OPoint<T, D> {
Point::from(rng.gen::<SVector<T, D>>()) OPoint::from(rng.gen::<OVector<T, D>>())
} }
} }
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Point<T, D> impl<T: Scalar + Arbitrary + Send, D: DimName> Arbitrary for OPoint<T, D>
where where
<DefaultAllocator as Allocator<T, Const<D>>>::Buffer: Send, <DefaultAllocator as Allocator<T, D>>::Buffer: Send,
DefaultAllocator: Allocator<T, D>,
{ {
#[inline] #[inline]
fn arbitrary(g: &mut Gen) -> Self { fn arbitrary(g: &mut Gen) -> Self {
Self::from(SVector::arbitrary(g)) Self::from(OVector::arbitrary(g))
} }
} }
@ -181,7 +192,7 @@ where
// NOTE: the impl for Point1 is not with the others so that we // NOTE: the impl for Point1 is not with the others so that we
// can add a section with the impl block comment. // can add a section with the impl block comment.
/// # Construction from individual components /// # Construction from individual components
impl<T> Point1<T> { impl<T: Scalar> Point1<T> {
/// Initializes this point from its components. /// Initializes this point from its components.
/// ///
/// # Example /// # Example
@ -192,7 +203,7 @@ impl<T> Point1<T> {
/// assert_eq!(p.x, 1.0); /// assert_eq!(p.x, 1.0);
/// ``` /// ```
#[inline] #[inline]
pub const fn new(x: T) -> Self { pub fn new(x: T) -> Self {
Point { Point {
coords: Vector1::new(x), coords: Vector1::new(x),
} }
@ -200,13 +211,13 @@ impl<T> Point1<T> {
} }
macro_rules! componentwise_constructors_impl( macro_rules! componentwise_constructors_impl(
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$( ($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
impl<T> $Point<T> { impl<T: Scalar> $Point<T> {
#[doc = "Initializes this point from its components."] #[doc = "Initializes this point from its components."]
#[doc = "# Example\n```"] #[doc = "# Example\n```"]
#[doc = $doc] #[doc = $doc]
#[doc = "```"] #[doc = "```"]
#[inline] #[inline]
pub const fn new($($args: T),*) -> Self { pub fn new($($args: T),*) -> Self {
Point { coords: $Vector::new($($args),*) } Point { coords: $Vector::new($($args),*) }
} }
} }

View File

@ -7,6 +7,7 @@ use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar}; use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar};
use crate::geometry::Point; use crate::geometry::Point;
use crate::{DimName, OPoint};
/* /*
* This file provides the following conversions: * This file provides the following conversions:
@ -16,67 +17,69 @@ use crate::geometry::Point;
* Point -> Vector (homogeneous) * Point -> Vector (homogeneous)
*/ */
impl<T1, T2, const D: usize> SubsetOf<Point<T2, D>> for Point<T1, D> impl<T1, T2, D: DimName> SubsetOf<OPoint<T2, D>> for OPoint<T1, D>
where where
T1: Scalar, T1: Scalar,
T2: Scalar + SupersetOf<T1>, T2: Scalar + SupersetOf<T1>,
DefaultAllocator: Allocator<T1, D> + Allocator<T2, D>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Point<T2, D> { fn to_superset(&self) -> OPoint<T2, D> {
Point::from(self.coords.to_superset()) OPoint::from(self.coords.to_superset())
} }
#[inline] #[inline]
fn is_in_subset(m: &Point<T2, D>) -> bool { fn is_in_subset(m: &OPoint<T2, D>) -> bool {
// TODO: is there a way to reuse the `.is_in_subset` from the matrix implementation of // TODO: is there a way to reuse the `.is_in_subset` from the matrix implementation of
// SubsetOf? // SubsetOf?
m.iter().all(|e| e.is_in_subset()) m.iter().all(|e| e.is_in_subset())
} }
#[inline] #[inline]
fn from_superset_unchecked(m: &Point<T2, D>) -> Self { fn from_superset_unchecked(m: &OPoint<T2, D>) -> Self {
Self::from(Matrix::from_superset_unchecked(&m.coords)) Self::from(Matrix::from_superset_unchecked(&m.coords))
} }
} }
impl<T1, T2, const D: usize> SubsetOf<OVector<T2, DimNameSum<Const<D>, U1>>> for Point<T1, D> impl<T1, T2, D> SubsetOf<OVector<T2, DimNameSum<D, U1>>> for OPoint<T1, D>
where where
Const<D>: DimNameAdd<U1>, D: DimNameAdd<U1>,
T1: Scalar, T1: Scalar,
T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>, T2: Scalar + Zero + One + ClosedDiv + SupersetOf<T1>,
DefaultAllocator: DefaultAllocator: Allocator<T1, D>
Allocator<T1, DimNameSum<Const<D>, U1>> + Allocator<T2, DimNameSum<Const<D>, U1>>, + Allocator<T2, D>
+ Allocator<T1, DimNameSum<D, U1>>
+ Allocator<T2, DimNameSum<D, U1>>,
// + Allocator<T1, D> // + Allocator<T1, D>
// + Allocator<T2, D>, // + Allocator<T2, D>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> OVector<T2, DimNameSum<Const<D>, U1>> { fn to_superset(&self) -> OVector<T2, DimNameSum<D, U1>> {
let p: Point<T2, D> = self.to_superset(); let p: OPoint<T2, D> = self.to_superset();
p.to_homogeneous() p.to_homogeneous()
} }
#[inline] #[inline]
fn is_in_subset(v: &OVector<T2, DimNameSum<Const<D>, U1>>) -> bool { fn is_in_subset(v: &OVector<T2, DimNameSum<D, U1>>) -> bool {
crate::is_convertible::<_, OVector<T1, DimNameSum<Const<D>, U1>>>(v) && !v[D].is_zero() crate::is_convertible::<_, OVector<T1, DimNameSum<D, U1>>>(v) && !v[D::dim()].is_zero()
} }
#[inline] #[inline]
fn from_superset_unchecked(v: &OVector<T2, DimNameSum<Const<D>, U1>>) -> Self { fn from_superset_unchecked(v: &OVector<T2, DimNameSum<D, U1>>) -> Self {
let coords = v.fixed_slice::<D, 1>(0, 0) / v[D].inlined_clone(); let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].inlined_clone();
Self { Self {
coords: crate::convert_unchecked(coords), coords: crate::convert_unchecked(coords),
} }
} }
} }
impl<T: Scalar + Zero + One, const D: usize> From<Point<T, D>> impl<T: Scalar + Zero + One, D: DimName> From<OPoint<T, D>> for OVector<T, DimNameSum<D, U1>>
for OVector<T, DimNameSum<Const<D>, U1>>
where where
Const<D>: DimNameAdd<U1>, D: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>>, DefaultAllocator: Allocator<T, DimNameSum<D, U1>> + Allocator<T, D>,
{ {
#[inline] #[inline]
fn from(t: Point<T, D>) -> Self { fn from(t: OPoint<T, D>) -> Self {
t.to_homogeneous() t.to_homogeneous()
} }
} }
@ -90,17 +93,20 @@ impl<T: Scalar, const D: usize> From<[T; D]> for Point<T, D> {
} }
} }
impl<T: Scalar, const D: usize> Into<[T; D]> for Point<T, D> { impl<T: Scalar, const D: usize> From<Point<T, D>> for [T; D] {
#[inline] #[inline]
fn into(self) -> [T; D] { fn from(p: Point<T, D>) -> Self {
self.coords.into() p.coords.into()
} }
} }
impl<T: Scalar, const D: usize> From<OVector<T, Const<D>>> for Point<T, D> { impl<T: Scalar, D: DimName> From<OVector<T, D>> for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
#[inline] #[inline]
fn from(coords: OVector<T, Const<D>>) -> Self { fn from(coords: OVector<T, D>) -> Self {
Point { coords } OPoint { coords }
} }
} }

View File

@ -1,9 +1,9 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
use crate::base::Scalar; use crate::base::{Scalar, U1, U2, U3, U4, U5, U6};
use crate::geometry::Point; use crate::geometry::OPoint;
/* /*
* *
@ -12,8 +12,8 @@ use crate::geometry::Point;
*/ */
macro_rules! deref_impl( macro_rules! deref_impl(
($D: expr, $Target: ident $(, $comps: ident)*) => { ($D: ty, $Target: ident $(, $comps: ident)*) => {
impl<T: Scalar> Deref for Point<T, $D> impl<T: Scalar> Deref for OPoint<T, $D>
{ {
type Target = $Target<T>; type Target = $Target<T>;
@ -23,7 +23,7 @@ macro_rules! deref_impl(
} }
} }
impl<T: Scalar> DerefMut for Point<T, $D> impl<T: Scalar> DerefMut for OPoint<T, $D>
{ {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
@ -33,9 +33,9 @@ macro_rules! deref_impl(
} }
); );
deref_impl!(1, X, x); deref_impl!(U1, X, x);
deref_impl!(2, XY, x, y); deref_impl!(U2, XY, x, y);
deref_impl!(3, XYZ, x, y, z); deref_impl!(U3, XYZ, x, y, z);
deref_impl!(4, XYZW, x, y, z, w); deref_impl!(U4, XYZW, x, y, z, w);
deref_impl!(5, XYZWA, x, y, z, w, a); deref_impl!(U5, XYZWA, x, y, z, w, a);
deref_impl!(6, XYZWAB, x, y, z, w, a, b); deref_impl!(U6, XYZWAB, x, y, z, w, a, b);

View File

@ -8,18 +8,23 @@ use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
use crate::base::constraint::{ use crate::base::constraint::{
AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
}; };
use crate::base::dimension::{Dim, U1}; use crate::base::dimension::{Dim, DimName, U1};
use crate::base::storage::Storage; use crate::base::storage::Storage;
use crate::base::{Const, Matrix, SVector, Scalar, Vector}; use crate::base::{Const, Matrix, OVector, Scalar, Vector};
use crate::geometry::Point; use crate::allocator::Allocator;
use crate::geometry::{OPoint, Point};
use crate::DefaultAllocator;
/* /*
* *
* Indexing. * Indexing.
* *
*/ */
impl<T: Scalar, const D: usize> Index<usize> for Point<T, D> { impl<T: Scalar, D: DimName> Index<usize> for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
type Output = T; type Output = T;
#[inline] #[inline]
@ -28,7 +33,10 @@ impl<T: Scalar, const D: usize> Index<usize> for Point<T, D> {
} }
} }
impl<T: Scalar, const D: usize> IndexMut<usize> for Point<T, D> { impl<T: Scalar, D: DimName> IndexMut<usize> for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
#[inline] #[inline]
fn index_mut(&mut self, i: usize) -> &mut Self::Output { fn index_mut(&mut self, i: usize) -> &mut Self::Output {
&mut self.coords[i] &mut self.coords[i]
@ -40,7 +48,10 @@ impl<T: Scalar, const D: usize> IndexMut<usize> for Point<T, D> {
* Neg. * Neg.
* *
*/ */
impl<T: Scalar + ClosedNeg, const D: usize> Neg for Point<T, D> { impl<T: Scalar + ClosedNeg, D: DimName> Neg for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
type Output = Self; type Output = Self;
#[inline] #[inline]
@ -49,8 +60,11 @@ impl<T: Scalar + ClosedNeg, const D: usize> Neg for Point<T, D> {
} }
} }
impl<'a, T: Scalar + ClosedNeg, const D: usize> Neg for &'a Point<T, D> { impl<'a, T: Scalar + ClosedNeg, D: DimName> Neg for &'a OPoint<T, D>
type Output = Point<T, D>; where
DefaultAllocator: Allocator<T, D>,
{
type Output = OPoint<T, D>;
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
@ -66,102 +80,103 @@ impl<'a, T: Scalar + ClosedNeg, const D: usize> Neg for &'a Point<T, D> {
// Point - Point // Point - Point
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1) (D, U1), (D, U1) -> (D, U1)
const D; for; where; const; for D; where D: DimName, DefaultAllocator: Allocator<T, D>;
self: &'a Point<T, D>, right: &'b Point<T, D>, Output = SVector<T, D>; self: &'a OPoint<T, D>, right: &'b OPoint<T, D>, Output = OVector<T, D>;
&self.coords - &right.coords; 'a, 'b); &self.coords - &right.coords; 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1) (D, U1), (D, U1) -> (D, U1)
const D; for; where; const; for D; where D: DimName, DefaultAllocator: Allocator<T, D>;
self: &'a Point<T, D>, right: Point<T, D>, Output = SVector<T, D>; self: &'a OPoint<T, D>, right: OPoint<T, D>, Output = OVector<T, D>;
&self.coords - right.coords; 'a); &self.coords - right.coords; 'a);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1) (D, U1), (D, U1) -> (D, U1)
const D; for; where; const; for D; where D: DimName, DefaultAllocator: Allocator<T, D>;
self: Point<T, D>, right: &'b Point<T, D>, Output = SVector<T, D>; self: OPoint<T, D>, right: &'b OPoint<T, D>, Output = OVector<T, D>;
self.coords - &right.coords; 'b); self.coords - &right.coords; 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1) (D, U1), (D, U1) -> (D, U1)
const D; for; where; const; for D; where D: DimName, DefaultAllocator: Allocator<T, D>;
self: Point<T, D>, right: Point<T, D>, Output = SVector<T, D>; self: OPoint<T, D>, right: OPoint<T, D>, Output = OVector<T, D>;
self.coords - right.coords; ); self.coords - right.coords; );
// Point - Vector // Point - Vector
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: &'a Point<T, D1>, right: &'b Vector<T, D2, SB>, Output = Point<T, D1>; self: &'a OPoint<T, D1>, right: &'b Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(&self.coords - right); 'a, 'b); Self::Output::from(&self.coords - right); 'a, 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: &'a Point<T, D1>, right: Vector<T, D2, SB>, Output = Point<T, D1>; self: &'a OPoint<T, D1>, right: Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(&self.coords - &right); 'a); // TODO: should not be a ref to `right`. Self::Output::from(&self.coords - &right); 'a); // TODO: should not be a ref to `right`.
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: Point<T, D1>, right: &'b Vector<T, D2, SB>, Output = Point<T, D1>; self: OPoint<T, D1>, right: &'b Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(self.coords - right); 'b); Self::Output::from(self.coords - right); 'b);
add_sub_impl!(Sub, sub, ClosedSub; add_sub_impl!(Sub, sub, ClosedSub;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: Point<T, D1>, right: Vector<T, D2, SB>, Output = Point<T, D1>; self: OPoint<T, D1>, right: Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(self.coords - right); ); Self::Output::from(self.coords - right); );
// Point + Vector // Point + Vector
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: &'a Point<T, D1>, right: &'b Vector<T, D2, SB>, Output = Point<T, D1>; self: &'a OPoint<T, D1>, right: &'b Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(&self.coords + right); 'a, 'b); Self::Output::from(&self.coords + right); 'a, 'b);
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: &'a Point<T, D1>, right: Vector<T, D2, SB>, Output = Point<T, D1>; self: &'a OPoint<T, D1>, right: Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(&self.coords + &right); 'a); // TODO: should not be a ref to `right`. Self::Output::from(&self.coords + &right); 'a); // TODO: should not be a ref to `right`.
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: Point<T, D1>, right: &'b Vector<T, D2, SB>, Output = Point<T, D1>; self: OPoint<T, D1>, right: &'b Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(self.coords + right); 'b); Self::Output::from(self.coords + right); 'b);
add_sub_impl!(Add, add, ClosedAdd; add_sub_impl!(Add, add, ClosedAdd;
(Const<D1>, U1), (D2, U1) -> (Const<D1>, U1) (D1, U1), (D2, U1) -> (D1, U1)
const D1; const;
for D2, SB; for D1, D2, SB;
where D2: Dim, SB: Storage<T, D2>; where D1: DimName, D2: Dim, SB: Storage<T, D2>, DefaultAllocator: Allocator<T, D1>;
self: Point<T, D1>, right: Vector<T, D2, SB>, Output = Point<T, D1>; self: OPoint<T, D1>, right: Vector<T, D2, SB>, Output = OPoint<T, D1>;
Self::Output::from(self.coords + right); ); Self::Output::from(self.coords + right); );
// TODO: replace by the shared macro: add_sub_assign_impl? // TODO: replace by the shared macro: add_sub_assign_impl?
macro_rules! op_assign_impl( macro_rules! op_assign_impl(
($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$( ($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$(
impl<'b, T, D2: Dim, SB, const D1: usize> $TraitAssign<&'b Vector<T, D2, SB>> for Point<T, D1> impl<'b, T, D1: DimName, D2: Dim, SB> $TraitAssign<&'b Vector<T, D2, SB>> for OPoint<T, D1>
where T: Scalar + $bound, where T: Scalar + $bound,
SB: Storage<T, D2>, SB: Storage<T, D2>,
ShapeConstraint: SameNumberOfRows<Const<D1>, D2> { ShapeConstraint: SameNumberOfRows<D1, D2>,
DefaultAllocator: Allocator<T, D1> {
#[inline] #[inline]
fn $method_assign(&mut self, right: &'b Vector<T, D2, SB>) { fn $method_assign(&mut self, right: &'b Vector<T, D2, SB>) {
@ -169,10 +184,11 @@ macro_rules! op_assign_impl(
} }
} }
impl<T, D2: Dim, SB, const D1: usize> $TraitAssign<Vector<T, D2, SB>> for Point<T, D1> impl<T, D1: DimName, D2: Dim, SB> $TraitAssign<Vector<T, D2, SB>> for OPoint<T, D1>
where T: Scalar + $bound, where T: Scalar + $bound,
SB: Storage<T, D2>, SB: Storage<T, D2>,
ShapeConstraint: SameNumberOfRows<Const<D1>, D2> { ShapeConstraint: SameNumberOfRows<D1, D2>,
DefaultAllocator: Allocator<T, D1> {
#[inline] #[inline]
fn $method_assign(&mut self, right: Vector<T, D2, SB>) { fn $method_assign(&mut self, right: Vector<T, D2, SB>) {
@ -214,28 +230,30 @@ md_impl_all!(
macro_rules! componentwise_scalarop_impl( macro_rules! componentwise_scalarop_impl(
($Trait: ident, $method: ident, $bound: ident; ($Trait: ident, $method: ident, $bound: ident;
$TraitAssign: ident, $method_assign: ident) => { $TraitAssign: ident, $method_assign: ident) => {
impl<T: Scalar + $bound, const D: usize> $Trait<T> for Point<T, D> impl<T: Scalar + $bound, D: DimName> $Trait<T> for OPoint<T, D>
where DefaultAllocator: Allocator<T, D>
{ {
type Output = Point<T, D>; type Output = OPoint<T, D>;
#[inline] #[inline]
fn $method(self, right: T) -> Self::Output { fn $method(self, right: T) -> Self::Output {
Point::from(self.coords.$method(right)) OPoint::from(self.coords.$method(right))
} }
} }
impl<'a, T: Scalar + $bound, const D: usize> $Trait<T> for &'a Point<T, D> impl<'a, T: Scalar + $bound, D: DimName> $Trait<T> for &'a OPoint<T, D>
where DefaultAllocator: Allocator<T, D>
{ {
type Output = Point<T, D>; type Output = OPoint<T, D>;
#[inline] #[inline]
fn $method(self, right: T) -> Self::Output { fn $method(self, right: T) -> Self::Output {
Point::from((&self.coords).$method(right)) OPoint::from((&self.coords).$method(right))
} }
} }
impl<T: Scalar + $bound, const D: usize> $TraitAssign<T> for Point<T, D> impl<T: Scalar + $bound, D: DimName> $TraitAssign<T> for OPoint<T, D>
/* where DefaultAllocator: Allocator<T, D> */ where DefaultAllocator: Allocator<T, D>
{ {
#[inline] #[inline]
fn $method_assign(&mut self, right: T) { fn $method_assign(&mut self, right: T) {
@ -250,23 +268,25 @@ componentwise_scalarop_impl!(Div, div, ClosedDiv; DivAssign, div_assign);
macro_rules! left_scalar_mul_impl( macro_rules! left_scalar_mul_impl(
($($T: ty),* $(,)*) => {$( ($($T: ty),* $(,)*) => {$(
impl<const D: usize> Mul<Point<$T, D>> for $T impl<D: DimName> Mul<OPoint<$T, D>> for $T
where DefaultAllocator: Allocator<$T, D>
{ {
type Output = Point<$T, D>; type Output = OPoint<$T, D>;
#[inline] #[inline]
fn mul(self, right: Point<$T, D>) -> Self::Output { fn mul(self, right: OPoint<$T, D>) -> Self::Output {
Point::from(self * right.coords) OPoint::from(self * right.coords)
} }
} }
impl<'b, const D: usize> Mul<&'b Point<$T, D>> for $T impl<'b, D: DimName> Mul<&'b OPoint<$T, D>> for $T
where DefaultAllocator: Allocator<$T, D>
{ {
type Output = Point<$T, D>; type Output = OPoint<$T, D>;
#[inline] #[inline]
fn mul(self, right: &'b Point<$T, D>) -> Self::Output { fn mul(self, right: &'b OPoint<$T, D>) -> Self::Output {
Point::from(self * &right.coords) OPoint::from(self * &right.coords)
} }
} }
)*} )*}

View File

@ -139,7 +139,7 @@ mod rkyv_impl {
impl<T: Serialize<S>, S: Fallible + ?Sized> Serialize<S> for Quaternion<T> { impl<T: Serialize<S>, S: Fallible + ?Sized> Serialize<S> for Quaternion<T> {
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> { fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
Ok(self.coords.serialize(serializer)?) self.coords.serialize(serializer)
} }
} }
@ -191,6 +191,7 @@ where
/// The imaginary part of this quaternion. /// The imaginary part of this quaternion.
#[inline] #[inline]
#[must_use]
pub fn imag(&self) -> Vector3<T> { pub fn imag(&self) -> Vector3<T> {
self.coords.xyz() self.coords.xyz()
} }
@ -223,6 +224,7 @@ where
/// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6)); /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp(&self, other: &Self, t: T) -> Self { pub fn lerp(&self, other: &Self, t: T) -> Self {
self * (T::one() - t) + other * t self * (T::one() - t) + other * t
} }
@ -238,6 +240,7 @@ where
/// assert_eq!(q.vector()[2], 4.0); /// assert_eq!(q.vector()[2], 4.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn vector(&self) -> MatrixSlice<T, U3, U1, RStride<T, U4, U1>, CStride<T, U4, U1>> { pub fn vector(&self) -> MatrixSlice<T, U3, U1, RStride<T, U4, U1>, CStride<T, U4, U1>> {
self.coords.fixed_rows::<3>(0) self.coords.fixed_rows::<3>(0)
} }
@ -251,6 +254,7 @@ where
/// assert_eq!(q.scalar(), 1.0); /// assert_eq!(q.scalar(), 1.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn scalar(&self) -> T { pub fn scalar(&self) -> T {
self.coords[3] self.coords[3]
} }
@ -266,6 +270,7 @@ where
/// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn as_vector(&self) -> &Vector4<T> { pub fn as_vector(&self) -> &Vector4<T> {
&self.coords &self.coords
} }
@ -280,6 +285,7 @@ where
/// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6); /// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn norm(&self) -> T { pub fn norm(&self) -> T {
self.coords.norm() self.coords.norm()
} }
@ -297,6 +303,7 @@ where
/// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6); /// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn magnitude(&self) -> T { pub fn magnitude(&self) -> T {
self.norm() self.norm()
} }
@ -310,6 +317,7 @@ where
/// assert_eq!(q.magnitude_squared(), 30.0); /// assert_eq!(q.magnitude_squared(), 30.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn norm_squared(&self) -> T { pub fn norm_squared(&self) -> T {
self.coords.norm_squared() self.coords.norm_squared()
} }
@ -326,6 +334,7 @@ where
/// assert_eq!(q.magnitude_squared(), 30.0); /// assert_eq!(q.magnitude_squared(), 30.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn magnitude_squared(&self) -> T { pub fn magnitude_squared(&self) -> T {
self.norm_squared() self.norm_squared()
} }
@ -340,6 +349,7 @@ where
/// assert_eq!(q1.dot(&q2), 70.0); /// assert_eq!(q1.dot(&q2), 70.0);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn dot(&self, rhs: &Self) -> T { pub fn dot(&self, rhs: &Self) -> T {
self.coords.dot(&rhs.coords) self.coords.dot(&rhs.coords)
} }
@ -409,6 +419,7 @@ where
/// let result = a.inner(&b); /// let result = a.inner(&b);
/// assert_relative_eq!(expected, result, epsilon = 1.0e-5); /// assert_relative_eq!(expected, result, epsilon = 1.0e-5);
#[inline] #[inline]
#[must_use]
pub fn inner(&self, other: &Self) -> Self { pub fn inner(&self, other: &Self) -> Self {
(self * other + other * self).half() (self * other + other * self).half()
} }
@ -428,6 +439,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-5); /// assert_relative_eq!(expected, result, epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn outer(&self, other: &Self) -> Self { pub fn outer(&self, other: &Self) -> Self {
#[allow(clippy::eq_op)] #[allow(clippy::eq_op)]
(self * other - other * self).half() (self * other - other * self).half()
@ -448,6 +460,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-5); /// assert_relative_eq!(expected, result, epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn project(&self, other: &Self) -> Option<Self> pub fn project(&self, other: &Self) -> Option<Self>
where where
T: RealField, T: RealField,
@ -470,6 +483,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-5); /// assert_relative_eq!(expected, result, epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn reject(&self, other: &Self) -> Option<Self> pub fn reject(&self, other: &Self) -> Option<Self>
where where
T: RealField, T: RealField,
@ -492,6 +506,7 @@ where
/// assert_eq!(half_ang, f32::consts::FRAC_PI_2); /// assert_eq!(half_ang, f32::consts::FRAC_PI_2);
/// assert_eq!(axis, Some(Vector3::x_axis())); /// assert_eq!(axis, Some(Vector3::x_axis()));
/// ``` /// ```
#[must_use]
pub fn polar_decomposition(&self) -> (T, T, Option<Unit<Vector3<T>>>) pub fn polar_decomposition(&self) -> (T, T, Option<Unit<Vector3<T>>>)
where where
T: RealField, T: RealField,
@ -519,6 +534,7 @@ where
/// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6) /// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6)
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn ln(&self) -> Self { pub fn ln(&self) -> Self {
let n = self.norm(); let n = self.norm();
let v = self.vector(); let v = self.vector();
@ -537,6 +553,7 @@ where
/// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5) /// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5)
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn exp(&self) -> Self { pub fn exp(&self) -> Self {
self.exp_eps(T::simd_default_epsilon()) self.exp_eps(T::simd_default_epsilon())
} }
@ -556,6 +573,7 @@ where
/// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity()); /// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn exp_eps(&self, eps: T) -> Self { pub fn exp_eps(&self, eps: T) -> Self {
let v = self.vector(); let v = self.vector();
let nn = v.norm_squared(); let nn = v.norm_squared();
@ -579,6 +597,7 @@ where
/// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6); /// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn powf(&self, n: T) -> Self { pub fn powf(&self, n: T) -> Self {
(self.ln() * n).exp() (self.ln() * n).exp()
} }
@ -674,18 +693,21 @@ where
/// Calculates square of a quaternion. /// Calculates square of a quaternion.
#[inline] #[inline]
#[must_use]
pub fn squared(&self) -> Self { pub fn squared(&self) -> Self {
self * self self * self
} }
/// Divides quaternion into two. /// Divides quaternion into two.
#[inline] #[inline]
#[must_use]
pub fn half(&self) -> Self { pub fn half(&self) -> Self {
self / crate::convert(2.0f64) self / crate::convert(2.0f64)
} }
/// Calculates square root. /// Calculates square root.
#[inline] #[inline]
#[must_use]
pub fn sqrt(&self) -> Self { pub fn sqrt(&self) -> Self {
self.powf(crate::convert(0.5)) self.powf(crate::convert(0.5))
} }
@ -694,12 +716,14 @@ where
/// ///
/// A quaternion is pure if it has no real part (`self.w == 0.0`). /// A quaternion is pure if it has no real part (`self.w == 0.0`).
#[inline] #[inline]
#[must_use]
pub fn is_pure(&self) -> bool { pub fn is_pure(&self) -> bool {
self.w.is_zero() self.w.is_zero()
} }
/// Convert quaternion to pure quaternion. /// Convert quaternion to pure quaternion.
#[inline] #[inline]
#[must_use]
pub fn pure(&self) -> Self { pub fn pure(&self) -> Self {
Self::from_imag(self.imag()) Self::from_imag(self.imag())
} }
@ -708,6 +732,7 @@ where
/// ///
/// Calculates B<sup>-1</sup> * A where A = self, B = other. /// Calculates B<sup>-1</sup> * A where A = self, B = other.
#[inline] #[inline]
#[must_use]
pub fn left_div(&self, other: &Self) -> Option<Self> pub fn left_div(&self, other: &Self) -> Option<Self>
where where
T: RealField, T: RealField,
@ -730,6 +755,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn right_div(&self, other: &Self) -> Option<Self> pub fn right_div(&self, other: &Self) -> Option<Self>
where where
T: RealField, T: RealField,
@ -749,6 +775,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn cos(&self) -> Self { pub fn cos(&self) -> Self {
let z = self.imag().magnitude(); let z = self.imag().magnitude();
let w = -self.w.simd_sin() * z.simd_sinhc(); let w = -self.w.simd_sin() * z.simd_sinhc();
@ -766,6 +793,7 @@ where
/// assert_relative_eq!(input, result, epsilon = 1.0e-7); /// assert_relative_eq!(input, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn acos(&self) -> Self { pub fn acos(&self) -> Self {
let u = Self::from_imag(self.imag().normalize()); let u = Self::from_imag(self.imag().normalize());
let identity = Self::identity(); let identity = Self::identity();
@ -787,6 +815,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn sin(&self) -> Self { pub fn sin(&self) -> Self {
let z = self.imag().magnitude(); let z = self.imag().magnitude();
let w = self.w.simd_cos() * z.simd_sinhc(); let w = self.w.simd_cos() * z.simd_sinhc();
@ -804,6 +833,7 @@ where
/// assert_relative_eq!(input, result, epsilon = 1.0e-7); /// assert_relative_eq!(input, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn asin(&self) -> Self { pub fn asin(&self) -> Self {
let u = Self::from_imag(self.imag().normalize()); let u = Self::from_imag(self.imag().normalize());
let identity = Self::identity(); let identity = Self::identity();
@ -825,6 +855,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn tan(&self) -> Self pub fn tan(&self) -> Self
where where
T: RealField, T: RealField,
@ -843,6 +874,7 @@ where
/// assert_relative_eq!(input, result, epsilon = 1.0e-7); /// assert_relative_eq!(input, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn atan(&self) -> Self pub fn atan(&self) -> Self
where where
T: RealField, T: RealField,
@ -867,6 +899,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn sinh(&self) -> Self { pub fn sinh(&self) -> Self {
(self.exp() - (-self).exp()).half() (self.exp() - (-self).exp()).half()
} }
@ -883,6 +916,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn asinh(&self) -> Self { pub fn asinh(&self) -> Self {
let identity = Self::identity(); let identity = Self::identity();
(self + (identity + self.squared()).sqrt()).ln() (self + (identity + self.squared()).sqrt()).ln()
@ -900,6 +934,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn cosh(&self) -> Self { pub fn cosh(&self) -> Self {
(self.exp() + (-self).exp()).half() (self.exp() + (-self).exp()).half()
} }
@ -916,6 +951,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn acosh(&self) -> Self { pub fn acosh(&self) -> Self {
let identity = Self::identity(); let identity = Self::identity();
(self + (self + identity).sqrt() * (self - identity).sqrt()).ln() (self + (self + identity).sqrt() * (self - identity).sqrt()).ln()
@ -933,6 +969,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn tanh(&self) -> Self pub fn tanh(&self) -> Self
where where
T: RealField, T: RealField,
@ -952,6 +989,7 @@ where
/// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// assert_relative_eq!(expected, result, epsilon = 1.0e-7);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn atanh(&self) -> Self { pub fn atanh(&self) -> Self {
let identity = Self::identity(); let identity = Self::identity();
((identity + self).ln() - (identity - self).ln()).half() ((identity + self).ln() - (identity - self).ln()).half()
@ -1069,6 +1107,7 @@ where
/// assert_eq!(rot.angle(), 1.78); /// assert_eq!(rot.angle(), 1.78);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle(&self) -> T { pub fn angle(&self) -> T {
let w = self.quaternion().scalar().simd_abs(); let w = self.quaternion().scalar().simd_abs();
self.quaternion().imag().norm().simd_atan2(w) * crate::convert(2.0f64) self.quaternion().imag().norm().simd_atan2(w) * crate::convert(2.0f64)
@ -1085,6 +1124,7 @@ where
/// assert_eq!(*axis.quaternion(), Quaternion::new(1.0, 0.0, 0.0, 0.0)); /// assert_eq!(*axis.quaternion(), Quaternion::new(1.0, 0.0, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn quaternion(&self) -> &Quaternion<T> { pub fn quaternion(&self) -> &Quaternion<T> {
self.as_ref() self.as_ref()
} }
@ -1133,6 +1173,7 @@ where
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle_to(&self, other: &Self) -> T { pub fn angle_to(&self, other: &Self) -> T {
let delta = self.rotation_to(other); let delta = self.rotation_to(other);
delta.angle() delta.angle()
@ -1152,6 +1193,7 @@ where
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn rotation_to(&self, other: &Self) -> Self { pub fn rotation_to(&self, other: &Self) -> Self {
other / self other / self
} }
@ -1168,6 +1210,7 @@ where
/// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(0.9, 0.1, 0.0, 0.0)); /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(0.9, 0.1, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn lerp(&self, other: &Self, t: T) -> Quaternion<T> { pub fn lerp(&self, other: &Self, t: T) -> Quaternion<T> {
self.as_ref().lerp(other.as_ref(), t) self.as_ref().lerp(other.as_ref(), t)
} }
@ -1184,6 +1227,7 @@ where
/// assert_eq!(q1.nlerp(&q2, 0.1), UnitQuaternion::new_normalize(Quaternion::new(0.9, 0.1, 0.0, 0.0))); /// assert_eq!(q1.nlerp(&q2, 0.1), UnitQuaternion::new_normalize(Quaternion::new(0.9, 0.1, 0.0, 0.0)));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn nlerp(&self, other: &Self, t: T) -> Self { pub fn nlerp(&self, other: &Self, t: T) -> Self {
let mut res = self.lerp(other, t); let mut res = self.lerp(other, t);
let _ = res.normalize_mut(); let _ = res.normalize_mut();
@ -1209,6 +1253,7 @@ where
/// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn slerp(&self, other: &Self, t: T) -> Self pub fn slerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,
@ -1228,6 +1273,7 @@ where
/// * `epsilon`: the value below which the sinus of the angle separating both quaternion /// * `epsilon`: the value below which the sinus of the angle separating both quaternion
/// must be to return `None`. /// must be to return `None`.
#[inline] #[inline]
#[must_use]
pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self> pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
where where
T: RealField, T: RealField,
@ -1287,6 +1333,7 @@ where
/// assert!(rot.axis().is_none()); /// assert!(rot.axis().is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn axis(&self) -> Option<Unit<Vector3<T>>> pub fn axis(&self) -> Option<Unit<Vector3<T>>>
where where
T: RealField, T: RealField,
@ -1311,6 +1358,7 @@ where
/// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6); /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn scaled_axis(&self) -> Vector3<T> pub fn scaled_axis(&self) -> Vector3<T>
where where
T: RealField, T: RealField,
@ -1339,6 +1387,7 @@ where
/// assert!(rot.axis_angle().is_none()); /// assert!(rot.axis_angle().is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn axis_angle(&self) -> Option<(Unit<Vector3<T>>, T)> pub fn axis_angle(&self) -> Option<(Unit<Vector3<T>>, T)>
where where
T: RealField, T: RealField,
@ -1350,6 +1399,7 @@ where
/// ///
/// Note that this function yields a `Quaternion<T>` because it loses the unit property. /// Note that this function yields a `Quaternion<T>` because it loses the unit property.
#[inline] #[inline]
#[must_use]
pub fn exp(&self) -> Quaternion<T> { pub fn exp(&self) -> Quaternion<T> {
self.as_ref().exp() self.as_ref().exp()
} }
@ -1369,6 +1419,7 @@ where
/// assert_relative_eq!(q.ln().vector().into_owned(), axisangle, epsilon = 1.0e-6); /// assert_relative_eq!(q.ln().vector().into_owned(), axisangle, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn ln(&self) -> Quaternion<T> pub fn ln(&self) -> Quaternion<T>
where where
T: RealField, T: RealField,
@ -1397,6 +1448,7 @@ where
/// assert_eq!(pow.angle(), 2.4); /// assert_eq!(pow.angle(), 2.4);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn powf(&self, n: T) -> Self pub fn powf(&self, n: T) -> Self
where where
T: RealField, T: RealField,
@ -1425,7 +1477,8 @@ where
/// assert_relative_eq!(*rot.matrix(), expected, epsilon = 1.0e-6); /// assert_relative_eq!(*rot.matrix(), expected, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn to_rotation_matrix(&self) -> Rotation<T, 3> { #[must_use]
pub fn to_rotation_matrix(self) -> Rotation<T, 3> {
let i = self.as_ref()[0]; let i = self.as_ref()[0];
let j = self.as_ref()[1]; let j = self.as_ref()[1];
let k = self.as_ref()[2]; let k = self.as_ref()[2];
@ -1460,7 +1513,7 @@ where
/// The angles are produced in the form (roll, pitch, yaw). /// The angles are produced in the form (roll, pitch, yaw).
#[inline] #[inline]
#[deprecated(note = "This is renamed to use `.euler_angles()`.")] #[deprecated(note = "This is renamed to use `.euler_angles()`.")]
pub fn to_euler_angles(&self) -> (T, T, T) pub fn to_euler_angles(self) -> (T, T, T)
where where
T: RealField, T: RealField,
{ {
@ -1482,6 +1535,7 @@ where
/// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn euler_angles(&self) -> (T, T, T) pub fn euler_angles(&self) -> (T, T, T)
where where
T: RealField, T: RealField,
@ -1506,7 +1560,8 @@ where
/// assert_relative_eq!(rot.to_homogeneous(), expected, epsilon = 1.0e-6); /// assert_relative_eq!(rot.to_homogeneous(), expected, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> Matrix4<T> { #[must_use]
pub fn to_homogeneous(self) -> Matrix4<T> {
self.to_rotation_matrix().to_homogeneous() self.to_rotation_matrix().to_homogeneous()
} }
@ -1526,6 +1581,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point3<T>) -> Point3<T> { pub fn transform_point(&self, pt: &Point3<T>) -> Point3<T> {
self * pt self * pt
} }
@ -1546,6 +1602,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &Vector3<T>) -> Vector3<T> { pub fn transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
self * v self * v
} }
@ -1566,6 +1623,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point3<T>) -> Point3<T> { pub fn inverse_transform_point(&self, pt: &Point3<T>) -> Point3<T> {
// TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement // TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement
// the inverse transformation explicitly here) ? // the inverse transformation explicitly here) ?
@ -1588,6 +1646,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &Vector3<T>) -> Vector3<T> { pub fn inverse_transform_vector(&self, v: &Vector3<T>) -> Vector3<T> {
self.inverse() * v self.inverse() * v
} }
@ -1608,6 +1667,7 @@ where
/// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector3<T>>) -> Unit<Vector3<T>> { pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector3<T>>) -> Unit<Vector3<T>> {
self.inverse() * v self.inverse() * v
} }
@ -1616,6 +1676,7 @@ where
/// ///
/// This is faster, but approximate, way to compute `UnitQuaternion::new(axisangle) * self`. /// This is faster, but approximate, way to compute `UnitQuaternion::new(axisangle) * self`.
#[inline] #[inline]
#[must_use]
pub fn append_axisangle_linearized(&self, axisangle: &Vector3<T>) -> Self { pub fn append_axisangle_linearized(&self, axisangle: &Vector3<T>) -> Self {
let half: T = crate::convert(0.5); let half: T = crate::convert(0.5);
let q1 = self.into_inner(); let q1 = self.into_inner();

View File

@ -171,7 +171,7 @@ where
Standard: Distribution<T>, Standard: Distribution<T>,
{ {
#[inline] #[inline]
fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Quaternion<T> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Quaternion<T> {
Quaternion::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()) Quaternion::new(rng.gen(), rng.gen(), rng.gen(), rng.gen())
} }
} }
@ -535,10 +535,10 @@ where
SC: Storage<T, U3>, SC: Storage<T, U3>,
{ {
// TODO: code duplication with Rotation. // TODO: code duplication with Rotation.
let c = na.cross(&nb); let c = na.cross(nb);
if let Some(axis) = Unit::try_new(c, T::default_epsilon()) { if let Some(axis) = Unit::try_new(c, T::default_epsilon()) {
let cos = na.dot(&nb); let cos = na.dot(nb);
// The cosinus may be out of [-1, 1] because of inaccuracies. // The cosinus may be out of [-1, 1] because of inaccuracies.
if cos <= -T::one() { if cos <= -T::one() {
@ -548,7 +548,7 @@ where
} else { } else {
Some(Self::from_axis_angle(&axis, cos.acos() * s)) Some(Self::from_axis_angle(&axis, cos.acos() * s))
} }
} else if na.dot(&nb) < T::zero() { } else if na.dot(nb) < T::zero() {
// PI // PI
// //
// The rotation axis is undefined but the angle not zero. This is not a // The rotation axis is undefined but the angle not zero. This is not a
@ -860,7 +860,7 @@ where
{ {
/// Generate a uniformly distributed random rotation quaternion. /// Generate a uniformly distributed random rotation quaternion.
#[inline] #[inline]
fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> UnitQuaternion<T> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UnitQuaternion<T> {
// Ken Shoemake's Subgroup Algorithm // Ken Shoemake's Subgroup Algorithm
// Uniform random rotations. // Uniform random rotations.
// In D. Kirk, editor, Graphics Gems III, pages 124-132. Academic, New York, 1992. // In D. Kirk, editor, Graphics Gems III, pages 124-132. Academic, New York, 1992.

View File

@ -1,4 +1,3 @@
use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use simba::simd::SimdValue; use simba::simd::SimdValue;
@ -13,13 +12,13 @@ impl<T: Scalar + SimdValue> Deref for Quaternion<T> {
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) } unsafe { &*(self as *const Self as *const Self::Target) }
} }
} }
impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> { impl<T: Scalar + SimdValue> DerefMut for Quaternion<T> {
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) } unsafe { &mut *(self as *mut Self as *mut Self::Target) }
} }
} }

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
/* /*
* This file provides: * This file provides:
* =================== * ===================

View File

@ -1,5 +1,5 @@
use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint}; use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint};
use crate::base::{Const, Matrix, Scalar, Unit, Vector}; use crate::base::{Const, Matrix, Unit, Vector};
use crate::dimension::{Dim, U1}; use crate::dimension::{Dim, U1};
use crate::storage::{Storage, StorageMut}; use crate::storage::{Storage, StorageMut};
use simba::scalar::ComplexField; use simba::scalar::ComplexField;
@ -7,7 +7,7 @@ use simba::scalar::ComplexField;
use crate::geometry::Point; use crate::geometry::Point;
/// A reflection wrt. a plane. /// A reflection wrt. a plane.
pub struct Reflection<T: Scalar, D: Dim, S: Storage<T, D>> { pub struct Reflection<T, D, S> {
axis: Vector<T, D, S>, axis: Vector<T, D, S>,
bias: T, bias: T,
} }
@ -34,6 +34,7 @@ impl<T: ComplexField, D: Dim, S: Storage<T, D>> Reflection<T, D, S> {
} }
/// The reflexion axis. /// The reflexion axis.
#[must_use]
pub fn axis(&self) -> &Vector<T, D, S> { pub fn axis(&self) -> &Vector<T, D, S> {
&self.axis &self.axis
} }
@ -89,7 +90,7 @@ impl<T: ComplexField, D: Dim, S: Storage<T, D>> Reflection<T, D, S> {
} }
let m_two: T = crate::convert(-2.0f64); let m_two: T = crate::convert(-2.0f64);
lhs.gerc(m_two, &work, &self.axis, T::one()); lhs.gerc(m_two, work, &self.axis, T::one());
} }
/// Applies the reflection to the rows of `lhs`. /// Applies the reflection to the rows of `lhs`.
@ -110,6 +111,6 @@ impl<T: ComplexField, D: Dim, S: Storage<T, D>> Reflection<T, D, S> {
} }
let m_two = sign.scale(crate::convert(-2.0f64)); let m_two = sign.scale(crate::convert(-2.0f64));
lhs.gerc(m_two, &work, &self.axis, sign); lhs.gerc(m_two, work, &self.axis, sign);
} }
} }

View File

@ -55,7 +55,7 @@ use crate::geometry::Point;
/// ///
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct Rotation<T: Scalar, const D: usize> { pub struct Rotation<T, const D: usize> {
matrix: SMatrix<T, D, D>, matrix: SMatrix<T, D, D>,
} }
@ -185,6 +185,7 @@ impl<T: Scalar, const D: usize> Rotation<T, D> {
/// assert_eq!(*rot.matrix(), expected); /// assert_eq!(*rot.matrix(), expected);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn matrix(&self) -> &SMatrix<T, D, D> { pub fn matrix(&self) -> &SMatrix<T, D, D> {
&self.matrix &self.matrix
} }
@ -198,9 +199,9 @@ impl<T: Scalar, const D: usize> Rotation<T, D> {
/// A mutable reference to the underlying matrix representation of this rotation. /// 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 /// This is suffixed by "_unchecked" because this allows the user to replace the
/// non-square, non-inversible, or non-orthonormal. If one of those properties is broken, /// matrix by another one that is non-inversible or non-orthonormal. If one of
/// subsequent method calls may be UB. /// those properties is broken, subsequent method calls may return bogus results.
#[inline] #[inline]
pub fn matrix_mut_unchecked(&mut self) -> &mut SMatrix<T, D, D> { pub fn matrix_mut_unchecked(&mut self) -> &mut SMatrix<T, D, D> {
&mut self.matrix &mut self.matrix
@ -262,6 +263,7 @@ impl<T: Scalar, const D: usize> Rotation<T, D> {
/// assert_eq!(rot.to_homogeneous(), expected); /// assert_eq!(rot.to_homogeneous(), expected);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
T: Zero + One, T: Zero + One,
@ -403,6 +405,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self * pt self * pt
} }
@ -422,6 +425,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self * v self * v
} }
@ -441,6 +445,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
Point::from(self.inverse_transform_vector(&pt.coords)) Point::from(self.inverse_transform_vector(&pt.coords))
} }
@ -460,6 +465,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self.matrix().tr_mul(v) self.matrix().tr_mul(v)
} }
@ -479,6 +485,7 @@ where
/// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_unit_vector(&self, v: &Unit<SVector<T, D>>) -> Unit<SVector<T, D>> { pub fn inverse_transform_unit_vector(&self, v: &Unit<SVector<T, D>>) -> Unit<SVector<T, D>> {
Unit::new_unchecked(self.inverse_transform_vector(&**v)) Unit::new_unchecked(self.inverse_transform_vector(&**v))
} }

View File

@ -267,10 +267,7 @@ where
{ {
#[inline] #[inline]
fn from(arr: [Rotation<T::Element, D>; 2]) -> Self { fn from(arr: [Rotation<T::Element, D>; 2]) -> Self {
Self::from_matrix_unchecked(OMatrix::from([ Self::from_matrix_unchecked(OMatrix::from([arr[0].into_inner(), arr[1].into_inner()]))
arr[0].clone().into_inner(),
arr[1].clone().into_inner(),
]))
} }
} }
@ -283,10 +280,10 @@ where
#[inline] #[inline]
fn from(arr: [Rotation<T::Element, D>; 4]) -> Self { fn from(arr: [Rotation<T::Element, D>; 4]) -> Self {
Self::from_matrix_unchecked(OMatrix::from([ Self::from_matrix_unchecked(OMatrix::from([
arr[0].clone().into_inner(), arr[0].into_inner(),
arr[1].clone().into_inner(), arr[1].into_inner(),
arr[2].clone().into_inner(), arr[2].into_inner(),
arr[3].clone().into_inner(), arr[3].into_inner(),
])) ]))
} }
} }
@ -300,14 +297,14 @@ where
#[inline] #[inline]
fn from(arr: [Rotation<T::Element, D>; 8]) -> Self { fn from(arr: [Rotation<T::Element, D>; 8]) -> Self {
Self::from_matrix_unchecked(OMatrix::from([ Self::from_matrix_unchecked(OMatrix::from([
arr[0].clone().into_inner(), arr[0].into_inner(),
arr[1].clone().into_inner(), arr[1].into_inner(),
arr[2].clone().into_inner(), arr[2].into_inner(),
arr[3].clone().into_inner(), arr[3].into_inner(),
arr[4].clone().into_inner(), arr[4].into_inner(),
arr[5].clone().into_inner(), arr[5].into_inner(),
arr[6].clone().into_inner(), arr[6].into_inner(),
arr[7].clone().into_inner(), arr[7].into_inner(),
])) ]))
} }
} }
@ -321,22 +318,22 @@ where
#[inline] #[inline]
fn from(arr: [Rotation<T::Element, D>; 16]) -> Self { fn from(arr: [Rotation<T::Element, D>; 16]) -> Self {
Self::from_matrix_unchecked(OMatrix::from([ Self::from_matrix_unchecked(OMatrix::from([
arr[0].clone().into_inner(), arr[0].into_inner(),
arr[1].clone().into_inner(), arr[1].into_inner(),
arr[2].clone().into_inner(), arr[2].into_inner(),
arr[3].clone().into_inner(), arr[3].into_inner(),
arr[4].clone().into_inner(), arr[4].into_inner(),
arr[5].clone().into_inner(), arr[5].into_inner(),
arr[6].clone().into_inner(), arr[6].into_inner(),
arr[7].clone().into_inner(), arr[7].into_inner(),
arr[8].clone().into_inner(), arr[8].into_inner(),
arr[9].clone().into_inner(), arr[9].into_inner(),
arr[10].clone().into_inner(), arr[10].into_inner(),
arr[11].clone().into_inner(), arr[11].into_inner(),
arr[12].clone().into_inner(), arr[12].into_inner(),
arr[13].clone().into_inner(), arr[13].into_inner(),
arr[14].clone().into_inner(), arr[14].into_inner(),
arr[15].clone().into_inner(), arr[15].into_inner(),
])) ]))
} }
} }

View File

@ -18,6 +18,7 @@ impl<T: SimdRealField> Rotation2<T> {
/// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn slerp(&self, other: &Self, t: T) -> Self pub fn slerp(&self, other: &Self, t: T) -> Self
where where
T::Element: SimdRealField, T::Element: SimdRealField,
@ -47,6 +48,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn slerp(&self, other: &Self, t: T) -> Self pub fn slerp(&self, other: &Self, t: T) -> Self
where where
T: RealField, T: RealField,
@ -67,12 +69,13 @@ impl<T: SimdRealField> Rotation3<T> {
/// * `epsilon`: the value below which the sinus of the angle separating both rotations /// * `epsilon`: the value below which the sinus of the angle separating both rotations
/// must be to return `None`. /// must be to return `None`.
#[inline] #[inline]
#[must_use]
pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self> pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
where where
T: RealField, T: RealField,
{ {
let q1 = Rotation3::from(*self); let q1 = UnitQuaternion::from(*self);
let q2 = Rotation3::from(*other); let q2 = UnitQuaternion::from(*other);
q1.try_slerp(&q2, t, epsilon).map(|q| q.into()) q1.try_slerp(&q2, t, epsilon).map(|q| q.into())
} }
} }

View File

@ -186,6 +186,7 @@ impl<T: SimdRealField> Rotation2<T> {
/// assert_relative_eq!(rot_to.inverse() * rot2, rot1); /// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn rotation_to(&self, other: &Self) -> Self { pub fn rotation_to(&self, other: &Self) -> Self {
other * self.inverse() other * self.inverse()
} }
@ -215,6 +216,7 @@ impl<T: SimdRealField> Rotation2<T> {
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78); /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn powf(&self, n: T) -> Self { pub fn powf(&self, n: T) -> Self {
Self::new(self.angle() * n) Self::new(self.angle() * n)
} }
@ -232,6 +234,7 @@ impl<T: SimdRealField> Rotation2<T> {
/// assert_relative_eq!(rot.angle(), 1.78); /// assert_relative_eq!(rot.angle(), 1.78);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle(&self) -> T { pub fn angle(&self) -> T {
self.matrix()[(1, 0)].simd_atan2(self.matrix()[(0, 0)]) self.matrix()[(1, 0)].simd_atan2(self.matrix()[(0, 0)])
} }
@ -247,6 +250,7 @@ impl<T: SimdRealField> Rotation2<T> {
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle_to(&self, other: &Self) -> T { pub fn angle_to(&self, other: &Self) -> T {
self.rotation_to(other).angle() self.rotation_to(other).angle()
} }
@ -256,6 +260,7 @@ impl<T: SimdRealField> Rotation2<T> {
/// This is generally used in the context of generic programming. Using /// This is generally used in the context of generic programming. Using
/// the `.angle()` method instead is more common. /// the `.angle()` method instead is more common.
#[inline] #[inline]
#[must_use]
pub fn scaled_axis(&self) -> SVector<T, 1> { pub fn scaled_axis(&self) -> SVector<T, 1> {
Vector1::new(self.angle()) Vector1::new(self.angle())
} }
@ -269,7 +274,7 @@ where
{ {
/// Generate a uniformly distributed random rotation. /// Generate a uniformly distributed random rotation.
#[inline] #[inline]
fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Rotation2<T> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation2<T> {
let twopi = Uniform::new(T::zero(), T::simd_two_pi()); let twopi = Uniform::new(T::zero(), T::simd_two_pi());
Rotation2::new(rng.sample(twopi)) Rotation2::new(rng.sample(twopi))
} }
@ -640,6 +645,7 @@ where
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn rotation_to(&self, other: &Self) -> Self { pub fn rotation_to(&self, other: &Self) -> Self {
other * self.inverse() other * self.inverse()
} }
@ -659,6 +665,7 @@ where
/// assert_eq!(pow.angle(), 2.4); /// assert_eq!(pow.angle(), 2.4);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn powf(&self, n: T) -> Self pub fn powf(&self, n: T) -> Self
where where
T: RealField, T: RealField,
@ -765,6 +772,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert_relative_eq!(rot.angle(), 1.78); /// assert_relative_eq!(rot.angle(), 1.78);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle(&self) -> T { pub fn angle(&self) -> T {
((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - T::one()) ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - T::one())
/ crate::convert(2.0)) / crate::convert(2.0))
@ -787,6 +795,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert!(rot.axis().is_none()); /// assert!(rot.axis().is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn axis(&self) -> Option<Unit<Vector3<T>>> pub fn axis(&self) -> Option<Unit<Vector3<T>>>
where where
T: RealField, T: RealField,
@ -811,6 +820,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6); /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn scaled_axis(&self) -> Vector3<T> pub fn scaled_axis(&self) -> Vector3<T>
where where
T: RealField, T: RealField,
@ -842,15 +852,12 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert!(rot.axis_angle().is_none()); /// assert!(rot.axis_angle().is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn axis_angle(&self) -> Option<(Unit<Vector3<T>>, T)> pub fn axis_angle(&self) -> Option<(Unit<Vector3<T>>, T)>
where where
T: RealField, T: RealField,
{ {
if let Some(axis) = self.axis() { self.axis().map(|axis| (axis, self.angle()))
Some((axis, self.angle()))
} else {
None
}
} }
/// The rotation angle needed to make `self` and `other` coincide. /// The rotation angle needed to make `self` and `other` coincide.
@ -864,6 +871,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle_to(&self, other: &Self) -> T pub fn angle_to(&self, other: &Self) -> T
where where
T::Element: SimdRealField, T::Element: SimdRealField,
@ -875,7 +883,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// ///
/// The angles are produced in the form (roll, pitch, yaw). /// The angles are produced in the form (roll, pitch, yaw).
#[deprecated(note = "This is renamed to use `.euler_angles()`.")] #[deprecated(note = "This is renamed to use `.euler_angles()`.")]
pub fn to_euler_angles(&self) -> (T, T, T) pub fn to_euler_angles(self) -> (T, T, T)
where where
T: RealField, T: RealField,
{ {
@ -896,6 +904,7 @@ impl<T: SimdRealField> Rotation3<T> {
/// assert_relative_eq!(euler.1, 0.2, 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); /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
/// ``` /// ```
#[must_use]
pub fn euler_angles(&self) -> (T, T, T) pub fn euler_angles(&self) -> (T, T, T)
where where
T: RealField, T: RealField,

View File

@ -27,19 +27,19 @@ use crate::geometry::{AbstractRotation, Isometry, Point, Translation};
#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize-no-std", feature = "serde-serialize-no-std",
serde(bound(serialize = "T: Serialize, serde(bound(serialize = "T: Scalar + Serialize,
R: Serialize, R: Serialize,
DefaultAllocator: Allocator<T, Const<D>>, DefaultAllocator: Allocator<T, Const<D>>,
Owned<T, Const<D>>: Serialize")) Owned<T, Const<D>>: Serialize"))
)] )]
#[cfg_attr( #[cfg_attr(
feature = "serde-serialize-no-std", feature = "serde-serialize-no-std",
serde(bound(deserialize = "T: Deserialize<'de>, serde(bound(deserialize = "T: Scalar + Deserialize<'de>,
R: Deserialize<'de>, R: Deserialize<'de>,
DefaultAllocator: Allocator<T, Const<D>>, DefaultAllocator: Allocator<T, Const<D>>,
Owned<T, Const<D>>: Deserialize<'de>")) Owned<T, Const<D>>: Deserialize<'de>"))
)] )]
pub struct Similarity<T: Scalar, R, const D: usize> { pub struct Similarity<T, R, const D: usize> {
/// The part of this similarity that does not include the scaling factor. /// The part of this similarity that does not include the scaling factor.
pub isometry: Isometry<T, R, D>, pub isometry: Isometry<T, R, D>,
scaling: T, scaling: T,
@ -122,6 +122,7 @@ where
impl<T: Scalar, R, const D: usize> Similarity<T, R, D> { impl<T: Scalar, R, const D: usize> Similarity<T, R, D> {
/// The scaling factor of this similarity transformation. /// The scaling factor of this similarity transformation.
#[inline] #[inline]
#[must_use]
pub fn scaling(&self) -> T { pub fn scaling(&self) -> T {
self.scaling.inlined_clone() self.scaling.inlined_clone()
} }
@ -177,7 +178,7 @@ where
); );
Self::from_parts( Self::from_parts(
Translation::from(&self.isometry.translation.vector * scaling), Translation::from(self.isometry.translation.vector * scaling),
self.isometry.rotation.clone(), self.isometry.rotation.clone(),
self.scaling * scaling, self.scaling * scaling,
) )
@ -248,6 +249,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5); /// assert_relative_eq!(transformed_point, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self * pt self * pt
} }
@ -269,6 +271,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5); /// assert_relative_eq!(transformed_vector, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self * v self * v
} }
@ -289,6 +292,7 @@ where
/// assert_relative_eq!(transformed_point, Point3::new(-1.5, 1.5, 1.5), epsilon = 1.0e-5); /// assert_relative_eq!(transformed_point, Point3::new(-1.5, 1.5, 1.5), epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self.isometry.inverse_transform_point(pt) / self.scaling() self.isometry.inverse_transform_point(pt) / self.scaling()
} }
@ -309,6 +313,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.5, 2.0), epsilon = 1.0e-5); /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.5, 2.0), epsilon = 1.0e-5);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self.isometry.inverse_transform_vector(v) / self.scaling() self.isometry.inverse_transform_vector(v) / self.scaling()
} }
@ -321,6 +326,7 @@ where
impl<T: SimdRealField, R, const D: usize> Similarity<T, R, D> { impl<T: SimdRealField, R, const D: usize> Similarity<T, R, D> {
/// Converts this similarity into its equivalent homogeneous transformation matrix. /// Converts this similarity into its equivalent homogeneous transformation matrix.
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
Const<D>: DimNameAdd<U1>, Const<D>: DimNameAdd<U1>,

View File

@ -197,7 +197,7 @@ where
{ {
#[inline] #[inline]
fn from(arr: [Similarity<T::Element, R::Element, D>; 2]) -> Self { fn from(arr: [Similarity<T::Element, R::Element, D>; 2]) -> Self {
let iso = Isometry::from([arr[0].isometry.clone(), arr[1].isometry.clone()]); let iso = Isometry::from([arr[0].isometry, arr[1].isometry]);
let scale = T::from([arr[0].scaling(), arr[1].scaling()]); let scale = T::from([arr[0].scaling(), arr[1].scaling()]);
Self::from_isometry(iso, scale) Self::from_isometry(iso, scale)
@ -216,10 +216,10 @@ where
#[inline] #[inline]
fn from(arr: [Similarity<T::Element, R::Element, D>; 4]) -> Self { fn from(arr: [Similarity<T::Element, R::Element, D>; 4]) -> Self {
let iso = Isometry::from([ let iso = Isometry::from([
arr[0].isometry.clone(), arr[0].isometry,
arr[1].isometry.clone(), arr[1].isometry,
arr[2].isometry.clone(), arr[2].isometry,
arr[3].isometry.clone(), arr[3].isometry,
]); ]);
let scale = T::from([ let scale = T::from([
arr[0].scaling(), arr[0].scaling(),
@ -244,14 +244,14 @@ where
#[inline] #[inline]
fn from(arr: [Similarity<T::Element, R::Element, D>; 8]) -> Self { fn from(arr: [Similarity<T::Element, R::Element, D>; 8]) -> Self {
let iso = Isometry::from([ let iso = Isometry::from([
arr[0].isometry.clone(), arr[0].isometry,
arr[1].isometry.clone(), arr[1].isometry,
arr[2].isometry.clone(), arr[2].isometry,
arr[3].isometry.clone(), arr[3].isometry,
arr[4].isometry.clone(), arr[4].isometry,
arr[5].isometry.clone(), arr[5].isometry,
arr[6].isometry.clone(), arr[6].isometry,
arr[7].isometry.clone(), arr[7].isometry,
]); ]);
let scale = T::from([ let scale = T::from([
arr[0].scaling(), arr[0].scaling(),
@ -280,22 +280,22 @@ where
#[inline] #[inline]
fn from(arr: [Similarity<T::Element, R::Element, D>; 16]) -> Self { fn from(arr: [Similarity<T::Element, R::Element, D>; 16]) -> Self {
let iso = Isometry::from([ let iso = Isometry::from([
arr[0].isometry.clone(), arr[0].isometry,
arr[1].isometry.clone(), arr[1].isometry,
arr[2].isometry.clone(), arr[2].isometry,
arr[3].isometry.clone(), arr[3].isometry,
arr[4].isometry.clone(), arr[4].isometry,
arr[5].isometry.clone(), arr[5].isometry,
arr[6].isometry.clone(), arr[6].isometry,
arr[7].isometry.clone(), arr[7].isometry,
arr[8].isometry.clone(), arr[8].isometry,
arr[9].isometry.clone(), arr[9].isometry,
arr[10].isometry.clone(), arr[10].isometry,
arr[11].isometry.clone(), arr[11].isometry,
arr[12].isometry.clone(), arr[12].isometry,
arr[13].isometry.clone(), arr[13].isometry,
arr[14].isometry.clone(), arr[14].isometry,
arr[15].isometry.clone(), arr[15].isometry,
]); ]);
let scale = T::from([ let scale = T::from([
arr[0].scaling(), arr[0].scaling(),

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
use num::{One, Zero}; use num::{One, Zero};
use std::ops::{Div, DivAssign, Mul, MulAssign}; use std::ops::{Div, DivAssign, Mul, MulAssign};
@ -219,7 +222,7 @@ md_assign_impl_all!(
const D; for; where; const D; for; where;
self: Similarity<T, Rotation<T, D>, D>, rhs: Rotation<T, D>; self: Similarity<T, Rotation<T, D>, D>, rhs: Rotation<T, D>;
[val] => self.isometry.rotation *= rhs; [val] => self.isometry.rotation *= rhs;
[ref] => self.isometry.rotation *= rhs.clone(); [ref] => self.isometry.rotation *= *rhs;
); );
md_assign_impl_all!( md_assign_impl_all!(

View File

@ -8,6 +8,7 @@ macro_rules! impl_swizzle {
$( $(
/// Builds a new point from components of `self`. /// Builds a new point from components of `self`.
#[inline] #[inline]
#[must_use]
pub fn $name(&self) -> $Result<T> pub fn $name(&self) -> $Result<T>
where <Const<D> as ToTypenum>::Typenum: Cmp<typenum::$BaseDim, Output=Greater> { where <Const<D> as ToTypenum>::Typenum: Cmp<typenum::$BaseDim, Output=Greater> {
$Result::new($(self[$i].inlined_clone()),*) $Result::new($(self[$i].inlined_clone()),*)

View File

@ -1,6 +1,7 @@
use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::Any; use std::any::Any;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData; use std::marker::PhantomData;
#[cfg(feature = "serde-serialize-no-std")] #[cfg(feature = "serde-serialize-no-std")]
@ -166,14 +167,16 @@ where
_phantom: PhantomData<C>, _phantom: PhantomData<C>,
} }
// TODO impl<T: RealField + hash::Hash, C: TCategory, const D: usize> hash::Hash for Transform<T, C, D>
// impl<T: RealField + hash::Hash, D: DimNameAdd<U1> + hash::Hash, C: TCategory> hash::Hash for Transform<T, C, D> where
// where DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>, Const<D>: DimNameAdd<U1>,
// Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash { DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
// fn hash<H: hash::Hasher>(&self, state: &mut H) { Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash,
// self.matrix.hash(state); {
// } fn hash<H: hash::Hasher>(&self, state: &mut H) {
// } self.matrix.hash(state);
}
}
impl<T: RealField, C: TCategory, const D: usize> Copy for Transform<T, C, D> impl<T: RealField, C: TCategory, const D: usize> Copy for Transform<T, C, D>
where where
@ -301,6 +304,7 @@ where
/// assert_eq!(*t.matrix(), m); /// assert_eq!(*t.matrix(), m);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn matrix(&self) -> &OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> { pub fn matrix(&self) -> &OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
&self.matrix &self.matrix
} }
@ -367,6 +371,7 @@ where
/// assert_eq!(t.into_inner(), m); /// assert_eq!(t.into_inner(), m);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> { pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
self.matrix().clone_owned() self.matrix().clone_owned()
} }
@ -397,11 +402,9 @@ where
#[inline] #[inline]
#[must_use = "Did you mean to use try_inverse_mut()?"] #[must_use = "Did you mean to use try_inverse_mut()?"]
pub fn try_inverse(self) -> Option<Transform<T, C, D>> { pub fn try_inverse(self) -> Option<Transform<T, C, D>> {
if let Some(m) = self.matrix.try_inverse() { self.matrix
Some(Transform::from_matrix_unchecked(m)) .try_inverse()
} else { .map(Transform::from_matrix_unchecked)
None
}
} }
/// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral` /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
@ -498,6 +501,7 @@ where
/// ///
/// This is the same as the multiplication `self * pt`. /// This is the same as the multiplication `self * pt`.
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self * pt self * pt
} }
@ -507,6 +511,7 @@ where
/// ///
/// This is the same as the multiplication `self * v`. /// This is the same as the multiplication `self * v`.
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self * v self * v
} }
@ -524,6 +529,7 @@ where
/// This may be cheaper than inverting the transformation and transforming /// This may be cheaper than inverting the transformation and transforming
/// the point. /// the point.
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self.clone().inverse() * pt self.clone().inverse() * pt
} }
@ -532,6 +538,7 @@ where
/// This may be cheaper than inverting the transformation and transforming /// This may be cheaper than inverting the transformation and transforming
/// the vector. /// the vector.
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> { pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self.clone().inverse() * v self.clone().inverse() * v
} }

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
use num::{One, Zero}; use num::{One, Zero};
use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign}; use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign};
@ -121,7 +124,7 @@ md_impl_all!(
if C::has_normalizer() { if C::has_normalizer() {
let normalizer = self.matrix().fixed_slice::<1, D>(D, 0); let normalizer = self.matrix().fixed_slice::<1, D>(D, 0);
let n = normalizer.tr_dot(&rhs); let n = normalizer.tr_dot(rhs);
if !n.is_zero() { if !n.is_zero() {
return transform * (rhs / n); return transform * (rhs / n);

View File

@ -38,7 +38,7 @@ where
} }
} }
impl<T: Scalar + Copy, const D: usize> Copy for Translation<T, D> where Owned<T, Const<D>>: Copy {} impl<T: Scalar + Copy, const D: usize> Copy for Translation<T, D> {}
impl<T: Scalar, const D: usize> Clone for Translation<T, D> impl<T: Scalar, const D: usize> Clone for Translation<T, D>
where where
@ -123,7 +123,7 @@ mod rkyv_impl {
impl<T: Serialize<S>, S: Fallible + ?Sized, const D: usize> Serialize<S> for Translation<T, D> { impl<T: Serialize<S>, S: Fallible + ?Sized, const D: usize> Serialize<S> for Translation<T, D> {
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> { fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
Ok(self.vector.serialize(serializer)?) self.vector.serialize(serializer)
} }
} }
@ -190,6 +190,7 @@ impl<T: Scalar, const D: usize> Translation<T, D> {
/// assert_eq!(t.to_homogeneous(), expected); /// assert_eq!(t.to_homogeneous(), expected);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where where
T: Zero + One, T: Zero + One,
@ -241,6 +242,7 @@ impl<T: Scalar + ClosedAdd, const D: usize> Translation<T, D> {
/// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0)); /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0));
/// assert_eq!(transformed_point, Point3::new(5.0, 7.0, 9.0)); /// assert_eq!(transformed_point, Point3::new(5.0, 7.0, 9.0));
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
pt + &self.vector pt + &self.vector
} }
@ -256,6 +258,7 @@ impl<T: Scalar + ClosedSub, const D: usize> Translation<T, D> {
/// let transformed_point = t.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0)); /// let transformed_point = t.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0));
/// assert_eq!(transformed_point, Point3::new(3.0, 3.0, 3.0)); /// assert_eq!(transformed_point, Point3::new(3.0, 3.0, 3.0));
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> { pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
pt - &self.vector pt - &self.vector
} }

View File

@ -69,7 +69,7 @@ where
{ {
/// Generate an arbitrary random variate for testing purposes. /// Generate an arbitrary random variate for testing purposes.
#[inline] #[inline]
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Translation<T, D> { fn sample<G: Rng + ?Sized>(&self, rng: &mut G) -> Translation<T, D> {
Translation::from(rng.gen::<SVector<T, D>>()) Translation::from(rng.gen::<SVector<T, D>>())
} }
} }

View File

@ -77,7 +77,7 @@ where
{ {
#[inline] #[inline]
fn to_superset(&self) -> UnitDualQuaternion<T2> { fn to_superset(&self) -> UnitDualQuaternion<T2> {
let dq = UnitDualQuaternion::<T1>::from_parts(self.clone(), UnitQuaternion::identity()); let dq = UnitDualQuaternion::<T1>::from_parts(*self, UnitQuaternion::identity());
dq.to_superset() dq.to_superset()
} }
@ -212,16 +212,14 @@ impl<T: Scalar, const D: usize> From<[T; D]> for Translation<T, D> {
impl<T: Scalar, const D: usize> From<Point<T, D>> for Translation<T, D> { impl<T: Scalar, const D: usize> From<Point<T, D>> for Translation<T, D> {
#[inline] #[inline]
fn from(pt: Point<T, D>) -> Self { fn from(pt: Point<T, D>) -> Self {
Translation { Translation { vector: pt.coords }
vector: pt.coords.into(),
}
} }
} }
impl<T: Scalar, const D: usize> Into<[T; D]> for Translation<T, D> { impl<T: Scalar, const D: usize> From<Translation<T, D>> for [T; D] {
#[inline] #[inline]
fn into(self) -> [T; D] { fn from(t: Translation<T, D>) -> Self {
self.vector.into() t.vector.into()
} }
} }

View File

@ -1,4 +1,3 @@
use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
@ -19,15 +18,14 @@ macro_rules! deref_impl(
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) } unsafe { &*(self as *const Translation<T, $D> as *const Self::Target) }
} }
} }
impl<T: Scalar> DerefMut for Translation<T, $D> impl<T: Scalar> DerefMut for Translation<T, $D> {
{
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) } unsafe { &mut *(self as *mut Translation<T, $D> as *mut Self::Target) }
} }
} }
} }

View File

@ -84,6 +84,7 @@ where
/// assert_eq!(rot.angle(), 1.78); /// assert_eq!(rot.angle(), 1.78);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle(&self) -> T { pub fn angle(&self) -> T {
self.im.simd_atan2(self.re) self.im.simd_atan2(self.re)
} }
@ -98,6 +99,7 @@ where
/// assert_eq!(rot.sin_angle(), angle.sin()); /// assert_eq!(rot.sin_angle(), angle.sin());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn sin_angle(&self) -> T { pub fn sin_angle(&self) -> T {
self.im self.im
} }
@ -112,6 +114,7 @@ where
/// assert_eq!(rot.cos_angle(),angle.cos()); /// assert_eq!(rot.cos_angle(),angle.cos());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn cos_angle(&self) -> T { pub fn cos_angle(&self) -> T {
self.re self.re
} }
@ -121,6 +124,7 @@ where
/// This is generally used in the context of generic programming. Using /// This is generally used in the context of generic programming. Using
/// the `.angle()` method instead is more common. /// the `.angle()` method instead is more common.
#[inline] #[inline]
#[must_use]
pub fn scaled_axis(&self) -> Vector1<T> { pub fn scaled_axis(&self) -> Vector1<T> {
Vector1::new(self.angle()) Vector1::new(self.angle())
} }
@ -131,6 +135,7 @@ where
/// the `.angle()` method instead is more common. /// the `.angle()` method instead is more common.
/// Returns `None` if the angle is zero. /// Returns `None` if the angle is zero.
#[inline] #[inline]
#[must_use]
pub fn axis_angle(&self) -> Option<(Unit<Vector1<T>>, T)> pub fn axis_angle(&self) -> Option<(Unit<Vector1<T>>, T)>
where where
T: RealField, T: RealField,
@ -157,6 +162,7 @@ where
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn angle_to(&self, other: &Self) -> T { pub fn angle_to(&self, other: &Self) -> T {
let delta = self.rotation_to(other); let delta = self.rotation_to(other);
delta.angle() delta.angle()
@ -254,7 +260,8 @@ where
/// assert_eq!(rot.to_rotation_matrix(), expected); /// assert_eq!(rot.to_rotation_matrix(), expected);
/// ``` /// ```
#[inline] #[inline]
pub fn to_rotation_matrix(&self) -> Rotation2<T> { #[must_use]
pub fn to_rotation_matrix(self) -> Rotation2<T> {
let r = self.re; let r = self.re;
let i = self.im; let i = self.im;
@ -274,7 +281,8 @@ where
/// assert_eq!(rot.to_homogeneous(), expected); /// assert_eq!(rot.to_homogeneous(), expected);
/// ``` /// ```
#[inline] #[inline]
pub fn to_homogeneous(&self) -> Matrix3<T> { #[must_use]
pub fn to_homogeneous(self) -> Matrix3<T> {
self.to_rotation_matrix().to_homogeneous() self.to_rotation_matrix().to_homogeneous()
} }
} }
@ -298,6 +306,7 @@ where
/// assert_relative_eq!(transformed_point, Point2::new(-2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point2::new(-2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point2<T>) -> Point2<T> { pub fn transform_point(&self, pt: &Point2<T>) -> Point2<T> {
self * pt self * pt
} }
@ -316,6 +325,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector2::new(-2.0, 1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, Vector2::new(-2.0, 1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn transform_vector(&self, v: &Vector2<T>) -> Vector2<T> { pub fn transform_vector(&self, v: &Vector2<T>) -> Vector2<T> {
self * v self * v
} }
@ -332,6 +342,7 @@ where
/// assert_relative_eq!(transformed_point, Point2::new(2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_point, Point2::new(2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point2<T>) -> Point2<T> { pub fn inverse_transform_point(&self, pt: &Point2<T>) -> Point2<T> {
// TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement // TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement
// the inverse transformation explicitly here) ? // the inverse transformation explicitly here) ?
@ -350,6 +361,7 @@ where
/// assert_relative_eq!(transformed_vector, Vector2::new(2.0, -1.0), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, Vector2::new(2.0, -1.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &Vector2<T>) -> Vector2<T> { pub fn inverse_transform_vector(&self, v: &Vector2<T>) -> Vector2<T> {
self.inverse() * v self.inverse() * v
} }
@ -366,6 +378,7 @@ where
/// assert_relative_eq!(transformed_vector, -Vector2::y_axis(), epsilon = 1.0e-6); /// assert_relative_eq!(transformed_vector, -Vector2::y_axis(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector2<T>>) -> Unit<Vector2<T>> { pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector2<T>>) -> Unit<Vector2<T>> {
self.inverse() * v self.inverse() * v
} }
@ -392,6 +405,7 @@ where
/// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn slerp(&self, other: &Self, t: T) -> Self { pub fn slerp(&self, other: &Self, t: T) -> Self {
Self::new(self.angle() * (T::one() - t) + other.angle() * t) Self::new(self.angle() * (T::one() - t) + other.angle() * t)
} }

View File

@ -148,6 +148,7 @@ where
/// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin())); /// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin()));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn complex(&self) -> &Complex<T> { pub fn complex(&self) -> &Complex<T> {
self.as_ref() self.as_ref()
} }
@ -244,6 +245,7 @@ where
/// assert_relative_eq!(rot_to.inverse() * rot2, rot1); /// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn rotation_to(&self, other: &Self) -> Self { pub fn rotation_to(&self, other: &Self) -> Self {
other / self other / self
} }
@ -262,6 +264,7 @@ where
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78); /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn powf(&self, n: T) -> Self { pub fn powf(&self, n: T) -> Self {
Self::from_angle(self.angle() * n) Self::from_angle(self.angle() * n)
} }
@ -380,8 +383,8 @@ where
SB: Storage<T, U2>, SB: Storage<T, U2>,
SC: Storage<T, U2>, SC: Storage<T, U2>,
{ {
let sang = na.perp(&nb); let sang = na.perp(nb);
let cang = na.dot(&nb); let cang = na.dot(nb);
Self::from_angle(sang.simd_atan2(cang) * s) Self::from_angle(sang.simd_atan2(cang) * s)
} }

View File

@ -1,3 +1,6 @@
// The macros break if the references are taken out, for some reason.
#![allow(clippy::op_ref)]
use std::ops::{Div, DivAssign, Mul, MulAssign}; use std::ops::{Div, DivAssign, Mul, MulAssign};
use crate::base::storage::Storage; use crate::base::storage::Storage;
@ -314,10 +317,10 @@ complex_op_impl_all!(
; ;
self: Translation<T, 2>, right: UnitComplex<T>, self: Translation<T, 2>, right: UnitComplex<T>,
Output = Isometry<T, UnitComplex<T>, 2>; Output = Isometry<T, UnitComplex<T>, 2>;
[val val] => Isometry::from_parts(self, right); [val val] => Isometry::from_parts(self, right);
[ref val] => Isometry::from_parts(self.clone(), right); [ref val] => Isometry::from_parts(*self, right);
[val ref] => Isometry::from_parts(self, *right); [val ref] => Isometry::from_parts(self, *right);
[ref ref] => Isometry::from_parts(self.clone(), *right); [ref ref] => Isometry::from_parts(*self, *right);
); );
// UnitComplex ×= UnitComplex // UnitComplex ×= UnitComplex
@ -327,7 +330,7 @@ where
{ {
#[inline] #[inline]
fn mul_assign(&mut self, rhs: UnitComplex<T>) { fn mul_assign(&mut self, rhs: UnitComplex<T>) {
*self = &*self * rhs *self = *self * rhs
} }
} }
@ -337,7 +340,7 @@ where
{ {
#[inline] #[inline]
fn mul_assign(&mut self, rhs: &'b UnitComplex<T>) { fn mul_assign(&mut self, rhs: &'b UnitComplex<T>) {
*self = &*self * rhs *self = *self * rhs
} }
} }
@ -348,7 +351,7 @@ where
{ {
#[inline] #[inline]
fn div_assign(&mut self, rhs: UnitComplex<T>) { fn div_assign(&mut self, rhs: UnitComplex<T>) {
*self = &*self / rhs *self = *self / rhs
} }
} }
@ -358,7 +361,7 @@ where
{ {
#[inline] #[inline]
fn div_assign(&mut self, rhs: &'b UnitComplex<T>) { fn div_assign(&mut self, rhs: &'b UnitComplex<T>) {
*self = &*self / rhs *self = *self / rhs
} }
} }
@ -369,7 +372,7 @@ where
{ {
#[inline] #[inline]
fn mul_assign(&mut self, rhs: Rotation<T, 2>) { fn mul_assign(&mut self, rhs: Rotation<T, 2>) {
*self = &*self * rhs *self = *self * rhs
} }
} }
@ -379,7 +382,7 @@ where
{ {
#[inline] #[inline]
fn mul_assign(&mut self, rhs: &'b Rotation<T, 2>) { fn mul_assign(&mut self, rhs: &'b Rotation<T, 2>) {
*self = &*self * rhs *self = *self * rhs
} }
} }
@ -390,7 +393,7 @@ where
{ {
#[inline] #[inline]
fn div_assign(&mut self, rhs: Rotation<T, 2>) { fn div_assign(&mut self, rhs: Rotation<T, 2>) {
*self = &*self / rhs *self = *self / rhs
} }
} }
@ -400,7 +403,7 @@ where
{ {
#[inline] #[inline]
fn div_assign(&mut self, rhs: &'b Rotation<T, 2>) { fn div_assign(&mut self, rhs: &'b Rotation<T, 2>) {
*self = &*self / rhs *self = *self / rhs
} }
} }

View File

@ -1,3 +1,4 @@
#![allow(clippy::type_complexity)]
/*! /*!
# nalgebra # nalgebra
@ -13,7 +14,7 @@ and the official package manager: [cargo](https://github.com/rust-lang/cargo).
Simply add the following to your `Cargo.toml` file: Simply add the following to your `Cargo.toml` file:
```.ignore ```ignore
[dependencies] [dependencies]
// TODO: replace the * by the latest version. // TODO: replace the * by the latest version.
nalgebra = "*" nalgebra = "*"
@ -25,7 +26,7 @@ Most useful functionalities of **nalgebra** are grouped in the root module `nalg
However, the recommended way to use **nalgebra** is to import types and traits However, the recommended way to use **nalgebra** is to import types and traits
explicitly, and call free-functions using the `na::` prefix: explicitly, and call free-functions using the `na::` prefix:
```.rust ```
#[macro_use] #[macro_use]
extern crate approx; // For the macro relative_eq! extern crate approx; // For the macro relative_eq!
extern crate nalgebra as na; extern crate nalgebra as na;
@ -86,7 +87,6 @@ an optimized set of tools for computer graphics and physics. Those features incl
html_root_url = "https://docs.rs/nalgebra/0.25.0" html_root_url = "https://docs.rs/nalgebra/0.25.0"
)] )]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
#![cfg_attr(feature = "no_unsound_assume_init", allow(unreachable_code))] #![cfg_attr(feature = "no_unsound_assume_init", allow(unreachable_code))]
#[cfg(feature = "rand-no-std")] #[cfg(feature = "rand-no-std")]
@ -101,6 +101,7 @@ extern crate approx;
extern crate num_traits as num; extern crate num_traits as num;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
#[cfg_attr(test, macro_use)]
extern crate alloc; extern crate alloc;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
@ -184,6 +185,7 @@ pub fn zero<T: Zero>() -> T {
/// Wraps `val` into the range `[min, max]` using modular arithmetics. /// Wraps `val` into the range `[min, max]` using modular arithmetics.
/// ///
/// The range must not be empty. /// The range must not be empty.
#[must_use]
#[inline] #[inline]
pub fn wrap<T>(mut val: T, min: T, max: T) -> T pub fn wrap<T>(mut val: T, min: T, max: T) -> T
where where
@ -198,19 +200,15 @@ where
while val < min { while val < min {
val += width val += width
} }
val
} else if val > max { } else if val > max {
val -= width; val -= width;
while val > max { while val > max {
val -= width val -= width
} }
val
} else {
val
} }
val
} }
/// Returns a reference to the input value clamped to the interval `[min, max]`. /// Returns a reference to the input value clamped to the interval `[min, max]`.
@ -219,6 +217,7 @@ where
/// * If `min < val < max`, this returns `val`. /// * If `min < val < max`, this returns `val`.
/// * If `val <= min`, this returns `min`. /// * If `val <= min`, this returns `min`.
/// * If `val >= max`, this returns `max`. /// * If `val >= max`, this returns `max`.
#[must_use]
#[inline] #[inline]
pub fn clamp<T: PartialOrd>(val: T, min: T, max: T) -> T { pub fn clamp<T: PartialOrd>(val: T, min: T, max: T) -> T {
if val > min { if val > min {
@ -391,7 +390,7 @@ pub fn center<T: SimdComplexField, const D: usize>(
p1: &Point<T, D>, p1: &Point<T, D>,
p2: &Point<T, D>, p2: &Point<T, D>,
) -> Point<T, D> { ) -> Point<T, D> {
((&p1.coords + &p2.coords) * convert::<_, T>(0.5)).into() ((p1.coords + p2.coords) * convert::<_, T>(0.5)).into()
} }
/// The distance between two points. /// The distance between two points.
@ -405,7 +404,7 @@ pub fn distance<T: SimdComplexField, const D: usize>(
p1: &Point<T, D>, p1: &Point<T, D>,
p2: &Point<T, D>, p2: &Point<T, D>,
) -> T::SimdRealField { ) -> T::SimdRealField {
(&p2.coords - &p1.coords).norm() (p2.coords - p1.coords).norm()
} }
/// The squared distance between two points. /// The squared distance between two points.
@ -419,7 +418,7 @@ pub fn distance_squared<T: SimdComplexField, const D: usize>(
p1: &Point<T, D>, p1: &Point<T, D>,
p2: &Point<T, D>, p2: &Point<T, D>,
) -> T::SimdRealField { ) -> T::SimdRealField {
(&p2.coords - &p1.coords).norm_squared() (p2.coords - p1.coords).norm_squared()
} }
/* /*

View File

@ -8,17 +8,17 @@ use crate::base::dimension::Dim;
use crate::base::storage::Storage; use crate::base::storage::Storage;
use crate::base::{Const, DefaultAllocator, OMatrix, OVector}; use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
/// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix `m` and returns /// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix and returns
/// the corresponding diagonal transformation. /// the corresponding diagonal transformation.
/// ///
/// See https://arxiv.org/pdf/1401.5766.pdf /// See https://arxiv.org/pdf/1401.5766.pdf
pub fn balance_parlett_reinsch<T: RealField, D: Dim>(m: &mut OMatrix<T, D, D>) -> OVector<T, D> pub fn balance_parlett_reinsch<T: RealField, D: Dim>(matrix: &mut OMatrix<T, D, D>) -> OVector<T, D>
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>, DefaultAllocator: Allocator<T, D, D> + Allocator<T, D>,
{ {
assert!(m.is_square(), "Unable to balance a non-square matrix."); assert!(matrix.is_square(), "Unable to balance a non-square matrix.");
let dim = m.data.shape().0; let dim = matrix.data.shape().0;
let radix: T = crate::convert(2.0f64); let radix: T = crate::convert(2.0f64);
let mut d = OVector::from_element_generic(dim, Const::<1>, T::one()); let mut d = OVector::from_element_generic(dim, Const::<1>, T::one());
@ -28,36 +28,37 @@ where
converged = true; converged = true;
for i in 0..dim.value() { for i in 0..dim.value() {
let mut c = m.column(i).norm_squared(); let mut n_col = matrix.column(i).norm_squared();
let mut r = m.row(i).norm_squared(); let mut n_row = matrix.row(i).norm_squared();
let mut f = T::one(); let mut f = T::one();
let s = c + r; let s = n_col + n_row;
c = c.sqrt(); n_col = n_col.sqrt();
r = r.sqrt(); n_row = n_row.sqrt();
if c.is_zero() || r.is_zero() { if n_col.is_zero() || n_row.is_zero() {
continue; continue;
} }
while c < r / radix { while n_col < n_row / radix {
c *= radix; n_col *= radix;
r /= radix; n_row /= radix;
f *= radix; f *= radix;
} }
while c >= r * radix { while n_col >= n_row * radix {
c /= radix; n_col /= radix;
r *= radix; n_row *= radix;
f /= radix; f /= radix;
} }
let eps: T = crate::convert(0.95); let eps: T = crate::convert(0.95);
if c * c + r * r < eps * s { #[allow(clippy::suspicious_operation_groupings)]
if n_col * n_col + n_row * n_row < eps * s {
converged = false; converged = false;
d[i] *= f; d[i] *= f;
m.column_mut(i).mul_assign(f); matrix.column_mut(i).mul_assign(f);
m.row_mut(i).div_assign(f); matrix.row_mut(i).div_assign(f);
} }
} }
} }

View File

@ -153,6 +153,7 @@ where
/// Indicates whether this decomposition contains an upper-diagonal matrix. /// Indicates whether this decomposition contains an upper-diagonal matrix.
#[inline] #[inline]
#[must_use]
pub fn is_upper_diagonal(&self) -> bool { pub fn is_upper_diagonal(&self) -> bool {
self.upper_diagonal self.upper_diagonal
} }
@ -188,6 +189,7 @@ where
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition. /// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn d(&self) -> OMatrix<T, DimMinimum<R, C>, DimMinimum<R, C>> pub fn d(&self) -> OMatrix<T, DimMinimum<R, C>, DimMinimum<R, C>>
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>,
@ -207,6 +209,7 @@ where
/// Computes the orthogonal matrix `U` of this `U * D * V` decomposition. /// Computes the orthogonal matrix `U` of this `U * D * V` decomposition.
// TODO: code duplication with householder::assemble_q. // TODO: code duplication with householder::assemble_q.
// Except that we are returning a rectangular matrix here. // Except that we are returning a rectangular matrix here.
#[must_use]
pub fn u(&self) -> OMatrix<T, R, DimMinimum<R, C>> pub fn u(&self) -> OMatrix<T, R, DimMinimum<R, C>>
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
@ -237,6 +240,7 @@ where
} }
/// Computes the orthogonal matrix `V_t` of this `U * D * V_t` decomposition. /// Computes the orthogonal matrix `V_t` of this `U * D * V_t` decomposition.
#[must_use]
pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C> pub fn v_t(&self) -> OMatrix<T, DimMinimum<R, C>, C>
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
@ -274,6 +278,7 @@ where
} }
/// The diagonal part of this decomposed matrix. /// The diagonal part of this decomposed matrix.
#[must_use]
pub fn diagonal(&self) -> OVector<T::RealField, DimMinimum<R, C>> pub fn diagonal(&self) -> OVector<T::RealField, DimMinimum<R, C>>
where where
DefaultAllocator: Allocator<T::RealField, DimMinimum<R, C>>, DefaultAllocator: Allocator<T::RealField, DimMinimum<R, C>>,
@ -282,6 +287,7 @@ where
} }
/// The off-diagonal part of this decomposed matrix. /// The off-diagonal part of this decomposed matrix.
#[must_use]
pub fn off_diagonal(&self) -> OVector<T::RealField, DimDiff<DimMinimum<R, C>, U1>> pub fn off_diagonal(&self) -> OVector<T::RealField, DimDiff<DimMinimum<R, C>, U1>>
where where
DefaultAllocator: Allocator<T::RealField, DimDiff<DimMinimum<R, C>, U1>>, DefaultAllocator: Allocator<T::RealField, DimDiff<DimMinimum<R, C>, U1>>,

View File

@ -92,6 +92,7 @@ where
/// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly
/// uppen-triangular part filled with zeros. /// uppen-triangular part filled with zeros.
#[must_use]
pub fn l(&self) -> OMatrix<T, D, D> { pub fn l(&self) -> OMatrix<T, D, D> {
self.chol.lower_triangle() self.chol.lower_triangle()
} }
@ -101,6 +102,7 @@ where
/// ///
/// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular /// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular
/// part are garbage and should be ignored by further computations. /// part are garbage and should be ignored by further computations.
#[must_use]
pub fn l_dirty(&self) -> &OMatrix<T, D, D> { pub fn l_dirty(&self) -> &OMatrix<T, D, D> {
&self.chol &self.chol
} }
@ -119,6 +121,7 @@ where
/// Returns the solution of the system `self * x = b` where `self` is the decomposed matrix and /// Returns the solution of the system `self * x = b` where `self` is the decomposed matrix and
/// `x` the unknown. /// `x` the unknown.
#[must_use = "Did you mean to use solve_mut()?"]
pub fn solve<R2: Dim, C2: Dim, S2>(&self, b: &Matrix<T, R2, C2, S2>) -> OMatrix<T, R2, C2> pub fn solve<R2: Dim, C2: Dim, S2>(&self, b: &Matrix<T, R2, C2, S2>) -> OMatrix<T, R2, C2>
where where
S2: Storage<T, R2, C2>, S2: Storage<T, R2, C2>,
@ -131,6 +134,7 @@ where
} }
/// Computes the inverse of the decomposed matrix. /// Computes the inverse of the decomposed matrix.
#[must_use]
pub fn inverse(&self) -> OMatrix<T, D, D> { pub fn inverse(&self) -> OMatrix<T, D, D> {
let shape = self.chol.data.shape(); let shape = self.chol.data.shape();
let mut res = OMatrix::identity_generic(shape.0, shape.1); let mut res = OMatrix::identity_generic(shape.0, shape.1);
@ -140,6 +144,7 @@ where
} }
/// Computes the determinant of the decomposed matrix. /// Computes the determinant of the decomposed matrix.
#[must_use]
pub fn determinant(&self) -> T::SimdRealField { pub fn determinant(&self) -> T::SimdRealField {
let dim = self.chol.nrows(); let dim = self.chol.nrows();
let mut prod_diag = T::one(); let mut prod_diag = T::one();
@ -287,6 +292,7 @@ where
/// Updates the decomposition such that we get the decomposition of the factored matrix with its `j`th column removed. /// Updates the decomposition such that we get the decomposition of the factored matrix with its `j`th column removed.
/// Since the matrix is square, the `j`th row will also be removed. /// Since the matrix is square, the `j`th row will also be removed.
#[must_use]
pub fn remove_column(&self, j: usize) -> Cholesky<T, DimDiff<D, U1>> pub fn remove_column(&self, j: usize) -> Cholesky<T, DimDiff<D, U1>>
where where
D: DimSub<U1>, D: DimSub<U1>,

View File

@ -95,6 +95,7 @@ where
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition. /// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C>
where where
DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>, DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>,
@ -126,6 +127,7 @@ where
} }
/// Computes the orthogonal matrix `Q` of this decomposition. /// Computes the orthogonal matrix `Q` of this decomposition.
#[must_use]
pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>>
where where
DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>, DefaultAllocator: Allocator<T, R, DimMinimum<R, C>>,
@ -150,6 +152,7 @@ where
} }
/// Retrieves the column permutation of this decomposition. /// Retrieves the column permutation of this decomposition.
#[inline] #[inline]
#[must_use]
pub fn p(&self) -> &PermutationSequence<DimMinimum<R, C>> { pub fn p(&self) -> &PermutationSequence<DimMinimum<R, C>> {
&self.p &self.p
} }
@ -201,6 +204,7 @@ where
/// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined.
/// ///
/// Returns `None` if `self` is not invertible. /// Returns `None` if `self` is not invertible.
#[must_use = "Did you mean to use solve_mut()?"]
pub fn solve<R2: Dim, C2: Dim, S2>( pub fn solve<R2: Dim, C2: Dim, S2>(
&self, &self,
b: &Matrix<T, R2, C2, S2>, b: &Matrix<T, R2, C2, S2>,
@ -283,6 +287,7 @@ where
/// Computes the inverse of the decomposed matrix. /// Computes the inverse of the decomposed matrix.
/// ///
/// Returns `None` if the decomposed matrix is not invertible. /// Returns `None` if the decomposed matrix is not invertible.
#[must_use]
pub fn try_inverse(&self) -> Option<OMatrix<T, D, D>> { pub fn try_inverse(&self) -> Option<OMatrix<T, D, D>> {
assert!( assert!(
self.col_piv_qr.is_square(), self.col_piv_qr.is_square(),
@ -301,6 +306,7 @@ where
} }
/// Indicates if the decomposed matrix is invertible. /// Indicates if the decomposed matrix is invertible.
#[must_use]
pub fn is_invertible(&self) -> bool { pub fn is_invertible(&self) -> bool {
assert!( assert!(
self.col_piv_qr.is_square(), self.col_piv_qr.is_square(),
@ -317,6 +323,7 @@ where
} }
/// Computes the determinant of the decomposed matrix. /// Computes the determinant of the decomposed matrix.
#[must_use]
pub fn determinant(&self) -> T { pub fn determinant(&self) -> T {
let dim = self.col_piv_qr.nrows(); let dim = self.col_piv_qr.nrows();
assert!( assert!(

View File

@ -112,6 +112,7 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
/// ///
/// # Errors /// # Errors
/// Inputs must satisfy `self.len() >= kernel.len() > 0`. /// Inputs must satisfy `self.len() >= kernel.len() > 0`.
#[must_use]
pub fn convolve_same<D2, S2>(&self, kernel: Vector<T, D2, S2>) -> OVector<T, D1> pub fn convolve_same<D2, S2>(&self, kernel: Vector<T, D2, S2>) -> OVector<T, D1>
where where
D2: Dim, D2: Dim,

View File

@ -12,6 +12,7 @@ impl<T: ComplexField, D: DimMin<D, Output = D>, S: Storage<T, D, D>> SquareMatri
/// ///
/// If the matrix has a dimension larger than 3, an LU decomposition is used. /// If the matrix has a dimension larger than 3, an LU decomposition is used.
#[inline] #[inline]
#[must_use]
pub fn determinant(&self) -> T pub fn determinant(&self) -> T
where where
DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), D>, DefaultAllocator: Allocator<T, D, D> + Allocator<(usize, usize), D>,

View File

@ -435,37 +435,38 @@ where
+ Allocator<T::RealField, D, D>, + Allocator<T::RealField, D, D>,
{ {
/// Computes exponential of this matrix /// Computes exponential of this matrix
#[must_use]
pub fn exp(&self) -> Self { pub fn exp(&self) -> Self {
// Simple case // Simple case
if self.nrows() == 1 { if self.nrows() == 1 {
return self.map(|v| v.exp()); return self.map(|v| v.exp());
} }
let mut h = ExpmPadeHelper::new(self.clone(), true); let mut helper = ExpmPadeHelper::new(self.clone(), true);
let eta_1 = T::RealField::max(h.d4_loose(), h.d6_loose()); let eta_1 = T::RealField::max(helper.d4_loose(), helper.d6_loose());
if eta_1 < convert(1.495_585_217_958_292e-2) && ell(&h.a, 3) == 0 { if eta_1 < convert(1.495_585_217_958_292e-2) && ell(&helper.a, 3) == 0 {
let (u, v) = h.pade3(); let (u, v) = helper.pade3();
return solve_p_q(u, v); return solve_p_q(u, v);
} }
let eta_2 = T::RealField::max(h.d4_tight(), h.d6_loose()); let eta_2 = T::RealField::max(helper.d4_tight(), helper.d6_loose());
if eta_2 < convert(2.539_398_330_063_230e-1) && ell(&h.a, 5) == 0 { if eta_2 < convert(2.539_398_330_063_23e-1) && ell(&helper.a, 5) == 0 {
let (u, v) = h.pade5(); let (u, v) = helper.pade5();
return solve_p_q(u, v); return solve_p_q(u, v);
} }
let eta_3 = T::RealField::max(h.d6_tight(), h.d8_loose()); let eta_3 = T::RealField::max(helper.d6_tight(), helper.d8_loose());
if eta_3 < convert(9.504_178_996_162_932e-1) && ell(&h.a, 7) == 0 { if eta_3 < convert(9.504_178_996_162_932e-1) && ell(&helper.a, 7) == 0 {
let (u, v) = h.pade7(); let (u, v) = helper.pade7();
return solve_p_q(u, v); return solve_p_q(u, v);
} }
if eta_3 < convert(2.097_847_961_257_068e+0) && ell(&h.a, 9) == 0 { if eta_3 < convert(2.097_847_961_257_068e0) && ell(&helper.a, 9) == 0 {
let (u, v) = h.pade9(); let (u, v) = helper.pade9();
return solve_p_q(u, v); return solve_p_q(u, v);
} }
let eta_4 = T::RealField::max(h.d8_loose(), h.d10_loose()); let eta_4 = T::RealField::max(helper.d8_loose(), helper.d10_loose());
let eta_5 = T::RealField::min(eta_3, eta_4); let eta_5 = T::RealField::min(eta_3, eta_4);
let theta_13 = convert(4.25); let theta_13 = convert(4.25);
@ -481,9 +482,12 @@ where
} }
}; };
s += ell(&(&h.a * convert::<f64, T>(2.0_f64.powf(-(s as f64)))), 13); s += ell(
&(&helper.a * convert::<f64, T>(2.0_f64.powf(-(s as f64)))),
13,
);
let (u, v) = h.pade13_scaled(s); let (u, v) = helper.pade13_scaled(s);
let mut x = solve_p_q(u, v); let mut x = solve_p_q(u, v);
for _ in 0..s { for _ in 0..s {

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