package com.ilm.sandwich.representation;
import android.util.Log;
/**
* The Class Matrixf4x4.
* <p/>
* Internal the matrix is structured as
* <p/>
* [ x0 , y0 , z0 , w0 ] [ x1 , y1 , z1 , w1 ] [ x2 , y2 , z2 , w2 ] [ x3 , y3 , z3 , w3 ]
* <p/>
* it is recommend that when setting the matrix values individually that you use the set{x,#} methods, where 'x' is
* either x, y, z or w and # is either 0, 1, 2 or 3, setY1 for example. The reason you should use these functions is
* because it will map directly to that part of the matrix regardless of whether or not the internal matrix is column
* major or not. If the matrix is either or length 9 or 16 it will be able to determine if it can set the value or not.
* If the matrix is of size 9 but you set say w2, the value will not be set and the set method will return without any
* error.
*/
public class Matrixf4x4 {
public static final int[] matIndCol9_3x3 = {0, 1, 2, 3, 4, 5, 6, 7, 8};
public static final int[] matIndCol16_3x3 = {0, 1, 2, 4, 5, 6, 8, 9, 10};
public static final int[] matIndRow9_3x3 = {0, 3, 6, 1, 4, 7, 3, 5, 8};
public static final int[] matIndRow16_3x3 = {0, 4, 8, 1, 5, 9, 2, 6, 10};
public static final int[] matIndCol16_4x4 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
public static final int[] matIndRow16_4x4 = {0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15};
/**
* The matrix.
*/
public float[] matrix;
private boolean colMaj = true;
private boolean matrixValid = false;
/**
* Instantiates a new matrixf4x4. The Matrix is assumed to be Column major, however you can change this by using the
* setColumnMajor function to false and it will operate like a row major matrix.
*/
public Matrixf4x4() {
// The matrix is defined as float[column][row]
this.matrix = new float[16];
Matrix.setIdentityM(this.matrix, 0);
matrixValid = true;
}
/**
* Gets the matrix.
*
* @return the matrix, can be null if the matrix is invalid
*/
public float[] getMatrix() {
return this.matrix;
}
/**
* Sets the matrix from a float[16] array. If the matrix you set isn't 16 long then the matrix will be set as
* invalid.
*
* @param matrix the new matrix
*/
public void setMatrix(float[] matrix) {
this.matrix = matrix;
if (matrix.length == 16 || matrix.length == 9)
this.matrixValid = true;
else {
this.matrixValid = false;
Log.e("matrix", "Matrix set is invalid, size is " + matrix.length + " expected 9 or 16");
}
}
public int size() {
return matrix.length;
}
public void setMatrixValues(float[] otherMatrix) {
if (this.matrix.length != otherMatrix.length) {
Log.e("matrix", "Matrix set is invalid, size is " + otherMatrix.length + " expected 9 or 16");
}
for (int i = 0; i < otherMatrix.length; i++) {
this.matrix[i] = otherMatrix[i];
}
}
/**
* Find out if the stored matrix is column major
*
* @return
*/
public boolean isColumnMajor() {
return colMaj;
}
/**
* Set whether the internal data is col major by passing true, or false for a row major matrix. The matrix is column
* major by default.
*
* @param colMajor
*/
public void setColumnMajor(boolean colMajor) {
this.colMaj = colMajor;
}
/**
* Multiply the given vector by this matrix. This should only be used if the matrix is of size 16 (use the
* matrix.size() method).
*
* @param vector A vector of length 4.
*/
public void multiplyVector4fByMatrix(Vector4f vector) {
if (matrixValid && matrix.length == 16) {
float x = 0;
float y = 0;
float z = 0;
float w = 0;
float[] vectorArray = vector.ToArray();
if (colMaj) {
for (int i = 0; i < 4; i++) {
int k = i * 4;
x += this.matrix[k + 0] * vectorArray[i];
y += this.matrix[k + 1] * vectorArray[i];
z += this.matrix[k + 2] * vectorArray[i];
w += this.matrix[k + 3] * vectorArray[i];
}
} else {
for (int i = 0; i < 4; i++) {
x += this.matrix[0 + i] * vectorArray[i];
y += this.matrix[4 + i] * vectorArray[i];
z += this.matrix[8 + i] * vectorArray[i];
w += this.matrix[12 + i] * vectorArray[i];
}
}
vector.setX(x);
vector.setY(y);
vector.setZ(z);
vector.setW(w);
} else
Log.e("matrix", "Matrix is invalid, is " + matrix.length + " long, this equation expects a 16 value matrix");
}
/**
* Multiply the given vector by this matrix. This should only be used if the matrix is of size 9 (use the
* matrix.size() method).
*
* @param vector A vector of length 3.
*/
public void multiplyVector3fByMatrix(Vector3f vector) {
if (matrixValid && matrix.length == 9) {
float x = 0;
float y = 0;
float z = 0;
float[] vectorArray = vector.toArray();
if (!colMaj) {
for (int i = 0; i < 3; i++) {
int k = i * 3;
x += this.matrix[k + 0] * vectorArray[i];
y += this.matrix[k + 1] * vectorArray[i];
z += this.matrix[k + 2] * vectorArray[i];
}
} else {
for (int i = 0; i < 3; i++) {
x += this.matrix[0 + i] * vectorArray[i];
y += this.matrix[3 + i] * vectorArray[i];
z += this.matrix[6 + i] * vectorArray[i];
}
}
vector.setX(x);
vector.setY(y);
vector.setZ(z);
} else
Log.e("matrix", "Matrix is invalid, is " + matrix.length
+ " long, this function expects the internal matrix to be of size 9");
}
public boolean isMatrixValid() {
return matrixValid;
}
/**
* Multiply matrix4x4 by matrix.
*
* @param matrixf the matrixf
*/
public void multiplyMatrix4x4ByMatrix(Matrixf4x4 matrixf) {
// TODO implement Strassen Algorithm in place of this slower naive one.
if (matrixValid && matrixf.isMatrixValid()) {
float[] bufferMatrix = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
float[] matrix = matrixf.getMatrix();
/**
* for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){
*
* int k = i * 4; bufferMatrix[0 + j] += this.matrix[k + j] * matrix[0 * 4 + i]; bufferMatrix[1 * 4 + j] +=
* this.matrix[k + j] * matrix[1 * 4 + i]; bufferMatrix[2 * 4 + j] += this.matrix[k + j] * matrix[2 * 4 +
* i]; bufferMatrix[3 * 4 + j] += this.matrix[k + j] * matrix[3 * 4 + i]; } }
*/
multiplyMatrix(matrix, 0, bufferMatrix, 0);
matrixf.setMatrix(bufferMatrix);
} else
Log.e("matrix", "Matrix is invalid, internal is " + matrix.length + " long" + " , input matrix is "
+ matrixf.getMatrix().length + " long");
}
public void multiplyMatrix(float[] input, int inputOffset, float[] output, int outputOffset) {
float[] bufferMatrix = output;
float[] matrix = input;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int k = i * 4;
bufferMatrix[outputOffset + 0 + j] += this.matrix[k + j] * matrix[inputOffset + 0 * 4 + i];
bufferMatrix[outputOffset + 1 * 4 + j] += this.matrix[k + j] * matrix[inputOffset + 1 * 4 + i];
bufferMatrix[outputOffset + 2 * 4 + j] += this.matrix[k + j] * matrix[inputOffset + 2 * 4 + i];
bufferMatrix[outputOffset + 3 * 4 + j] += this.matrix[k + j] * matrix[inputOffset + 3 * 4 + i];
}
}
}
/**
* This will rearrange the internal structure of the matrix. Be careful though as this is an expensive operation.
*/
public void transpose() {
if (matrixValid) {
if (this.matrix.length == 16) {
float[] newMatrix = new float[16];
for (int i = 0; i < 4; i++) {
int k = i * 4;
newMatrix[k] = matrix[i];
newMatrix[k + 1] = matrix[4 + i];
newMatrix[k + 2] = matrix[8 + i];
newMatrix[k + 3] = matrix[12 + i];
}
matrix = newMatrix;
} else {
float[] newMatrix = new float[9];
for (int i = 0; i < 3; i++) {
int k = i * 3;
newMatrix[k] = matrix[i];
newMatrix[k + 1] = matrix[3 + i];
newMatrix[k + 2] = matrix[6 + i];
}
matrix = newMatrix;
}
}
}
public void setX0(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[0]] = value;
else
matrix[matIndRow16_3x3[0]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[0]] = value;
else
matrix[matIndRow9_3x3[0]] = value;
}
}
}
public void setX1(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[1]] = value;
else
matrix[matIndRow16_3x3[1]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[1]] = value;
else
matrix[matIndRow9_3x3[1]] = value;
}
}
}
public void setX2(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[2]] = value;
else
matrix[matIndRow16_3x3[2]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[2]] = value;
else
matrix[matIndRow9_3x3[2]] = value;
}
}
}
public void setY0(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[3]] = value;
else
matrix[matIndRow16_3x3[3]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[3]] = value;
else
matrix[matIndRow9_3x3[3]] = value;
}
}
}
public void setY1(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[4]] = value;
else
matrix[matIndRow16_3x3[4]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[4]] = value;
else
matrix[matIndRow9_3x3[4]] = value;
}
}
}
public void setY2(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[5]] = value;
else
matrix[matIndRow16_3x3[5]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[5]] = value;
else
matrix[matIndRow9_3x3[5]] = value;
}
}
}
public void setZ0(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[6]] = value;
else
matrix[matIndRow16_3x3[6]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[6]] = value;
else
matrix[matIndRow9_3x3[6]] = value;
}
}
}
public void setZ1(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[7]] = value;
else
matrix[matIndRow16_3x3[7]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[7]] = value;
else
matrix[matIndRow9_3x3[7]] = value;
}
}
}
public void setZ2(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_3x3[8]] = value;
else
matrix[matIndRow16_3x3[8]] = value;
} else {
if (colMaj)
matrix[matIndCol9_3x3[8]] = value;
else
matrix[matIndRow9_3x3[8]] = value;
}
}
}
public void setX3(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[3]] = value;
else
matrix[matIndRow16_4x4[3]] = value;
}
}
}
public void setY3(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[7]] = value;
else
matrix[matIndRow16_4x4[7]] = value;
}
}
}
public void setZ3(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[11]] = value;
else
matrix[matIndRow16_4x4[11]] = value;
}
}
}
public void setW0(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[12]] = value;
else
matrix[matIndRow16_4x4[12]] = value;
}
}
}
public void setW1(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[13]] = value;
else
matrix[matIndRow16_4x4[13]] = value;
}
}
}
public void setW2(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[14]] = value;
else
matrix[matIndRow16_4x4[14]] = value;
}
}
}
public void setW3(float value) {
if (matrixValid) {
if (matrix.length == 16) {
if (colMaj)
matrix[matIndCol16_4x4[15]] = value;
else
matrix[matIndRow16_4x4[15]] = value;
}
}
}
}