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