1+ use super :: Transform ;
12use ndarray:: { array, prelude:: * } ;
3+ use ndarray_linalg:: Inverse ;
24
5+ /// converts a matrix into an equivalent `AffineTransform`
6+ pub fn transform_from_2dmatrix ( in_array : Array2 < f64 > ) -> AffineTransform {
7+ let transform = match in_array. inv ( ) {
8+ Ok ( inv) => AffineTransform {
9+ matrix2d_transform : in_array. clone ( ) ,
10+ matrix2d_transform_inverse : inv,
11+ inverse_exists : true ,
12+ } ,
13+ Err ( e) => AffineTransform {
14+ matrix2d_transform : in_array. clone ( ) ,
15+ matrix2d_transform_inverse : Array2 :: zeros ( ( 2 , 2 ) ) ,
16+ inverse_exists : false ,
17+ } ,
18+ } ;
19+ return transform;
20+ }
21+
22+ /// a linear transform of an image represented by either size 2x2
23+ /// or 3x3 ( right column is a translation and projection ) matrix applied to the image index
24+ /// coordinates
25+ pub struct AffineTransform {
26+ matrix2d_transform : Array2 < f64 > ,
27+ matrix2d_transform_inverse : Array2 < f64 > ,
28+ inverse_exists : bool ,
29+ }
30+
31+ fn source_coordinate ( p : ( f64 , f64 ) , trans : ArrayView2 < f64 > ) -> ( f64 , f64 ) {
32+ let p = match trans. shape ( ) [ 0 ] {
33+ 2 => array ! [ [ p. 0 ] , [ p. 1 ] ] ,
34+ 3 => array ! [ [ p. 0 ] , [ p. 1 ] , [ 1.0 ] ] ,
35+ _ => unreachable ! ( ) ,
36+ } ;
37+
38+ let result = trans. dot ( & p) ;
39+ let x = result[ [ 0 , 0 ] ] ;
40+ let y = result[ [ 1 , 0 ] ] ;
41+ let w = match trans. shape ( ) [ 0 ] {
42+ 2 => 1.0 ,
43+ 3 => result[ [ 2 , 0 ] ] ,
44+ _ => unreachable ! ( ) ,
45+ } ;
46+ if ( w - 1.0 ) . abs ( ) > std:: f64:: EPSILON {
47+ ( x / w, y / w)
48+ } else {
49+ ( x, y)
50+ }
51+ }
52+
53+ impl Transform for AffineTransform {
54+ fn apply ( & self , p : ( f64 , f64 ) ) -> ( f64 , f64 ) {
55+ return source_coordinate ( p, self . matrix2d_transform . view ( ) ) ;
56+ }
57+
58+ fn apply_inverse ( & self , p : ( f64 , f64 ) ) -> ( f64 , f64 ) {
59+ return source_coordinate ( p, self . matrix2d_transform_inverse . view ( ) ) ;
60+ }
61+
62+ fn inverse_exists ( & self ) -> bool {
63+ return self . inverse_exists ;
64+ }
65+ }
66+
67+ /// describes the Axes to use in rotation_3d
68+ /// X and Y correspond to the image index coordinates and
69+ /// Z is perpendicular out of the image plane
370pub enum Axes {
471 X ,
572 Y ,
673 Z ,
774}
875
76+ /// generates a 2d matrix describing a rotation around a 2d coordinate
977pub fn rotate_around_centre ( radians : f64 , centre : ( f64 , f64 ) ) -> Array2 < f64 > {
1078 translation ( centre. 0 , centre. 1 )
1179 . dot ( & rotation_3d ( radians, Axes :: Z ) )
1280 . dot ( & translation ( -centre. 0 , -centre. 1 ) )
1381}
1482
83+ /// generates a matrix describing 2d rotation around origin
1584pub fn rotation_2d ( radians : f64 ) -> Array2 < f64 > {
1685 let s = radians. sin ( ) ;
1786 let c = radians. cos ( ) ;
1887 array ! [ [ c, -s] , [ s, c] ]
1988}
2089
90+ /// generates a 3x3 matrix describing a rotation around either the index coordinate axes
91+ /// (X,Y) or in the perpendicular axes to the image (Z)
2192pub fn rotation_3d ( radians : f64 , ax : Axes ) -> Array2 < f64 > {
2293 let s = radians. sin ( ) ;
2394 let c = radians. cos ( ) ;
@@ -29,14 +100,17 @@ pub fn rotation_3d(radians: f64, ax: Axes) -> Array2<f64> {
29100 }
30101}
31102
103+ /// generates a matrix describing translation in the image index space
32104pub fn translation ( x : f64 , y : f64 ) -> Array2 < f64 > {
33105 array ! [ [ 1.0 , 0.0 , x] , [ 0.0 , 1.0 , y] , [ 0.0 , 0.0 , 1.0 ] ]
34106}
35107
108+ /// generates a matrix describing scaling in image index space
36109pub fn scale ( x : f64 , y : f64 ) -> Array2 < f64 > {
37110 array ! [ [ x, 0.0 , 0.0 ] , [ 0.0 , y, 0.0 ] , [ 0.0 , 0.0 , 1.0 ] ]
38111}
39112
113+ /// generates a matrix describing shear in image index space
40114pub fn shear ( x : f64 , y : f64 ) -> Array2 < f64 > {
41115 array ! [ [ 1.0 , x, 0.0 ] , [ y, 1.0 , 0.0 ] , [ 0.0 , 0.0 , 1.0 ] ]
42116}
0 commit comments