commit
3e2ab0119e
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -4,10 +4,25 @@ documented here.
|
||||||
|
|
||||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||||
|
|
||||||
|
## [0.24.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* 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,
|
||||||
|
and normalization.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* There is no blanket `impl<T> PartialEq for Unit<T>` any more. Instead, it is
|
||||||
|
implemented specifically for `UnitComplex`, `UnitQuaternion` and `Unit<Vector>`.
|
||||||
|
|
||||||
## [0.23.2]
|
## [0.23.2]
|
||||||
In this release, we improved the documentation of some of the geometric types
|
In this release, we improved the documentation of some of the geometric types
|
||||||
by applying changes similar to what we did in the version 0.23.1 for matrices.
|
by applying changes similar to what we did in the version 0.23.1 for matrices.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* The `Isometry::inv_mul` method which is a more efficient way of doing
|
||||||
|
`isometry1.inverse() * isometry2`.
|
||||||
|
|
||||||
## [0.23.1]
|
## [0.23.1]
|
||||||
In this release we improved the documentation of the matrix and vector types by:
|
In this release we improved the documentation of the matrix and vector types by:
|
||||||
- Grouping `impl` bocks logically, adding a title comment to these impl blocks.
|
- Grouping `impl` bocks logically, adding a title comment to these impl blocks.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nalgebra"
|
name = "nalgebra"
|
||||||
version = "0.23.2"
|
version = "0.24.0"
|
||||||
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
|
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
|
||||||
|
|
||||||
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
|
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nalgebra-glm"
|
name = "nalgebra-glm"
|
||||||
version = "0.9.0"
|
version = "0.10.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."
|
||||||
|
@ -25,4 +25,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.4", default-features = false }
|
approx = { version = "0.4", default-features = false }
|
||||||
simba = { version = "0.3", default-features = false }
|
simba = { version = "0.3", default-features = false }
|
||||||
nalgebra = { path = "..", version = "0.23", default-features = false }
|
nalgebra = { path = "..", version = "0.24", default-features = false }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nalgebra-lapack"
|
name = "nalgebra-lapack"
|
||||||
version = "0.14.0"
|
version = "0.15.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 = "Linear algebra library with transformations and satically-sized or dynamically-sized matrices."
|
description = "Linear algebra library with transformations and satically-sized or dynamically-sized matrices."
|
||||||
|
@ -23,7 +23,7 @@ accelerate = ["lapack-src/accelerate"]
|
||||||
intel-mkl = ["lapack-src/intel-mkl"]
|
intel-mkl = ["lapack-src/intel-mkl"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version = "0.22" } # , path = ".." }
|
nalgebra = { version = "0.24", path = ".." }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-complex = { version = "0.2", default-features = false }
|
num-complex = { version = "0.2", default-features = false }
|
||||||
simba = "0.2"
|
simba = "0.2"
|
||||||
|
@ -34,7 +34,7 @@ lapack-src = { version = "0.5", default-features = false }
|
||||||
# clippy = "*"
|
# clippy = "*"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nalgebra = { version = "0.22", features = [ "arbitrary" ] } # path = ".." }
|
nalgebra = { version = "0.24", features = [ "arbitrary" ], path = ".." }
|
||||||
quickcheck = "0.9"
|
quickcheck = "0.9"
|
||||||
approx = "0.3"
|
approx = "0.3"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
|
|
|
@ -11,7 +11,8 @@ use abomonation::Abomonation;
|
||||||
|
|
||||||
use crate::allocator::Allocator;
|
use crate::allocator::Allocator;
|
||||||
use crate::base::DefaultAllocator;
|
use crate::base::DefaultAllocator;
|
||||||
use crate::{Dim, MatrixMN, RealField, Scalar, SimdComplexField, SimdRealField};
|
use crate::storage::Storage;
|
||||||
|
use crate::{Dim, Matrix, MatrixMN, RealField, Scalar, SimdComplexField, SimdRealField};
|
||||||
|
|
||||||
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
/// A wrapper that ensures the underlying algebraic entity has a unit norm.
|
||||||
///
|
///
|
||||||
|
@ -24,7 +25,7 @@ use crate::{Dim, MatrixMN, RealField, Scalar, SimdComplexField, SimdRealField};
|
||||||
/// and [`UnitQuaternion`](crate::UnitQuaternion); both built on top of `Unit`. If you are interested
|
/// and [`UnitQuaternion`](crate::UnitQuaternion); both built on top of `Unit`. If you are interested
|
||||||
/// in their documentation, read their dedicated pages directly.
|
/// in their documentation, read their dedicated pages directly.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)]
|
#[derive(Clone, Hash, Debug, Copy)]
|
||||||
pub struct Unit<T> {
|
pub struct Unit<T> {
|
||||||
pub(crate) value: T,
|
pub(crate) value: T,
|
||||||
}
|
}
|
||||||
|
@ -64,6 +65,28 @@ impl<T: Abomonation> Abomonation for Unit<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N, R, C, S> PartialEq for Unit<Matrix<N, R, C, S>>
|
||||||
|
where
|
||||||
|
N: Scalar + PartialEq,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: Storage<N, R, C>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
self.value.eq(&rhs.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N, R, C, S> Eq for Unit<Matrix<N, R, C, S>>
|
||||||
|
where
|
||||||
|
N: Scalar + Eq,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
S: Storage<N, R, C>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait implemented by entities scan be be normalized and put in an `Unit` struct.
|
/// Trait implemented by entities scan be be normalized and put in an `Unit` struct.
|
||||||
pub trait Normed {
|
pub trait Normed {
|
||||||
/// The type of the norm.
|
/// The type of the norm.
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
use crate::{Quaternion, SimdRealField};
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
/// A dual quaternion.
|
||||||
|
///
|
||||||
|
/// # Indexing
|
||||||
|
///
|
||||||
|
/// DualQuaternions are stored as \[..real, ..dual\].
|
||||||
|
/// Both of the quaternion components are laid out in `i, j, k, w` order.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{DualQuaternion, Quaternion};
|
||||||
|
///
|
||||||
|
/// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
|
/// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
|
||||||
|
///
|
||||||
|
/// let dq = DualQuaternion::from_real_and_dual(real, dual);
|
||||||
|
/// assert_eq!(dq[0], 2.0);
|
||||||
|
/// assert_eq!(dq[1], 3.0);
|
||||||
|
///
|
||||||
|
/// assert_eq!(dq[4], 6.0);
|
||||||
|
/// assert_eq!(dq[7], 5.0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// NOTE:
|
||||||
|
/// As of December 2020, dual quaternion support is a work in progress.
|
||||||
|
/// 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
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Eq, PartialEq, Copy, Clone)]
|
||||||
|
pub struct DualQuaternion<N: SimdRealField> {
|
||||||
|
/// The real component of the quaternion
|
||||||
|
pub real: Quaternion<N>,
|
||||||
|
/// The dual component of the quaternion
|
||||||
|
pub dual: Quaternion<N>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N::Element: SimdRealField,
|
||||||
|
{
|
||||||
|
/// Normalizes this quaternion.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # use nalgebra::{DualQuaternion, Quaternion};
|
||||||
|
/// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
|
/// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
|
||||||
|
/// let dq = DualQuaternion::from_real_and_dual(real, dual);
|
||||||
|
///
|
||||||
|
/// let dq_normalized = dq.normalize();
|
||||||
|
///
|
||||||
|
/// relative_eq!(dq_normalized.real.norm(), 1.0);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
#[must_use = "Did you mean to use normalize_mut()?"]
|
||||||
|
pub fn normalize(&self) -> Self {
|
||||||
|
let real_norm = self.real.norm();
|
||||||
|
|
||||||
|
Self::from_real_and_dual(self.real / real_norm, self.dual / real_norm)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Normalizes this quaternion.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # use nalgebra::{DualQuaternion, Quaternion};
|
||||||
|
/// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
|
/// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0);
|
||||||
|
/// let mut dq = DualQuaternion::from_real_and_dual(real, dual);
|
||||||
|
///
|
||||||
|
/// dq.normalize_mut();
|
||||||
|
///
|
||||||
|
/// relative_eq!(dq.real.norm(), 1.0);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn normalize_mut(&mut self) {
|
||||||
|
*self = self.normalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
impl<N: SimdRealField> Serialize for DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N: Serialize,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.as_ref().serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde-serialize")]
|
||||||
|
impl<'a, N: SimdRealField> Deserialize<'a> for DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N: Deserialize<'a>,
|
||||||
|
{
|
||||||
|
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||||
|
where
|
||||||
|
Des: Deserializer<'a>,
|
||||||
|
{
|
||||||
|
type Dq<N> = [N; 8];
|
||||||
|
|
||||||
|
let dq: Dq<N> = Dq::<N>::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
real: Quaternion::new(dq[3], dq[0], dq[1], dq[2]),
|
||||||
|
dual: Quaternion::new(dq[7], dq[4], dq[5], dq[6]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
use crate::{DualQuaternion, Quaternion, SimdRealField};
|
||||||
|
|
||||||
|
impl<N: SimdRealField> DualQuaternion<N> {
|
||||||
|
/// Creates a dual quaternion from its rotation and translation components.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{DualQuaternion, Quaternion};
|
||||||
|
/// let rot = Quaternion::new(1.0, 2.0, 3.0, 4.0);
|
||||||
|
/// let trans = Quaternion::new(5.0, 6.0, 7.0, 8.0);
|
||||||
|
///
|
||||||
|
/// let dq = DualQuaternion::from_real_and_dual(rot, trans);
|
||||||
|
/// assert_eq!(dq.real.w, 1.0);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn from_real_and_dual(real: Quaternion<N>, dual: Quaternion<N>) -> Self {
|
||||||
|
Self { real, dual }
|
||||||
|
}
|
||||||
|
/// The dual quaternion multiplicative identity
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{DualQuaternion, Quaternion};
|
||||||
|
///
|
||||||
|
/// let dq1 = DualQuaternion::identity();
|
||||||
|
/// let dq2 = DualQuaternion::from_real_and_dual(
|
||||||
|
/// Quaternion::new(1.,2.,3.,4.),
|
||||||
|
/// Quaternion::new(5.,6.,7.,8.)
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// assert_eq!(dq1 * dq2, dq2);
|
||||||
|
/// assert_eq!(dq2 * dq1, dq2);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn identity() -> Self {
|
||||||
|
Self::from_real_and_dual(
|
||||||
|
Quaternion::from_real(N::one()),
|
||||||
|
Quaternion::from_real(N::zero()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* This file provides:
|
||||||
|
*
|
||||||
|
* NOTE: Work in progress https://github.com/dimforge/nalgebra/issues/487
|
||||||
|
*
|
||||||
|
* (Dual Quaternion)
|
||||||
|
*
|
||||||
|
* Index<usize>
|
||||||
|
* IndexMut<usize>
|
||||||
|
*
|
||||||
|
* (Assignment Operators)
|
||||||
|
*
|
||||||
|
* DualQuaternion × Scalar
|
||||||
|
* DualQuaternion × DualQuaternion
|
||||||
|
* DualQuaternion + DualQuaternion
|
||||||
|
* DualQuaternion - DualQuaternion
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
* Multiplication:
|
||||||
|
* - https://cs.gmu.edu/~jmlien/teaching/cs451/uploads/Main/dual-quaternion.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{DualQuaternion, SimdRealField};
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{Add, Index, IndexMut, Mul, Sub};
|
||||||
|
|
||||||
|
impl<N: SimdRealField> AsRef<[N; 8]> for DualQuaternion<N> {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &[N; 8] {
|
||||||
|
unsafe { mem::transmute(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> AsMut<[N; 8]> for DualQuaternion<N> {
|
||||||
|
#[inline]
|
||||||
|
fn as_mut(&mut self) -> &mut [N; 8] {
|
||||||
|
unsafe { mem::transmute(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> Index<usize> for DualQuaternion<N> {
|
||||||
|
type Output = N;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, i: usize) -> &Self::Output {
|
||||||
|
&self.as_ref()[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> IndexMut<usize> for DualQuaternion<N> {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, i: usize) -> &mut N {
|
||||||
|
&mut self.as_mut()[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> Mul<DualQuaternion<N>> for DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N::Element: SimdRealField,
|
||||||
|
{
|
||||||
|
type Output = DualQuaternion<N>;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::from_real_and_dual(
|
||||||
|
self.real * rhs.real,
|
||||||
|
self.real * rhs.dual + self.dual * rhs.real,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> Mul<N> for DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N::Element: SimdRealField,
|
||||||
|
{
|
||||||
|
type Output = DualQuaternion<N>;
|
||||||
|
|
||||||
|
fn mul(self, rhs: N) -> Self::Output {
|
||||||
|
Self::from_real_and_dual(self.real * rhs, self.dual * rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> Add<DualQuaternion<N>> for DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N::Element: SimdRealField,
|
||||||
|
{
|
||||||
|
type Output = DualQuaternion<N>;
|
||||||
|
|
||||||
|
fn add(self, rhs: DualQuaternion<N>) -> Self::Output {
|
||||||
|
Self::from_real_and_dual(self.real + rhs.real, self.dual + rhs.dual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: SimdRealField> Sub<DualQuaternion<N>> for DualQuaternion<N>
|
||||||
|
where
|
||||||
|
N::Element: SimdRealField,
|
||||||
|
{
|
||||||
|
type Output = DualQuaternion<N>;
|
||||||
|
|
||||||
|
fn sub(self, rhs: DualQuaternion<N>) -> Self::Output {
|
||||||
|
Self::from_real_and_dual(self.real - rhs.real, self.dual - rhs.dual)
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,10 @@ mod quaternion_coordinates;
|
||||||
mod quaternion_ops;
|
mod quaternion_ops;
|
||||||
mod quaternion_simba;
|
mod quaternion_simba;
|
||||||
|
|
||||||
|
mod dual_quaternion;
|
||||||
|
mod dual_quaternion_construction;
|
||||||
|
mod dual_quaternion_ops;
|
||||||
|
|
||||||
mod unit_complex;
|
mod unit_complex;
|
||||||
#[cfg(feature = "alga")]
|
#[cfg(feature = "alga")]
|
||||||
mod unit_complex_alga;
|
mod unit_complex_alga;
|
||||||
|
@ -98,6 +102,8 @@ pub use self::rotation_alias::*;
|
||||||
|
|
||||||
pub use self::quaternion::*;
|
pub use self::quaternion::*;
|
||||||
|
|
||||||
|
pub use self::dual_quaternion::*;
|
||||||
|
|
||||||
pub use self::unit_complex::*;
|
pub use self::unit_complex::*;
|
||||||
|
|
||||||
pub use self::translation::*;
|
pub use self::translation::*;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash;
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use std::io::{Result as IOResult, Write};
|
use std::io::{Result as IOResult, Write};
|
||||||
|
|
||||||
|
@ -13,8 +12,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
use abomonation::Abomonation;
|
use abomonation::Abomonation;
|
||||||
|
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::{ClosedNeg, RealField};
|
||||||
use simba::simd::{SimdBool, SimdOption, SimdRealField, SimdValue};
|
use simba::simd::{SimdBool, SimdOption, SimdRealField};
|
||||||
|
|
||||||
use crate::base::dimension::{U1, U3, U4};
|
use crate::base::dimension::{U1, U3, U4};
|
||||||
use crate::base::storage::{CStride, RStride};
|
use crate::base::storage::{CStride, RStride};
|
||||||
|
@ -27,13 +26,13 @@ use crate::geometry::{Point3, Rotation};
|
||||||
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
|
/// A quaternion. See the type alias `UnitQuaternion = Unit<Quaternion>` for a quaternion
|
||||||
/// that may be used as a rotation.
|
/// that may be used as a rotation.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct Quaternion<N: Scalar + SimdValue> {
|
pub struct Quaternion<N: Scalar> {
|
||||||
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
|
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.
|
||||||
pub coords: Vector4<N>,
|
pub coords: Vector4<N>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: RealField> Default for Quaternion<N> {
|
impl<N: Scalar + Zero> Default for Quaternion<N> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Quaternion {
|
Quaternion {
|
||||||
coords: Vector4::zeros(),
|
coords: Vector4::zeros(),
|
||||||
|
@ -42,7 +41,7 @@ impl<N: RealField> Default for Quaternion<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<N: SimdRealField> Abomonation for Quaternion<N>
|
impl<N: Scalar> Abomonation for Quaternion<N>
|
||||||
where
|
where
|
||||||
Vector4<N>: Abomonation,
|
Vector4<N>: Abomonation,
|
||||||
{
|
{
|
||||||
|
@ -59,36 +58,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: SimdRealField + Eq> Eq for Quaternion<N> where N::Element: SimdRealField {}
|
|
||||||
|
|
||||||
impl<N: SimdRealField> PartialEq for Quaternion<N>
|
|
||||||
where
|
|
||||||
N::Element: SimdRealField,
|
|
||||||
{
|
|
||||||
fn eq(&self, rhs: &Self) -> bool {
|
|
||||||
self.coords == rhs.coords ||
|
|
||||||
// Account for the double-covering of S², i.e. q = -q
|
|
||||||
self.as_vector().iter().zip(rhs.as_vector().iter()).all(|(a, b)| *a == -*b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: SimdRealField + hash::Hash> hash::Hash for Quaternion<N> {
|
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.coords.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Scalar + Copy + SimdValue> Copy for Quaternion<N> {}
|
|
||||||
|
|
||||||
impl<N: Scalar + SimdValue> Clone for Quaternion<N> {
|
|
||||||
#[inline]
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self::from(self.coords.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
impl<N: SimdRealField> Serialize for Quaternion<N>
|
impl<N: Scalar> Serialize for Quaternion<N>
|
||||||
where
|
where
|
||||||
Owned<N, U4>: Serialize,
|
Owned<N, U4>: Serialize,
|
||||||
{
|
{
|
||||||
|
@ -101,7 +72,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde-serialize")]
|
#[cfg(feature = "serde-serialize")]
|
||||||
impl<'a, N: SimdRealField> Deserialize<'a> for Quaternion<N>
|
impl<'a, N: Scalar> Deserialize<'a> for Quaternion<N>
|
||||||
where
|
where
|
||||||
Owned<N, U4>: Deserialize<'a>,
|
Owned<N, U4>: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
|
@ -980,6 +951,17 @@ impl<N: RealField + fmt::Display> fmt::Display for Quaternion<N> {
|
||||||
/// A unit quaternions. May be used to represent a rotation.
|
/// A unit quaternions. May be used to represent a rotation.
|
||||||
pub type UnitQuaternion<N> = Unit<Quaternion<N>>;
|
pub type UnitQuaternion<N> = Unit<Quaternion<N>>;
|
||||||
|
|
||||||
|
impl<N: Scalar + ClosedNeg + PartialEq> PartialEq for UnitQuaternion<N> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
self.coords == rhs.coords ||
|
||||||
|
// Account for the double-covering of S², i.e. q = -q
|
||||||
|
self.coords.iter().zip(rhs.coords.iter()).all(|(a, b)| *a == -b.inlined_clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Scalar + ClosedNeg + Eq> Eq for UnitQuaternion<N> {}
|
||||||
|
|
||||||
impl<N: SimdRealField> Normed for Quaternion<N> {
|
impl<N: SimdRealField> Normed for Quaternion<N> {
|
||||||
type Norm = N::SimdRealField;
|
type Norm = N::SimdRealField;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rand::distributions::{Distribution, OpenClosed01, Standard};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::RealField;
|
||||||
use simba::simd::{SimdBool, SimdValue};
|
use simba::simd::SimdBool;
|
||||||
|
|
||||||
use crate::base::dimension::U3;
|
use crate::base::dimension::U3;
|
||||||
use crate::base::storage::Storage;
|
use crate::base::storage::Storage;
|
||||||
|
@ -19,7 +19,7 @@ use crate::{Scalar, SimdRealField};
|
||||||
|
|
||||||
use crate::geometry::{Quaternion, Rotation3, UnitQuaternion};
|
use crate::geometry::{Quaternion, Rotation3, UnitQuaternion};
|
||||||
|
|
||||||
impl<N: Scalar + SimdValue> Quaternion<N> {
|
impl<N: Scalar> Quaternion<N> {
|
||||||
/// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w`
|
/// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w`
|
||||||
/// vector component.
|
/// vector component.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -184,36 +184,36 @@ impl<N1: RealField, N2: RealField + SupersetOf<N1>> SubsetOf<Matrix4<N2>> for Un
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
impl<N: SimdRealField> From<mint::Quaternion<N>> for Quaternion<N> {
|
impl<N: Scalar> From<mint::Quaternion<N>> for Quaternion<N> {
|
||||||
fn from(q: mint::Quaternion<N>) -> Self {
|
fn from(q: mint::Quaternion<N>) -> Self {
|
||||||
Self::new(q.s, q.v.x, q.v.y, q.v.z)
|
Self::new(q.s, q.v.x, q.v.y, q.v.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
impl<N: SimdRealField> Into<mint::Quaternion<N>> for Quaternion<N> {
|
impl<N: Scalar> Into<mint::Quaternion<N>> for Quaternion<N> {
|
||||||
fn into(self) -> mint::Quaternion<N> {
|
fn into(self) -> mint::Quaternion<N> {
|
||||||
mint::Quaternion {
|
mint::Quaternion {
|
||||||
v: mint::Vector3 {
|
v: mint::Vector3 {
|
||||||
x: self[0],
|
x: self[0].inlined_clone(),
|
||||||
y: self[1],
|
y: self[1].inlined_clone(),
|
||||||
z: self[2],
|
z: self[2].inlined_clone(),
|
||||||
},
|
},
|
||||||
s: self[3],
|
s: self[3].inlined_clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mint")]
|
#[cfg(feature = "mint")]
|
||||||
impl<N: SimdRealField> Into<mint::Quaternion<N>> for UnitQuaternion<N> {
|
impl<N: Scalar + SimdValue> Into<mint::Quaternion<N>> for UnitQuaternion<N> {
|
||||||
fn into(self) -> mint::Quaternion<N> {
|
fn into(self) -> mint::Quaternion<N> {
|
||||||
mint::Quaternion {
|
mint::Quaternion {
|
||||||
v: mint::Vector3 {
|
v: mint::Vector3 {
|
||||||
x: self[0],
|
x: self[0].inlined_clone(),
|
||||||
y: self[1],
|
y: self[1].inlined_clone(),
|
||||||
z: self[2],
|
z: self[2].inlined_clone(),
|
||||||
},
|
},
|
||||||
s: self[3],
|
s: self[3].inlined_clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,14 +258,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar + SimdValue> From<Vector4<N>> for Quaternion<N> {
|
impl<N: Scalar> From<Vector4<N>> for Quaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: Vector4<N>) -> Self {
|
fn from(coords: Vector4<N>) -> Self {
|
||||||
Self { coords }
|
Self { coords }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Scalar + SimdValue> From<[N; 4]> for Quaternion<N> {
|
impl<N: Scalar> From<[N; 4]> for Quaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(coords: [N; 4]) -> Self {
|
fn from(coords: [N; 4]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -57,12 +57,12 @@ use std::ops::{
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::dimension::{U1, U3, U4};
|
use crate::base::dimension::{U1, U3, U4};
|
||||||
use crate::base::storage::Storage;
|
use crate::base::storage::Storage;
|
||||||
use crate::base::{DefaultAllocator, Unit, Vector, Vector3};
|
use crate::base::{DefaultAllocator, Scalar, Unit, Vector, Vector3};
|
||||||
use crate::SimdRealField;
|
use crate::SimdRealField;
|
||||||
|
|
||||||
use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion};
|
use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion};
|
||||||
|
|
||||||
impl<N: SimdRealField> Index<usize> for Quaternion<N> {
|
impl<N: Scalar> Index<usize> for Quaternion<N> {
|
||||||
type Output = N;
|
type Output = N;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -71,7 +71,7 @@ impl<N: SimdRealField> Index<usize> for Quaternion<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: SimdRealField> IndexMut<usize> for Quaternion<N> {
|
impl<N: Scalar> IndexMut<usize> for Quaternion<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, i: usize) -> &mut N {
|
fn index_mut(&mut self, i: usize) -> &mut N {
|
||||||
&mut self.coords[i]
|
&mut self.coords[i]
|
||||||
|
|
|
@ -4,8 +4,10 @@ use std::fmt;
|
||||||
|
|
||||||
use crate::base::{Matrix2, Matrix3, Normed, Unit, Vector1, Vector2};
|
use crate::base::{Matrix2, Matrix3, Normed, Unit, Vector1, Vector2};
|
||||||
use crate::geometry::{Point2, Rotation2};
|
use crate::geometry::{Point2, Rotation2};
|
||||||
|
use crate::Scalar;
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::RealField;
|
||||||
use simba::simd::SimdRealField;
|
use simba::simd::SimdRealField;
|
||||||
|
use std::cmp::{Eq, PartialEq};
|
||||||
|
|
||||||
/// A 2D rotation represented as a complex number with magnitude 1.
|
/// A 2D rotation represented as a complex number with magnitude 1.
|
||||||
///
|
///
|
||||||
|
@ -29,6 +31,15 @@ use simba::simd::SimdRealField;
|
||||||
/// * [Conversion to a matrix <span style="float:right;">`to_rotation_matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
|
/// * [Conversion to a matrix <span style="float:right;">`to_rotation_matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
|
||||||
pub type UnitComplex<N> = Unit<Complex<N>>;
|
pub type UnitComplex<N> = Unit<Complex<N>>;
|
||||||
|
|
||||||
|
impl<N: Scalar + PartialEq> PartialEq for UnitComplex<N> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
(**self).eq(&**rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Scalar + Eq> Eq for UnitComplex<N> {}
|
||||||
|
|
||||||
impl<N: SimdRealField> Normed for Complex<N> {
|
impl<N: SimdRealField> Normed for Complex<N> {
|
||||||
type Norm = N::SimdRealField;
|
type Norm = N::SimdRealField;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,15 @@
|
||||||
//! The tests here only check that the necessary trait implementations are correctly implemented,
|
//! The tests here only check that the necessary trait implementations are correctly implemented,
|
||||||
//! in addition to some sanity checks with example input.
|
//! in addition to some sanity checks with example input.
|
||||||
|
|
||||||
use nalgebra::{DMatrix, MatrixMN, U4, U5};
|
use nalgebra::{MatrixMN, U4, U5};
|
||||||
|
|
||||||
use matrixcompare::{assert_matrix_eq, DenseAccess};
|
#[cfg(feature = "arbitrary")]
|
||||||
|
use nalgebra::DMatrix;
|
||||||
|
|
||||||
|
use matrixcompare::assert_matrix_eq;
|
||||||
|
|
||||||
|
#[cfg(feature = "arbitrary")]
|
||||||
|
use matrixcompare::DenseAccess;
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
|
|
|
@ -114,7 +114,6 @@ quickcheck!(
|
||||||
*/
|
*/
|
||||||
fn unit_quaternion_double_covering(q: UnitQuaternion<f64>) -> bool {
|
fn unit_quaternion_double_covering(q: UnitQuaternion<f64>) -> bool {
|
||||||
let mq = UnitQuaternion::new_unchecked(-q.into_inner());
|
let mq = UnitQuaternion::new_unchecked(-q.into_inner());
|
||||||
|
|
||||||
mq == q && mq.angle() == q.angle() && mq.axis() == q.axis()
|
mq == q && mq.angle() == q.angle() && mq.axis() == q.axis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue