/* * Moonlight|3D Copyright (C) 2005 The Moonlight|3D team * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Created on Jan 5, 2005 */ package ml.math; /** * The Matrix3 class is a representation of a 4x4 matrix and some of the * operations possible on it. * * @author gregor */ public class Matrix4 implements Cloneable { public double X[][]; // first index is row, second index is column /** * Simple constructor. it does not initialise the values * of the matrix. */ public Matrix4() { X=new double[4][]; for(int i=0;i<4;i++) { X[i]=new double[4]; } } /** * Construct a new matrix from a 3x3 matrix * * @param matrix the 3x3 matrix to extend */ public Matrix4(Matrix3 matrix) { X=new double[4][]; for(int i=0;i<4;i++) { X[i]=new double[4]; } fromMatrix3(matrix); } /** * Clear the matrix by setting all values to 0.0. */ public void clear() { for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { X[i][j]=0.0; } } } /** * Set this matrix to the identity matrix. */ public void setIdentity() { for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { if(i!=j) { X[i][j]=0.0; } else { X[i][j]=1.0; } } } } /** * Return a deep copy of the matrix. * * @return a copy of the matrix */ @Override public Matrix4 clone() { Matrix4 ret=new Matrix4(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { ret.X[i][j]=X[i][j]; } } return ret; } /** * Build the transpose of the matrix and return it. This does * not affect the original matrix instance. * * @return the transposed matrix \f$A^T\f$ */ public Matrix4 transpose() { Matrix4 ret=new Matrix4(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { ret.X[j][i]=X[i][j]; } } return ret; } /** * returns the subdeterminant composed by the given rows and colums, \f$ * X_{r_0,c_0} \left( X_{r_1,c_1} X_{r_2,c_2} - X_{r_2,c_1} X_{r_1,c_2} * \right) - X_{r_0,c_1} \left( X_{r_1,c_0} X_{r_2,c_2} - X_{r_2,c_0} * X_{r_1,c_2} \right) + X_{r_0,c_2} \left( X_{r_1,c_0} X_{r_2,c_1} - * X_{r_2,c_0} X_{r_1,c_1} \right) \f$ */ protected double subDeterminant(int r0, int r1, int r2, int c0, int c1, int c2) { return X[r0][c0] * (X[r1][c1] * X[r2][c2] - X[r2][c1] * X[r1][c2]) - X[r0][c1] * (X[r1][c0] * X[r2][c2] - X[r2][c0] * X[r1][c2]) + X[r0][c2] * (X[r1][c0] * X[r2][c1] - X[r2][c0] * X[r1][c1]); } /** * @return the determinant of the matirx, \f$ \det A \f$ */ public double det() { return X[0][0] * subDeterminant(1, 2, 3, 1, 2, 3) - X[0][1] * subDeterminant(1, 2, 3, 0, 2, 3) + X[0][2] * subDeterminant(1, 2, 3, 0, 1, 3) - X[0][3] * subDeterminant(1, 2, 3, 0, 1, 2); } /** * Calculate the adjoint of this matrix and return it. This * operation does not affect the current matrix. * * @return the adjoint of this matrix */ Matrix4 adjoint() { Matrix4 a = new Matrix4(); a.X[0][0] = subDeterminant(1, 2, 3, 1, 2, 3); a.X[0][1] = -subDeterminant(0, 2, 3, 1, 2, 3); a.X[0][2] = subDeterminant(0, 1, 3, 1, 2, 3); a.X[0][3] = -subDeterminant(0, 1, 2, 1, 2, 3); a.X[1][0] = -subDeterminant(1, 2, 3, 0, 2, 3); a.X[1][1] = subDeterminant(0, 2, 3, 0, 2, 3); a.X[1][2] = -subDeterminant(0, 1, 3, 0, 2, 3); a.X[1][3] = subDeterminant(0, 1, 2, 0, 2, 3); a.X[2][0] = subDeterminant(1, 2, 3, 0, 1, 3); a.X[2][1] = -subDeterminant(0, 2, 3, 0, 1, 3); a.X[2][2] = subDeterminant(0, 1, 3, 0, 1, 3); a.X[2][3] = -subDeterminant(0, 1, 2, 0, 1, 3); a.X[3][0] = -subDeterminant(1, 2, 3, 0, 1, 2); a.X[3][1] = subDeterminant(0, 2, 3, 0, 1, 2); a.X[3][2] = -subDeterminant(0, 1, 3, 0, 1, 2); a.X[3][3] = subDeterminant(0, 1, 2, 0, 1, 2); return a; } /** * returns the inverse matrix, \f$ A^{-1} \f$ */ public Matrix4 invert() { Matrix4 a; double invDet = 1.0 / det(); a = adjoint(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { a.X[i][j] *= invDet; } } return a; } /** * Return a human readable string representation of this matrix * suitable for debugging output. * * @return the multi-line string as an array */ public String[] toStringArray() { String[] ret=new String[4]; for(int i=0;i<4;i++) { ret[i]="(" + X[i][0] + ", " + X[i][1] + ", " + X[i][2] + ", " + X[i][3] + ")"; } return ret; } /** * Return a representation of this matrix suitable for use with * OpenGL. * * @return the matrix as a onedimensional array of doubles */ public double[] getOpenGLMatrix() { double[] openGLMatrix = new double[16]; int index = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { openGLMatrix[index] = X[j][i]; index++; } } return openGLMatrix; } /** * Set the matrix from the representation that is used by OpenGL. * * @param openGLMatrix the matrix as onedimensional array of doubles */ public void setFromOpenGLMatrix(double[] openGLMatrix) { int index = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { X[j][i] = openGLMatrix[index]; index++; } } } /** * Populate the matrix with a translation by the given vector. * * @param translation translation vector for transformation */ public void fromTranslation(Vector3D translation) { setIdentity(); X[0][3]=translation.X1; X[1][3]=translation.X2; X[2][3]=translation.X3; } /** * Populate the matrix with a non-uniform scale with factors * given by the scale vector. * * @param scale vector giving the scaling factors along the axes */ public void fromScale(Vector3D scale) { setIdentity(); X[0][0]=scale.X1; X[1][1]=scale.X2; X[2][2]=scale.X3; } /** * Popylate the matrix from a 3x3 matrix. * * @param matrix the 3x3 matrix to extend */ public void fromMatrix3(Matrix3 matrix) { clear(); for(int i=0;i<3;i++) { for(int j=0;j<3;j++) { X[i][j]=matrix.X[i][j]; } } X[3][3]=1.0; } /** * Test if the given matrix is equal to this one. Two * matrices are equal if all components are equal. * * @param a the matrix to test for equality * @return true of matrices are equal, false otherwise */ public boolean equals(Matrix4 a) { for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { if(X[i][j]!=a.X[i][j]) { return false; } } } return true; } /** * Add given matrix a to the current one and return the result. * This operation does not affect the current matrix. * * @param a the matrix to add * @return the sum of both matrices \f$a_{ij}+b_{ij}\f$ */ public Matrix4 add(Matrix4 a) { Matrix4 ret=new Matrix4(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { ret.X[i][j]=X[i][j]+a.X[i][j]; } } return ret; } /** * Subtract given matrix a from the current one and return the result. * This operation does not affect the current matrix. * * @param a the matrix to subtract * @return the difference of both matrices \f$b_{ij}-a_{ij}\f$ */ public Matrix4 sub(Matrix4 a) { Matrix4 ret=new Matrix4(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { ret.X[i][j]=X[i][j]-a.X[i][j]; } } return ret; } /** * Multiplies this matrix with an other 4x4 matrix * @param a the matrix to multiply with * @return the resulting matrix */ public Matrix4 multiply(Matrix4 a) { Matrix4 ret = new Matrix4(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { ret.X[i][j]=X[i][0]*a.X[0][j]+X[i][1]*a.X[1][j]+X[i][2]*a.X[2][j]+X[i][3]*a.X[3][j]; } } return ret; } /** * Multiplies a 3D vector with this 4x4 matrix by adding 1 as a fourth component. * @param a the vector to multiply with * @return the result vector with the omitted fourth component scaled back to 1 */ public Vector3D multiply(Vector3D a) { Vector3D res = new Vector3D(); double res4; res4=X[3][0]*a.X1+X[3][1]*a.X2+X[3][2]*a.X3+X[3][3]; res.X1=X[0][0]*a.X1+X[0][1]*a.X2+X[0][2]*a.X3+X[0][3]; res.X1/=res4; res.X2=X[1][0]*a.X1+X[1][1]*a.X2+X[1][2]*a.X3+X[1][3]; res.X2/=res4; res.X3=X[2][0]*a.X1+X[2][1]*a.X2+X[2][2]*a.X3+X[2][3]; res.X3/=res4; return res; } /** * Multiplies this matrix with a scalar value * @param a the scalar to multiply with * @return the resulting matrix */ public Matrix4 multiply(double a) { Matrix4 ret = new Matrix4(); for(int i=0;i<4;i++) { for(int j=0;j<4;j++) { ret.X[i][j]=X[i][j]*a; } } return ret; } /** * Extract the pure translation portion of the transformation * * @return the translation part of this transformation */ public Vector3D getTranslation() { return new Vector3D(X[0][3], X[1][3], X[2][3]); } }