use nalgebra::{Point3, Vector3, Matrix4, Isometry3, Transform3, UnitQuaternion};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Transform3D {
pub matrix: Matrix4<f32>,
}
impl Transform3D {
pub fn identity() -> Self {
Self {
matrix: Matrix4::identity(),
}
}
pub fn translation(translation: Vector3<f32>) -> Self {
Self {
matrix: Matrix4::new_translation(&translation),
}
}
pub fn rotation(rotation: UnitQuaternion<f32>) -> Self {
Self {
matrix: rotation.to_homogeneous(),
}
}
pub fn scaling(scale: Vector3<f32>) -> Self {
Self {
matrix: Matrix4::new_nonuniform_scaling(&scale),
}
}
pub fn uniform_scaling(scale: f32) -> Self {
Self {
matrix: Matrix4::new_scaling(scale),
}
}
pub fn from_translation_rotation(
translation: Vector3<f32>,
rotation: UnitQuaternion<f32>,
) -> Self {
let isometry = Isometry3::from_parts(translation.into(), rotation);
Self {
matrix: isometry.to_homogeneous(),
}
}
pub fn transform_point(&self, point: &Point3<f32>) -> Point3<f32> {
let homogeneous = self.matrix * point.to_homogeneous();
Point3::from_homogeneous(homogeneous).unwrap_or(*point)
}
pub fn transform_vector(&self, vector: &Vector3<f32>) -> Vector3<f32> {
let homogeneous = self.matrix.fixed_view::<3, 3>(0, 0) * vector;
homogeneous
}
pub fn compose(self, other: Self) -> Self {
Self {
matrix: self.matrix * other.matrix,
}
}
pub fn inverse(self) -> Option<Self> {
self.matrix.try_inverse().map(|inv_matrix| Self {
matrix: inv_matrix,
})
}
pub fn is_identity(&self, epsilon: f32) -> bool {
let identity = Matrix4::identity();
(self.matrix - identity).norm() < epsilon
}
}
impl Default for Transform3D {
fn default() -> Self {
Self::identity()
}
}
impl std::ops::Mul for Transform3D {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
self.compose(rhs)
}
}
impl From<Matrix4<f32>> for Transform3D {
fn from(matrix: Matrix4<f32>) -> Self {
Self { matrix }
}
}
impl From<Isometry3<f32>> for Transform3D {
fn from(isometry: Isometry3<f32>) -> Self {
Self {
matrix: isometry.to_homogeneous(),
}
}
}
impl From<Transform3<f32>> for Transform3D {
fn from(transform: Transform3<f32>) -> Self {
Self {
matrix: transform.into_inner(),
}
}
}