ndarray_vision/transform/
affine.rs1use super::Transform;
2use ndarray::{array, prelude::*};
3use ndarray_linalg::Inverse;
4
5pub fn transform_from_2dmatrix(in_array: Array2<f64>) -> AffineTransform {
7 match in_array.inv() {
8 Ok(inv) => AffineTransform {
9 matrix2d_transform: in_array,
10 matrix2d_transform_inverse: inv,
11 inverse_exists: true,
12 },
13 Err(_e) => AffineTransform {
14 matrix2d_transform: in_array,
15 matrix2d_transform_inverse: Array2::zeros((2, 2)),
16 inverse_exists: false,
17 },
18 }
19}
20
21pub struct AffineTransform {
25 matrix2d_transform: Array2<f64>,
26 matrix2d_transform_inverse: Array2<f64>,
27 inverse_exists: bool,
28}
29
30fn source_coordinate(p: (f64, f64), trans: ArrayView2<f64>) -> (f64, f64) {
31 let p = match trans.shape()[0] {
32 2 => array![[p.0], [p.1]],
33 3 => array![[p.0], [p.1], [1.0]],
34 _ => unreachable!(),
35 };
36
37 let result = trans.dot(&p);
38 let x = result[[0, 0]];
39 let y = result[[1, 0]];
40 let w = match trans.shape()[0] {
41 2 => 1.0,
42 3 => result[[2, 0]],
43 _ => unreachable!(),
44 };
45 if (w - 1.0).abs() > std::f64::EPSILON {
46 (x / w, y / w)
47 } else {
48 (x, y)
49 }
50}
51
52impl Transform for AffineTransform {
53 fn apply(&self, p: (f64, f64)) -> (f64, f64) {
54 return source_coordinate(p, self.matrix2d_transform.view());
55 }
56
57 fn apply_inverse(&self, p: (f64, f64)) -> (f64, f64) {
58 return source_coordinate(p, self.matrix2d_transform_inverse.view());
59 }
60
61 fn inverse_exists(&self) -> bool {
62 self.inverse_exists
63 }
64}
65
66pub enum Axes {
70 X,
71 Y,
72 Z,
73}
74
75pub fn rotate_around_centre(radians: f64, centre: (f64, f64)) -> Array2<f64> {
77 translation(centre.0, centre.1)
78 .dot(&rotation_3d(radians, Axes::Z))
79 .dot(&translation(-centre.0, -centre.1))
80}
81
82pub fn rotation_2d(radians: f64) -> Array2<f64> {
84 let s = radians.sin();
85 let c = radians.cos();
86 array![[c, -s], [s, c]]
87}
88
89pub fn rotation_3d(radians: f64, ax: Axes) -> Array2<f64> {
92 let s = radians.sin();
93 let c = radians.cos();
94
95 match ax {
96 Axes::X => array![[1.0, 0.0, 0.0], [0.0, c, -s], [0.0, s, c]],
97 Axes::Y => array![[c, 0.0, s], [0.0, 1.0, 0.0], [-s, 0.0, c]],
98 Axes::Z => array![[c, -s, 0.0], [s, c, 0.0], [0.0, 0.0, 1.0]],
99 }
100}
101
102pub fn translation(x: f64, y: f64) -> Array2<f64> {
104 array![[1.0, 0.0, x], [0.0, 1.0, y], [0.0, 0.0, 1.0]]
105}
106
107pub fn scale(x: f64, y: f64) -> Array2<f64> {
109 array![[x, 0.0, 0.0], [0.0, y, 0.0], [0.0, 0.0, 1.0]]
110}
111
112pub fn shear(x: f64, y: f64) -> Array2<f64> {
114 array![[1.0, x, 0.0], [y, 1.0, 0.0], [0.0, 0.0, 1.0]]
115}