ruby_math/algebra/
transform.rs1use 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}