#![cfg_attr(feature = "rkyv-serialize", allow(unsafe_op_in_unsafe_fn))]
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use num::{One, Zero};
use std::fmt;
use std::hash;
#[cfg(feature = "serde-serialize-no-std")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde-serialize-no-std")]
use crate::base::storage::Owned;
use simba::scalar::RealField;
use simba::simd::SimdRealField;
use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::{Const, DefaultAllocator, OMatrix, SMatrix, SVector, Scalar, Unit};
use crate::geometry::Point;
#[cfg(feature = "rkyv-serialize")]
use rkyv::bytecheck;
#[repr(C)]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize),
archive(
as = "Rotation<T::Archived, D>",
bound(archive = "
T: rkyv::Archive,
SMatrix<T, D, D>: rkyv::Archive<Archived = SMatrix<T::Archived, D, D>>
")
)
)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone)]
pub struct Rotation<T, const D: usize> {
matrix: SMatrix<T, D, D>,
}
impl<T: fmt::Debug, const D: usize> fmt::Debug for Rotation<T, D> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.matrix.fmt(formatter)
}
}
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Rotation<T, D>
where
<DefaultAllocator as Allocator<Const<D>, Const<D>>>::Buffer<T>: hash::Hash,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.matrix.hash(state)
}
}
#[cfg(feature = "bytemuck")]
unsafe impl<T, const D: usize> bytemuck::Zeroable for Rotation<T, D>
where
T: Scalar + bytemuck::Zeroable,
SMatrix<T, D, D>: bytemuck::Zeroable,
{
}
#[cfg(feature = "bytemuck")]
unsafe impl<T, const D: usize> bytemuck::Pod for Rotation<T, D>
where
T: Scalar + bytemuck::Pod,
SMatrix<T, D, D>: bytemuck::Pod,
{
}
#[cfg(feature = "serde-serialize-no-std")]
impl<T: Scalar, const D: usize> Serialize for Rotation<T, D>
where
Owned<T, Const<D>, Const<D>>: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.matrix.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize-no-std")]
impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Rotation<T, D>
where
Owned<T, Const<D>, Const<D>>: Deserialize<'a>,
{
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
where
Des: Deserializer<'a>,
{
let matrix = SMatrix::<T, D, D>::deserialize(deserializer)?;
Ok(Self::from_matrix_unchecked(matrix))
}
}
impl<T, const D: usize> Rotation<T, D> {
#[inline]
pub const fn from_matrix_unchecked(matrix: SMatrix<T, D, D>) -> Self {
Self { matrix }
}
}
impl<T: Scalar, const D: usize> Rotation<T, D> {
#[inline]
#[must_use]
pub const fn matrix(&self) -> &SMatrix<T, D, D> {
&self.matrix
}
#[inline]
#[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")]
pub const unsafe fn matrix_mut(&mut self) -> &mut SMatrix<T, D, D> {
&mut self.matrix
}
#[inline]
pub const fn matrix_mut_unchecked(&mut self) -> &mut SMatrix<T, D, D> {
&mut self.matrix
}
#[inline]
pub fn into_inner(self) -> SMatrix<T, D, D> {
self.matrix
}
#[deprecated(note = "use `.into_inner()` instead")]
#[inline]
pub fn unwrap(self) -> SMatrix<T, D, D> {
self.matrix
}
#[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
where
T: Zero + One,
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
{
let mut res = OMatrix::<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>::identity();
res.fixed_view_mut::<D, D>(0, 0).copy_from(&self.matrix);
res
}
}
impl<T: Scalar, const D: usize> Rotation<T, D> {
#[inline]
#[must_use = "Did you mean to use transpose_mut()?"]
pub fn transpose(&self) -> Self {
Self::from_matrix_unchecked(self.matrix.transpose())
}
#[inline]
#[must_use = "Did you mean to use inverse_mut()?"]
pub fn inverse(&self) -> Self {
self.transpose()
}
#[inline]
pub fn transpose_mut(&mut self) {
self.matrix.transpose_mut()
}
#[inline]
pub fn inverse_mut(&mut self) {
self.transpose_mut()
}
}
impl<T: SimdRealField, const D: usize> Rotation<T, D>
where
T::Element: SimdRealField,
{
#[inline]
#[must_use]
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self * pt
}
#[inline]
#[must_use]
pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self * v
}
#[inline]
#[must_use]
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
Point::from(self.inverse_transform_vector(&pt.coords))
}
#[inline]
#[must_use]
pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self.matrix().tr_mul(v)
}
#[inline]
#[must_use]
pub fn inverse_transform_unit_vector(&self, v: &Unit<SVector<T, D>>) -> Unit<SVector<T, D>> {
Unit::new_unchecked(self.inverse_transform_vector(&**v))
}
}
impl<T: Scalar + Eq, const D: usize> Eq for Rotation<T, D> {}
impl<T: Scalar + PartialEq, const D: usize> PartialEq for Rotation<T, D> {
#[inline]
fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix
}
}
impl<T, const D: usize> AbsDiffEq for Rotation<T, D>
where
T: Scalar + AbsDiffEq,
T::Epsilon: Clone,
{
type Epsilon = T::Epsilon;
#[inline]
fn default_epsilon() -> Self::Epsilon {
T::default_epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.matrix.abs_diff_eq(&other.matrix, epsilon)
}
}
impl<T, const D: usize> RelativeEq for Rotation<T, D>
where
T: Scalar + RelativeEq,
T::Epsilon: Clone,
{
#[inline]
fn default_max_relative() -> Self::Epsilon {
T::default_max_relative()
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.matrix
.relative_eq(&other.matrix, epsilon, max_relative)
}
}
impl<T, const D: usize> UlpsEq for Rotation<T, D>
where
T: Scalar + UlpsEq,
T::Epsilon: Clone,
{
#[inline]
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.matrix.ulps_eq(&other.matrix, epsilon, max_ulps)
}
}
impl<T, const D: usize> fmt::Display for Rotation<T, D>
where
T: RealField + fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let precision = f.precision().unwrap_or(3);
writeln!(f, "Rotation matrix {{")?;
write!(f, "{:.*}", precision, self.matrix)?;
writeln!(f, "}}")
}
}