1use std::f64::consts::PI;
2
3use crate::core::algebra::{mat3_mat3_mul, mat3_vec3_mul, mat4_vec4_mul};
4
5pub fn transform_nodes(
12 nodes: &mut [[f64; 3]],
13 transformation_matrix: &[[f64; 4]; 4],
14 origin: &[f64; 3],
15) {
16 for node in nodes.iter_mut() {
17 transform_node(node, transformation_matrix, origin)
18 }
19}
20
21pub fn transform_selected_nodes(
34 original_nodes: &[[f64; 3]],
35 node_ids: &[usize],
36 transform_matrix: &[[f64; 4]; 4],
37 origin: &[f64; 3],
38) -> Vec<[f64; 3]> {
39 let mut transformed_nodes = original_nodes.to_vec();
40
41 for &id in node_ids {
42 if id < transformed_nodes.len() {
43 transform_node(&mut transformed_nodes[id], transform_matrix, origin);
44 }
45 }
46
47 transformed_nodes
48}
49
50pub fn transform_node(
57 node: &mut [f64; 3],
58 transformation_matrix: &[[f64; 4]; 4],
59 origin: &[f64; 3],
60) {
61 let new_node = [
62 node[0] - origin[0],
63 node[1] - origin[1],
64 node[2] - origin[2],
65 1.0,
66 ];
67
68 let product = mat4_vec4_mul(transformation_matrix, &new_node);
69
70 node[0] = product[0] + origin[0];
71 node[1] = product[1] + origin[1];
72 node[2] = product[2] + origin[2];
73}
74
75pub fn build_transformation_matrix(
85 translation: [f64; 3],
86 rotation: [f64; 3],
87 scaling: [f64; 3],
88) -> [[f64; 4]; 4] {
89 let mut tmat: [[f64; 4]; 4] = [
90 [1.0, 0.0, 0.0, 0.0],
91 [0.0, 1.0, 0.0, 0.0],
92 [0.0, 0.0, 1.0, 0.0],
93 [0.0, 0.0, 0.0, 1.0],
94 ];
95
96 tmat[0][3] = translation[0];
98 tmat[1][3] = translation[1];
99 tmat[2][3] = translation[2];
100
101 let rot_mat = build_rotation_matrix(&rotation);
103
104 for i in 0..3 {
105 for j in 0..3 {
106 tmat[i][j] = rot_mat[i][j];
107 }
108 }
109
110 for row in tmat.iter_mut().take(3) {
112 row[0] *= scaling[0];
113 row[1] *= scaling[1];
114 row[2] *= scaling[2];
115 }
116
117 tmat
118}
119
120pub fn translate_nodes(nodes: &mut [[f64; 3]], translation: &[f64; 3]) {
126 for node in nodes.iter_mut() {
127 for j in 0..3 {
128 node[j] += translation[j];
129 }
130 }
131}
132
133pub fn rotate_nodes(nodes: &mut [[f64; 3]], theta: &[f64; 3], origin: &[f64; 3]) {
140 let rotation_matrix = build_rotation_matrix(theta);
141
142 nodes
143 .iter_mut()
144 .for_each(|node| rotate_node(node, &rotation_matrix, origin));
145}
146
147pub fn rotate_node(
164 node: &mut [f64; 3],
165 rotation_matrix: &[[f64; 3]; 3],
166 origin: &[f64; 3],
167) {
168 node[0] -= origin[0];
169 node[1] -= origin[1];
170 node[2] -= origin[2];
171
172 let rotated_node = mat3_vec3_mul(rotation_matrix, node);
173
174 node[0] = rotated_node[0] + origin[0];
175 node[1] = rotated_node[1] + origin[1];
176 node[2] = rotated_node[2] + origin[2];
177}
178
179pub fn build_rotation_matrix(theta: &[f64; 3]) -> [[f64; 3]; 3] {
193 let (alpha, beta, gamma) = (
194 theta[0] * PI / 180.0,
195 theta[1] * PI / 180.0,
196 theta[2] * PI / 180.0,
197 );
198
199 let mut rotation_matrix = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]];
200
201 if gamma != 0.0 {
202 let (c, s) = (gamma.cos(), gamma.sin());
203 let r = [[c, -s, 0.0], [s, c, 0.0], [0.0, 0.0, 1.0]];
204 rotation_matrix = mat3_mat3_mul(&r, &rotation_matrix);
205 }
206 if beta != 0.0 {
207 let (c, s) = (beta.cos(), beta.sin());
208 let r = [[c, 0.0, s], [0.0, 1.0, 0.0], [-s, 0.0, c]];
209 rotation_matrix = mat3_mat3_mul(&r, &rotation_matrix);
210 }
211 if alpha != 0.0 {
212 let (c, s) = (alpha.cos(), alpha.sin());
213 let r = [[1.0, 0.0, 0.0], [0.0, c, -s], [0.0, s, c]];
214 rotation_matrix = mat3_mat3_mul(&r, &rotation_matrix);
215 }
216 rotation_matrix
217}
218
219pub fn scale_nodes(nodes: &mut [[f64; 3]], scaling: &[f64; 3], origin: &[f64; 3]) {
226 for node in nodes.iter_mut() {
227 scale_node(node, scaling, origin);
228 }
229}
230
231pub fn scale_node(node: &mut [f64; 3], scaling: &[f64; 3], origin: &[f64; 3]) {
238 for j in 0..3 {
239 node[j] -= origin[j];
240 node[j] *= scaling[j];
241 node[j] += origin[j];
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn test_transform_nodes() {
251 let transformation_matrix =
252 build_transformation_matrix([1.3, 15., 2.5], [25., 25., 25.], [2., 5., 2.]);
253
254 let mut nodes = vec![[1.4, 1.2, 3.5], [34., 23., 53.]];
255
256 transform_nodes(&mut nodes, &transformation_matrix, &[0., 0., 0.]);
257
258 let expected_nodes = vec![
259 [4.260097156389118, 18.32001817946411, 11.047239560979023],
260 [57.90475899451524, 97.23229418127102, 140.77057189748564],
261 ];
262
263 let mut equal = true;
264 'outer: for i in 0..2 {
265 for j in 0..3 {
266 if (nodes[i][j] - expected_nodes[i][j]).abs() > 1e-5 {
267 equal = false;
268 break 'outer;
269 }
270 }
271 }
272
273 assert!(equal);
274 }
275
276 #[test]
277 fn test_rotation_matrix() {
278 let theta: [f64; 3] = [45.0, 45.0, 45.0];
279 let rotation_matrix = build_rotation_matrix(&theta);
280
281 let expected_matrix = [
282 [0.5, -0.5, 0.70710678],
283 [0.85355339, 0.14644661, -0.5],
284 [0.14644661, 0.85355339, 0.5],
285 ];
286
287 let mut equal = true;
288 'outer: for i in 0..3 {
289 for j in 0..3 {
290 if (rotation_matrix[i][j] - expected_matrix[i][j]).abs() > 1e-5 {
291 equal = false;
292 break 'outer;
293 }
294 }
295 }
296
297 assert!(equal);
298 }
299
300 #[test]
301 fn test_rotate_node() {
302 let mut node: [f64; 3] = [1.0, 0.0, 0.0];
303 let origin: [f64; 3] = [0.0, 0.0, 0.0];
304 let rotation_matrix = [
305 [0.5, -0.5, 0.70710678],
306 [0.85355339, 0.14644661, -0.5],
307 [0.14644661, 0.85355339, 0.5],
308 ];
309
310 rotate_node(&mut node, &rotation_matrix, &origin);
311 let expected_node: [f64; 3] = [0.5, 0.85355339, 0.14644661];
312
313 assert!((node[0] - expected_node[0]).abs() < 1e-5);
314 assert!((node[1] - expected_node[1]).abs() < 1e-5);
315 assert!((node[2] - expected_node[2]).abs() < 1e-5);
316 }
317
318 #[test]
319 fn test_rotate_nodes() {
320 let mut nodes = vec![[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]];
321 let theta = [0.0, 0.0, 90.0];
322 let origin = [0.0, 0.0, 0.0];
323
324 rotate_nodes(&mut nodes, &theta, &origin);
325
326 let expected_nodes = vec![[0.0, 1.0, 0.0], [-1.0, 0.0, 0.0]];
327
328 let mut equal = true;
329 'outer: for i in 0..nodes.len() {
330 for j in 0..3 {
331 if (nodes[i][j] - expected_nodes[i][j]).abs() > 1e-5 {
332 equal = false;
333 break 'outer;
334 }
335 }
336 }
337
338 assert!(equal);
339 }
340
341 #[test]
342 fn test_translate_nodes() {
343 let mut nodes = vec![[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]];
344 let translation = [1.0, 1.0, 1.0];
345 translate_nodes(&mut nodes, &translation);
346 assert_eq!(nodes, vec![[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]]);
347 }
348
349 #[test]
350 fn test_scale_nodes() {
351 let mut nodes = vec![[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]];
352 let origin = [1.0, 1.0, 1.0];
353 let scaling = [2.0, 2.0, 2.0];
354 scale_nodes(&mut nodes, &scaling, &origin);
355 assert_eq!(nodes, vec![[1.0, 1.0, 1.0], [3.0, 3.0, 3.0]]);
356 }
357}