Merge pull request #819 from dimforge/dev

Release v0.24.0
This commit is contained in:
Sébastien Crozet 2020-12-30 15:23:53 +01:00 committed by GitHub
commit 3e2ab0119e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 370 additions and 66 deletions

View File

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

View File

@ -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."

View File

@ -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 }

View File

@ -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"

View File

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

View File

@ -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]),
})
}
}

View File

@ -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()),
)
}
}

View File

@ -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)
}
}

View File

@ -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::*;

View File

@ -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;

View File

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

View File

@ -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 {

View File

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

View File

@ -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;

View File

@ -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! {

View File

@ -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()
} }