X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fmath%2FRotatableMatrix.java;h=f3bf436e13bb5b03877a796fa04a2ac4a1c54316;hb=7420ce36f2b43280ef610e3743960207e4c2dbe3;hp=d9f4bd588af1b88d35d0a3e3f053eba53bbb47cd;hpb=99c58ee0ae2a848f982552e53feaf6d5cb9925e5;p=jalview.git diff --git a/src/jalview/math/RotatableMatrix.java b/src/jalview/math/RotatableMatrix.java index d9f4bd5..f3bf436 100755 --- a/src/jalview/math/RotatableMatrix.java +++ b/src/jalview/math/RotatableMatrix.java @@ -1,389 +1,258 @@ -/* -* Jalview - A Sequence Alignment Editor and Viewer -* Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -*/ - -package jalview.math; - - - -public class RotatableMatrix { - - float matrix[][]; - - float[] temp; - - float[][] rot; - - - - public RotatableMatrix(int rows, int cols) { - - matrix = new float[rows][cols]; - - temp = new float[3]; - - rot = new float[3][3]; - - } - - - - public void addElement(int i, int j, float value) { - - matrix[i][j] = value; - - } - - - - public void print() { - - System.out.println(matrix[0][0] + " " + matrix[0][1] + " " + matrix[0][2]); - - System.out.println(matrix[1][0] + " " + matrix[1][1] + " " + matrix[1][2]); - - System.out.println(matrix[2][0] + " " + matrix[2][1] + " " + matrix[2][2]); - - } - - - - public void rotate (float degrees, char axis) { - - - - float costheta = (float)Math.cos(degrees*Math.PI/(float)180.0); - - float sintheta = (float)Math.sin(degrees*Math.PI/(float)180.0); - - - - if (axis == 'z') { - - - - rot[0][0] = (float)costheta; - - rot[0][1] = (float)-sintheta; - - rot[0][2] = (float)0.0; - - - - rot[1][0] = (float)sintheta; - - rot[1][1] = (float)costheta; - - rot[1][2] = (float)0.0; - - - - rot[2][0] = (float)0.0; - - rot[2][1] = (float)0.0; - - rot[2][2] = (float)1.0; - - - - preMultiply(rot); - - } - - if (axis == 'x') { - - rot[0][0] = (float)1.0; - - rot[0][1] = (float)0.0; - - rot[0][2] = (float)0.0; - - - - rot[1][0] = (float)0.0; - - rot[1][1] = (float)costheta; - - rot[1][2] = (float)sintheta; - - - - rot[2][0] = (float)0.0; - - rot[2][1] = (float)-sintheta; - - rot[2][2] = (float)costheta; - - - - preMultiply(rot); - - - - } - - if (axis == 'y') { - - rot[0][0] = (float)costheta; - - rot[0][1] = (float)0.0; - - rot[0][2] = (float)-sintheta; - - - - rot[1][0] = (float)0.0; - - rot[1][1] = (float)1.0; - - rot[1][2] = (float)0.0; - - - - rot[2][0] = (float)sintheta; - - rot[2][1] = (float)0.0; - - rot[2][2] = (float)costheta; - - - - preMultiply(rot); - - - - } - - - - } - - - - public float[] vectorMultiply(float[] vect) { - - temp[0] = vect[0]; - - temp[1] = vect[1]; - - temp[2] = vect[2]; - - - - for (int i = 0; i < 3; i++) { - - temp[i] = matrix[i][0]*vect[0] + matrix[i][1]*vect[1] + matrix[i][2]*vect[2]; - - } - - - - vect[0] = temp[0]; - - vect[1] = temp[1]; - - vect[2] = temp[2]; - - - - return vect; - - } - - - - public void preMultiply(float mat[][]) { - - float tmp[][] = new float[3][3]; - - - - for (int i = 0; i < 3 ; i++) { - - for (int j = 0; j < 3; j++ ) { - - tmp[i][j] = mat[i][0]*matrix[0][j] + - - mat[i][1]*matrix[1][j] + - - mat[i][2]*matrix[2][j]; - - } - - } - - - - for (int i = 0; i < 3 ; i++) { - - for (int j = 0; j < 3; j++ ) { - - matrix[i][j] = tmp[i][j]; - - } - - } - - } - - - - public void postMultiply(float mat[][]) { - - float tmp[][] = new float[3][3]; - - - - for (int i = 0; i < 3 ; i++) { - - for (int j = 0; j < 3; j++ ) { - - tmp[i][j] = matrix[i][0]*mat[0][j] + - - matrix[i][1]*mat[1][j] + - - matrix[i][2]*mat[2][j]; - - } - - } - - - - for (int i = 0; i < 3 ; i++) { - - for (int j = 0; j < 3; j++ ) { - - matrix[i][j] = tmp[i][j]; - - } - - } - - } - - - - public static void main(String[] args) { - - - - RotatableMatrix m = new RotatableMatrix(3,3); - - m.addElement(0,0,1); - - m.addElement(0,1,0); - - m.addElement(0,2,0); - - m.addElement(1,0,0); - - m.addElement(1,1,2); - - m.addElement(1,2,0); - - m.addElement(2,0,0); - - m.addElement(2,1,0); - - m.addElement(2,2,1); - - - - m.print(); - - - - RotatableMatrix n = new RotatableMatrix(3,3); - - n.addElement(0,0,2); - - n.addElement(0,1,1); - - n.addElement(0,2,1); - - n.addElement(1,0,2); - - n.addElement(1,1,1); - - n.addElement(1,2,1); - - n.addElement(2,0,2); - - n.addElement(2,1,1); - - n.addElement(2,2,1); - - - - n.print(); - - - - //m.postMultiply(n.matrix); - - //m.print(); - - // m.rotate(45,'z',new RotatableMatrix(3,3)); - - - - float vect[] = new float[3]; - - vect[0] = 2; - - vect[1] = 4; - - vect[2] = 6; - - - - vect = m.vectorMultiply(vect); - - System.out.println(vect[0] + " " + vect[1] + " " + vect[2]); - - - - } - - public void setIdentity() { - - matrix[0][0] = (float)1.0; - - matrix[1][1] = (float)1.0; - - matrix[2][2] = (float)1.0; - - matrix[0][1] = (float)0.0; - - matrix[0][2] = (float)0.0; - - matrix[1][0] = (float)0.0; - - matrix[1][2] = (float) 0.0; - - matrix[2][0] = (float)0.0; - - matrix[2][1] = (float)0.0; - - } - -} - - - +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.math; + +import jalview.datamodel.Point; + +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Model for a 3x3 matrix which provides methods for rotation in 3-D space + */ +public class RotatableMatrix +{ + private static final int DIMS = 3; + + /* + * cache the most used rotations: +/- 1, 2, 3, 4 degrees around x or y axis + */ + private static Map> cachedRotations; + + static + { + cachedRotations = new HashMap<>(); + for (Axis axis : Axis.values()) + { + HashMap map = new HashMap<>(); + cachedRotations.put(axis, map); + for (int deg = 1; deg < 5; deg++) + { + float[][] rotation = getRotation(deg, axis); + map.put(Float.valueOf(deg), rotation); + rotation = getRotation(-deg, axis); + map.put(Float.valueOf(-deg), rotation); + } + } + } + + public enum Axis + { + X, Y, Z + } + + float[][] matrix; + + /** + * Constructor creates a new identity matrix (all values zero except for 1 on + * the diagonal) + */ + public RotatableMatrix() + { + matrix = new float[DIMS][DIMS]; + for (int j = 0; j < DIMS; j++) + { + matrix[j][j] = 1f; + } + } + + /** + * Sets the value at position (i, j) of the matrix + * + * @param i + * @param j + * @param value + */ + public void setValue(int i, int j, float value) + { + matrix[i][j] = value; + } + + /** + * Answers the value at position (i, j) of the matrix + * + * @param i + * @param j + * @return + */ + public float getValue(int i, int j) + { + return matrix[i][j]; + } + + /** + * Prints the matrix in rows of space-delimited values + */ + public void print(PrintStream ps) + { + ps.println(matrix[0][0] + " " + matrix[0][1] + " " + matrix[0][2]); + ps.println(matrix[1][0] + " " + matrix[1][1] + " " + matrix[1][2]); + ps.println(matrix[2][0] + " " + matrix[2][1] + " " + matrix[2][2]); + } + + /** + * Rotates the matrix through the specified number of degrees around the + * specified axis + * + * @param degrees + * @param axis + */ + public void rotate(float degrees, Axis axis) + { + float[][] rot = getRotation(degrees, axis); + + preMultiply(rot); + } + + /** + * Answers a matrix which, when it pre-multiplies another matrix, applies a + * rotation of the specified number of degrees around the specified axis + * + * @param degrees + * @param axis + * @return + * @see https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + */ + protected static float[][] getRotation(float degrees, Axis axis) + { + Float floatValue = Float.valueOf(degrees); + if (cachedRotations.get(axis).containsKey(floatValue)) + { + // System.out.println("getRotation from cache: " + (int) degrees); + return cachedRotations.get(axis).get(floatValue); + } + + float costheta = (float) Math.cos(degrees * Math.PI / 180f); + + float sintheta = (float) Math.sin(degrees * Math.PI / 180f); + + float[][] rot = new float[DIMS][DIMS]; + + switch (axis) + { + case X: + rot[0][0] = 1f; + rot[1][1] = costheta; + rot[1][2] = sintheta; + rot[2][1] = -sintheta; + rot[2][2] = costheta; + break; + case Y: + rot[0][0] = costheta; + rot[0][2] = -sintheta; + rot[1][1] = 1f; + rot[2][0] = sintheta; + rot[2][2] = costheta; + break; + case Z: + rot[0][0] = costheta; + rot[0][1] = -sintheta; + rot[1][0] = sintheta; + rot[1][1] = costheta; + rot[2][2] = 1f; + break; + } + return rot; + } + + /** + * Answers a new array of float values which is the result of pre-multiplying + * this matrix by the given vector. Each value of the result is the dot + * product of the vector with one column of this matrix. The matrix and input + * vector are not modified. + * + * @param vect + * + * @return + */ + public float[] vectorMultiply(float[] vect) + { + float[] result = new float[DIMS]; + + for (int i = 0; i < DIMS; i++) + { + result[i] = (matrix[i][0] * vect[0]) + (matrix[i][1] * vect[1]) + + (matrix[i][2] * vect[2]); + } + + return result; + } + + /** + * Performs pre-multiplication of this matrix by the given one. Value (i, j) + * of the result is the dot product of the i'th row of mat with + * the j'th column of this matrix. + * + * @param mat + */ + public void preMultiply(float[][] mat) + { + float[][] tmp = new float[DIMS][DIMS]; + + for (int i = 0; i < DIMS; i++) + { + for (int j = 0; j < DIMS; j++) + { + tmp[i][j] = (mat[i][0] * matrix[0][j]) + (mat[i][1] * matrix[1][j]) + + (mat[i][2] * matrix[2][j]); + } + } + + matrix = tmp; + } + + /** + * Performs post-multiplication of this matrix by the given one. Value (i, j) + * of the result is the dot product of the i'th row of this matrix with the + * j'th column of mat. + * + * @param mat + */ + public void postMultiply(float[][] mat) + { + float[][] tmp = new float[DIMS][DIMS]; + + for (int i = 0; i < DIMS; i++) + { + for (int j = 0; j < DIMS; j++) + { + tmp[i][j] = (matrix[i][0] * mat[0][j]) + (matrix[i][1] * mat[1][j]) + + (matrix[i][2] * mat[2][j]); + } + } + + matrix = tmp; + } + + /** + * Performs a vector multiplication whose result is the Point representing the + * input point's value vector post-multiplied by this matrix. + * + * @param coord + * @return + */ + public Point vectorMultiply(Point coord) + { + float[] v = vectorMultiply(new float[] { coord.x, coord.y, coord.z }); + return new Point(v[0], v[1], v[2]); + } +}