cadcore_math/
transform.rs1use crate::{Mat3, Point3, Vec3};
7use std::ops::Mul;
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 {
31 rotation: Mat3::IDENTITY,
32 translation: t,
33 }
34 }
35
36 #[inline]
38 pub fn from_rotation(axis: crate::UnitVec3, angle: f64) -> Self {
39 Self {
40 rotation: Mat3::rotation(axis, angle),
41 translation: Vec3::ZERO,
42 }
43 }
44
45 #[inline]
47 pub fn apply_point(self, p: Point3) -> Point3 {
48 Point3::from_vec(self.rotation * p.to_vec()) + self.translation
49 }
50
51 #[inline]
53 pub fn apply_vec(self, v: Vec3) -> Vec3 {
54 self.rotation * v
55 }
56
57 pub fn inverse(self) -> Self {
59 let r_inv = self.rotation.transpose(); let t_inv = -(r_inv * self.translation);
61 Self {
62 rotation: r_inv,
63 translation: t_inv,
64 }
65 }
66
67 #[inline]
69 pub fn compose(self, rhs: Self) -> Self {
70 Self {
71 rotation: self.rotation * rhs.rotation,
72 translation: self.rotation * rhs.translation + self.translation,
73 }
74 }
75}
76
77impl Mul for Transform3 {
79 type Output = Self;
80 #[inline]
81 fn mul(self, rhs: Self) -> Self {
82 self.compose(rhs)
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::UnitVec3;
90
91 #[test]
92 fn inverse_round_trip() {
93 let t = Transform3 {
94 rotation: Mat3::rotation(UnitVec3::Z, 0.7),
95 translation: Vec3::new(1.0, 2.0, 3.0),
96 };
97 let p = Point3::new(4.0, 5.0, 6.0);
98 let q = t.inverse().apply_point(t.apply_point(p));
99 assert!((p - q).length() < 1e-10);
100 }
101}