optic_render/util/transform/
trans3d.rs1use cgmath::*;
2
3#[derive(Clone, Debug)]
34pub struct Transform3D {
35 matrix: Matrix4<f32>,
36 pos: Vector3<f32>,
37 rot: Vector3<f32>,
38 scale: Vector3<f32>,
39}
40
41impl Default for Transform3D {
42 fn default() -> Self {
43 Self {
44 matrix: Matrix4::identity(),
45 pos: Vector3::new(0.0, 0.0, 0.0),
46 rot: Vector3::new(0.0, 0.0, 0.0),
47 scale: Vector3::new(1.0, 1.0, 1.0),
48 }
49 }
50}
51
52impl Transform3D {
53 fn calc_pos_matrix(&self) -> Matrix4<f32> {
54 Matrix4::from_translation(self.pos)
55 }
56
57 fn calc_rot_matrix(&self) -> Matrix4<f32> {
58 let x = Matrix4::from_angle_x(Rad::from(Deg(self.rot.x)));
59 let y = Matrix4::from_angle_y(Rad::from(Deg(self.rot.y)));
60 let z = Matrix4::from_angle_z(Rad::from(Deg(self.rot.z)));
61 x * y * z
62 }
63
64 fn calc_scale_matrix(&self) -> Matrix4<f32> {
65 Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z)
66 }
67
68 pub fn calc_matrix(&mut self) {
70 self.matrix = self.calc_pos_matrix() * self.calc_rot_matrix() * self.calc_scale_matrix();
71 }
72
73 pub fn pos(&self) -> Vector3<f32> { self.pos }
75 pub fn rot(&self) -> Vector3<f32> { self.rot }
77 pub fn scale(&self) -> Vector3<f32> { self.scale }
79 pub fn matrix(&self) -> Matrix4<f32> { self.matrix }
81
82 pub fn move_all(&mut self, x: f32, y: f32, z: f32) { self.pos += vec3(x, y, z); }
84 pub fn move_x(&mut self, x: f32) { self.pos.x += x; }
86 pub fn move_y(&mut self, y: f32) { self.pos.y += y; }
88 pub fn move_z(&mut self, z: f32) { self.pos.z += z; }
90 pub fn set_pos_all(&mut self, x: f32, y: f32, z: f32) { self.pos = vec3(x, y, z); }
92 pub fn set_pos_x(&mut self, x: f32) { self.pos.x = x; }
94 pub fn set_pos_y(&mut self, y: f32) { self.pos.y = y; }
96 pub fn set_pos_z(&mut self, z: f32) { self.pos.z = z; }
98
99 pub fn rotate_all(&mut self, x: f32, y: f32, z: f32) { self.rot += vec3(x, y, z); }
101 pub fn rotate_x(&mut self, x: f32) { self.rot.x += x; }
103 pub fn rotate_y(&mut self, y: f32) { self.rot.y += y; }
105 pub fn rotate_z(&mut self, z: f32) { self.rot.z += z; }
107 pub fn set_rot_all(&mut self, x: f32, y: f32, z: f32) { self.rot = vec3(x, y, z); }
109 pub fn set_rot_x(&mut self, x: f32) { self.rot.x = x; }
111 pub fn set_rot_y(&mut self, y: f32) { self.rot.y = y; }
113 pub fn set_rot_z(&mut self, z: f32) { self.rot.z = z; }
115
116 pub fn scale_all(&mut self, x: f32, y: f32, z: f32) { self.scale += vec3(x, y, z); }
118 pub fn scale_same(&mut self, xyz: f32) { self.scale_all(xyz, xyz, xyz); }
120 pub fn scale_x(&mut self, x: f32) { self.scale.x += x; }
122 pub fn scale_y(&mut self, y: f32) { self.scale.y += y; }
124 pub fn scale_z(&mut self, z: f32) { self.scale.z += z; }
126 pub fn set_scale_all(&mut self, x: f32, y: f32, z: f32) { self.scale = vec3(x, y, z); }
128 pub fn set_scale_same(&mut self, xyz: f32) { self.set_scale_all(xyz, xyz, xyz); }
130 pub fn set_scale_x(&mut self, x: f32) { self.scale.x = x; }
132 pub fn set_scale_y(&mut self, y: f32) { self.scale.y = y; }
134 pub fn set_scale_z(&mut self, z: f32) { self.scale.z = z; }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 fn approx_eq(a: f32, b: f32) -> bool {
143 (a - b).abs() < 1e-5
144 }
145
146 fn mat_approx_eq(m1: &Matrix4<f32>, m2: &Matrix4<f32>) -> bool {
147 for c in 0..4 {
148 for r in 0..4 {
149 if !approx_eq(m1[c][r], m2[c][r]) {
150 return false;
151 }
152 }
153 }
154 true
155 }
156
157 fn is_identity(m: &Matrix4<f32>) -> bool {
158 mat_approx_eq(m, &Matrix4::identity())
159 }
160
161 #[test]
162 fn transform3d_default() {
163 let t = Transform3D::default();
164 assert_eq!(t.pos(), vec3(0.0, 0.0, 0.0));
165 assert_eq!(t.rot(), vec3(0.0, 0.0, 0.0));
166 assert_eq!(t.scale(), vec3(1.0, 1.0, 1.0));
167 assert!(is_identity(&t.matrix()));
168 }
169
170 #[test]
171 fn transform3d_set_pos() {
172 let mut t = Transform3D::default();
173 t.set_pos_all(10.0, 20.0, 30.0);
174 assert_eq!(t.pos(), vec3(10.0, 20.0, 30.0));
175 }
176
177 #[test]
178 fn transform3d_move() {
179 let mut t = Transform3D::default();
180 t.move_all(1.0, 2.0, 3.0);
181 assert_eq!(t.pos(), vec3(1.0, 2.0, 3.0));
182 t.move_x(10.0);
183 assert_eq!(t.pos().x, 11.0);
184 t.move_y(20.0);
185 assert_eq!(t.pos().y, 22.0);
186 t.move_z(30.0);
187 assert_eq!(t.pos().z, 33.0);
188 }
189
190 #[test]
191 fn transform3d_rotate() {
192 let mut t = Transform3D::default();
193 t.rotate_all(90.0, 0.0, 0.0);
194 assert_eq!(t.rot(), vec3(90.0, 0.0, 0.0));
195 t.rotate_x(45.0);
196 assert!(approx_eq(t.rot().x, 135.0));
197 t.rotate_y(30.0);
198 assert!(approx_eq(t.rot().y, 30.0));
199 t.rotate_z(60.0);
200 assert!(approx_eq(t.rot().z, 60.0));
201 }
202
203 #[test]
204 fn transform3d_set_rot() {
205 let mut t = Transform3D::default();
206 t.set_rot_all(45.0, 90.0, 180.0);
207 assert_eq!(t.rot(), vec3(45.0, 90.0, 180.0));
208 t.set_rot_x(10.0);
209 t.set_rot_y(20.0);
210 t.set_rot_z(30.0);
211 assert_eq!(t.rot(), vec3(10.0, 20.0, 30.0));
212 }
213
214 #[test]
215 fn transform3d_scale() {
216 let mut t = Transform3D::default();
217 t.set_scale_all(2.0, 3.0, 4.0);
218 assert_eq!(t.scale(), vec3(2.0, 3.0, 4.0));
219 }
220
221 #[test]
222 fn transform3d_scale_operations() {
223 let mut t = Transform3D::default();
224 t.scale_all(1.0, 2.0, 3.0);
225 assert_eq!(t.scale(), vec3(2.0, 3.0, 4.0));
226 t.scale_same(5.0);
227 assert_eq!(t.scale(), vec3(7.0, 8.0, 9.0));
228 t.scale_x(1.0);
229 t.scale_y(1.0);
230 t.scale_z(1.0);
231 assert_eq!(t.scale(), vec3(8.0, 9.0, 10.0));
232 }
233
234 #[test]
235 fn transform3d_set_scale_individual() {
236 let mut t = Transform3D::default();
237 t.set_scale_x(5.0);
238 t.set_scale_y(6.0);
239 t.set_scale_z(7.0);
240 assert_eq!(t.scale(), vec3(5.0, 6.0, 7.0));
241 }
242
243 #[test]
244 fn transform3d_calc_matrix() {
245 let mut t = Transform3D::default();
246 t.calc_matrix();
248 assert!(is_identity(&t.matrix()));
249
250 t.set_pos_all(1.0, 2.0, 3.0);
252 t.calc_matrix();
253 let m = t.matrix();
254 assert!(approx_eq(m[3][0], 1.0));
255 assert!(approx_eq(m[3][1], 2.0));
256 assert!(approx_eq(m[3][2], 3.0));
257 }
258
259 #[test]
260 fn transform3d_matrix_combines() {
261 let mut t = Transform3D::default();
262 t.set_pos_all(10.0, 0.0, 0.0);
263 t.set_scale_all(2.0, 1.0, 1.0);
264 t.calc_matrix();
265 let m = t.matrix();
266 assert!(approx_eq(m[0][0], 2.0));
268 assert!(approx_eq(m[3][0], 10.0));
269 }
270
271 #[test]
272 fn transform3d_set_scale_same() {
273 let mut t = Transform3D::default();
274 t.set_scale_same(3.0);
275 assert_eq!(t.scale(), vec3(3.0, 3.0, 3.0));
276 }
277}