ruby_math/algebra/
transform.rs

1use std::{fmt::Display, ops::Mul};
2
3use super::{Mat4d, Mat4f, Vec3d, Vec3f, Vec4d};
4
5#[derive(Clone, Copy, Debug, PartialEq)]
6pub struct Transform {
7    matrix: Mat4d,
8}
9
10pub trait Transformable {
11    fn apply(&self, transform: Transform) -> Self;
12    fn apply_matrix4d(&self, matrix: Mat4d) -> Self;
13}
14
15impl Default for Transform {
16    fn default() -> Self {
17        Self {
18            matrix: Mat4d::identity(),
19        }
20    }
21}
22
23impl Display for Transform {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        let m = self.matrix.to_array();
26        write!(
27            f,
28            "Transform(matrix: ({} {} {} {} | {} {} {} {} | {} {} {} {} | {} {} {} {}))",
29            m[0],
30            m[1],
31            m[2],
32            m[3],
33            m[4],
34            m[5],
35            m[6],
36            m[7],
37            m[8],
38            m[9],
39            m[10],
40            m[11],
41            m[12],
42            m[13],
43            m[14],
44            m[15]
45        )
46    }
47}
48
49impl Mul<Transform> for Transform {
50    type Output = Transform;
51
52    fn mul(self, rhs: Transform) -> Self::Output {
53        self.apply(rhs)
54    }
55}
56
57impl Transform {
58    pub fn from_matrix4d(matrix: Mat4d) -> Self {
59        Self { matrix }
60    }
61
62    pub fn from_matrix4f(matrix: Mat4f) -> Self {
63        Self {
64            matrix: matrix.to_mat4d(),
65        }
66    }
67
68    pub fn matrix(&self) -> Mat4d {
69        self.matrix
70    }
71
72    pub fn inverse(&self) -> Self {
73        Self {
74            matrix: self.matrix.inverse(),
75        }
76    }
77}
78
79impl Transform {
80    pub fn from_translation(translate: Vec3d) -> Self {
81        Self::from_matrix4d(Mat4d::translation(translate))
82    }
83
84    pub fn from_rotation_x(angle: f64) -> Self {
85        Self::from_matrix4d(Mat4d::rotation_x(angle))
86    }
87
88    pub fn from_rotation_y(angle: f64) -> Self {
89        Self::from_matrix4d(Mat4d::rotation_y(angle))
90    }
91
92    pub fn from_rotation_z(angle: f64) -> Self {
93        Self::from_matrix4d(Mat4d::rotation_z(angle))
94    }
95
96    pub fn from_rotation_axis(axis: Vec3d, angle: f64) -> Self {
97        Self::from_matrix4d(Mat4d::rotation_axis(axis, angle))
98    }
99
100    pub fn from_scale(scale: Vec3d) -> Self {
101        Self::from_matrix4d(Mat4d::scale(scale))
102    }
103}
104
105impl Transform {
106    pub fn translate(&self, translate: Vec3d) -> Self {
107        self.apply_matrix4d(Mat4d::translation(translate))
108    }
109
110    pub fn rotate_x(&self, angle: f64) -> Self {
111        self.apply_matrix4d(Mat4d::rotation_x(angle))
112    }
113
114    pub fn rotate_y(&self, angle: f64) -> Self {
115        self.apply_matrix4d(Mat4d::rotation_y(angle))
116    }
117
118    pub fn rotate_z(&self, angle: f64) -> Self {
119        self.apply_matrix4d(Mat4d::rotation_z(angle))
120    }
121
122    pub fn rotate_axis(&self, axis: Vec3d, angle: f64) -> Self {
123        self.apply_matrix4d(Mat4d::rotation_axis(axis, angle))
124    }
125
126    pub fn scale(&self, scale: Vec3d) -> Self {
127        self.apply_matrix4d(Mat4d::scale(scale))
128    }
129}
130
131impl Transform {
132    pub fn transform_homogeneous_coord(&self, coord: Vec4d) -> Vec4d {
133        self.matrix * coord
134    }
135
136    pub fn transform_point3f(&self, point: Vec3f) -> Vec3f {
137        let p = point.to_homogeneous_coord_point().to_vec4d();
138        let p = self.transform_homogeneous_coord(p);
139        (p.xyz() / p.w()).to_vec3f()
140    }
141
142    pub fn transform_vector3f(&self, vector: Vec3f) -> Vec3f {
143        let v = vector.to_homogeneous_coord_vector().to_vec4d();
144        let v = self.transform_homogeneous_coord(v);
145        v.xyz().to_vec3f()
146    }
147
148    pub fn transform_normal3f(&self, normal: Vec3f) -> Vec3f {
149        let m = self.matrix.inverse().transpose();
150        let n = normal.to_homogeneous_coord_vector().to_vec4d();
151        let n = m * n;
152        n.xyz().normalize().to_vec3f()
153    }
154
155    pub fn transform_point3d(&self, point: Vec3d) -> Vec3d {
156        let p = point.to_homogeneous_coord_point();
157        let p = self.transform_homogeneous_coord(p);
158        p.xyz() / p.w()
159    }
160
161    pub fn transform_vector3d(&self, vector: Vec3d) -> Vec3d {
162        let v = vector.to_homogeneous_coord_vector();
163        let v = self.transform_homogeneous_coord(v);
164        v.xyz()
165    }
166
167    pub fn transform_normal3d(&self, normal: Vec3d) -> Vec3d {
168        let m = self.matrix.inverse().transpose();
169        let n = normal.to_homogeneous_coord_vector();
170        let n = m * n;
171        n.xyz().normalize()
172    }
173
174    pub fn transform<T: Transformable>(&self, object: T) -> T {
175        object.apply(*self)
176    }
177}
178
179impl Transformable for Transform {
180    fn apply(&self, transform: Transform) -> Self {
181        self.apply_matrix4d(transform.matrix)
182    }
183
184    fn apply_matrix4d(&self, matrix: Mat4d) -> Self {
185        Self::from_matrix4d(matrix * self.matrix)
186    }
187}