use na::Dim;
use crate::{Mat3, MatrixView, MatrixViewMut, Real, Vec3, Vec4};
pub trait Vec3Ext {
fn into_cross_matrix(self) -> Mat3;
}
impl Vec3Ext for Vec3 {
#[inline]
fn into_cross_matrix(self) -> Mat3 {
Mat3::from_columns(&[
na::vector![0.0, self.z, -self.y],
na::vector![-self.z, 0.0, self.x],
na::vector![self.y, -self.x, 0.0],
])
}
}
pub trait UnitQuatExt {
fn from_array_unchecked(array: [Real; 4]) -> Self;
fn from_vec4_unchecked(v: Vec4) -> Self;
fn is_valid(array: [Real; 4], eps: Real) -> bool;
}
impl UnitQuatExt for na::UnitQuaternion<Real> {
#[inline]
fn from_array_unchecked(array: [Real; 4]) -> Self {
na::UnitQuaternion::new_unchecked(na::Quaternion::from(array))
}
#[inline]
fn from_vec4_unchecked(v: Vec4) -> Self {
na::UnitQuaternion::new_unchecked(na::Quaternion::from(v))
}
#[inline]
fn is_valid(array: [Real; 4], eps: Real) -> bool {
let length = Vec4::from(array).norm();
(length - 1.0).abs() < eps
}
}
pub trait ViewMatrix {
fn view_matrix<const R: usize, const C: usize>(
&self,
element_offset: usize,
) -> MatrixView<R, C>;
}
pub trait ViewMatrixMut {
fn view_matrix_mut<const R: usize, const C: usize>(
&mut self,
element_offset: usize,
) -> MatrixViewMut<R, C>;
}
macro_rules! impl_view_matrix {
($type:ty) => {
impl ViewMatrix for $type {
#[inline]
fn view_matrix<const R: usize, const C: usize>(
&self,
element_offset: usize,
) -> MatrixView<R, C> {
MatrixView::<R, C>::from_slice(&self[element_offset..])
}
}
};
}
macro_rules! impl_view_matrix_mut {
($type:ty) => {
impl ViewMatrixMut for $type {
#[inline]
fn view_matrix_mut<const R: usize, const C: usize>(
&mut self,
element_offset: usize,
) -> MatrixViewMut<R, C> {
MatrixViewMut::<R, C>::from_slice(&mut self[element_offset..])
}
}
};
}
impl_view_matrix! {[Real]}
impl_view_matrix! {Vec<Real>}
impl_view_matrix_mut! {[Real]}
impl_view_matrix_mut! {Vec<Real>}
pub trait MatrixExt {
fn any_nan(&self) -> bool;
}
impl<R, C, S> MatrixExt for na::Matrix<Real, R, C, S>
where
R: na::Dim,
C: na::Dim,
S: na::RawStorage<Real, R, C>,
{
#[inline]
fn any_nan(&self) -> bool {
self.iter().any(
#[inline]
|x| x.is_nan(),
)
}
}
pub trait SquareMatrixExt {
fn is_positive_definite(&self) -> bool;
}
impl<R, S> SquareMatrixExt for na::Matrix<Real, R, R, S>
where
R: Dim,
S: na::RawStorage<Real, R, R>,
{
#[inline]
fn is_positive_definite(&self) -> bool {
for size in 1..=self.ncols() {
let d = self.view((0, 0), (size, size)).determinant();
if d <= 0.0 {
return false;
}
}
true
}
}
pub trait RealSliceExt {
fn array<const N: usize>(&self, offset: usize) -> [Real; N];
}
impl RealSliceExt for [Real] {
#[inline]
fn array<const N: usize>(&self, offset: usize) -> [Real; N] {
self[offset..offset + N]
.try_into()
.expect("no enough elements")
}
}
#[cfg(test)]
mod tests {
use super::Vec3Ext;
use crate::exts::SquareMatrixExt;
use crate::{SMatrix, vec3};
#[test]
fn test_cross_matrix() {
let v = vec3(1.0, 2.0, 3.0);
let m = v.into_cross_matrix();
assert_eq!(m.column(0), vec3(0.0, 3.0, -2.0));
assert_eq!(m.column(1), vec3(-3.0, 0.0, 1.0));
assert_eq!(m.column(2), vec3(2.0, -1.0, 0.0));
assert_eq!(m, v.cross_matrix());
}
#[test]
fn test_positive_define() {
let m = SMatrix::<1, 1>::new(-1.0);
assert!(!m.is_positive_definite());
let m = SMatrix::<2, 2>::new(1.0, 0.0, 0.0, 1.0);
assert!(m.is_positive_definite());
}
}