From f74b8401ad9ef50b8cdbf1f43a2b21f6c42b0ebc Mon Sep 17 00:00:00 2001 From: Sébastien Crozet Date: Sun, 2 Jan 2022 14:47:40 +0100 Subject: Implement multibody joints and the new solver --- src/utils.rs | 226 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 135 insertions(+), 91 deletions(-) (limited to 'src/utils.rs') diff --git a/src/utils.rs b/src/utils.rs index 7f0cf46..9aa4bf2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,9 @@ //! Miscellaneous utilities. -use na::{Matrix3, Point2, Point3, Scalar, SimdRealField, Vector2, Vector3}; +use na::{ + Matrix1, Matrix2, Matrix3, Point2, Point3, RowVector2, Scalar, SimdRealField, UnitComplex, + UnitQuaternion, Vector1, Vector2, Vector3, +}; use num::Zero; use simba::simd::SimdValue; use std::ops::IndexMut; @@ -12,6 +15,10 @@ use { num::One, }; +pub trait WReal: SimdRealField + Copy {} +impl WReal for Real {} +impl WReal for SimdReal {} + pub(crate) fn inv(val: Real) -> Real { if val == 0.0 { 0.0 @@ -20,6 +27,10 @@ pub(crate) fn inv(val: Real) -> Real { } } +pub(crate) fn simd_inv(val: N) -> N { + N::zero().select(val.simd_eq(N::zero()), N::one() / val) +} + /// Trait to copy the sign of each component of one scalar/vector/matrix to another. pub trait WSign: Sized { // See SIMD implementations of copy_sign there: https://stackoverflow.com/a/57872652 @@ -234,32 +245,79 @@ where pub(crate) trait WCrossMatrix: Sized { type CrossMat; + type CrossMatTr; fn gcross_matrix(self) -> Self::CrossMat; + fn gcross_matrix_tr(self) -> Self::CrossMatTr; } -impl WCrossMatrix for Vector3 { - type CrossMat = Matrix3; +impl WCrossMatrix for Vector3 { + type CrossMat = Matrix3; + type CrossMatTr = Matrix3; #[inline] #[rustfmt::skip] fn gcross_matrix(self) -> Self::CrossMat { Matrix3::new( - 0.0, -self.z, self.y, - self.z, 0.0, -self.x, - -self.y, self.x, 0.0, + N::zero(), -self.z, self.y, + self.z, N::zero(), -self.x, + -self.y, self.x, N::zero(), + ) + } + + #[inline] + #[rustfmt::skip] + fn gcross_matrix_tr(self) -> Self::CrossMatTr { + Matrix3::new( + N::zero(), self.z, -self.y, + -self.z, N::zero(), self.x, + self.y, -self.x, N::zero(), ) } } -impl WCrossMatrix for Vector2 { - type CrossMat = Vector2; +impl WCrossMatrix for Vector2 { + type CrossMat = RowVector2; + type CrossMatTr = Vector2; #[inline] fn gcross_matrix(self) -> Self::CrossMat { + RowVector2::new(-self.y, self.x) + } + #[inline] + fn gcross_matrix_tr(self) -> Self::CrossMatTr { Vector2::new(-self.y, self.x) } } +impl WCrossMatrix for Real { + type CrossMat = Matrix2; + type CrossMatTr = Matrix2; + + #[inline] + fn gcross_matrix(self) -> Matrix2 { + Matrix2::new(0.0, -self, self, 0.0) + } + + #[inline] + fn gcross_matrix_tr(self) -> Matrix2 { + Matrix2::new(0.0, self, -self, 0.0) + } +} + +impl WCrossMatrix for SimdReal { + type CrossMat = Matrix2; + type CrossMatTr = Matrix2; + + #[inline] + fn gcross_matrix(self) -> Matrix2 { + Matrix2::new(SimdReal::zero(), -self, self, SimdReal::zero()) + } + + #[inline] + fn gcross_matrix_tr(self) -> Matrix2 { + Matrix2::new(SimdReal::zero(), self, -self, SimdReal::zero()) + } +} pub(crate) trait WCross: Sized { type Result; @@ -295,50 +353,43 @@ pub(crate) trait WDot: Sized { fn gdot(&self, rhs: Rhs) -> Self::Result; } -impl WDot> for Vector3 { - type Result = Real; +impl WDot> for Vector3 { + type Result = N; - fn gdot(&self, rhs: Vector3) -> Self::Result { + fn gdot(&self, rhs: Vector3) -> Self::Result { self.x * rhs.x + self.y * rhs.y + self.z * rhs.z } } -impl WDot> for Vector2 { - type Result = Real; +impl WDot> for Vector2 { + type Result = N; - fn gdot(&self, rhs: Vector2) -> Self::Result { + fn gdot(&self, rhs: Vector2) -> Self::Result { self.x * rhs.x + self.y * rhs.y } } -impl WDot for Real { - type Result = Real; +impl WDot> for N { + type Result = N; - fn gdot(&self, rhs: Real) -> Self::Result { - *self * rhs + fn gdot(&self, rhs: Vector1) -> Self::Result { + *self * rhs.x } } -impl WCrossMatrix for Vector3 { - type CrossMat = Matrix3; +impl WDot for N { + type Result = N; - #[inline] - #[rustfmt::skip] - fn gcross_matrix(self) -> Self::CrossMat { - Matrix3::new( - SimdReal::zero(), -self.z, self.y, - self.z, SimdReal::zero(), -self.x, - -self.y, self.x, SimdReal::zero(), - ) + fn gdot(&self, rhs: N) -> Self::Result { + *self * rhs } } -impl WCrossMatrix for Vector2 { - type CrossMat = Vector2; +impl WDot for Vector1 { + type Result = N; - #[inline] - fn gcross_matrix(self) -> Self::CrossMat { - Vector2::new(-self.y, self.x) + fn gdot(&self, rhs: N) -> Self::Result { + self.x * rhs } } @@ -368,27 +419,42 @@ impl WCross> for Vector2 { } } -impl WDot> for Vector3 { - type Result = SimdReal; +pub trait WQuat { + type Result; - fn gdot(&self, rhs: Vector3) -> Self::Result { - self.x * rhs.x + self.y * rhs.y + self.z * rhs.z - } + fn diff_conj1_2(&self, rhs: &Self) -> Self::Result; } -impl WDot> for Vector2 { - type Result = SimdReal; +impl WQuat for UnitComplex +where + ::Element: SimdRealField, +{ + type Result = Matrix1; - fn gdot(&self, rhs: Vector2) -> Self::Result { - self.x * rhs.x + self.y * rhs.y + fn diff_conj1_2(&self, rhs: &Self) -> Self::Result { + let two: N = na::convert(2.0); + Matrix1::new((self.im * rhs.im + self.re * rhs.re) * two) } } -impl WDot for SimdReal { - type Result = SimdReal; +impl WQuat for UnitQuaternion +where + ::Element: SimdRealField, +{ + type Result = Matrix3; - fn gdot(&self, rhs: SimdReal) -> Self::Result { - *self * rhs + fn diff_conj1_2(&self, rhs: &Self) -> Self::Result { + let half: N = na::convert(0.5); + let v1 = self.imag(); + let v2 = rhs.imag(); + let w1 = self.w; + let w2 = rhs.w; + + // TODO: this can probably be optimized a lot by unrolling the ops. + (v1 * v2.transpose() + Matrix3::from_diagonal_element(w1 * w2) + - (v1 * w2 + v2 * w1).cross_matrix() + + v1.cross_matrix() * v2.cross_matrix()) + * half } } @@ -404,59 +470,23 @@ pub(crate) trait WAngularInertia { fn into_matrix(self) -> Self::AngMatrix; } -impl WAngularInertia for Real { - type AngVector = Real; - type LinVector = Vector2; - type AngMatrix = Real; - - fn inverse(&self) -> Self { - if *self != 0.0 { - 1.0 / *self - } else { - 0.0 - } - } - - fn transform_lin_vector(&self, pt: Vector2) -> Vector2 { - *self * pt - } - fn transform_vector(&self, pt: Real) -> Real { - *self * pt - } - - fn squared(&self) -> Real { - *self * *self - } - - fn transform_matrix(&self, mat: &Self::AngMatrix) -> Self::AngMatrix { - mat * *self - } - - fn into_matrix(self) -> Self::AngMatrix { - self - } -} - -impl WAngularInertia for SimdReal { - type AngVector = SimdReal; - type LinVector = Vector2; - type AngMatrix = SimdReal; +impl WAngularInertia for N { + type AngVector = N; + type LinVector = Vector2; + type AngMatrix = N; fn inverse(&self) -> Self { - let zero = ::zero(); - let is_zero = self.simd_eq(zero); - (::one() / *self).select(is_zero, zero) + simd_inv(*self) } - fn transform_lin_vector(&self, pt: Vector2) -> Vector2 { + fn transform_lin_vector(&self, pt: Vector2) -> Vector2 { pt * *self } - - fn transform_vector(&self, pt: SimdReal) -> SimdReal { - *self * pt + fn transform_vector(&self, pt: N) -> N { + pt * *self } - fn squared(&self) -> SimdReal { + fn squared(&self) -> N { *self * *self } @@ -757,3 +787,17 @@ impl IndexMut2 for Vec { } } } + +impl IndexMut2 for [T] { + #[inline] + fn index_mut2(&mut self, i: usize, j: usize) -> (&mut T, &mut T) { + assert!(i != j, "Unable to index the same element twice."); + assert!(i < self.len() && j < self.len(), "Index out of bounds."); + + unsafe { + let a = &mut *(self.get_unchecked_mut(i) as *mut _); + let b = &mut *(self.get_unchecked_mut(j) as *mut _); + (a, b) + } + } +} -- cgit