cadcore_math/
transform.rs1use std::ops::Mul;
7use crate::{Mat3, Point3, Vec3};
8
9#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct Transform3 {
14 pub rotation: Mat3,
16 pub translation: Vec3,
18}
19
20impl Transform3 {
21 pub const IDENTITY: Self = Self {
23 rotation: Mat3::IDENTITY,
24 translation: Vec3::ZERO,
25 };
26
27 #[inline]
29 pub fn from_translation(t: Vec3) -> Self {
30 Self { rotation: Mat3::IDENTITY, translation: t }
31 }
32
33 #[inline]
35 pub fn from_rotation(axis: crate::UnitVec3, angle: f64) -> Self {
36 Self { rotation: Mat3::rotation(axis, angle), translation: Vec3::ZERO }
37 }
38
39 #[inline]
41 pub fn apply_point(self, p: Point3) -> Point3 {
42 Point3::from_vec(self.rotation * p.to_vec()) + self.translation
43 }
44
45 #[inline]
47 pub fn apply_vec(self, v: Vec3) -> Vec3 {
48 self.rotation * v
49 }
50
51 pub fn inverse(self) -> Self {
53 let r_inv = self.rotation.transpose(); let t_inv = -(r_inv * self.translation);
55 Self { rotation: r_inv, translation: t_inv }
56 }
57
58 #[inline]
60 pub fn compose(self, rhs: Self) -> Self {
61 Self {
62 rotation: self.rotation * rhs.rotation,
63 translation: self.rotation * rhs.translation + self.translation,
64 }
65 }
66}
67
68impl Mul for Transform3 {
70 type Output = Self;
71 #[inline] fn mul(self, rhs: Self) -> Self { self.compose(rhs) }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::UnitVec3;
78
79 #[test]
80 fn inverse_round_trip() {
81 let t = Transform3 {
82 rotation: Mat3::rotation(UnitVec3::Z, 0.7),
83 translation: Vec3::new(1.0, 2.0, 3.0),
84 };
85 let p = Point3::new(4.0, 5.0, 6.0);
86 let q = t.inverse().apply_point(t.apply_point(p));
87 assert!((p - q).length() < 1e-10);
88 }
89}