31b47aac56da483ee0707a9aad70925faf25d39c
[jalview.git] / test / jalview / math / RotatableMatrixTest.java
1 package jalview.math;
2
3 import static org.testng.Assert.assertEquals;
4
5 import jalview.math.RotatableMatrix.Axis;
6
7 import java.io.ByteArrayOutputStream;
8 import java.io.PrintStream;
9
10 import org.testng.annotations.BeforeMethod;
11 import org.testng.annotations.Test;
12
13 public class RotatableMatrixTest
14 {
15   private RotatableMatrix rm;
16
17   @BeforeMethod(alwaysRun = true)
18   public void setUp()
19   {
20     rm = new RotatableMatrix();
21
22     /*
23      * 0.5 1.0 1.5
24      * 1.0 2.0 3.0
25      * 1.5 3.0 4.5
26      */
27     for (int i = 1; i <= 3; i++)
28     {
29       for (int j = 1; j <= 3; j++)
30       {
31         rm.setValue(i - 1, j - 1, i * j / 2f);
32       }
33     }
34   }
35
36   @Test(groups = "Functional")
37   public void testPrint()
38   {
39     String expected = "0.5 1.0 1.5\n1.0 2.0 3.0\n1.5 3.0 4.5\n";
40     ByteArrayOutputStream os = new ByteArrayOutputStream();
41     PrintStream ps = new PrintStream(os, true);
42     rm.print(ps);
43     String result = new String(os.toByteArray());
44     assertEquals(result, expected);
45   }
46
47   @Test(groups = "Functional")
48   public void testPreMultiply()
49   {
50     float[][] pre = new float[3][3];
51     int i = 1;
52     for (int j = 0; j < 3; j++)
53     {
54       for (int k = 0; k < 3; k++)
55       {
56         pre[j][k] = i++;
57       }
58     }
59
60     rm.preMultiply(pre);
61
62     /*
63      * check rm[i, j] is now the product of the i'th row of pre
64      * and the j'th column of (original) rm
65      */
66     for (int j = 0; j < 3; j++)
67     {
68       for (int k = 0; k < 3; k++)
69       {
70         float expected = 0f;
71         for (int l = 0; l < 3; l++)
72         {
73           float rm_l_k = (l + 1) * (k + 1) / 2f;
74           expected += pre[j][l] * rm_l_k;
75         }
76         assertEquals(rm.getValue(j, k), expected,
77                 String.format("[%d, %d]", j, k));
78       }
79     }
80   }
81
82   @Test(groups = "Functional")
83   public void testVectorMultiply()
84   {
85     float[] result = rm.vectorMultiply(new float[] { 2f, 3f, 4.5f });
86
87     // vector times first column of matrix
88     assertEquals(result[0], 2f * 0.5f + 3f * 1f + 4.5f * 1.5f);
89
90     // vector times second column of matrix
91     assertEquals(result[1], 2f * 1.0f + 3f * 2f + 4.5f * 3f);
92
93     // vector times third column of matrix
94     assertEquals(result[2], 2f * 1.5f + 3f * 3f + 4.5f * 4.5f);
95   }
96
97   @Test(groups = "Functional")
98   public void testGetRotation()
99   {
100     float theta = 60f;
101     double cosTheta = Math.cos((theta * Math.PI / 180f));
102     double sinTheta = Math.sin((theta * Math.PI / 180f));
103
104     /*
105      * sanity check that sin(60) = sqrt(3) / 2, cos(60) = 1/2
106      */
107     double delta = 0.0001d;
108     assertEquals(cosTheta, 0.5f, delta);
109     assertEquals(sinTheta, Math.sqrt(3d) / 2d, delta);
110
111     /*
112      * so far so good, now verify rotations
113      * @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
114      */
115
116     /*
117      * 60 degrees about X axis should be
118      *  1   0   0 
119      *  0  cos -sin
120      *  0  sin cos
121      *  but code applies the negative of this
122      *  nb cos(-x) = cos(x), sin(-x) = -sin(x)
123      */
124     float[][] rot = RotatableMatrix.getRotation(theta, Axis.X);
125     assertEquals(rot[0][0], 1f, delta);
126     assertEquals(rot[0][1], 0f, delta);
127     assertEquals(rot[0][2], 0f, delta);
128     assertEquals(rot[1][0], 0f, delta);
129     assertEquals(rot[1][1], cosTheta, delta);
130     assertEquals(rot[1][2], sinTheta, delta);
131     assertEquals(rot[2][0], 0f, delta);
132     assertEquals(rot[2][1], -sinTheta, delta);
133     assertEquals(rot[2][2], cosTheta, delta);
134
135     /*
136      * 60 degrees about Y axis should be
137      *   cos 0 sin
138      *    0  1  0
139      *  -sin 0 cos
140      *  but code applies the negative of this
141      */
142     rot = RotatableMatrix.getRotation(theta, Axis.Y);
143     assertEquals(rot[0][0], cosTheta, delta);
144     assertEquals(rot[0][1], 0f, delta);
145     assertEquals(rot[0][2], -sinTheta, delta);
146     assertEquals(rot[1][0], 0f, delta);
147     assertEquals(rot[1][1], 1f, delta);
148     assertEquals(rot[1][2], 0f, delta);
149     assertEquals(rot[2][0], sinTheta, delta);
150     assertEquals(rot[2][1], 0f, delta);
151     assertEquals(rot[2][2], cosTheta, delta);
152
153     /*
154      * 60 degrees about Z axis should be
155      *  cos -sin 0
156      *  sin  cos 0
157      *   0    0  1
158      * - and it is!
159      */
160     rot = RotatableMatrix.getRotation(theta, Axis.Z);
161     assertEquals(rot[0][0], cosTheta, delta);
162     assertEquals(rot[0][1], -sinTheta, delta);
163     assertEquals(rot[0][2], 0f, delta);
164     assertEquals(rot[1][0], sinTheta, delta);
165     assertEquals(rot[1][1], cosTheta, delta);
166     assertEquals(rot[1][2], 0f, delta);
167     assertEquals(rot[2][0], 0f, delta);
168     assertEquals(rot[2][1], 0f, delta);
169     assertEquals(rot[2][2], 1f, delta);
170   }
171 }