JAL-3746 apply copyright to tests
[jalview.git] / test / jalview / math / RotatableMatrixTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.math;
22
23 import static org.testng.Assert.assertEquals;
24
25 import jalview.math.RotatableMatrix.Axis;
26
27 import java.io.ByteArrayOutputStream;
28 import java.io.PrintStream;
29
30 import org.testng.annotations.BeforeMethod;
31 import org.testng.annotations.Test;
32
33 public class RotatableMatrixTest
34 {
35   private RotatableMatrix rm;
36
37   @BeforeMethod(alwaysRun = true)
38   public void setUp()
39   {
40     rm = new RotatableMatrix();
41
42     /*
43      * 0.5 1.0 1.5
44      * 1.0 2.0 3.0
45      * 1.5 3.0 4.5
46      */
47     for (int i = 1; i <= 3; i++)
48     {
49       for (int j = 1; j <= 3; j++)
50       {
51         rm.setValue(i - 1, j - 1, i * j / 2f);
52       }
53     }
54   }
55
56   @Test(groups = "Functional")
57   public void testPrint()
58   {
59     String expected = "0.5 1.0 1.5\n1.0 2.0 3.0\n1.5 3.0 4.5\n";
60     ByteArrayOutputStream os = new ByteArrayOutputStream();
61     PrintStream ps = new PrintStream(os, true);
62     rm.print(ps);
63     String result = new String(os.toByteArray());
64     assertEquals(result, expected);
65   }
66
67   @Test(groups = "Functional")
68   public void testPreMultiply()
69   {
70     float[][] pre = new float[3][3];
71     int i = 1;
72     for (int j = 0; j < 3; j++)
73     {
74       for (int k = 0; k < 3; k++)
75       {
76         pre[j][k] = i++;
77       }
78     }
79
80     rm.preMultiply(pre);
81
82     /*
83      * check rm[i, j] is now the product of the i'th row of pre
84      * and the j'th column of (original) rm
85      */
86     for (int j = 0; j < 3; j++)
87     {
88       for (int k = 0; k < 3; k++)
89       {
90         float expected = 0f;
91         for (int l = 0; l < 3; l++)
92         {
93           float rm_l_k = (l + 1) * (k + 1) / 2f;
94           expected += pre[j][l] * rm_l_k;
95         }
96         assertEquals(rm.getValue(j, k), expected,
97                 String.format("[%d, %d]", j, k));
98       }
99     }
100   }
101
102   @Test(groups = "Functional")
103   public void testVectorMultiply()
104   {
105     float[] result = rm.vectorMultiply(new float[] { 2f, 3f, 4.5f });
106
107     // vector times first column of matrix
108     assertEquals(result[0], 2f * 0.5f + 3f * 1f + 4.5f * 1.5f);
109
110     // vector times second column of matrix
111     assertEquals(result[1], 2f * 1.0f + 3f * 2f + 4.5f * 3f);
112
113     // vector times third column of matrix
114     assertEquals(result[2], 2f * 1.5f + 3f * 3f + 4.5f * 4.5f);
115   }
116
117   @Test(groups = "Functional")
118   public void testGetRotation()
119   {
120     float theta = 60f;
121     double cosTheta = Math.cos((theta * Math.PI / 180f));
122     double sinTheta = Math.sin((theta * Math.PI / 180f));
123
124     /*
125      * sanity check that sin(60) = sqrt(3) / 2, cos(60) = 1/2
126      */
127     double delta = 0.0001d;
128     assertEquals(cosTheta, 0.5f, delta);
129     assertEquals(sinTheta, Math.sqrt(3d) / 2d, delta);
130
131     /*
132      * so far so good, now verify rotations
133      * @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
134      */
135
136     /*
137      * 60 degrees about X axis should be
138      *  1   0   0 
139      *  0  cos -sin
140      *  0  sin cos
141      *  but code applies the negative of this
142      *  nb cos(-x) = cos(x), sin(-x) = -sin(x)
143      */
144     float[][] rot = RotatableMatrix.getRotation(theta, Axis.X);
145     assertEquals(rot[0][0], 1f, delta);
146     assertEquals(rot[0][1], 0f, delta);
147     assertEquals(rot[0][2], 0f, delta);
148     assertEquals(rot[1][0], 0f, delta);
149     assertEquals(rot[1][1], cosTheta, delta);
150     assertEquals(rot[1][2], sinTheta, delta);
151     assertEquals(rot[2][0], 0f, delta);
152     assertEquals(rot[2][1], -sinTheta, delta);
153     assertEquals(rot[2][2], cosTheta, delta);
154
155     /*
156      * 60 degrees about Y axis should be
157      *   cos 0 sin
158      *    0  1  0
159      *  -sin 0 cos
160      *  but code applies the negative of this
161      */
162     rot = RotatableMatrix.getRotation(theta, Axis.Y);
163     assertEquals(rot[0][0], cosTheta, delta);
164     assertEquals(rot[0][1], 0f, delta);
165     assertEquals(rot[0][2], -sinTheta, delta);
166     assertEquals(rot[1][0], 0f, delta);
167     assertEquals(rot[1][1], 1f, delta);
168     assertEquals(rot[1][2], 0f, delta);
169     assertEquals(rot[2][0], sinTheta, delta);
170     assertEquals(rot[2][1], 0f, delta);
171     assertEquals(rot[2][2], cosTheta, delta);
172
173     /*
174      * 60 degrees about Z axis should be
175      *  cos -sin 0
176      *  sin  cos 0
177      *   0    0  1
178      * - and it is!
179      */
180     rot = RotatableMatrix.getRotation(theta, Axis.Z);
181     assertEquals(rot[0][0], cosTheta, delta);
182     assertEquals(rot[0][1], -sinTheta, delta);
183     assertEquals(rot[0][2], 0f, delta);
184     assertEquals(rot[1][0], sinTheta, delta);
185     assertEquals(rot[1][1], cosTheta, delta);
186     assertEquals(rot[1][2], 0f, delta);
187     assertEquals(rot[2][0], 0f, delta);
188     assertEquals(rot[2][1], 0f, delta);
189     assertEquals(rot[2][2], 1f, delta);
190   }
191 }