//! Miscellaneous utilities.
use na::{Matrix3, Point2, Point3, Scalar, SimdRealField, Vector2, Vector3};
use num::Zero;
use simba::simd::SimdValue;
use std::ops::IndexMut;
use parry::utils::SdpMatrix3;
use {
crate::math::{Real, SimdReal},
na::SimdPartialOrd,
num::One,
};
pub(crate) fn inv(val: Real) -> Real {
if val == 0.0 {
0.0
} else {
1.0 / val
}
}
/// Trait to copy the sign of each component of one scalar/vector/matrix to another.
pub trait WSign<Rhs>: Sized {
// See SIMD implementations of copy_sign there: https://stackoverflow.com/a/57872652
/// Copy the sign of each component of `self` to the corresponding component of `to`.
fn copy_sign_to(self, to: Rhs) -> Rhs;
}
impl WSign<Real> for Real {
fn copy_sign_to(self, to: Self) -> Self {
const MINUS_ZERO: Real = -0.0;
let signbit = MINUS_ZERO.to_bits();
Real::from_bits((signbit & self.to_bits()) | ((!signbit) & to.to_bits()))
}
}
impl<N: Scalar + Copy + WSign<N>> WSign<Vector2<N>> for N {
fn copy_sign_to(self, to: Vector2<N>) -> Vector2<N> {
Vector2::new(self.copy_sign_to(to.x), self.copy_sign_to(to.y))
}
}
impl<N: Scalar + Copy + WSign<N>> WSign<Vector3<N>> for N {
fn copy_sign_to(self, to: Vector3<N>) -> Vector3<N> {
Vector3::new(
self.copy_sign_to(to.x),
self.copy_sign_to(to.y),
self.copy_sign_to(to.z),
)
}
}
impl<N: Scalar + Copy + WSign<N>> WSign<Vector2<N>> for Vector2<N> {
fn copy_sign_to(self, to: Vector2<N>) -> Vector2<N> {
Vector2::new(self.x.copy_sign_to(to.x), self.y.copy_sign_to(to.y))
}
}
impl<N: Scalar + Copy + WSign<N>> WSign<Vector3<N>> for Vector3<N> {
fn copy_sign_to(self, to: Vector3<N>) -> Vector3<N> {
Vector3::new(
self.x.copy_sign_to(to.x),
self.y.copy_sign_to(to.y),
self.z.copy_sign_to(to.z),
)
}
}
impl WSign<SimdReal> for SimdReal {
fn copy_sign_to(self, to: SimdReal) -> SimdReal {
to.simd_copysign(self)
}
}
pub(crate) trait WComponent: Sized {
type Element;
fn min_component(self) -> Self::Element;
fn max_component(self) -> Self::Element;
}
impl WComponent for Real {
type Element = Real;
fn min_component(self) -> Self::Element {
self
}
fn max_component(self) -> Self::Element {
self
}
}
impl WComponent for SimdReal {
type Element = Real;
fn min_component(self) -> Self::Element {
self.simd_horizontal_min()
}
fn max_component(self) -> Self::Element {
self.simd_horizontal_max()
}
}
/// Trait to compute the orthonormal basis of a vector.
pub trait WBasis: Sized {
/// The type of the array of orthonormal vectors.
type Basis;
/// Computes the vectors which, when combined with `self`, form an orthonormal basis.
fn orthonormal_basis(self) -> Self::Basis;
/// Computes a vector orthogonal to `self` with a unit length (if `self` has a unit length).
fn orthonormal_vector(self) -> Self;
}
impl<N: SimdRealField> WBasis for Vector2<N> {
type Basis = [Vector2<N>; 1];
fn orthonormal_basis(self) -> [Vector2<N>; 1] {
[Vector2::new(-self.y, self.x)]
}
fn orthonormal_vector(self) -> Vector2<N> {
Vector2::new(-self.y, self.x)
}
}
impl<N: SimdRealField + WSign<N>> WBasis for Vector3<N> {
type Basis = [Vector3<N>; 2];
// Robust and branchless implementation from Pixar:
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
fn orthonormal_basis(self) -> [Vector3<N>; 2] {
let sign = self.z.copy_sign_to(N::one());
let a = -N::one() / (sign + self.z);
let b = self.x * self.y * a;
[
Vector3::new(
N::one() + sign * self.x * self.x * a,
sign * b,
-sign * self.x,
),
Vector3::new(b, sign + self.y * self.y *