1extern crate num_traits;
2
3use nalgebra::{DMatrix, Dim, Matrix3, VecStorage, Vector2, Vector3, QR};
4
5#[derive(Debug)]
6pub enum Direction {
8 ToSlide,
10 FromSlide,
12}
13
14pub trait TransformScalar:
16 nalgebra::Scalar
17 + num_traits::identities::Zero
18 + num_traits::identities::One
19 + nalgebra::ClosedAdd
20 + nalgebra::ClosedMul
21 + nalgebra::ComplexField
22 + Copy
23{
24}
25impl<T> TransformScalar for T where
26 T: nalgebra::Scalar
27 + num_traits::identities::Zero
28 + num_traits::identities::One
29 + nalgebra::ClosedAdd
30 + nalgebra::ClosedMul
31 + nalgebra::ComplexField
32 + Copy
33{
34}
35
36#[derive(Debug)]
38pub struct AffineTransform<T>
39where
40 T: TransformScalar,
41{
42 direction: Direction,
43
44 matrix: Matrix3<T>,
45 inv_matix: Option<Matrix3<T>>,
46}
47
48fn points_to_dmatrix<T>(points: Vec<Vector2<T>>) -> DMatrix<T>
49where
50 T: TransformScalar,
51{
52 let mut data: Vec<T> = Vec::with_capacity(points.len() * 3);
53
54 for coord in 0..3 {
55 if coord < 2 {
56 for index in 0..points.len() {
57 let point = points.get(index).expect("Point should be present");
58
59 data.push(point[coord]);
60 }
61 } else {
62 for _index in 0..points.len() {
63 data.push(T::one());
64 }
65 }
66 }
67
68 let vec_storage = VecStorage::new(Dim::from_usize(points.len()), Dim::from_usize(3), data);
69 DMatrix::from_data(vec_storage)
70}
71
72impl<T> AffineTransform<T>
73where
74 T: TransformScalar,
75{
76 pub fn identity() -> Self {
78 let mut matrix = Matrix3::zeros();
79 matrix.m11 = T::one();
80 matrix.m22 = T::one();
81 matrix.m33 = T::one();
82
83 let inv_matrix = matrix.try_inverse();
84
85 AffineTransform {
86 direction: Direction::ToSlide,
87 matrix,
88 inv_matix: inv_matrix,
89 }
90 }
91
92 pub fn from_points(moving_points: Vec<Vector2<T>>, fixed_points: Vec<Vector2<T>>) -> Self {
94 let moving = points_to_dmatrix(moving_points);
95 let fixed = points_to_dmatrix(fixed_points);
96
97 let qr = QR::new(fixed);
98 let res = qr.solve(&moving).unwrap();
99 let mut matrix = Matrix3::zeros();
102
103 matrix.m11 = res[(0, 0)];
104 matrix.m21 = res[(0, 1)]; matrix.m31 = res[(0, 2)]; matrix.m12 = res[(1, 0)]; matrix.m22 = res[(1, 1)]; matrix.m32 = res[(1, 2)]; matrix.m13 = res[(2, 0)]; matrix.m23 = res[(2, 1)]; matrix.m33 = T::one();
112
113 AffineTransform {
114 direction: Direction::ToSlide,
115 matrix,
116 inv_matix: matrix.try_inverse(),
117 }
118 }
119
120 pub fn inverse_transform(&self) -> Option<AffineTransform<T>> {
122 let direction = match self.direction {
124 Direction::ToSlide => Direction::FromSlide,
125 Direction::FromSlide => Direction::ToSlide,
126 };
127
128 Some(AffineTransform {
129 direction,
130 matrix: Matrix3::<T>::identity() * self.inv_matix?,
131 inv_matix: Some(Matrix3::<T>::identity() * self.matrix),
132 })
133 }
134
135 pub fn to_slide_matrix(&self) -> Option<&Matrix3<T>> {
137 match self.direction {
138 Direction::ToSlide => Some(&self.matrix),
139 Direction::FromSlide => self.inv_matix.as_ref(),
140 }
141 }
142
143 pub fn from_slide_matrix(&self) -> Option<&Matrix3<T>> {
145 match self.direction {
146 Direction::ToSlide => self.inv_matix.as_ref(),
147 Direction::FromSlide => Some(&self.matrix),
148 }
149 }
150
151 pub fn transform_to_slide(&self, x: T, y: T) -> Option<Vector3<T>> {
160 let point = Vector3::new(x, y, T::one());
161 let point = self.to_slide_matrix()? * point;
162
163 Some(point)
164 }
165
166 pub fn transform_from_slide(&self, x: T, y: T) -> Option<Vector3<T>> {
168 let point = Vector3::new(x, y, T::one());
169 let point = self.from_slide_matrix()? * point;
170
171 Some(point)
172 }
173
174 }