use crate::{Mat3, Quat, Vec3};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Affine3 {
pub matrix: Mat3,
pub translation: Vec3,
}
impl Affine3 {
pub const IDENTITY: Affine3 = Affine3 {
matrix: Mat3::IDENTITY,
translation: Vec3::ZERO,
};
#[inline(always)]
pub const fn new(matrix: Mat3, translation: Vec3) -> Self {
Self { matrix, translation }
}
#[inline]
pub fn from_translation(translation: Vec3) -> Self {
Self {
matrix: Mat3::IDENTITY,
translation,
}
}
#[inline]
pub fn from_quat(quat: Quat) -> Self {
Self {
matrix: Mat3::from_quat(quat),
translation: Vec3::ZERO,
}
}
#[inline]
pub fn from_scale(scale: Vec3) -> Self {
Self {
matrix: Mat3::from_nonuniform_scale(scale),
translation: Vec3::ZERO,
}
}
#[inline]
pub fn from_rotation_translation(quat: Quat, translation: Vec3) -> Self {
Self {
matrix: Mat3::from_quat(quat),
translation,
}
}
#[inline]
pub fn from_scale_rotation_translation(scale: Vec3, quat: Quat, translation: Vec3) -> Self {
let mut mat = Mat3::from_quat(quat);
mat.x_axis *= scale.x;
mat.y_axis *= scale.y;
mat.z_axis *= scale.z;
Self {
matrix: mat,
translation,
}
}
#[inline]
pub fn transform_point3(self, point: Vec3) -> Vec3 {
self.matrix * point + self.translation
}
#[inline]
pub fn transform_vector3(self, vector: Vec3) -> Vec3 {
self.matrix * vector
}
#[inline]
pub fn inverse(self) -> Option<Self> {
let mat_inv = self.matrix.inverse()?;
Some(Self {
matrix: mat_inv,
translation: mat_inv * (-self.translation),
})
}
#[inline]
pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
let f = (center - eye).normalize();
let s = f.cross(up).normalize();
let u = s.cross(f);
Self {
matrix: Mat3::from_cols(
Vec3::new(s.x, u.x, -f.x),
Vec3::new(s.y, u.y, -f.y),
Vec3::new(s.z, u.z, -f.z),
),
translation: Vec3::new(-s.dot(eye), -u.dot(eye), f.dot(eye)),
}
}
}
impl std::ops::Mul for Affine3 {
type Output = Self;
#[inline]
fn mul(self, other: Self) -> Self {
Self {
matrix: self.matrix * other.matrix,
translation: self.matrix * other.translation + self.translation,
}
}
}
impl std::ops::Mul<Vec3> for Affine3 {
type Output = Vec3;
#[inline]
fn mul(self, point: Vec3) -> Vec3 {
self.transform_point3(point)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_affine3_identity() {
let a = Affine3::IDENTITY;
let p = Vec3::new(1.0, 2.0, 3.0);
assert_eq!(a.transform_point3(p), p);
}
#[test]
fn test_affine3_translation() {
let a = Affine3::from_translation(Vec3::new(1.0, 2.0, 3.0));
let p = Vec3::ZERO;
assert_eq!(a.transform_point3(p), Vec3::new(1.0, 2.0, 3.0));
}
#[test]
fn test_affine3_mul() {
let a = Affine3::from_translation(Vec3::new(1.0, 0.0, 0.0));
let b = Affine3::from_translation(Vec3::new(0.0, 1.0, 0.0));
let c = a * b;
let p = Vec3::ZERO;
assert_eq!(c.transform_point3(p), Vec3::new(1.0, 1.0, 0.0));
}
}