1pub fn transform_points3d(
24 src_points: &[[f64; 3]],
25 dst_r_src: &[[f64; 3]; 3],
26 dst_t_src: &[f64; 3],
27 dst_points: &mut [[f64; 3]],
28) -> Result<(), Box<dyn std::error::Error>> {
29 if dst_points.len() != src_points.len() {
30 return Err("dst_points must have the same length as src_points".into());
31 }
32
33 for (point_dst, point_src) in dst_points.iter_mut().zip(src_points.iter()) {
34 point_dst[0] = dot_product3(&dst_r_src[0], point_src) + dst_t_src[0];
35 point_dst[1] = dot_product3(&dst_r_src[1], point_src) + dst_t_src[1];
36 point_dst[2] = dot_product3(&dst_r_src[2], point_src) + dst_t_src[2];
37 }
38
39 Ok(())
40}
41
42pub fn dot_product3(a: &[f64; 3], b: &[f64; 3]) -> f64 {
68 a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
69}
70
71pub fn matmul33(a: &[[f64; 3]; 3], b: &[[f64; 3]; 3], m: &mut [[f64; 3]; 3]) {
92 m[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0];
93 m[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1];
94 m[0][2] = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2];
95
96 m[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0];
97 m[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1];
98 m[1][2] = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2];
99
100 m[2][0] = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0];
101 m[2][1] = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1];
102 m[2][2] = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2];
103}
104
105pub fn transpose_mat33(a: &[[f64; 3]; 3], m: &mut [[f64; 3]; 3]) {
124 m[0] = [a[0][0], a[1][0], a[2][0]]; m[1] = [a[0][1], a[1][1], a[2][1]]; m[2] = [a[0][2], a[1][2], a[2][2]]; }
128
129pub fn transpose_mat33_inplace(a: &mut [[f64; 3]; 3]) {
144 let a01 = a[0][1];
145 let a02 = a[0][2];
146 let a12 = a[1][2];
147
148 a[0][1] = a[1][0];
149 a[0][2] = a[2][0];
150 a[1][2] = a[2][1];
151 a[1][0] = a01;
152 a[2][0] = a02;
153 a[2][1] = a12;
154}
155
156pub fn mat33_mul_vec3(a: &[[f64; 3]; 3], b: &[f64; 3], m: &mut [f64; 3]) {
177 m[0] = dot_product3(&a[0], b);
178 m[1] = dot_product3(&a[1], b);
179 m[2] = dot_product3(&a[2], b);
180}
181
182pub fn frobenius_norm33(m: &[[f64; 3]; 3]) -> f64 {
202 m.iter().flatten().map(|x| x * x).sum::<f64>().sqrt()
203}
204
205pub fn mat33_div_scalar_inplace(m: &mut [[f64; 3]; 3], scalar: f64) {
221 m.iter_mut().flatten().for_each(|x| *x /= scalar);
222}
223
224pub fn det_mat33(m: &[[f64; 3]; 3]) -> f64 {
244 m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
245 - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
246 + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0])
247}
248
249pub fn cross_vec3(a: &[f64; 3], b: &[f64; 3], c: &mut [f64; 3]) {
270 c[0] = a[1] * b[2] - a[2] * b[1]; c[1] = a[2] * b[0] - a[0] * b[2]; c[2] = a[0] * b[1] - a[1] * b[0]; }
274
275pub fn normalize_mat33_inplace(m: &mut [[f64; 3]; 3]) {
290 let norm = m[2][2];
291 mat33_div_scalar_inplace(m, norm);
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn test_dot_product3() {
300 let a = [1.0, 2.0, 3.0];
301 let b = [4.0, 5.0, 6.0];
302 let result = dot_product3(&a, &b);
303 assert_eq!(result, 32.0);
304 }
305
306 #[test]
307 fn test_matmul33() {
308 let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
309 let b = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
310 let mut m = [[0.0; 3]; 3];
311 matmul33(&a, &b, &mut m);
312 assert_eq!(
313 m,
314 [
315 [30.0, 36.0, 42.0],
316 [66.0, 81.0, 96.0],
317 [102.0, 126.0, 150.0]
318 ]
319 );
320 }
321
322 #[test]
323 fn test_transpose_mat33() {
324 let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
325 let mut m = [[0.0; 3]; 3];
326 transpose_mat33(&a, &mut m);
327 assert_eq!(m, [[1.0, 4.0, 7.0], [2.0, 5.0, 8.0], [3.0, 6.0, 9.0]]);
328 }
329
330 #[test]
331 fn test_transpose_mat33_inplace() {
332 let mut a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
333 transpose_mat33_inplace(&mut a);
334 assert_eq!(a, [[1.0, 4.0, 7.0], [2.0, 5.0, 8.0], [3.0, 6.0, 9.0]]);
335 }
336
337 #[test]
338 fn test_mat33_mul_vec3() {
339 let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
340 let b = [1.0, 2.0, 3.0];
341 let mut m = [0.0; 3];
342 mat33_mul_vec3(&a, &b, &mut m);
343 assert_eq!(m, [14.0, 32.0, 50.0]);
344 }
345
346 #[test]
347 fn test_mat33_div_scalar_inplace() {
348 let mut a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
349 mat33_div_scalar_inplace(&mut a, 2.0);
350 assert_eq!(a, [[0.5, 1.0, 1.5], [2.0, 2.5, 3.0], [3.5, 4.0, 4.5]]);
351 }
352
353 #[test]
354 fn test_det_mat33() {
355 let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
356 let result = det_mat33(&a);
357 assert_eq!(result, 0.0);
358 }
359
360 #[test]
361 fn test_frobenius_norm33() {
362 let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
363 let result = frobenius_norm33(&a);
364 assert_eq!(result, 285.0_f64.sqrt());
365 }
366
367 #[test]
368 fn test_cross_vec3() {
369 let a = [1.0, 2.0, 3.0];
370 let b = [4.0, 5.0, 6.0];
371 let mut c = [0.0; 3];
372 cross_vec3(&a, &b, &mut c);
373 assert_eq!(c, [-3.0, 6.0, -3.0]);
374 }
375
376 #[test]
377 fn test_normalize_mat33_inplace() {
378 let mut a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]];
379 normalize_mat33_inplace(&mut a);
380 assert_eq!(
381 a,
382 [
383 [1.0 / 9.0, 2.0 / 9.0, 3.0 / 9.0],
384 [4.0 / 9.0, 5.0 / 9.0, 6.0 / 9.0],
385 [7.0 / 9.0, 8.0 / 9.0, 9.0 / 9.0]
386 ]
387 );
388 }
389
390 #[test]
391 fn test_transform_points_identity() -> Result<(), Box<dyn std::error::Error>> {
392 let src_points = vec![[2.0, 2.0, 2.0], [3.0, 4.0, 5.0]];
393 let rotation = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]];
394 let translation = [0.0, 0.0, 0.0];
395 let mut dst_points = vec![[0.0; 3]; src_points.len()];
396 transform_points3d(&src_points, &rotation, &translation, &mut dst_points)?;
397
398 assert_eq!(dst_points, src_points);
399
400 Ok(())
401 }
402
403 #[test]
404 fn test_transform_points_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
405 let src_points = vec![[2.0, 2.0, 2.0], [3.0, 4.0, 5.0]];
406 let rotation = [[1.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]];
407 let translation = [1.0, 2.0, 3.0];
408
409 let mut dst_points = vec![[0.0; 3]; src_points.len()];
410 transform_points3d(&src_points, &rotation, &translation, &mut dst_points)?;
411
412 let dst_r_src = {
414 let rotation_slice = unsafe {
415 std::slice::from_raw_parts(rotation.as_ptr() as *const f64, rotation.len() * 3)
416 };
417 faer::mat::from_row_major_slice(rotation_slice, 3, 3)
418 };
419 let dst_t_src = faer::col![translation[0], translation[1], translation[2]];
420 let src_r_dst = dst_r_src.transpose();
422 let src_t_dst = -src_r_dst * dst_t_src;
424 let (rotation_inv, translation_inv) = {
425 let mut rotation_inv = [[0.0; 3]; 3];
426 for (i, row) in rotation_inv.iter_mut().enumerate() {
427 for (j, val) in row.iter_mut().enumerate() {
428 *val = src_r_dst.read(i, j);
429 }
430 }
431 let mut translation_inv = [0.0; 3];
432 for (i, val) in translation_inv.iter_mut().enumerate() {
433 *val = src_t_dst.read(i);
434 }
435 (rotation_inv, translation_inv)
436 };
437
438 let mut dst_points_src = vec![[0.0; 3]; dst_points.len()];
440 transform_points3d(
441 &dst_points,
442 &rotation_inv,
443 &translation_inv,
444 &mut dst_points_src,
445 )?;
446
447 assert_eq!(dst_points_src, src_points);
448
449 Ok(())
450 }
451}