use std::ops::Deref;
use num_traits::{ConstOne, ConstZero};
use serde::{Deserialize, Serialize};
use super::{quat, vector};
use super::{Float, Quaternion, SqMatrix3, SqMatrix4, Vector};
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(transparent)]
pub struct QArray<F>
where
F: Float,
{
data: [F; 4],
}
macro_rules! qarray_basic_traits {
{ $f:ty, $ty:ty } => {
impl std::default::Default for $ty {
fn default() -> Self {
[<$f>::ZERO,
<$f>::ZERO,
<$f>::ZERO,
<$f>::ONE,
].into()
}
}
impl std::fmt::Display for $ty {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
vector::fmt(f, &self.data)
}
}
}
}
macro_rules! qarray_mul_div_traits {
{ $f:ty, $ty:ty } => {
impl std::ops::Mul for $ty {
type Output = $ty;
fn mul(self, other: $ty) -> $ty {
quat::multiply(self.deref(), other.deref()).into()
}
}
impl <'a> std::ops::Mul<&'a $ty> for $ty {
type Output = $ty;
fn mul(self, other: &'a $ty) -> $ty {
(&self) * other
}
}
impl <'a> std::ops::Mul<&'a $ty> for &'a $ty {
type Output = $ty;
fn mul(self, other: &'a $ty) -> $ty {
*self * other
}
}
impl<'a> std::ops::Mul<$ty> for &'a $ty {
type Output = $ty;
fn mul(self, other: $ty) -> $ty {
*self * other
}
}
impl <'a> std::ops::MulAssign<&'a $ty> for $ty {
fn mul_assign(&mut self, other: &'a $ty) {
*self = self.deref() * other;
}
}
impl std::ops::MulAssign for $ty {
fn mul_assign(&mut self, other: Self) {
*self = self.deref() * other;
}
}
impl<'a, V:Vector<$f, 3>> std::ops::Mul<&'a V> for &'a $ty
{
type Output = V;
fn mul(self, other: &'a V) -> V {
quat::apply3(&self.data, other.as_ref()).into()
}
}
impl<'a, V:Vector<$f, 3>> std::ops::Mul<&'a V> for $ty
{
type Output = V;
fn mul(self, other: &'a V) -> V {
quat::apply3(&self.data, other.as_ref()).into()
}
}
impl std::ops::Div for $ty {
type Output = $ty;
fn div(self, other: $ty) -> $ty {
quat::divide(self.deref(), other.deref()).into()
}
}
impl <'a> std::ops::Div<&'a [$f; 4]> for $ty {
type Output = $ty;
fn div(self, other: &'a [$f; 4]) -> $ty {
quat::divide(self.deref(), other).into()
}
}
impl <'a> std::ops::Div<&'a $ty> for $ty {
type Output = $ty;
fn div(self, other: &'a $ty) -> $ty {
(&self) / other
}
}
impl <'a> std::ops::Div<&'a $ty> for &'a $ty {
type Output = $ty;
fn div(self, other: &'a $ty) -> $ty {
*self / other
}
}
impl<'a> std::ops::Div<$ty> for &'a $ty {
type Output = $ty;
fn div(self, other: $ty) -> $ty {
*self / other.deref()
}
}
impl <'a> std::ops::DivAssign<&'a $ty> for $ty {
fn div_assign(&mut self, other: &'a $ty) {
*self = self.deref() / other;
}
}
impl <'a> std::ops::DivAssign<&'a [$f; 4]> for $ty {
fn div_assign(&mut self, other: &'a [$f; 4]) {
*self = *self / other;
}
}
impl std::ops::DivAssign<Self> for $ty {
fn div_assign(&mut self, other: Self) {
*self = *self / other.deref();
}
}
}
}
macro_rules! qarray_quaternion_trait {
{ $f:ty, $ty:ty } => {
impl Quaternion<$f> for $ty
{
#[inline]
fn as_rijk(&self) -> ($f, $f, $f, $f) {
quat::as_rijk(self.deref())
}
#[inline]
fn of_rijk(r: $f, i: $f, j: $f, k: $f) -> Self {
quat::of_rijk(r, i, j, k).into()
}
#[inline]
fn of_rotation3<M>(rotation: &M) -> Self
where
M: SqMatrix3<$f>
{
quat::of_rotation(rotation.as_ref()).into()
}
#[inline]
fn set_rotation3<M> (&self, matrix3:&mut M)
where
M: SqMatrix3<$f>
{
quat::to_rotation3(&self.data, matrix3.as_mut())
}
#[inline]
fn set_rotation4<M> (&self, matrix:&mut M)
where
M: SqMatrix4<$f>
{
quat::to_rotation4(&self.data, matrix.as_mut())
}
}
}
}
macro_rules! qarray_traits {
{ $f:ty, $ty:ty } => {
qarray_basic_traits!{$f, $ty}
crate::ref_traits!{$f, 4, $ty}
crate::convert_traits!{$f, 4, $ty}
crate::serialize_traits!{$f, 4, $ty}
crate::unary_traits!{$f, 4, $ty}
crate::elementwise_traits!{$f, 4, $ty, Add, add, +, AddAssign, add_assign, +=}
crate::elementwise_traits!{$f, 4, $ty, Sub, sub, -, SubAssign, sub_assign, -=}
crate::scale_by_f_traits!{$f, $ty, Mul, mul, *, MulAssign, mul_assign, *=}
crate::scale_by_f_traits!{$f, $ty, Div, div, /, DivAssign, div_assign, /=}
qarray_mul_div_traits!{$f, $ty}
qarray_quaternion_trait!{$f, $ty}
}
}
qarray_traits! { f32, QArray<f32>}
qarray_traits! { f64, QArray<f64>}