use std::ops::{Mul, MulAssign, Neg};
mod vec3d;
pub use vec3d::Vec3D;
mod fast_rotate;
use fast_rotate::CachedRotation3D;
#[derive(Debug, Clone, Copy)]
pub struct Transform3D {
pub translation: Vec3D,
pub rotation: Vec3D,
pub scale: Vec3D,
}
impl Default for Transform3D {
fn default() -> Self {
Self::DEFAULT
}
}
impl Transform3D {
pub const DEFAULT: Self = Self::new_trs(Vec3D::ZERO, Vec3D::ZERO, Vec3D::ONE);
#[must_use]
pub const fn new_trs(translation: Vec3D, rotation: Vec3D, scale: Vec3D) -> Self {
Self {
translation,
rotation,
scale,
}
}
#[must_use]
pub const fn new_tr(translation: Vec3D, rotation: Vec3D) -> Self {
Self {
translation,
rotation,
scale: Vec3D::ONE,
}
}
#[must_use]
pub const fn new_t(translation: Vec3D) -> Self {
Self {
translation,
rotation: Vec3D::ZERO,
scale: Vec3D::ONE,
}
}
#[must_use]
pub const fn new_r(rotation: Vec3D) -> Self {
Self {
translation: Vec3D::ZERO,
rotation,
scale: Vec3D::ONE,
}
}
#[allow(clippy::let_and_return)]
#[must_use]
pub fn apply_to(&self, vertices: &[Vec3D]) -> Vec<Vec3D> {
let rotation = CachedRotation3D::new(self.rotation);
vertices
.iter()
.map(|v| {
let rhs = *v;
let rhs = rhs * self.scale;
let rhs = rotation.rotate(rhs);
let rhs = rhs + self.translation;
rhs
})
.collect()
}
#[allow(clippy::let_and_return)]
#[must_use]
pub(crate) fn apply_viewport_transform(&self, vertices: &[Vec3D]) -> Vec<Vec3D> {
let rotation = CachedRotation3D::new(-self.rotation);
vertices
.iter()
.map(|v| {
let rhs = *v;
let rhs = rhs - self.translation; let rhs = (rotation).rotate(rhs);
rhs
})
.collect()
}
#[must_use]
pub fn rotate(&self, value: Vec3D) -> Vec3D {
let rotation = CachedRotation3D::new(self.rotation);
rotation.rotate(value)
}
}
impl Neg for Transform3D {
type Output = Self;
fn neg(self) -> Self::Output {
Self::new_trs(-self.translation, -self.rotation, self.scale)
}
}
impl Mul<Self> for Transform3D {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::new_trs(
self.translation + rhs.translation,
self.rotation + rhs.rotation,
self.scale * rhs.scale,
)
}
}
impl MulAssign<Self> for Transform3D {
fn mul_assign(&mut self, rhs: Self) {
self.translation += rhs.translation;
self.rotation += rhs.rotation;
self.scale *= rhs.scale;
}
}
impl Mul<Vec3D> for Transform3D {
type Output = Vec3D;
#[allow(clippy::let_and_return)]
fn mul(self, rhs: Vec3D) -> Self::Output {
let rhs = rhs * self.scale;
let rhs = self.rotate(rhs);
let rhs = rhs + self.translation;
rhs
}
}