use std::ops::Mul;
use crate::{Mat3, Point3, Vec3};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform3 {
pub rotation: Mat3,
pub translation: Vec3,
}
impl Transform3 {
pub const IDENTITY: Self = Self {
rotation: Mat3::IDENTITY,
translation: Vec3::ZERO,
};
#[inline]
pub fn from_translation(t: Vec3) -> Self {
Self { rotation: Mat3::IDENTITY, translation: t }
}
#[inline]
pub fn from_rotation(axis: crate::UnitVec3, angle: f64) -> Self {
Self { rotation: Mat3::rotation(axis, angle), translation: Vec3::ZERO }
}
#[inline]
pub fn apply_point(self, p: Point3) -> Point3 {
Point3::from_vec(self.rotation * p.to_vec()) + self.translation
}
#[inline]
pub fn apply_vec(self, v: Vec3) -> Vec3 {
self.rotation * v
}
pub fn inverse(self) -> Self {
let r_inv = self.rotation.transpose(); let t_inv = -(r_inv * self.translation);
Self { rotation: r_inv, translation: t_inv }
}
#[inline]
pub fn compose(self, rhs: Self) -> Self {
Self {
rotation: self.rotation * rhs.rotation,
translation: self.rotation * rhs.translation + self.translation,
}
}
}
impl Mul for Transform3 {
type Output = Self;
#[inline] fn mul(self, rhs: Self) -> Self { self.compose(rhs) }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::UnitVec3;
#[test]
fn inverse_round_trip() {
let t = Transform3 {
rotation: Mat3::rotation(UnitVec3::Z, 0.7),
translation: Vec3::new(1.0, 2.0, 3.0),
};
let p = Point3::new(4.0, 5.0, 6.0);
let q = t.inverse().apply_point(t.apply_point(p));
assert!((p - q).length() < 1e-10);
}
}