commit
4a5855a1c4
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -4,6 +4,37 @@ documented here.
|
|||
|
||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [0.32.4] (19 Feb 2023)
|
||||
- Add the `glam-0.25` feature to enable conversion from/to types from `glam` v0.25.
|
||||
|
||||
## [0.32.3] (09 July 2023)
|
||||
|
||||
### Modified
|
||||
- Statically sized matrices are now serialized as tuples to match how serde
|
||||
serialized plain arrays.
|
||||
- Don’t require `Scalar` for matrix `PartialEq` and `Eq`.
|
||||
|
||||
### Added
|
||||
- Allow trailing punctuation in macros `vector!`, `matrix!`, `point!`, etc.
|
||||
- Add the methods `Matrix1::as_scalar`, `::as_scalar_mut`, `::to_scalar`, `::into_scalar`.
|
||||
- Add `Rotation3::euler_angles_ordered`, a generalized euler angles calculation.
|
||||
- Add the `glam-0.24` feature to enable conversion from/to types from `glam` v0.24.
|
||||
- Add the `lerp` method to points.
|
||||
- Implement `Clone` for `MatrixIter`.
|
||||
|
||||
### Fixed
|
||||
- Fixed severe catastrophic cancellation issue in variance calculation.
|
||||
|
||||
## [0.32.2] (07 March 2023)
|
||||
|
||||
### Added
|
||||
- Add the `glam-0.23` to enable conversion from/to type from `glam` v0.23.
|
||||
|
||||
## [0.32.1] (14 Jan. 2023)
|
||||
|
||||
### Modified
|
||||
- Updated `nalgebra-macros` to use the new `Dyn`, avoiding macro-generated deprecation warnings.
|
||||
|
||||
## [0.32.0] (14 Jan. 2023)
|
||||
|
||||
### Modified
|
||||
|
|
16
Cargo.toml
16
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "nalgebra"
|
||||
version = "0.32.0"
|
||||
version = "0.32.4"
|
||||
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
|
||||
|
||||
description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices."
|
||||
|
@ -47,6 +47,9 @@ convert-glam019 = [ "glam019" ]
|
|||
convert-glam020 = [ "glam020" ]
|
||||
convert-glam021 = [ "glam021" ]
|
||||
convert-glam022 = [ "glam022" ]
|
||||
convert-glam023 = [ "glam023" ]
|
||||
convert-glam024 = [ "glam024" ]
|
||||
convert-glam025 = [ "glam025" ]
|
||||
|
||||
# Serialization
|
||||
## To use serde in a #[no-std] environment, enable the
|
||||
|
@ -56,7 +59,7 @@ convert-glam022 = [ "glam022" ]
|
|||
serde-serialize-no-std = [ "serde", "num-complex/serde" ]
|
||||
serde-serialize = [ "serde-serialize-no-std", "serde/std" ]
|
||||
rkyv-serialize-no-std = [ "rkyv/size_32" ]
|
||||
rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std", "rkyv/validation", "bytecheck" ]
|
||||
rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std", "rkyv/validation" ]
|
||||
|
||||
# Randomness
|
||||
## To use rand in a #[no-std] environment, enable the
|
||||
|
@ -71,7 +74,7 @@ slow-tests = []
|
|||
rkyv-safe-deser = [ "rkyv-serialize", "rkyv/validation" ]
|
||||
|
||||
[dependencies]
|
||||
nalgebra-macros = { version = "0.1", path = "nalgebra-macros", optional = true }
|
||||
nalgebra-macros = { version = "0.2.1", path = "nalgebra-macros", optional = true }
|
||||
typenum = "1.12"
|
||||
rand-package = { package = "rand", version = "0.8", optional = true, default-features = false }
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
|
@ -83,8 +86,7 @@ alga = { version = "0.9", default-features = false, optional = true }
|
|||
rand_distr = { version = "0.4", default-features = false, optional = true }
|
||||
matrixmultiply = { version = "0.3", optional = true }
|
||||
serde = { version = "1.0", default-features = false, features = [ "derive" ], optional = true }
|
||||
rkyv = { version = "0.7", default-features = false, optional = true }
|
||||
bytecheck = { version = "~0.6.1", optional = true }
|
||||
rkyv = { version = "0.7.41", default-features = false, optional = true }
|
||||
mint = { version = "0.5", optional = true }
|
||||
quickcheck = { version = "1", optional = true }
|
||||
pest = { version = "2", optional = true }
|
||||
|
@ -101,6 +103,9 @@ glam019 = { package = "glam", version = "0.19", optional = true }
|
|||
glam020 = { package = "glam", version = "0.20", optional = true }
|
||||
glam021 = { package = "glam", version = "0.21", optional = true }
|
||||
glam022 = { package = "glam", version = "0.22", optional = true }
|
||||
glam023 = { package = "glam", version = "0.23", optional = true }
|
||||
glam024 = { package = "glam", version = "0.24", optional = true }
|
||||
glam025 = { package = "glam", version = "0.25", optional = true }
|
||||
cust_core = { version = "0.1", optional = true }
|
||||
rayon = { version = "1.6", optional = true }
|
||||
|
||||
|
@ -109,6 +114,7 @@ serde_json = "1.0"
|
|||
rand_xorshift = "0.3"
|
||||
rand_isaac = "0.3"
|
||||
criterion = { version = "0.4", features = ["html_reports"] }
|
||||
nalgebra = { path = ".", features = ["debug", "compare", "rand", "macros"]}
|
||||
|
||||
# For matrix comparison macro
|
||||
matrixcompare = "0.3.0"
|
||||
|
|
19
README.md
19
README.md
|
@ -29,22 +29,3 @@
|
|||
</p>
|
||||
|
||||
-----
|
||||
|
||||
## Acknowledgements
|
||||
nalgebra is supported by our **platinum** sponsors:
|
||||
<p>
|
||||
<a href="https://embark-studios.com">
|
||||
<img src="https://www.embark.dev/img/logo_black.png" width="301px">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
And our gold sponsors:
|
||||
|
||||
<p>
|
||||
<a href="https://fragcolor.com">
|
||||
<img src="https://dimforge.com/img/fragcolor_logo2_color_black.svg" width="300px">
|
||||
</a>
|
||||
<a href="https://resolutiongames.com/">
|
||||
<img src="https://dimforge.com/img/logo_resolution_games.png" width="300px" />
|
||||
</a>
|
||||
</p>
|
|
@ -7,24 +7,24 @@ use na::DefaultAllocator;
|
|||
use crate::traits::{Alloc, Number, Dimension};
|
||||
use crate::aliases::TVec;
|
||||
|
||||
/// Component-wise approximate equality beween two vectors.
|
||||
/// Component-wise approximate equality between two vectors.
|
||||
pub fn epsilon_equal<T: Number, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>, epsilon: T) -> TVec<bool, D>
|
||||
where DefaultAllocator: Alloc<T, D> {
|
||||
x.zip_map(y, |x, y| abs_diff_eq!(x, y, epsilon = epsilon))
|
||||
}
|
||||
|
||||
/// Component-wise approximate equality beween two scalars.
|
||||
/// Component-wise approximate equality between two scalars.
|
||||
pub fn epsilon_equal2<T: AbsDiffEq<Epsilon = T>>(x: T, y: T, epsilon: T) -> bool {
|
||||
abs_diff_eq!(x, y, epsilon = epsilon)
|
||||
}
|
||||
|
||||
/// Component-wise approximate non-equality beween two vectors.
|
||||
/// Component-wise approximate non-equality between two vectors.
|
||||
pub fn epsilon_not_equal<T: Number, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>, epsilon: T) -> TVec<bool, D>
|
||||
where DefaultAllocator: Alloc<T, D> {
|
||||
x.zip_map(y, |x, y| abs_diff_ne!(x, y, epsilon = epsilon))
|
||||
}
|
||||
|
||||
/// Component-wise approximate non-equality beween two scalars.
|
||||
/// Component-wise approximate non-equality between two scalars.
|
||||
pub fn epsilon_not_equal2<T: AbsDiffEq<Epsilon = T>>(x: T, y: T, epsilon: T) -> bool {
|
||||
abs_diff_ne!(x, y, epsilon = epsilon)
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ pub fn quat_to_mat3<T: RealNumber>(x: &Qua<T>) -> TMat3<T> {
|
|||
.into_inner()
|
||||
}
|
||||
|
||||
/// Converts a quaternion to a rotation matrix in homogenous coordinates.
|
||||
/// Converts a quaternion to a rotation matrix in homogeneous coordinates.
|
||||
pub fn quat_to_mat4<T: RealNumber>(x: &Qua<T>) -> TMat4<T> {
|
||||
UnitQuaternion::new_unchecked(*x).to_homogeneous()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "nalgebra-macros"
|
||||
version = "0.1.0"
|
||||
version = "0.2.1"
|
||||
authors = [ "Andreas Longva", "Sébastien Crozet <developer@crozet.re>" ]
|
||||
edition = "2018"
|
||||
description = "Procedural macros for nalgebra"
|
||||
|
|
|
@ -223,7 +223,7 @@ impl Parse for Vector {
|
|||
elements: Vec::new(),
|
||||
})
|
||||
} else {
|
||||
let elements = MatrixRowSyntax::parse_separated_nonempty(input)?
|
||||
let elements = MatrixRowSyntax::parse_terminated(input)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
Ok(Self { elements })
|
||||
|
|
|
@ -94,6 +94,12 @@ fn dmatrix_small_dims_exhaustive() {
|
|||
DMatrix::from_row_slice(4, 4, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_trailing_semi() {
|
||||
matrix![1, 2;];
|
||||
dmatrix![1, 2;];
|
||||
}
|
||||
|
||||
// Skip rustfmt because it just makes the test bloated without making it more readable
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
|
@ -151,6 +157,13 @@ fn dvector_small_dims_exhaustive() {
|
|||
assert_eq_and_type!(dvector![1, 2, 3, 4, 5, 6], DVector::from_column_slice(&[1, 2, 3, 4, 5, 6]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector_trailing_comma() {
|
||||
vector![1, 2,];
|
||||
point![1, 2,];
|
||||
dvector![1, 2,];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_trybuild_tests() {
|
||||
let t = trybuild::TestCases::new();
|
||||
|
|
|
@ -494,7 +494,7 @@ where
|
|||
assert_eq!(source_minor_indices.len(), values.len());
|
||||
let nnz = values.len();
|
||||
|
||||
// Count the number of occurences of each minor index
|
||||
// Count the number of occurrences of each minor index
|
||||
let mut minor_counts = vec![0; minor_dim];
|
||||
for minor_idx in source_minor_indices {
|
||||
minor_counts[*minor_idx] += 1;
|
||||
|
|
|
@ -98,7 +98,7 @@ where
|
|||
|
||||
/// Faster sparse-sparse matrix multiplication, `C <- beta * C + alpha * op(A) * op(B)`.
|
||||
/// This will not return an error even if the patterns don't match.
|
||||
/// Should be used for situations where pattern creation immediately preceeds multiplication.
|
||||
/// Should be used for situations where pattern creation immediately precedes multiplication.
|
||||
///
|
||||
/// Panics if the dimensions of the matrices involved are not compatible with the expression.
|
||||
pub fn spmm_csc_prealloc_unchecked<T>(
|
||||
|
|
|
@ -89,7 +89,7 @@ where
|
|||
|
||||
/// Faster sparse-sparse matrix multiplication, `C <- beta * C + alpha * op(A) * op(B)`.
|
||||
/// This will not return an error even if the patterns don't match.
|
||||
/// Should be used for situations where pattern creation immediately preceeds multiplication.
|
||||
/// Should be used for situations where pattern creation immediately precedes multiplication.
|
||||
///
|
||||
/// Panics if the dimensions of the matrices involved are not compatible with the expression.
|
||||
pub fn spmm_csr_prealloc_unchecked<T>(
|
||||
|
|
|
@ -81,32 +81,32 @@ pub type MatrixXx5<T> = Matrix<T, Dyn, U5, VecStorage<T, Dyn, U5>>;
|
|||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub type MatrixXx6<T> = Matrix<T, Dyn, U6, VecStorage<T, Dyn, U6>>;
|
||||
|
||||
/// A heap-allocated, row-major, matrix with 1 rows and a dynamic number of columns.
|
||||
/// A heap-allocated, column-major, matrix with 1 rows and a dynamic number of columns.
|
||||
///
|
||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub type Matrix1xX<T> = Matrix<T, U1, Dyn, VecStorage<T, U1, Dyn>>;
|
||||
/// A heap-allocated, row-major, matrix with 2 rows and a dynamic number of columns.
|
||||
/// A heap-allocated, column-major, matrix with 2 rows and a dynamic number of columns.
|
||||
///
|
||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub type Matrix2xX<T> = Matrix<T, U2, Dyn, VecStorage<T, U2, Dyn>>;
|
||||
/// A heap-allocated, row-major, matrix with 3 rows and a dynamic number of columns.
|
||||
/// A heap-allocated, column-major, matrix with 3 rows and a dynamic number of columns.
|
||||
///
|
||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub type Matrix3xX<T> = Matrix<T, U3, Dyn, VecStorage<T, U3, Dyn>>;
|
||||
/// A heap-allocated, row-major, matrix with 4 rows and a dynamic number of columns.
|
||||
/// A heap-allocated, column-major, matrix with 4 rows and a dynamic number of columns.
|
||||
///
|
||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub type Matrix4xX<T> = Matrix<T, U4, Dyn, VecStorage<T, U4, Dyn>>;
|
||||
/// A heap-allocated, row-major, matrix with 5 rows and a dynamic number of columns.
|
||||
/// A heap-allocated, column-major, matrix with 5 rows and a dynamic number of columns.
|
||||
///
|
||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub type Matrix5xX<T> = Matrix<T, U5, Dyn, VecStorage<T, U5, Dyn>>;
|
||||
/// A heap-allocated, row-major, matrix with 6 rows and a dynamic number of columns.
|
||||
/// A heap-allocated, column-major, matrix with 6 rows and a dynamic number of columns.
|
||||
///
|
||||
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
|
|
|
@ -20,9 +20,9 @@ use std::mem::MaybeUninit;
|
|||
/// Every allocator must be both static and dynamic. Though not all implementations may share the
|
||||
/// same `Buffer` type.
|
||||
pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
|
||||
/// The type of buffer this allocator can instanciate.
|
||||
/// The type of buffer this allocator can instantiate.
|
||||
type Buffer: StorageMut<T, R, C> + IsContiguous + Clone + Debug;
|
||||
/// The type of buffer with uninitialized components this allocator can instanciate.
|
||||
/// The type of buffer with uninitialized components this allocator can instantiate.
|
||||
type BufferUninit: RawStorageMut<MaybeUninit<T>, R, C> + IsContiguous;
|
||||
|
||||
/// Allocates a buffer with the given number of rows and columns without initializing its content.
|
||||
|
|
|
@ -5,12 +5,15 @@ use std::ops::Mul;
|
|||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use serde::de::{Error, SeqAccess, Visitor};
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use serde::ser::SerializeSeq;
|
||||
use serde::ser::SerializeTuple;
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
use crate::base::allocator::Allocator;
|
||||
use crate::base::default_allocator::DefaultAllocator;
|
||||
use crate::base::dimension::{Const, ToTypenum};
|
||||
|
@ -189,7 +192,7 @@ where
|
|||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut serializer = serializer.serialize_seq(Some(R * C))?;
|
||||
let mut serializer = serializer.serialize_tuple(R * C)?;
|
||||
|
||||
for e in self.as_slice().iter() {
|
||||
serializer.serialize_element(e)?;
|
||||
|
@ -208,7 +211,7 @@ where
|
|||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
deserializer.deserialize_seq(ArrayStorageVisitor::new())
|
||||
deserializer.deserialize_tuple(R * C, ArrayStorageVisitor::new())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use std::fmt::Debug;
|
|||
use std::ops::{Add, Div, Mul, Sub};
|
||||
use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
|
|
|
@ -1077,7 +1077,7 @@ where
|
|||
}
|
||||
|
||||
// Move the elements of `data` in such a way that the matrix with
|
||||
// the rows `[i, i + nremove[` deleted is represented in a contigous
|
||||
// the rows `[i, i + nremove[` deleted is represented in a contiguous
|
||||
// way in `data` after this method completes.
|
||||
// Every deleted element are manually dropped by this method.
|
||||
unsafe fn compress_rows<T: Scalar>(
|
||||
|
|
|
@ -15,9 +15,9 @@ use crate::base::storage::{RawStorage, RawStorageMut};
|
|||
use crate::base::{Matrix, MatrixView, MatrixViewMut, Scalar};
|
||||
|
||||
macro_rules! iterator {
|
||||
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
|
||||
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty, $($derives:ident),* $(,)?) => {
|
||||
/// An iterator through a dense matrix with arbitrary strides matrix.
|
||||
#[derive(Debug)]
|
||||
#[derive($($derives),*)]
|
||||
pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> {
|
||||
ptr: $Ptr,
|
||||
inner_ptr: $Ptr,
|
||||
|
@ -39,7 +39,7 @@ macro_rules! iterator {
|
|||
let ptr = storage.$ptr();
|
||||
|
||||
// If we have a size of 0, 'ptr' must be
|
||||
// dangling. Howver, 'inner_offset' might
|
||||
// dangling. However, 'inner_offset' might
|
||||
// not be zero if only one dimension is zero, so
|
||||
// we don't want to call 'offset'.
|
||||
// This pointer will never actually get used
|
||||
|
@ -177,8 +177,8 @@ macro_rules! iterator {
|
|||
};
|
||||
}
|
||||
|
||||
iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S);
|
||||
iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S);
|
||||
iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S, Clone, Debug);
|
||||
iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S, Debug);
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
|
@ -13,6 +13,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|||
|
||||
#[cfg(feature = "rkyv-serialize-no-std")]
|
||||
use super::rkyv_wrappers::CustomPhantom;
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
#[cfg(feature = "rkyv-serialize-no-std")]
|
||||
use rkyv::{with::With, Archive, Archived};
|
||||
|
||||
|
@ -1859,14 +1861,14 @@ where
|
|||
|
||||
impl<T, R: Dim, C: Dim, S> Eq for Matrix<T, R, C, S>
|
||||
where
|
||||
T: Scalar + Eq,
|
||||
T: Eq,
|
||||
S: RawStorage<T, R, C>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, R, R2, C, C2, S, S2> PartialEq<Matrix<T, R2, C2, S2>> for Matrix<T, R, C, S>
|
||||
where
|
||||
T: Scalar + PartialEq,
|
||||
T: PartialEq,
|
||||
C: Dim,
|
||||
C2: Dim,
|
||||
R: Dim,
|
||||
|
@ -2244,3 +2246,102 @@ where
|
|||
Unit::new_unchecked(crate::convert_ref(self.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Matrix<T, U1, U1, S>
|
||||
where
|
||||
S: RawStorage<T, U1, U1>,
|
||||
{
|
||||
/// Returns a reference to the single element in this matrix.
|
||||
///
|
||||
/// As opposed to indexing, using this provides type-safety
|
||||
/// when flattening dimensions.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let inner_product: f32 = *(v.transpose() * v).as_scalar();
|
||||
/// ```
|
||||
///
|
||||
///```compile_fail
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let inner_product = (v * v.transpose()).item(); // Typo, does not compile.
|
||||
///```
|
||||
pub fn as_scalar(&self) -> &T {
|
||||
&self[(0, 0)]
|
||||
}
|
||||
/// Get a mutable reference to the single element in this matrix
|
||||
///
|
||||
/// As opposed to indexing, using this provides type-safety
|
||||
/// when flattening dimensions.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let mut inner_product = (v.transpose() * v);
|
||||
/// *inner_product.as_scalar_mut() = 3.;
|
||||
/// ```
|
||||
///
|
||||
///```compile_fail
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let mut inner_product = (v * v.transpose());
|
||||
/// *inner_product.as_scalar_mut() = 3.;
|
||||
///```
|
||||
pub fn as_scalar_mut(&mut self) -> &mut T
|
||||
where
|
||||
S: RawStorageMut<T, U1>,
|
||||
{
|
||||
&mut self[(0, 0)]
|
||||
}
|
||||
/// Convert this 1x1 matrix by reference into a scalar.
|
||||
///
|
||||
/// As opposed to indexing, using this provides type-safety
|
||||
/// when flattening dimensions.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let mut inner_product: f32 = (v.transpose() * v).to_scalar();
|
||||
/// ```
|
||||
///
|
||||
///```compile_fail
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let mut inner_product: f32 = (v * v.transpose()).to_scalar();
|
||||
///```
|
||||
pub fn to_scalar(&self) -> T
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.as_scalar().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> super::alias::Matrix1<T> {
|
||||
/// Convert this 1x1 matrix into a scalar.
|
||||
///
|
||||
/// As opposed to indexing, using this provides type-safety
|
||||
/// when flattening dimensions.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Matrix2, U1};
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let inner_product: f32 = (v.transpose() * v).into_scalar();
|
||||
/// assert_eq!(inner_product, 1.);
|
||||
/// ```
|
||||
///
|
||||
///```compile_fail
|
||||
/// # use nalgebra::Vector3;
|
||||
/// let v = Vector3::new(0., 0., 1.);
|
||||
/// let mut inner_product: f32 = (v * v.transpose()).into_scalar();
|
||||
///```
|
||||
pub fn into_scalar(self) -> T {
|
||||
let [[scalar]] = self.data.0;
|
||||
scalar
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
use rayon::iter::plumbing::Producer;
|
||||
use rayon::{iter::plumbing::bridge, prelude::*};
|
||||
|
||||
/// A rayon parallel iterator over the colums of a matrix. It is created
|
||||
/// A rayon parallel iterator over the columns of a matrix. It is created
|
||||
/// using the [`par_column_iter`] method of [`Matrix`].
|
||||
///
|
||||
/// *Only available if compiled with the feature `rayon`.*
|
||||
|
@ -89,7 +89,7 @@ pub struct ParColumnIterMut<
|
|||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))]
|
||||
/// *only availabe if compiled with the feature `rayon`*
|
||||
/// *only available if compiled with the feature `rayon`*
|
||||
impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S>
|
||||
where
|
||||
R: Dim,
|
||||
|
@ -161,7 +161,7 @@ where
|
|||
S: Sync,
|
||||
{
|
||||
/// Iterate through the columns of the matrix in parallel using rayon.
|
||||
/// This iterates over *immutable* references ot the columns of the matrix,
|
||||
/// This iterates over *immutable* references to the columns of the matrix,
|
||||
/// if *mutable* access to the columns is required, use [`par_column_iter_mut`]
|
||||
/// instead.
|
||||
///
|
||||
|
|
|
@ -335,12 +335,12 @@ impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
|||
if self.is_empty() {
|
||||
T::zero()
|
||||
} else {
|
||||
let val = self.iter().cloned().fold((T::zero(), T::zero()), |a, b| {
|
||||
(a.0 + b.clone() * b.clone(), a.1 + b)
|
||||
});
|
||||
let denom = T::one() / crate::convert::<_, T>(self.len() as f64);
|
||||
let vd = val.1 * denom.clone();
|
||||
val.0 * denom - vd.clone() * vd
|
||||
let n_elements: T = crate::convert(self.len() as f64);
|
||||
let mean = self.mean();
|
||||
|
||||
self.iter().cloned().fold(T::zero(), |acc, x| {
|
||||
acc + (x.clone() - mean.clone()) * (x.clone() - mean.clone())
|
||||
}) / n_elements
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ pub unsafe trait InitStatus<T>: Copy {
|
|||
/// A type implementing `InitStatus` indicating that the value is completely initialized.
|
||||
pub struct Init;
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
/// A type implementing `InitStatus` indicating that the value is completely unitialized.
|
||||
/// A type implementing `InitStatus` indicating that the value is completely uninitialized.
|
||||
pub struct Uninit;
|
||||
|
||||
unsafe impl<T> InitStatus<T> for Init {
|
||||
|
|
|
@ -9,6 +9,9 @@ use crate::base::DefaultAllocator;
|
|||
use crate::storage::RawStorage;
|
||||
use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
||||
///
|
||||
/// **It is likely that the only piece of documentation that you need in this page are:**
|
||||
|
|
|
@ -148,7 +148,7 @@ impl<T, R: Dim, C: Dim> VecStorage<T, R, C> {
|
|||
};
|
||||
|
||||
// Avoid double-free by forgetting `self` because its data buffer has
|
||||
// been transfered to `new_data`.
|
||||
// been transferred to `new_data`.
|
||||
std::mem::forget(self);
|
||||
new_data
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// The macros break if the references are taken out, for some reason.
|
||||
#![allow(clippy::op_ref)]
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
use crate::{
|
||||
Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3,
|
||||
Unit, UnitQuaternion, Vector3, Zero, U8,
|
||||
|
|
|
@ -14,6 +14,9 @@ use crate::base::storage::Owned;
|
|||
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit};
|
||||
use crate::geometry::{AbstractRotation, Point, Translation};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A direct isometry, i.e., a rotation followed by a translation (aka. a rigid-body motion).
|
||||
///
|
||||
/// This is also known as an element of a Special Euclidean (SE) group.
|
||||
|
|
|
@ -42,7 +42,7 @@ impl<T: SimdRealField> Isometry3<T> {
|
|||
/// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined).
|
||||
///
|
||||
/// # Examples:
|
||||
|
@ -118,7 +118,7 @@ impl<T: SimdRealField> IsometryMatrix3<T> {
|
|||
/// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined).
|
||||
///
|
||||
/// # Examples:
|
||||
|
|
|
@ -17,6 +17,9 @@ use crate::base::{Matrix4, Vector, Vector3};
|
|||
|
||||
use crate::geometry::{Point3, Projective3};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(
|
||||
|
|
|
@ -18,6 +18,9 @@ use crate::base::{Matrix4, Vector, Vector3};
|
|||
|
||||
use crate::geometry::{Point3, Projective3};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A 3D perspective projection stored as a homogeneous 4x4 matrix.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||
use num::One;
|
||||
use num::{One, Zero};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::hash;
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
|
@ -13,6 +15,7 @@ use crate::base::allocator::Allocator;
|
|||
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
|
||||
use crate::base::iter::{MatrixIter, MatrixIterMut};
|
||||
use crate::base::{Const, DefaultAllocator, OVector, Scalar};
|
||||
use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub};
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
/// A point in an euclidean space.
|
||||
|
@ -221,6 +224,31 @@ where
|
|||
unsafe { res.assume_init() }
|
||||
}
|
||||
|
||||
/// Linear interpolation between two points.
|
||||
///
|
||||
/// Returns `self * (1.0 - t) + rhs.coords * t`, i.e., the linear blend of the points
|
||||
/// `self` and `rhs` using the scalar value `t`.
|
||||
///
|
||||
/// The value for a is not restricted to the range `[0, 1]`.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::Point3;
|
||||
/// let a = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let b = Point3::new(10.0, 20.0, 30.0);
|
||||
/// assert_eq!(a.lerp(&b, 0.1), Point3::new(1.9, 3.8, 5.7));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn lerp(&self, rhs: &OPoint<T, D>, t: T) -> OPoint<T, D>
|
||||
where
|
||||
T: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul,
|
||||
{
|
||||
OPoint {
|
||||
coords: self.coords.lerp(&rhs.coords, t),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new point with the given coordinates.
|
||||
#[deprecated(note = "Use Point::from(vector) instead.")]
|
||||
#[inline]
|
||||
|
|
|
@ -19,6 +19,9 @@ use crate::base::{
|
|||
|
||||
use crate::geometry::{Point3, Rotation};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
|
||||
/// that may be used as a rotation.
|
||||
#[repr(C)]
|
||||
|
@ -1577,7 +1580,7 @@ where
|
|||
#[inline]
|
||||
#[must_use]
|
||||
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 performance-wise not to call inverse explicitly (i-e. implement
|
||||
// the inverse transformation explicitly here) ?
|
||||
self.inverse() * pt
|
||||
}
|
||||
|
|
|
@ -17,6 +17,9 @@ use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
|||
use crate::base::{Const, DefaultAllocator, OMatrix, SMatrix, SVector, Scalar, Unit};
|
||||
use crate::geometry::Point;
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A rotation matrix.
|
||||
///
|
||||
/// This is also known as an element of a Special Orthogonal (SO) group.
|
||||
|
|
|
@ -478,9 +478,10 @@ where
|
|||
SB: Storage<T, U3>,
|
||||
SC: Storage<T, U3>,
|
||||
{
|
||||
// Gram–Schmidt process
|
||||
let zaxis = dir.normalize();
|
||||
let xaxis = up.cross(&zaxis).normalize();
|
||||
let yaxis = zaxis.cross(&xaxis).normalize();
|
||||
let yaxis = zaxis.cross(&xaxis);
|
||||
|
||||
Self::from_matrix_unchecked(SMatrix::<T, 3, 3>::new(
|
||||
xaxis.x.clone(),
|
||||
|
@ -979,6 +980,176 @@ impl<T: SimdRealField> Rotation3<T> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represent this rotation as Euler angles.
|
||||
///
|
||||
/// Returns the angles produced in the order provided by seq parameter, along with the
|
||||
/// observability flag. The Euler axes passed to seq must form an orthonormal basis. If the
|
||||
/// rotation is gimbal locked, then the observability flag is false.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the Euler axes in `seq` are not orthonormal.
|
||||
///
|
||||
/// # Example 1:
|
||||
/// ```
|
||||
/// use std::f64::consts::PI;
|
||||
/// use approx::assert_relative_eq;
|
||||
/// use nalgebra::{Matrix3, Rotation3, Unit, Vector3};
|
||||
///
|
||||
/// // 3-1-2
|
||||
/// let n = [
|
||||
/// Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)),
|
||||
/// Unit::new_unchecked(Vector3::new(1.0, 0.0, 0.0)),
|
||||
/// Unit::new_unchecked(Vector3::new(0.0, 1.0, 0.0)),
|
||||
/// ];
|
||||
///
|
||||
/// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0);
|
||||
/// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0);
|
||||
/// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0);
|
||||
///
|
||||
/// let d = r3 * r2 * r1;
|
||||
///
|
||||
/// let (angles, observable) = d.euler_angles_ordered(n, false);
|
||||
/// assert!(observable);
|
||||
/// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12);
|
||||
/// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12);
|
||||
/// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12);
|
||||
/// ```
|
||||
///
|
||||
/// # Example 2:
|
||||
/// ```
|
||||
/// use std::f64::consts::PI;
|
||||
/// use approx::assert_relative_eq;
|
||||
/// use nalgebra::{Matrix3, Rotation3, Unit, Vector3};
|
||||
///
|
||||
/// let sqrt_2 = 2.0_f64.sqrt();
|
||||
/// let n = [
|
||||
/// Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, 1.0 / sqrt_2, 0.0)),
|
||||
/// Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, -1.0 / sqrt_2, 0.0)),
|
||||
/// Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)),
|
||||
/// ];
|
||||
///
|
||||
/// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0);
|
||||
/// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0);
|
||||
/// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0);
|
||||
///
|
||||
/// let d = r3 * r2 * r1;
|
||||
///
|
||||
/// let (angles, observable) = d.euler_angles_ordered(n, false);
|
||||
/// assert!(observable);
|
||||
/// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12);
|
||||
/// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12);
|
||||
/// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12);
|
||||
/// ```
|
||||
///
|
||||
/// Algorithm based on:
|
||||
/// Malcolm D. Shuster, F. Landis Markley, “General formula for extraction the Euler
|
||||
/// angles”, Journal of guidance, control, and dynamics, vol. 29.1, pp. 215-221. 2006,
|
||||
/// and modified to be able to produce extrinsic rotations.
|
||||
#[must_use]
|
||||
pub fn euler_angles_ordered(
|
||||
&self,
|
||||
mut seq: [Unit<Vector3<T>>; 3],
|
||||
extrinsic: bool,
|
||||
) -> ([T; 3], bool)
|
||||
where
|
||||
T: RealField + Copy,
|
||||
{
|
||||
let mut angles = [T::zero(); 3];
|
||||
let eps = T::from_subset(&1e-7);
|
||||
let _2 = T::from_subset(&2.0);
|
||||
|
||||
if extrinsic {
|
||||
seq.reverse();
|
||||
}
|
||||
|
||||
let [n1, n2, n3] = &seq;
|
||||
assert_relative_eq!(n1.dot(n2), T::zero(), epsilon = eps);
|
||||
assert_relative_eq!(n3.dot(n1), T::zero(), epsilon = eps);
|
||||
|
||||
let n1_c_n2 = n1.cross(n2);
|
||||
let s1 = n1_c_n2.dot(n3);
|
||||
let c1 = n1.dot(n3);
|
||||
let lambda = s1.atan2(c1);
|
||||
|
||||
let mut c = Matrix3::zeros();
|
||||
c.column_mut(0).copy_from(n2);
|
||||
c.column_mut(1).copy_from(&n1_c_n2);
|
||||
c.column_mut(2).copy_from(n1);
|
||||
c.transpose_mut();
|
||||
|
||||
let r1l = Matrix3::new(
|
||||
T::one(),
|
||||
T::zero(),
|
||||
T::zero(),
|
||||
T::zero(),
|
||||
c1,
|
||||
s1,
|
||||
T::zero(),
|
||||
-s1,
|
||||
c1,
|
||||
);
|
||||
let o_t = &c * self.matrix() * (c.transpose() * r1l);
|
||||
angles[1] = o_t.m33.acos();
|
||||
|
||||
let safe1 = angles[1].abs() >= eps;
|
||||
let safe2 = (angles[1] - T::pi()).abs() >= eps;
|
||||
let observable = safe1 && safe2;
|
||||
angles[1] += lambda;
|
||||
|
||||
if observable {
|
||||
angles[0] = o_t.m13.atan2(-o_t.m23);
|
||||
angles[2] = o_t.m31.atan2(o_t.m32);
|
||||
} else {
|
||||
// gimbal lock detected
|
||||
if extrinsic {
|
||||
// angle1 is initialized to zero
|
||||
if !safe1 {
|
||||
angles[2] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22);
|
||||
} else {
|
||||
angles[2] = -(o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22);
|
||||
};
|
||||
} else {
|
||||
// angle3 is initialized to zero
|
||||
if !safe1 {
|
||||
angles[0] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22);
|
||||
} else {
|
||||
angles[0] = (o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
let adjust = if seq[0] == seq[2] {
|
||||
// lambda = 0, so ensure angle2 -> [0, pi]
|
||||
angles[1] < T::zero() || angles[1] > T::pi()
|
||||
} else {
|
||||
// lamda = + or - pi/2, so ensure angle2 -> [-pi/2, pi/2]
|
||||
angles[1] < -T::frac_pi_2() || angles[1] > T::frac_pi_2()
|
||||
};
|
||||
|
||||
// dont adjust gimbal locked rotation
|
||||
if adjust && observable {
|
||||
angles[0] += T::pi();
|
||||
angles[1] = _2 * lambda - angles[1];
|
||||
angles[2] -= T::pi();
|
||||
}
|
||||
|
||||
// ensure all angles are within [-pi, pi]
|
||||
for angle in angles.as_mut_slice().iter_mut() {
|
||||
if *angle < -T::pi() {
|
||||
*angle += T::two_pi();
|
||||
} else if *angle > T::pi() {
|
||||
*angle -= T::two_pi();
|
||||
}
|
||||
}
|
||||
|
||||
if extrinsic {
|
||||
angles.reverse();
|
||||
}
|
||||
|
||||
(angles, observable)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand-no-std")]
|
||||
|
|
|
@ -15,6 +15,9 @@ use crate::ClosedMul;
|
|||
|
||||
use crate::geometry::Point;
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A scale which supports non-uniform scaling.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(
|
||||
|
|
|
@ -15,6 +15,9 @@ use crate::base::storage::Owned;
|
|||
use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
||||
use crate::geometry::{AbstractRotation, Isometry, Point, Translation};
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
|
|
@ -122,7 +122,7 @@ macro_rules! category_mul_impl(
|
|||
)*}
|
||||
);
|
||||
|
||||
// We require stability uppon multiplication.
|
||||
// We require stability upon multiplication.
|
||||
impl<T: TCategory> TCategoryMul<T> for T {
|
||||
type Representative = T;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
|
|||
|
||||
use crate::geometry::Point;
|
||||
|
||||
#[cfg(feature = "rkyv-serialize")]
|
||||
use rkyv::bytecheck;
|
||||
|
||||
/// A translation.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(
|
||||
|
|
|
@ -347,7 +347,7 @@ where
|
|||
#[inline]
|
||||
#[must_use]
|
||||
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 performance-wise not to call inverse explicitly (i-e. implement
|
||||
// the inverse transformation explicitly here) ?
|
||||
self.inverse() * pt
|
||||
}
|
||||
|
|
|
@ -47,11 +47,11 @@ impl<T: RealField, D1: Dim, S1: Storage<T, D1>> Vector<T, D1, S1> {
|
|||
let u_f = cmp::min(i, vec - 1);
|
||||
|
||||
if u_i == u_f {
|
||||
conv[i] += self[u_i].clone() * kernel[(i - u_i)].clone();
|
||||
conv[i] += self[u_i].clone() * kernel[i - u_i].clone();
|
||||
} else {
|
||||
for u in u_i..(u_f + 1) {
|
||||
if i - u < ker {
|
||||
conv[i] += self[u].clone() * kernel[(i - u)].clone();
|
||||
conv[i] += self[u].clone() * kernel[i - u].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -724,7 +724,7 @@ where
|
|||
|
||||
/// Sort the estimated components of the SVD by its singular values in descending order.
|
||||
/// Such an ordering is often implicitly required when the decompositions are used for estimation or fitting purposes.
|
||||
/// Using this function is only required if `new_unordered` or `try_new_unorderd` were used and the specific sorting is required afterward.
|
||||
/// Using this function is only required if `new_unordered` or `try_new_unordered` were used and the specific sorting is required afterward.
|
||||
pub fn sort_by_singular_values(&mut self) {
|
||||
const VALUE_PROCESSED: usize = usize::MAX;
|
||||
|
||||
|
|
|
@ -498,7 +498,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Remove dupliate entries on a sorted CsMatrix.
|
||||
// Remove duplicate entries on a sorted CsMatrix.
|
||||
pub(crate) fn dedup(&mut self)
|
||||
where
|
||||
T: Zero + ClosedAdd,
|
||||
|
|
|
@ -16,3 +16,9 @@ mod v020;
|
|||
mod v021;
|
||||
#[cfg(feature = "glam022")]
|
||||
mod v022;
|
||||
#[cfg(feature = "glam023")]
|
||||
mod v023;
|
||||
#[cfg(feature = "glam024")]
|
||||
mod v024;
|
||||
#[cfg(feature = "glam025")]
|
||||
mod v025;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#[path = "../common/glam_isometry.rs"]
|
||||
mod glam_isometry;
|
||||
#[path = "../common/glam_matrix.rs"]
|
||||
mod glam_matrix;
|
||||
#[path = "../common/glam_point.rs"]
|
||||
mod glam_point;
|
||||
#[path = "../common/glam_quaternion.rs"]
|
||||
mod glam_quaternion;
|
||||
#[path = "../common/glam_rotation.rs"]
|
||||
mod glam_rotation;
|
||||
#[path = "../common/glam_similarity.rs"]
|
||||
mod glam_similarity;
|
||||
#[path = "../common/glam_translation.rs"]
|
||||
mod glam_translation;
|
||||
#[path = "../common/glam_unit_complex.rs"]
|
||||
mod glam_unit_complex;
|
||||
|
||||
pub(self) use glam023 as glam;
|
|
@ -0,0 +1,18 @@
|
|||
#[path = "../common/glam_isometry.rs"]
|
||||
mod glam_isometry;
|
||||
#[path = "../common/glam_matrix.rs"]
|
||||
mod glam_matrix;
|
||||
#[path = "../common/glam_point.rs"]
|
||||
mod glam_point;
|
||||
#[path = "../common/glam_quaternion.rs"]
|
||||
mod glam_quaternion;
|
||||
#[path = "../common/glam_rotation.rs"]
|
||||
mod glam_rotation;
|
||||
#[path = "../common/glam_similarity.rs"]
|
||||
mod glam_similarity;
|
||||
#[path = "../common/glam_translation.rs"]
|
||||
mod glam_translation;
|
||||
#[path = "../common/glam_unit_complex.rs"]
|
||||
mod glam_unit_complex;
|
||||
|
||||
pub(self) use glam024 as glam;
|
|
@ -0,0 +1,18 @@
|
|||
#[path = "../common/glam_isometry.rs"]
|
||||
mod glam_isometry;
|
||||
#[path = "../common/glam_matrix.rs"]
|
||||
mod glam_matrix;
|
||||
#[path = "../common/glam_point.rs"]
|
||||
mod glam_point;
|
||||
#[path = "../common/glam_quaternion.rs"]
|
||||
mod glam_quaternion;
|
||||
#[path = "../common/glam_rotation.rs"]
|
||||
mod glam_rotation;
|
||||
#[path = "../common/glam_similarity.rs"]
|
||||
mod glam_similarity;
|
||||
#[path = "../common/glam_translation.rs"]
|
||||
mod glam_translation;
|
||||
#[path = "../common/glam_unit_complex.rs"]
|
||||
mod glam_unit_complex;
|
||||
|
||||
pub(self) use glam025 as glam;
|
|
@ -11,6 +11,7 @@ mod reshape;
|
|||
#[cfg(feature = "rkyv-serialize-no-std")]
|
||||
mod rkyv;
|
||||
mod serde;
|
||||
mod variance;
|
||||
|
||||
#[cfg(feature = "compare")]
|
||||
mod matrixcompare;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
use nalgebra::DVector;
|
||||
|
||||
#[test]
|
||||
fn test_variance_catastrophic_cancellation() {
|
||||
let long_repeating_vector = DVector::repeat(10_000, 100000000.0);
|
||||
assert_eq!(long_repeating_vector.variance(), 0.0);
|
||||
|
||||
let short_vec = DVector::from_vec(vec![1., 2., 3.]);
|
||||
assert_eq!(short_vec.variance(), 2.0 / 3.0);
|
||||
|
||||
let short_vec =
|
||||
DVector::<f64>::from_vec(vec![1.0e8 + 4.0, 1.0e8 + 7.0, 1.0e8 + 13.0, 1.0e8 + 16.0]);
|
||||
assert_eq!(short_vec.variance(), 22.5);
|
||||
|
||||
let short_vec =
|
||||
DVector::<f64>::from_vec(vec![1.0e9 + 4.0, 1.0e9 + 7.0, 1.0e9 + 13.0, 1.0e9 + 16.0]);
|
||||
assert_eq!(short_vec.variance(), 22.5);
|
||||
}
|
|
@ -123,7 +123,7 @@ fn symmetric_eigen_singular_24x24() {
|
|||
//
|
||||
// /*
|
||||
// * NOTE: for the following tests, we use only upper-triangular matrices.
|
||||
// * Thes ensures the schur decomposition will work, and allows use to test the eigenvector
|
||||
// * This ensures the schur decomposition will work, and allows use to test the eigenvector
|
||||
// * computation.
|
||||
// */
|
||||
// fn eigen(n: usize) -> bool {
|
||||
|
@ -134,11 +134,11 @@ fn symmetric_eigen_singular_24x24() {
|
|||
// verify_eigenvectors(m, eig)
|
||||
// }
|
||||
//
|
||||
// fn eigen_with_adjascent_duplicate_diagonals(n: usize) -> bool {
|
||||
// fn eigen_with_adjacent_duplicate_diagonals(n: usize) -> bool {
|
||||
// let n = cmp::max(1, cmp::min(n, 10));
|
||||
// let mut m = DMatrix::<f64>::new_random(n, n).upper_triangle();
|
||||
//
|
||||
// // Suplicate some adjascent diagonal elements.
|
||||
// // Suplicate some adjacent diagonal elements.
|
||||
// for i in 0 .. n / 2 {
|
||||
// m[(i * 2 + 1, i * 2 + 1)] = m[(i * 2, i * 2)];
|
||||
// }
|
||||
|
@ -147,7 +147,7 @@ fn symmetric_eigen_singular_24x24() {
|
|||
// verify_eigenvectors(m, eig)
|
||||
// }
|
||||
//
|
||||
// fn eigen_with_nonadjascent_duplicate_diagonals(n: usize) -> bool {
|
||||
// fn eigen_with_nonadjacent_duplicate_diagonals(n: usize) -> bool {
|
||||
// let n = cmp::max(3, cmp::min(n, 10));
|
||||
// let mut m = DMatrix::<f64>::new_random(n, n).upper_triangle();
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue