From ba15cc68caa27455aa39b46ba568d5f27be440c0 Mon Sep 17 00:00:00 2001 From: "Sha..om" Date: Tue, 10 Jan 2012 14:51:52 +0000 Subject: [PATCH] * determinate -> determinant in Matrix3f git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9016 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- engine/src/core/com/jme3/math/Matrix3f.java | 2774 +++++++++---------- 1 file changed, 1387 insertions(+), 1387 deletions(-) diff --git a/engine/src/core/com/jme3/math/Matrix3f.java b/engine/src/core/com/jme3/math/Matrix3f.java index 76d50fa53..96bf1b39e 100644 --- a/engine/src/core/com/jme3/math/Matrix3f.java +++ b/engine/src/core/com/jme3/math/Matrix3f.java @@ -1,1387 +1,1387 @@ -/* - * Copyright (c) 2009-2010 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.math; - -import com.jme3.export.*; -import com.jme3.util.BufferUtils; -import com.jme3.util.TempVars; -import java.io.IOException; -import java.nio.FloatBuffer; -import java.util.logging.Logger; - -/** - * Matrix3f defines a 3x3 matrix. Matrix data is maintained - * internally and is accessible via the get and set methods. Convenience methods - * are used for matrix operations as well as generating a matrix from a given - * set of values. - * - * @author Mark Powell - * @author Joshua Slack - */ -public final class Matrix3f implements Savable, Cloneable, java.io.Serializable { - - static final long serialVersionUID = 1; - - private static final Logger logger = Logger.getLogger(Matrix3f.class.getName()); - protected float m00, m01, m02; - protected float m10, m11, m12; - protected float m20, m21, m22; - public static final Matrix3f ZERO = new Matrix3f(0, 0, 0, 0, 0, 0, 0, 0, 0); - public static final Matrix3f IDENTITY = new Matrix3f(); - - /** - * Constructor instantiates a new Matrix3f object. The - * initial values for the matrix is that of the identity matrix. - * - */ - public Matrix3f() { - loadIdentity(); - } - - /** - * constructs a matrix with the given values. - * - * @param m00 - * 0x0 in the matrix. - * @param m01 - * 0x1 in the matrix. - * @param m02 - * 0x2 in the matrix. - * @param m10 - * 1x0 in the matrix. - * @param m11 - * 1x1 in the matrix. - * @param m12 - * 1x2 in the matrix. - * @param m20 - * 2x0 in the matrix. - * @param m21 - * 2x1 in the matrix. - * @param m22 - * 2x2 in the matrix. - */ - public Matrix3f(float m00, float m01, float m02, float m10, float m11, - float m12, float m20, float m21, float m22) { - - this.m00 = m00; - this.m01 = m01; - this.m02 = m02; - this.m10 = m10; - this.m11 = m11; - this.m12 = m12; - this.m20 = m20; - this.m21 = m21; - this.m22 = m22; - } - - /** - * Copy constructor that creates a new Matrix3f object that - * is the same as the provided matrix. - * - * @param mat - * the matrix to copy. - */ - public Matrix3f(Matrix3f mat) { - set(mat); - } - - /** - * Takes the absolute value of all matrix fields locally. - */ - public void absoluteLocal() { - m00 = FastMath.abs(m00); - m01 = FastMath.abs(m01); - m02 = FastMath.abs(m02); - m10 = FastMath.abs(m10); - m11 = FastMath.abs(m11); - m12 = FastMath.abs(m12); - m20 = FastMath.abs(m20); - m21 = FastMath.abs(m21); - m22 = FastMath.abs(m22); - } - - /** - * copy transfers the contents of a given matrix to this - * matrix. If a null matrix is supplied, this matrix is set to the identity - * matrix. - * - * @param matrix - * the matrix to copy. - * @return this - */ - public Matrix3f set(Matrix3f matrix) { - if (null == matrix) { - loadIdentity(); - } else { - m00 = matrix.m00; - m01 = matrix.m01; - m02 = matrix.m02; - m10 = matrix.m10; - m11 = matrix.m11; - m12 = matrix.m12; - m20 = matrix.m20; - m21 = matrix.m21; - m22 = matrix.m22; - } - return this; - } - - /** - * get retrieves a value from the matrix at the given - * position. If the position is invalid a JmeException is - * thrown. - * - * @param i - * the row index. - * @param j - * the colum index. - * @return the value at (i, j). - */ - @SuppressWarnings("fallthrough") - public float get(int i, int j) { - switch (i) { - case 0: - switch (j) { - case 0: - return m00; - case 1: - return m01; - case 2: - return m02; - } - case 1: - switch (j) { - case 0: - return m10; - case 1: - return m11; - case 2: - return m12; - } - case 2: - switch (j) { - case 0: - return m20; - case 1: - return m21; - case 2: - return m22; - } - } - - logger.warning("Invalid matrix index."); - throw new IllegalArgumentException("Invalid indices into matrix."); - } - - /** - * get(float[]) returns the matrix in row-major or column-major order. - * - * @param data - * The array to return the data into. This array can be 9 or 16 floats in size. - * Only the upper 3x3 are assigned to in the case of a 16 element array. - * @param rowMajor - * True for row major storage in the array (translation in elements 3, 7, 11 for a 4x4), - * false for column major (translation in elements 12, 13, 14 for a 4x4). - */ - public void get(float[] data, boolean rowMajor) { - if (data.length == 9) { - if (rowMajor) { - data[0] = m00; - data[1] = m01; - data[2] = m02; - data[3] = m10; - data[4] = m11; - data[5] = m12; - data[6] = m20; - data[7] = m21; - data[8] = m22; - } else { - data[0] = m00; - data[1] = m10; - data[2] = m20; - data[3] = m01; - data[4] = m11; - data[5] = m21; - data[6] = m02; - data[7] = m12; - data[8] = m22; - } - } else if (data.length == 16) { - if (rowMajor) { - data[0] = m00; - data[1] = m01; - data[2] = m02; - data[4] = m10; - data[5] = m11; - data[6] = m12; - data[8] = m20; - data[9] = m21; - data[10] = m22; - } else { - data[0] = m00; - data[1] = m10; - data[2] = m20; - data[4] = m01; - data[5] = m11; - data[6] = m21; - data[8] = m02; - data[9] = m12; - data[10] = m22; - } - } else { - throw new IndexOutOfBoundsException("Array size must be 9 or 16 in Matrix3f.get()."); - } - } - - /** - * getColumn returns one of three columns specified by the - * parameter. This column is returned as a Vector3f object. - * - * @param i - * the column to retrieve. Must be between 0 and 2. - * @return the column specified by the index. - */ - public Vector3f getColumn(int i) { - return getColumn(i, null); - } - - /** - * getColumn returns one of three columns specified by the - * parameter. This column is returned as a Vector3f object. - * - * @param i - * the column to retrieve. Must be between 0 and 2. - * @param store - * the vector object to store the result in. if null, a new one - * is created. - * @return the column specified by the index. - */ - public Vector3f getColumn(int i, Vector3f store) { - if (store == null) { - store = new Vector3f(); - } - switch (i) { - case 0: - store.x = m00; - store.y = m10; - store.z = m20; - break; - case 1: - store.x = m01; - store.y = m11; - store.z = m21; - break; - case 2: - store.x = m02; - store.y = m12; - store.z = m22; - break; - default: - logger.warning("Invalid column index."); - throw new IllegalArgumentException("Invalid column index. " + i); - } - return store; - } - - /** - * getColumn returns one of three rows as specified by the - * parameter. This row is returned as a Vector3f object. - * - * @param i - * the row to retrieve. Must be between 0 and 2. - * @return the row specified by the index. - */ - public Vector3f getRow(int i) { - return getRow(i, null); - } - - /** - * getRow returns one of three rows as specified by the - * parameter. This row is returned as a Vector3f object. - * - * @param i - * the row to retrieve. Must be between 0 and 2. - * @param store - * the vector object to store the result in. if null, a new one - * is created. - * @return the row specified by the index. - */ - public Vector3f getRow(int i, Vector3f store) { - if (store == null) { - store = new Vector3f(); - } - switch (i) { - case 0: - store.x = m00; - store.y = m01; - store.z = m02; - break; - case 1: - store.x = m10; - store.y = m11; - store.z = m12; - break; - case 2: - store.x = m20; - store.y = m21; - store.z = m22; - break; - default: - logger.warning("Invalid row index."); - throw new IllegalArgumentException("Invalid row index. " + i); - } - return store; - } - - /** - * toFloatBuffer returns a FloatBuffer object that contains - * the matrix data. - * - * @return matrix data as a FloatBuffer. - */ - public FloatBuffer toFloatBuffer() { - FloatBuffer fb = BufferUtils.createFloatBuffer(9); - - fb.put(m00).put(m01).put(m02); - fb.put(m10).put(m11).put(m12); - fb.put(m20).put(m21).put(m22); - fb.rewind(); - return fb; - } - - /** - * fillFloatBuffer fills a FloatBuffer object with the matrix - * data. - * - * @param fb - * the buffer to fill, starting at current position. Must have - * room for 9 more floats. - * @return matrix data as a FloatBuffer. (position is advanced by 9 and any - * limit set is not changed). - */ - public FloatBuffer fillFloatBuffer(FloatBuffer fb, boolean columnMajor) { -// if (columnMajor){ -// fb.put(m00).put(m10).put(m20); -// fb.put(m01).put(m11).put(m21); -// fb.put(m02).put(m12).put(m22); -// }else{ -// fb.put(m00).put(m01).put(m02); -// fb.put(m10).put(m11).put(m12); -// fb.put(m20).put(m21).put(m22); -// } - - TempVars vars = TempVars.get(); - - - fillFloatArray(vars.matrixWrite, columnMajor); - fb.put(vars.matrixWrite, 0, 9); - - vars.release(); - - return fb; - } - - public void fillFloatArray(float[] f, boolean columnMajor) { - if (columnMajor) { - f[ 0] = m00; - f[ 1] = m10; - f[ 2] = m20; - f[ 3] = m01; - f[ 4] = m11; - f[ 5] = m21; - f[ 6] = m02; - f[ 7] = m12; - f[ 8] = m22; - } else { - f[ 0] = m00; - f[ 1] = m01; - f[ 2] = m02; - f[ 3] = m10; - f[ 4] = m11; - f[ 5] = m12; - f[ 6] = m20; - f[ 7] = m21; - f[ 8] = m22; - } - } - - /** - * - * setColumn sets a particular column of this matrix to that - * represented by the provided vector. - * - * @param i - * the column to set. - * @param column - * the data to set. - * @return this - */ - public Matrix3f setColumn(int i, Vector3f column) { - - if (column == null) { - logger.warning("Column is null. Ignoring."); - return this; - } - switch (i) { - case 0: - m00 = column.x; - m10 = column.y; - m20 = column.z; - break; - case 1: - m01 = column.x; - m11 = column.y; - m21 = column.z; - break; - case 2: - m02 = column.x; - m12 = column.y; - m22 = column.z; - break; - default: - logger.warning("Invalid column index."); - throw new IllegalArgumentException("Invalid column index. " + i); - } - return this; - } - - /** - * - * setRow sets a particular row of this matrix to that - * represented by the provided vector. - * - * @param i - * the row to set. - * @param row - * the data to set. - * @return this - */ - public Matrix3f setRow(int i, Vector3f row) { - - if (row == null) { - logger.warning("Row is null. Ignoring."); - return this; - } - switch (i) { - case 0: - m00 = row.x; - m01 = row.y; - m02 = row.z; - break; - case 1: - m10 = row.x; - m11 = row.y; - m12 = row.z; - break; - case 2: - m20 = row.x; - m21 = row.y; - m22 = row.z; - break; - default: - logger.warning("Invalid row index."); - throw new IllegalArgumentException("Invalid row index. " + i); - } - return this; - } - - /** - * set places a given value into the matrix at the given - * position. If the position is invalid a JmeException is - * thrown. - * - * @param i - * the row index. - * @param j - * the colum index. - * @param value - * the value for (i, j). - * @return this - */ - @SuppressWarnings("fallthrough") - public Matrix3f set(int i, int j, float value) { - switch (i) { - case 0: - switch (j) { - case 0: - m00 = value; - return this; - case 1: - m01 = value; - return this; - case 2: - m02 = value; - return this; - } - case 1: - switch (j) { - case 0: - m10 = value; - return this; - case 1: - m11 = value; - return this; - case 2: - m12 = value; - return this; - } - case 2: - switch (j) { - case 0: - m20 = value; - return this; - case 1: - m21 = value; - return this; - case 2: - m22 = value; - return this; - } - } - - logger.warning("Invalid matrix index."); - throw new IllegalArgumentException("Invalid indices into matrix."); - } - - /** - * - * set sets the values of the matrix to those supplied by the - * 3x3 two dimenion array. - * - * @param matrix - * the new values of the matrix. - * @throws JmeException - * if the array is not of size 9. - * @return this - */ - public Matrix3f set(float[][] matrix) { - if (matrix.length != 3 || matrix[0].length != 3) { - throw new IllegalArgumentException( - "Array must be of size 9."); - } - - m00 = matrix[0][0]; - m01 = matrix[0][1]; - m02 = matrix[0][2]; - m10 = matrix[1][0]; - m11 = matrix[1][1]; - m12 = matrix[1][2]; - m20 = matrix[2][0]; - m21 = matrix[2][1]; - m22 = matrix[2][2]; - - return this; - } - - /** - * Recreate Matrix using the provided axis. - * - * @param uAxis - * Vector3f - * @param vAxis - * Vector3f - * @param wAxis - * Vector3f - */ - public void fromAxes(Vector3f uAxis, Vector3f vAxis, Vector3f wAxis) { - m00 = uAxis.x; - m10 = uAxis.y; - m20 = uAxis.z; - - m01 = vAxis.x; - m11 = vAxis.y; - m21 = vAxis.z; - - m02 = wAxis.x; - m12 = wAxis.y; - m22 = wAxis.z; - } - - /** - * set sets the values of this matrix from an array of - * values assuming that the data is rowMajor order; - * - * @param matrix - * the matrix to set the value to. - * @return this - */ - public Matrix3f set(float[] matrix) { - return set(matrix, true); - } - - /** - * set sets the values of this matrix from an array of - * values; - * - * @param matrix - * the matrix to set the value to. - * @param rowMajor - * whether the incoming data is in row or column major order. - * @return this - */ - public Matrix3f set(float[] matrix, boolean rowMajor) { - if (matrix.length != 9) { - throw new IllegalArgumentException( - "Array must be of size 9."); - } - - if (rowMajor) { - m00 = matrix[0]; - m01 = matrix[1]; - m02 = matrix[2]; - m10 = matrix[3]; - m11 = matrix[4]; - m12 = matrix[5]; - m20 = matrix[6]; - m21 = matrix[7]; - m22 = matrix[8]; - } else { - m00 = matrix[0]; - m01 = matrix[3]; - m02 = matrix[6]; - m10 = matrix[1]; - m11 = matrix[4]; - m12 = matrix[7]; - m20 = matrix[2]; - m21 = matrix[5]; - m22 = matrix[8]; - } - return this; - } - - /** - * - * set defines the values of the matrix based on a supplied - * Quaternion. It should be noted that all previous values - * will be overridden. - * - * @param quaternion - * the quaternion to create a rotational matrix from. - * @return this - */ - public Matrix3f set(Quaternion quaternion) { - return quaternion.toRotationMatrix(this); - } - - /** - * loadIdentity sets this matrix to the identity matrix. - * Where all values are zero except those along the diagonal which are one. - * - */ - public void loadIdentity() { - m01 = m02 = m10 = m12 = m20 = m21 = 0; - m00 = m11 = m22 = 1; - } - - /** - * @return true if this matrix is identity - */ - public boolean isIdentity() { - return (m00 == 1 && m01 == 0 && m02 == 0) - && (m10 == 0 && m11 == 1 && m12 == 0) - && (m20 == 0 && m21 == 0 && m22 == 1); - } - - /** - * fromAngleAxis sets this matrix4f to the values specified - * by an angle and an axis of rotation. This method creates an object, so - * use fromAngleNormalAxis if your axis is already normalized. - * - * @param angle - * the angle to rotate (in radians). - * @param axis - * the axis of rotation. - */ - public void fromAngleAxis(float angle, Vector3f axis) { - Vector3f normAxis = axis.normalize(); - fromAngleNormalAxis(angle, normAxis); - } - - /** - * fromAngleNormalAxis sets this matrix4f to the values - * specified by an angle and a normalized axis of rotation. - * - * @param angle - * the angle to rotate (in radians). - * @param axis - * the axis of rotation (already normalized). - */ - public void fromAngleNormalAxis(float angle, Vector3f axis) { - float fCos = FastMath.cos(angle); - float fSin = FastMath.sin(angle); - float fOneMinusCos = ((float) 1.0) - fCos; - float fX2 = axis.x * axis.x; - float fY2 = axis.y * axis.y; - float fZ2 = axis.z * axis.z; - float fXYM = axis.x * axis.y * fOneMinusCos; - float fXZM = axis.x * axis.z * fOneMinusCos; - float fYZM = axis.y * axis.z * fOneMinusCos; - float fXSin = axis.x * fSin; - float fYSin = axis.y * fSin; - float fZSin = axis.z * fSin; - - m00 = fX2 * fOneMinusCos + fCos; - m01 = fXYM - fZSin; - m02 = fXZM + fYSin; - m10 = fXYM + fZSin; - m11 = fY2 * fOneMinusCos + fCos; - m12 = fYZM - fXSin; - m20 = fXZM - fYSin; - m21 = fYZM + fXSin; - m22 = fZ2 * fOneMinusCos + fCos; - } - - /** - * mult multiplies this matrix by a given matrix. The result - * matrix is returned as a new object. If the given matrix is null, a null - * matrix is returned. - * - * @param mat - * the matrix to multiply this matrix by. - * @return the result matrix. - */ - public Matrix3f mult(Matrix3f mat) { - return mult(mat, null); - } - - /** - * mult multiplies this matrix by a given matrix. The result - * matrix is returned as a new object. - * - * @param mat - * the matrix to multiply this matrix by. - * @param product - * the matrix to store the result in. if null, a new matrix3f is - * created. It is safe for mat and product to be the same object. - * @return a matrix3f object containing the result of this operation - */ - public Matrix3f mult(Matrix3f mat, Matrix3f product) { - - float temp00, temp01, temp02; - float temp10, temp11, temp12; - float temp20, temp21, temp22; - - if (product == null) { - product = new Matrix3f(); - } - temp00 = m00 * mat.m00 + m01 * mat.m10 + m02 * mat.m20; - temp01 = m00 * mat.m01 + m01 * mat.m11 + m02 * mat.m21; - temp02 = m00 * mat.m02 + m01 * mat.m12 + m02 * mat.m22; - temp10 = m10 * mat.m00 + m11 * mat.m10 + m12 * mat.m20; - temp11 = m10 * mat.m01 + m11 * mat.m11 + m12 * mat.m21; - temp12 = m10 * mat.m02 + m11 * mat.m12 + m12 * mat.m22; - temp20 = m20 * mat.m00 + m21 * mat.m10 + m22 * mat.m20; - temp21 = m20 * mat.m01 + m21 * mat.m11 + m22 * mat.m21; - temp22 = m20 * mat.m02 + m21 * mat.m12 + m22 * mat.m22; - - product.m00 = temp00; - product.m01 = temp01; - product.m02 = temp02; - product.m10 = temp10; - product.m11 = temp11; - product.m12 = temp12; - product.m20 = temp20; - product.m21 = temp21; - product.m22 = temp22; - - return product; - } - - /** - * mult multiplies this matrix by a given - * Vector3f object. The result vector is returned. If the - * given vector is null, null will be returned. - * - * @param vec - * the vector to multiply this matrix by. - * @return the result vector. - */ - public Vector3f mult(Vector3f vec) { - return mult(vec, null); - } - - /** - * Multiplies this 3x3 matrix by the 1x3 Vector vec and stores the result in - * product. - * - * @param vec - * The Vector3f to multiply. - * @param product - * The Vector3f to store the result, it is safe for this to be - * the same as vec. - * @return The given product vector. - */ - public Vector3f mult(Vector3f vec, Vector3f product) { - - if (null == product) { - product = new Vector3f(); - } - - float x = vec.x; - float y = vec.y; - float z = vec.z; - - product.x = m00 * x + m01 * y + m02 * z; - product.y = m10 * x + m11 * y + m12 * z; - product.z = m20 * x + m21 * y + m22 * z; - return product; - } - - /** - * multLocal multiplies this matrix internally by - * a given float scale factor. - * - * @param scale - * the value to scale by. - * @return this Matrix3f - */ - public Matrix3f multLocal(float scale) { - m00 *= scale; - m01 *= scale; - m02 *= scale; - m10 *= scale; - m11 *= scale; - m12 *= scale; - m20 *= scale; - m21 *= scale; - m22 *= scale; - return this; - } - - /** - * multLocal multiplies this matrix by a given - * Vector3f object. The result vector is stored inside the - * passed vector, then returned . If the given vector is null, null will be - * returned. - * - * @param vec - * the vector to multiply this matrix by. - * @return The passed vector after multiplication - */ - public Vector3f multLocal(Vector3f vec) { - if (vec == null) { - return null; - } - float x = vec.x; - float y = vec.y; - vec.x = m00 * x + m01 * y + m02 * vec.z; - vec.y = m10 * x + m11 * y + m12 * vec.z; - vec.z = m20 * x + m21 * y + m22 * vec.z; - return vec; - } - - /** - * mult multiplies this matrix by a given matrix. The result - * matrix is saved in the current matrix. If the given matrix is null, - * nothing happens. The current matrix is returned. This is equivalent to - * this*=mat - * - * @param mat - * the matrix to multiply this matrix by. - * @return This matrix, after the multiplication - */ - public Matrix3f multLocal(Matrix3f mat) { - return mult(mat, this); - } - - /** - * Transposes this matrix in place. Returns this matrix for chaining - * - * @return This matrix after transpose - */ - public Matrix3f transposeLocal() { -// float[] tmp = new float[9]; -// get(tmp, false); -// set(tmp, true); - - float tmp = m01; - m01 = m10; - m10 = tmp; - - tmp = m02; - m02 = m20; - m20 = tmp; - - tmp = m12; - m12 = m21; - m21 = tmp; - - return this; - } - - /** - * Inverts this matrix as a new Matrix3f. - * - * @return The new inverse matrix - */ - public Matrix3f invert() { - return invert(null); - } - - /** - * Inverts this matrix and stores it in the given store. - * - * @return The store - */ - public Matrix3f invert(Matrix3f store) { - if (store == null) { - store = new Matrix3f(); - } - - float det = determinant(); - if (FastMath.abs(det) <= FastMath.FLT_EPSILON) { - return store.zero(); - } - - store.m00 = m11 * m22 - m12 * m21; - store.m01 = m02 * m21 - m01 * m22; - store.m02 = m01 * m12 - m02 * m11; - store.m10 = m12 * m20 - m10 * m22; - store.m11 = m00 * m22 - m02 * m20; - store.m12 = m02 * m10 - m00 * m12; - store.m20 = m10 * m21 - m11 * m20; - store.m21 = m01 * m20 - m00 * m21; - store.m22 = m00 * m11 - m01 * m10; - - store.multLocal(1f / det); - return store; - } - - /** - * Inverts this matrix locally. - * - * @return this - */ - public Matrix3f invertLocal() { - float det = determinant(); - if (FastMath.abs(det) <= 0f) { - return zero(); - } - - float f00 = m11 * m22 - m12 * m21; - float f01 = m02 * m21 - m01 * m22; - float f02 = m01 * m12 - m02 * m11; - float f10 = m12 * m20 - m10 * m22; - float f11 = m00 * m22 - m02 * m20; - float f12 = m02 * m10 - m00 * m12; - float f20 = m10 * m21 - m11 * m20; - float f21 = m01 * m20 - m00 * m21; - float f22 = m00 * m11 - m01 * m10; - - m00 = f00; - m01 = f01; - m02 = f02; - m10 = f10; - m11 = f11; - m12 = f12; - m20 = f20; - m21 = f21; - m22 = f22; - - multLocal(1f / det); - return this; - } - - /** - * Returns a new matrix representing the adjoint of this matrix. - * - * @return The adjoint matrix - */ - public Matrix3f adjoint() { - return adjoint(null); - } - - /** - * Places the adjoint of this matrix in store (creates store if null.) - * - * @param store - * The matrix to store the result in. If null, a new matrix is created. - * @return store - */ - public Matrix3f adjoint(Matrix3f store) { - if (store == null) { - store = new Matrix3f(); - } - - store.m00 = m11 * m22 - m12 * m21; - store.m01 = m02 * m21 - m01 * m22; - store.m02 = m01 * m12 - m02 * m11; - store.m10 = m12 * m20 - m10 * m22; - store.m11 = m00 * m22 - m02 * m20; - store.m12 = m02 * m10 - m00 * m12; - store.m20 = m10 * m21 - m11 * m20; - store.m21 = m01 * m20 - m00 * m21; - store.m22 = m00 * m11 - m01 * m10; - - return store; - } - - /** - * determinant generates the determinate of this matrix. - * - * @return the determinate - */ - public float determinant() { - float fCo00 = m11 * m22 - m12 * m21; - float fCo10 = m12 * m20 - m10 * m22; - float fCo20 = m10 * m21 - m11 * m20; - float fDet = m00 * fCo00 + m01 * fCo10 + m02 * fCo20; - return fDet; - } - - /** - * Sets all of the values in this matrix to zero. - * - * @return this matrix - */ - public Matrix3f zero() { - m00 = m01 = m02 = m10 = m11 = m12 = m20 = m21 = m22 = 0.0f; - return this; - } - - /** - * transpose locally transposes this Matrix. - * This is inconsistent with general value vs local semantics, but is - * preserved for backwards compatibility. Use transposeNew() to transpose - * to a new object (value). - * - * @return this object for chaining. - */ - public Matrix3f transpose() { - return transposeLocal(); - } - - /** - * transposeNew returns a transposed version of this matrix. - * - * @return The new Matrix3f object. - */ - public Matrix3f transposeNew() { - Matrix3f ret = new Matrix3f(m00, m10, m20, m01, m11, m21, m02, m12, m22); - return ret; - } - - /** - * toString returns the string representation of this object. - * It is in a format of a 3x3 matrix. For example, an identity matrix would - * be represented by the following string. com.jme.math.Matrix3f
[
- * 1.0 0.0 0.0
- * 0.0 1.0 0.0
- * 0.0 0.0 1.0
]
- * - * @return the string representation of this object. - */ - @Override - public String toString() { - StringBuilder result = new StringBuilder("Matrix3f\n[\n"); - result.append(" "); - result.append(m00); - result.append(" "); - result.append(m01); - result.append(" "); - result.append(m02); - result.append(" \n"); - result.append(" "); - result.append(m10); - result.append(" "); - result.append(m11); - result.append(" "); - result.append(m12); - result.append(" \n"); - result.append(" "); - result.append(m20); - result.append(" "); - result.append(m21); - result.append(" "); - result.append(m22); - result.append(" \n]"); - return result.toString(); - } - - /** - * - * hashCode returns the hash code value as an integer and is - * supported for the benefit of hashing based collection classes such as - * Hashtable, HashMap, HashSet etc. - * - * @return the hashcode for this instance of Matrix4f. - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - int hash = 37; - hash = 37 * hash + Float.floatToIntBits(m00); - hash = 37 * hash + Float.floatToIntBits(m01); - hash = 37 * hash + Float.floatToIntBits(m02); - - hash = 37 * hash + Float.floatToIntBits(m10); - hash = 37 * hash + Float.floatToIntBits(m11); - hash = 37 * hash + Float.floatToIntBits(m12); - - hash = 37 * hash + Float.floatToIntBits(m20); - hash = 37 * hash + Float.floatToIntBits(m21); - hash = 37 * hash + Float.floatToIntBits(m22); - - return hash; - } - - /** - * are these two matrices the same? they are is they both have the same mXX values. - * - * @param o - * the object to compare for equality - * @return true if they are equal - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof Matrix3f) || o == null) { - return false; - } - - if (this == o) { - return true; - } - - Matrix3f comp = (Matrix3f) o; - if (Float.compare(m00, comp.m00) != 0) { - return false; - } - if (Float.compare(m01, comp.m01) != 0) { - return false; - } - if (Float.compare(m02, comp.m02) != 0) { - return false; - } - - if (Float.compare(m10, comp.m10) != 0) { - return false; - } - if (Float.compare(m11, comp.m11) != 0) { - return false; - } - if (Float.compare(m12, comp.m12) != 0) { - return false; - } - - if (Float.compare(m20, comp.m20) != 0) { - return false; - } - if (Float.compare(m21, comp.m21) != 0) { - return false; - } - if (Float.compare(m22, comp.m22) != 0) { - return false; - } - - return true; - } - - public void write(JmeExporter e) throws IOException { - OutputCapsule cap = e.getCapsule(this); - cap.write(m00, "m00", 1); - cap.write(m01, "m01", 0); - cap.write(m02, "m02", 0); - cap.write(m10, "m10", 0); - cap.write(m11, "m11", 1); - cap.write(m12, "m12", 0); - cap.write(m20, "m20", 0); - cap.write(m21, "m21", 0); - cap.write(m22, "m22", 1); - } - - public void read(JmeImporter e) throws IOException { - InputCapsule cap = e.getCapsule(this); - m00 = cap.readFloat("m00", 1); - m01 = cap.readFloat("m01", 0); - m02 = cap.readFloat("m02", 0); - m10 = cap.readFloat("m10", 0); - m11 = cap.readFloat("m11", 1); - m12 = cap.readFloat("m12", 0); - m20 = cap.readFloat("m20", 0); - m21 = cap.readFloat("m21", 0); - m22 = cap.readFloat("m22", 1); - } - - /** - * A function for creating a rotation matrix that rotates a vector called - * "start" into another vector called "end". - * - * @param start - * normalized non-zero starting vector - * @param end - * normalized non-zero ending vector - * @see "Tomas M�ller, John Hughes \"Efficiently Building a Matrix to Rotate \ - * One Vector to Another\" Journal of Graphics Tools, 4(4):1-4, 1999" - */ - public void fromStartEndVectors(Vector3f start, Vector3f end) { - Vector3f v = new Vector3f(); - float e, h, f; - - start.cross(end, v); - e = start.dot(end); - f = (e < 0) ? -e : e; - - // if "from" and "to" vectors are nearly parallel - if (f > 1.0f - FastMath.ZERO_TOLERANCE) { - Vector3f u = new Vector3f(); - Vector3f x = new Vector3f(); - float c1, c2, c3; /* coefficients for later use */ - int i, j; - - x.x = (start.x > 0.0) ? start.x : -start.x; - x.y = (start.y > 0.0) ? start.y : -start.y; - x.z = (start.z > 0.0) ? start.z : -start.z; - - if (x.x < x.y) { - if (x.x < x.z) { - x.x = 1.0f; - x.y = x.z = 0.0f; - } else { - x.z = 1.0f; - x.x = x.y = 0.0f; - } - } else { - if (x.y < x.z) { - x.y = 1.0f; - x.x = x.z = 0.0f; - } else { - x.z = 1.0f; - x.x = x.y = 0.0f; - } - } - - u.x = x.x - start.x; - u.y = x.y - start.y; - u.z = x.z - start.z; - v.x = x.x - end.x; - v.y = x.y - end.y; - v.z = x.z - end.z; - - c1 = 2.0f / u.dot(u); - c2 = 2.0f / v.dot(v); - c3 = c1 * c2 * u.dot(v); - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - float val = -c1 * u.get(i) * u.get(j) - c2 * v.get(i) - * v.get(j) + c3 * v.get(i) * u.get(j); - set(i, j, val); - } - float val = get(i, i); - set(i, i, val + 1.0f); - } - } else { - // the most common case, unless "start"="end", or "start"=-"end" - float hvx, hvz, hvxy, hvxz, hvyz; - h = 1.0f / (1.0f + e); - hvx = h * v.x; - hvz = h * v.z; - hvxy = hvx * v.y; - hvxz = hvx * v.z; - hvyz = hvz * v.y; - set(0, 0, e + hvx * v.x); - set(0, 1, hvxy - v.z); - set(0, 2, hvxz + v.y); - - set(1, 0, hvxy + v.z); - set(1, 1, e + h * v.y * v.y); - set(1, 2, hvyz - v.x); - - set(2, 0, hvxz - v.y); - set(2, 1, hvyz + v.x); - set(2, 2, e + hvz * v.z); - } - } - - /** - * scale scales the operation performed by this matrix on a - * per-component basis. - * - * @param scale - * The scale applied to each of the X, Y and Z output values. - */ - public void scale(Vector3f scale) { - m00 *= scale.x; - m10 *= scale.x; - m20 *= scale.x; - m01 *= scale.y; - m11 *= scale.y; - m21 *= scale.y; - m02 *= scale.z; - m12 *= scale.z; - m22 *= scale.z; - } - - static boolean equalIdentity(Matrix3f mat) { - if (Math.abs(mat.m00 - 1) > 1e-4) { - return false; - } - if (Math.abs(mat.m11 - 1) > 1e-4) { - return false; - } - if (Math.abs(mat.m22 - 1) > 1e-4) { - return false; - } - - if (Math.abs(mat.m01) > 1e-4) { - return false; - } - if (Math.abs(mat.m02) > 1e-4) { - return false; - } - - if (Math.abs(mat.m10) > 1e-4) { - return false; - } - if (Math.abs(mat.m12) > 1e-4) { - return false; - } - - if (Math.abs(mat.m20) > 1e-4) { - return false; - } - if (Math.abs(mat.m21) > 1e-4) { - return false; - } - - return true; - } - - @Override - public Matrix3f clone() { - try { - return (Matrix3f) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); // can not happen - } - } -} +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.math; + +import com.jme3.export.*; +import com.jme3.util.BufferUtils; +import com.jme3.util.TempVars; +import java.io.IOException; +import java.nio.FloatBuffer; +import java.util.logging.Logger; + +/** + * Matrix3f defines a 3x3 matrix. Matrix data is maintained + * internally and is accessible via the get and set methods. Convenience methods + * are used for matrix operations as well as generating a matrix from a given + * set of values. + * + * @author Mark Powell + * @author Joshua Slack + */ +public final class Matrix3f implements Savable, Cloneable, java.io.Serializable { + + static final long serialVersionUID = 1; + + private static final Logger logger = Logger.getLogger(Matrix3f.class.getName()); + protected float m00, m01, m02; + protected float m10, m11, m12; + protected float m20, m21, m22; + public static final Matrix3f ZERO = new Matrix3f(0, 0, 0, 0, 0, 0, 0, 0, 0); + public static final Matrix3f IDENTITY = new Matrix3f(); + + /** + * Constructor instantiates a new Matrix3f object. The + * initial values for the matrix is that of the identity matrix. + * + */ + public Matrix3f() { + loadIdentity(); + } + + /** + * constructs a matrix with the given values. + * + * @param m00 + * 0x0 in the matrix. + * @param m01 + * 0x1 in the matrix. + * @param m02 + * 0x2 in the matrix. + * @param m10 + * 1x0 in the matrix. + * @param m11 + * 1x1 in the matrix. + * @param m12 + * 1x2 in the matrix. + * @param m20 + * 2x0 in the matrix. + * @param m21 + * 2x1 in the matrix. + * @param m22 + * 2x2 in the matrix. + */ + public Matrix3f(float m00, float m01, float m02, float m10, float m11, + float m12, float m20, float m21, float m22) { + + this.m00 = m00; + this.m01 = m01; + this.m02 = m02; + this.m10 = m10; + this.m11 = m11; + this.m12 = m12; + this.m20 = m20; + this.m21 = m21; + this.m22 = m22; + } + + /** + * Copy constructor that creates a new Matrix3f object that + * is the same as the provided matrix. + * + * @param mat + * the matrix to copy. + */ + public Matrix3f(Matrix3f mat) { + set(mat); + } + + /** + * Takes the absolute value of all matrix fields locally. + */ + public void absoluteLocal() { + m00 = FastMath.abs(m00); + m01 = FastMath.abs(m01); + m02 = FastMath.abs(m02); + m10 = FastMath.abs(m10); + m11 = FastMath.abs(m11); + m12 = FastMath.abs(m12); + m20 = FastMath.abs(m20); + m21 = FastMath.abs(m21); + m22 = FastMath.abs(m22); + } + + /** + * copy transfers the contents of a given matrix to this + * matrix. If a null matrix is supplied, this matrix is set to the identity + * matrix. + * + * @param matrix + * the matrix to copy. + * @return this + */ + public Matrix3f set(Matrix3f matrix) { + if (null == matrix) { + loadIdentity(); + } else { + m00 = matrix.m00; + m01 = matrix.m01; + m02 = matrix.m02; + m10 = matrix.m10; + m11 = matrix.m11; + m12 = matrix.m12; + m20 = matrix.m20; + m21 = matrix.m21; + m22 = matrix.m22; + } + return this; + } + + /** + * get retrieves a value from the matrix at the given + * position. If the position is invalid a JmeException is + * thrown. + * + * @param i + * the row index. + * @param j + * the colum index. + * @return the value at (i, j). + */ + @SuppressWarnings("fallthrough") + public float get(int i, int j) { + switch (i) { + case 0: + switch (j) { + case 0: + return m00; + case 1: + return m01; + case 2: + return m02; + } + case 1: + switch (j) { + case 0: + return m10; + case 1: + return m11; + case 2: + return m12; + } + case 2: + switch (j) { + case 0: + return m20; + case 1: + return m21; + case 2: + return m22; + } + } + + logger.warning("Invalid matrix index."); + throw new IllegalArgumentException("Invalid indices into matrix."); + } + + /** + * get(float[]) returns the matrix in row-major or column-major order. + * + * @param data + * The array to return the data into. This array can be 9 or 16 floats in size. + * Only the upper 3x3 are assigned to in the case of a 16 element array. + * @param rowMajor + * True for row major storage in the array (translation in elements 3, 7, 11 for a 4x4), + * false for column major (translation in elements 12, 13, 14 for a 4x4). + */ + public void get(float[] data, boolean rowMajor) { + if (data.length == 9) { + if (rowMajor) { + data[0] = m00; + data[1] = m01; + data[2] = m02; + data[3] = m10; + data[4] = m11; + data[5] = m12; + data[6] = m20; + data[7] = m21; + data[8] = m22; + } else { + data[0] = m00; + data[1] = m10; + data[2] = m20; + data[3] = m01; + data[4] = m11; + data[5] = m21; + data[6] = m02; + data[7] = m12; + data[8] = m22; + } + } else if (data.length == 16) { + if (rowMajor) { + data[0] = m00; + data[1] = m01; + data[2] = m02; + data[4] = m10; + data[5] = m11; + data[6] = m12; + data[8] = m20; + data[9] = m21; + data[10] = m22; + } else { + data[0] = m00; + data[1] = m10; + data[2] = m20; + data[4] = m01; + data[5] = m11; + data[6] = m21; + data[8] = m02; + data[9] = m12; + data[10] = m22; + } + } else { + throw new IndexOutOfBoundsException("Array size must be 9 or 16 in Matrix3f.get()."); + } + } + + /** + * getColumn returns one of three columns specified by the + * parameter. This column is returned as a Vector3f object. + * + * @param i + * the column to retrieve. Must be between 0 and 2. + * @return the column specified by the index. + */ + public Vector3f getColumn(int i) { + return getColumn(i, null); + } + + /** + * getColumn returns one of three columns specified by the + * parameter. This column is returned as a Vector3f object. + * + * @param i + * the column to retrieve. Must be between 0 and 2. + * @param store + * the vector object to store the result in. if null, a new one + * is created. + * @return the column specified by the index. + */ + public Vector3f getColumn(int i, Vector3f store) { + if (store == null) { + store = new Vector3f(); + } + switch (i) { + case 0: + store.x = m00; + store.y = m10; + store.z = m20; + break; + case 1: + store.x = m01; + store.y = m11; + store.z = m21; + break; + case 2: + store.x = m02; + store.y = m12; + store.z = m22; + break; + default: + logger.warning("Invalid column index."); + throw new IllegalArgumentException("Invalid column index. " + i); + } + return store; + } + + /** + * getColumn returns one of three rows as specified by the + * parameter. This row is returned as a Vector3f object. + * + * @param i + * the row to retrieve. Must be between 0 and 2. + * @return the row specified by the index. + */ + public Vector3f getRow(int i) { + return getRow(i, null); + } + + /** + * getRow returns one of three rows as specified by the + * parameter. This row is returned as a Vector3f object. + * + * @param i + * the row to retrieve. Must be between 0 and 2. + * @param store + * the vector object to store the result in. if null, a new one + * is created. + * @return the row specified by the index. + */ + public Vector3f getRow(int i, Vector3f store) { + if (store == null) { + store = new Vector3f(); + } + switch (i) { + case 0: + store.x = m00; + store.y = m01; + store.z = m02; + break; + case 1: + store.x = m10; + store.y = m11; + store.z = m12; + break; + case 2: + store.x = m20; + store.y = m21; + store.z = m22; + break; + default: + logger.warning("Invalid row index."); + throw new IllegalArgumentException("Invalid row index. " + i); + } + return store; + } + + /** + * toFloatBuffer returns a FloatBuffer object that contains + * the matrix data. + * + * @return matrix data as a FloatBuffer. + */ + public FloatBuffer toFloatBuffer() { + FloatBuffer fb = BufferUtils.createFloatBuffer(9); + + fb.put(m00).put(m01).put(m02); + fb.put(m10).put(m11).put(m12); + fb.put(m20).put(m21).put(m22); + fb.rewind(); + return fb; + } + + /** + * fillFloatBuffer fills a FloatBuffer object with the matrix + * data. + * + * @param fb + * the buffer to fill, starting at current position. Must have + * room for 9 more floats. + * @return matrix data as a FloatBuffer. (position is advanced by 9 and any + * limit set is not changed). + */ + public FloatBuffer fillFloatBuffer(FloatBuffer fb, boolean columnMajor) { +// if (columnMajor){ +// fb.put(m00).put(m10).put(m20); +// fb.put(m01).put(m11).put(m21); +// fb.put(m02).put(m12).put(m22); +// }else{ +// fb.put(m00).put(m01).put(m02); +// fb.put(m10).put(m11).put(m12); +// fb.put(m20).put(m21).put(m22); +// } + + TempVars vars = TempVars.get(); + + + fillFloatArray(vars.matrixWrite, columnMajor); + fb.put(vars.matrixWrite, 0, 9); + + vars.release(); + + return fb; + } + + public void fillFloatArray(float[] f, boolean columnMajor) { + if (columnMajor) { + f[ 0] = m00; + f[ 1] = m10; + f[ 2] = m20; + f[ 3] = m01; + f[ 4] = m11; + f[ 5] = m21; + f[ 6] = m02; + f[ 7] = m12; + f[ 8] = m22; + } else { + f[ 0] = m00; + f[ 1] = m01; + f[ 2] = m02; + f[ 3] = m10; + f[ 4] = m11; + f[ 5] = m12; + f[ 6] = m20; + f[ 7] = m21; + f[ 8] = m22; + } + } + + /** + * + * setColumn sets a particular column of this matrix to that + * represented by the provided vector. + * + * @param i + * the column to set. + * @param column + * the data to set. + * @return this + */ + public Matrix3f setColumn(int i, Vector3f column) { + + if (column == null) { + logger.warning("Column is null. Ignoring."); + return this; + } + switch (i) { + case 0: + m00 = column.x; + m10 = column.y; + m20 = column.z; + break; + case 1: + m01 = column.x; + m11 = column.y; + m21 = column.z; + break; + case 2: + m02 = column.x; + m12 = column.y; + m22 = column.z; + break; + default: + logger.warning("Invalid column index."); + throw new IllegalArgumentException("Invalid column index. " + i); + } + return this; + } + + /** + * + * setRow sets a particular row of this matrix to that + * represented by the provided vector. + * + * @param i + * the row to set. + * @param row + * the data to set. + * @return this + */ + public Matrix3f setRow(int i, Vector3f row) { + + if (row == null) { + logger.warning("Row is null. Ignoring."); + return this; + } + switch (i) { + case 0: + m00 = row.x; + m01 = row.y; + m02 = row.z; + break; + case 1: + m10 = row.x; + m11 = row.y; + m12 = row.z; + break; + case 2: + m20 = row.x; + m21 = row.y; + m22 = row.z; + break; + default: + logger.warning("Invalid row index."); + throw new IllegalArgumentException("Invalid row index. " + i); + } + return this; + } + + /** + * set places a given value into the matrix at the given + * position. If the position is invalid a JmeException is + * thrown. + * + * @param i + * the row index. + * @param j + * the colum index. + * @param value + * the value for (i, j). + * @return this + */ + @SuppressWarnings("fallthrough") + public Matrix3f set(int i, int j, float value) { + switch (i) { + case 0: + switch (j) { + case 0: + m00 = value; + return this; + case 1: + m01 = value; + return this; + case 2: + m02 = value; + return this; + } + case 1: + switch (j) { + case 0: + m10 = value; + return this; + case 1: + m11 = value; + return this; + case 2: + m12 = value; + return this; + } + case 2: + switch (j) { + case 0: + m20 = value; + return this; + case 1: + m21 = value; + return this; + case 2: + m22 = value; + return this; + } + } + + logger.warning("Invalid matrix index."); + throw new IllegalArgumentException("Invalid indices into matrix."); + } + + /** + * + * set sets the values of the matrix to those supplied by the + * 3x3 two dimenion array. + * + * @param matrix + * the new values of the matrix. + * @throws JmeException + * if the array is not of size 9. + * @return this + */ + public Matrix3f set(float[][] matrix) { + if (matrix.length != 3 || matrix[0].length != 3) { + throw new IllegalArgumentException( + "Array must be of size 9."); + } + + m00 = matrix[0][0]; + m01 = matrix[0][1]; + m02 = matrix[0][2]; + m10 = matrix[1][0]; + m11 = matrix[1][1]; + m12 = matrix[1][2]; + m20 = matrix[2][0]; + m21 = matrix[2][1]; + m22 = matrix[2][2]; + + return this; + } + + /** + * Recreate Matrix using the provided axis. + * + * @param uAxis + * Vector3f + * @param vAxis + * Vector3f + * @param wAxis + * Vector3f + */ + public void fromAxes(Vector3f uAxis, Vector3f vAxis, Vector3f wAxis) { + m00 = uAxis.x; + m10 = uAxis.y; + m20 = uAxis.z; + + m01 = vAxis.x; + m11 = vAxis.y; + m21 = vAxis.z; + + m02 = wAxis.x; + m12 = wAxis.y; + m22 = wAxis.z; + } + + /** + * set sets the values of this matrix from an array of + * values assuming that the data is rowMajor order; + * + * @param matrix + * the matrix to set the value to. + * @return this + */ + public Matrix3f set(float[] matrix) { + return set(matrix, true); + } + + /** + * set sets the values of this matrix from an array of + * values; + * + * @param matrix + * the matrix to set the value to. + * @param rowMajor + * whether the incoming data is in row or column major order. + * @return this + */ + public Matrix3f set(float[] matrix, boolean rowMajor) { + if (matrix.length != 9) { + throw new IllegalArgumentException( + "Array must be of size 9."); + } + + if (rowMajor) { + m00 = matrix[0]; + m01 = matrix[1]; + m02 = matrix[2]; + m10 = matrix[3]; + m11 = matrix[4]; + m12 = matrix[5]; + m20 = matrix[6]; + m21 = matrix[7]; + m22 = matrix[8]; + } else { + m00 = matrix[0]; + m01 = matrix[3]; + m02 = matrix[6]; + m10 = matrix[1]; + m11 = matrix[4]; + m12 = matrix[7]; + m20 = matrix[2]; + m21 = matrix[5]; + m22 = matrix[8]; + } + return this; + } + + /** + * + * set defines the values of the matrix based on a supplied + * Quaternion. It should be noted that all previous values + * will be overridden. + * + * @param quaternion + * the quaternion to create a rotational matrix from. + * @return this + */ + public Matrix3f set(Quaternion quaternion) { + return quaternion.toRotationMatrix(this); + } + + /** + * loadIdentity sets this matrix to the identity matrix. + * Where all values are zero except those along the diagonal which are one. + * + */ + public void loadIdentity() { + m01 = m02 = m10 = m12 = m20 = m21 = 0; + m00 = m11 = m22 = 1; + } + + /** + * @return true if this matrix is identity + */ + public boolean isIdentity() { + return (m00 == 1 && m01 == 0 && m02 == 0) + && (m10 == 0 && m11 == 1 && m12 == 0) + && (m20 == 0 && m21 == 0 && m22 == 1); + } + + /** + * fromAngleAxis sets this matrix4f to the values specified + * by an angle and an axis of rotation. This method creates an object, so + * use fromAngleNormalAxis if your axis is already normalized. + * + * @param angle + * the angle to rotate (in radians). + * @param axis + * the axis of rotation. + */ + public void fromAngleAxis(float angle, Vector3f axis) { + Vector3f normAxis = axis.normalize(); + fromAngleNormalAxis(angle, normAxis); + } + + /** + * fromAngleNormalAxis sets this matrix4f to the values + * specified by an angle and a normalized axis of rotation. + * + * @param angle + * the angle to rotate (in radians). + * @param axis + * the axis of rotation (already normalized). + */ + public void fromAngleNormalAxis(float angle, Vector3f axis) { + float fCos = FastMath.cos(angle); + float fSin = FastMath.sin(angle); + float fOneMinusCos = ((float) 1.0) - fCos; + float fX2 = axis.x * axis.x; + float fY2 = axis.y * axis.y; + float fZ2 = axis.z * axis.z; + float fXYM = axis.x * axis.y * fOneMinusCos; + float fXZM = axis.x * axis.z * fOneMinusCos; + float fYZM = axis.y * axis.z * fOneMinusCos; + float fXSin = axis.x * fSin; + float fYSin = axis.y * fSin; + float fZSin = axis.z * fSin; + + m00 = fX2 * fOneMinusCos + fCos; + m01 = fXYM - fZSin; + m02 = fXZM + fYSin; + m10 = fXYM + fZSin; + m11 = fY2 * fOneMinusCos + fCos; + m12 = fYZM - fXSin; + m20 = fXZM - fYSin; + m21 = fYZM + fXSin; + m22 = fZ2 * fOneMinusCos + fCos; + } + + /** + * mult multiplies this matrix by a given matrix. The result + * matrix is returned as a new object. If the given matrix is null, a null + * matrix is returned. + * + * @param mat + * the matrix to multiply this matrix by. + * @return the result matrix. + */ + public Matrix3f mult(Matrix3f mat) { + return mult(mat, null); + } + + /** + * mult multiplies this matrix by a given matrix. The result + * matrix is returned as a new object. + * + * @param mat + * the matrix to multiply this matrix by. + * @param product + * the matrix to store the result in. if null, a new matrix3f is + * created. It is safe for mat and product to be the same object. + * @return a matrix3f object containing the result of this operation + */ + public Matrix3f mult(Matrix3f mat, Matrix3f product) { + + float temp00, temp01, temp02; + float temp10, temp11, temp12; + float temp20, temp21, temp22; + + if (product == null) { + product = new Matrix3f(); + } + temp00 = m00 * mat.m00 + m01 * mat.m10 + m02 * mat.m20; + temp01 = m00 * mat.m01 + m01 * mat.m11 + m02 * mat.m21; + temp02 = m00 * mat.m02 + m01 * mat.m12 + m02 * mat.m22; + temp10 = m10 * mat.m00 + m11 * mat.m10 + m12 * mat.m20; + temp11 = m10 * mat.m01 + m11 * mat.m11 + m12 * mat.m21; + temp12 = m10 * mat.m02 + m11 * mat.m12 + m12 * mat.m22; + temp20 = m20 * mat.m00 + m21 * mat.m10 + m22 * mat.m20; + temp21 = m20 * mat.m01 + m21 * mat.m11 + m22 * mat.m21; + temp22 = m20 * mat.m02 + m21 * mat.m12 + m22 * mat.m22; + + product.m00 = temp00; + product.m01 = temp01; + product.m02 = temp02; + product.m10 = temp10; + product.m11 = temp11; + product.m12 = temp12; + product.m20 = temp20; + product.m21 = temp21; + product.m22 = temp22; + + return product; + } + + /** + * mult multiplies this matrix by a given + * Vector3f object. The result vector is returned. If the + * given vector is null, null will be returned. + * + * @param vec + * the vector to multiply this matrix by. + * @return the result vector. + */ + public Vector3f mult(Vector3f vec) { + return mult(vec, null); + } + + /** + * Multiplies this 3x3 matrix by the 1x3 Vector vec and stores the result in + * product. + * + * @param vec + * The Vector3f to multiply. + * @param product + * The Vector3f to store the result, it is safe for this to be + * the same as vec. + * @return The given product vector. + */ + public Vector3f mult(Vector3f vec, Vector3f product) { + + if (null == product) { + product = new Vector3f(); + } + + float x = vec.x; + float y = vec.y; + float z = vec.z; + + product.x = m00 * x + m01 * y + m02 * z; + product.y = m10 * x + m11 * y + m12 * z; + product.z = m20 * x + m21 * y + m22 * z; + return product; + } + + /** + * multLocal multiplies this matrix internally by + * a given float scale factor. + * + * @param scale + * the value to scale by. + * @return this Matrix3f + */ + public Matrix3f multLocal(float scale) { + m00 *= scale; + m01 *= scale; + m02 *= scale; + m10 *= scale; + m11 *= scale; + m12 *= scale; + m20 *= scale; + m21 *= scale; + m22 *= scale; + return this; + } + + /** + * multLocal multiplies this matrix by a given + * Vector3f object. The result vector is stored inside the + * passed vector, then returned . If the given vector is null, null will be + * returned. + * + * @param vec + * the vector to multiply this matrix by. + * @return The passed vector after multiplication + */ + public Vector3f multLocal(Vector3f vec) { + if (vec == null) { + return null; + } + float x = vec.x; + float y = vec.y; + vec.x = m00 * x + m01 * y + m02 * vec.z; + vec.y = m10 * x + m11 * y + m12 * vec.z; + vec.z = m20 * x + m21 * y + m22 * vec.z; + return vec; + } + + /** + * mult multiplies this matrix by a given matrix. The result + * matrix is saved in the current matrix. If the given matrix is null, + * nothing happens. The current matrix is returned. This is equivalent to + * this*=mat + * + * @param mat + * the matrix to multiply this matrix by. + * @return This matrix, after the multiplication + */ + public Matrix3f multLocal(Matrix3f mat) { + return mult(mat, this); + } + + /** + * Transposes this matrix in place. Returns this matrix for chaining + * + * @return This matrix after transpose + */ + public Matrix3f transposeLocal() { +// float[] tmp = new float[9]; +// get(tmp, false); +// set(tmp, true); + + float tmp = m01; + m01 = m10; + m10 = tmp; + + tmp = m02; + m02 = m20; + m20 = tmp; + + tmp = m12; + m12 = m21; + m21 = tmp; + + return this; + } + + /** + * Inverts this matrix as a new Matrix3f. + * + * @return The new inverse matrix + */ + public Matrix3f invert() { + return invert(null); + } + + /** + * Inverts this matrix and stores it in the given store. + * + * @return The store + */ + public Matrix3f invert(Matrix3f store) { + if (store == null) { + store = new Matrix3f(); + } + + float det = determinant(); + if (FastMath.abs(det) <= FastMath.FLT_EPSILON) { + return store.zero(); + } + + store.m00 = m11 * m22 - m12 * m21; + store.m01 = m02 * m21 - m01 * m22; + store.m02 = m01 * m12 - m02 * m11; + store.m10 = m12 * m20 - m10 * m22; + store.m11 = m00 * m22 - m02 * m20; + store.m12 = m02 * m10 - m00 * m12; + store.m20 = m10 * m21 - m11 * m20; + store.m21 = m01 * m20 - m00 * m21; + store.m22 = m00 * m11 - m01 * m10; + + store.multLocal(1f / det); + return store; + } + + /** + * Inverts this matrix locally. + * + * @return this + */ + public Matrix3f invertLocal() { + float det = determinant(); + if (FastMath.abs(det) <= 0f) { + return zero(); + } + + float f00 = m11 * m22 - m12 * m21; + float f01 = m02 * m21 - m01 * m22; + float f02 = m01 * m12 - m02 * m11; + float f10 = m12 * m20 - m10 * m22; + float f11 = m00 * m22 - m02 * m20; + float f12 = m02 * m10 - m00 * m12; + float f20 = m10 * m21 - m11 * m20; + float f21 = m01 * m20 - m00 * m21; + float f22 = m00 * m11 - m01 * m10; + + m00 = f00; + m01 = f01; + m02 = f02; + m10 = f10; + m11 = f11; + m12 = f12; + m20 = f20; + m21 = f21; + m22 = f22; + + multLocal(1f / det); + return this; + } + + /** + * Returns a new matrix representing the adjoint of this matrix. + * + * @return The adjoint matrix + */ + public Matrix3f adjoint() { + return adjoint(null); + } + + /** + * Places the adjoint of this matrix in store (creates store if null.) + * + * @param store + * The matrix to store the result in. If null, a new matrix is created. + * @return store + */ + public Matrix3f adjoint(Matrix3f store) { + if (store == null) { + store = new Matrix3f(); + } + + store.m00 = m11 * m22 - m12 * m21; + store.m01 = m02 * m21 - m01 * m22; + store.m02 = m01 * m12 - m02 * m11; + store.m10 = m12 * m20 - m10 * m22; + store.m11 = m00 * m22 - m02 * m20; + store.m12 = m02 * m10 - m00 * m12; + store.m20 = m10 * m21 - m11 * m20; + store.m21 = m01 * m20 - m00 * m21; + store.m22 = m00 * m11 - m01 * m10; + + return store; + } + + /** + * determinant generates the determinant of this matrix. + * + * @return the determinant + */ + public float determinant() { + float fCo00 = m11 * m22 - m12 * m21; + float fCo10 = m12 * m20 - m10 * m22; + float fCo20 = m10 * m21 - m11 * m20; + float fDet = m00 * fCo00 + m01 * fCo10 + m02 * fCo20; + return fDet; + } + + /** + * Sets all of the values in this matrix to zero. + * + * @return this matrix + */ + public Matrix3f zero() { + m00 = m01 = m02 = m10 = m11 = m12 = m20 = m21 = m22 = 0.0f; + return this; + } + + /** + * transpose locally transposes this Matrix. + * This is inconsistent with general value vs local semantics, but is + * preserved for backwards compatibility. Use transposeNew() to transpose + * to a new object (value). + * + * @return this object for chaining. + */ + public Matrix3f transpose() { + return transposeLocal(); + } + + /** + * transposeNew returns a transposed version of this matrix. + * + * @return The new Matrix3f object. + */ + public Matrix3f transposeNew() { + Matrix3f ret = new Matrix3f(m00, m10, m20, m01, m11, m21, m02, m12, m22); + return ret; + } + + /** + * toString returns the string representation of this object. + * It is in a format of a 3x3 matrix. For example, an identity matrix would + * be represented by the following string. com.jme.math.Matrix3f
[
+ * 1.0 0.0 0.0
+ * 0.0 1.0 0.0
+ * 0.0 0.0 1.0
]
+ * + * @return the string representation of this object. + */ + @Override + public String toString() { + StringBuilder result = new StringBuilder("Matrix3f\n[\n"); + result.append(" "); + result.append(m00); + result.append(" "); + result.append(m01); + result.append(" "); + result.append(m02); + result.append(" \n"); + result.append(" "); + result.append(m10); + result.append(" "); + result.append(m11); + result.append(" "); + result.append(m12); + result.append(" \n"); + result.append(" "); + result.append(m20); + result.append(" "); + result.append(m21); + result.append(" "); + result.append(m22); + result.append(" \n]"); + return result.toString(); + } + + /** + * + * hashCode returns the hash code value as an integer and is + * supported for the benefit of hashing based collection classes such as + * Hashtable, HashMap, HashSet etc. + * + * @return the hashcode for this instance of Matrix4f. + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + int hash = 37; + hash = 37 * hash + Float.floatToIntBits(m00); + hash = 37 * hash + Float.floatToIntBits(m01); + hash = 37 * hash + Float.floatToIntBits(m02); + + hash = 37 * hash + Float.floatToIntBits(m10); + hash = 37 * hash + Float.floatToIntBits(m11); + hash = 37 * hash + Float.floatToIntBits(m12); + + hash = 37 * hash + Float.floatToIntBits(m20); + hash = 37 * hash + Float.floatToIntBits(m21); + hash = 37 * hash + Float.floatToIntBits(m22); + + return hash; + } + + /** + * are these two matrices the same? they are is they both have the same mXX values. + * + * @param o + * the object to compare for equality + * @return true if they are equal + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Matrix3f) || o == null) { + return false; + } + + if (this == o) { + return true; + } + + Matrix3f comp = (Matrix3f) o; + if (Float.compare(m00, comp.m00) != 0) { + return false; + } + if (Float.compare(m01, comp.m01) != 0) { + return false; + } + if (Float.compare(m02, comp.m02) != 0) { + return false; + } + + if (Float.compare(m10, comp.m10) != 0) { + return false; + } + if (Float.compare(m11, comp.m11) != 0) { + return false; + } + if (Float.compare(m12, comp.m12) != 0) { + return false; + } + + if (Float.compare(m20, comp.m20) != 0) { + return false; + } + if (Float.compare(m21, comp.m21) != 0) { + return false; + } + if (Float.compare(m22, comp.m22) != 0) { + return false; + } + + return true; + } + + public void write(JmeExporter e) throws IOException { + OutputCapsule cap = e.getCapsule(this); + cap.write(m00, "m00", 1); + cap.write(m01, "m01", 0); + cap.write(m02, "m02", 0); + cap.write(m10, "m10", 0); + cap.write(m11, "m11", 1); + cap.write(m12, "m12", 0); + cap.write(m20, "m20", 0); + cap.write(m21, "m21", 0); + cap.write(m22, "m22", 1); + } + + public void read(JmeImporter e) throws IOException { + InputCapsule cap = e.getCapsule(this); + m00 = cap.readFloat("m00", 1); + m01 = cap.readFloat("m01", 0); + m02 = cap.readFloat("m02", 0); + m10 = cap.readFloat("m10", 0); + m11 = cap.readFloat("m11", 1); + m12 = cap.readFloat("m12", 0); + m20 = cap.readFloat("m20", 0); + m21 = cap.readFloat("m21", 0); + m22 = cap.readFloat("m22", 1); + } + + /** + * A function for creating a rotation matrix that rotates a vector called + * "start" into another vector called "end". + * + * @param start + * normalized non-zero starting vector + * @param end + * normalized non-zero ending vector + * @see "Tomas M�ller, John Hughes \"Efficiently Building a Matrix to Rotate \ + * One Vector to Another\" Journal of Graphics Tools, 4(4):1-4, 1999" + */ + public void fromStartEndVectors(Vector3f start, Vector3f end) { + Vector3f v = new Vector3f(); + float e, h, f; + + start.cross(end, v); + e = start.dot(end); + f = (e < 0) ? -e : e; + + // if "from" and "to" vectors are nearly parallel + if (f > 1.0f - FastMath.ZERO_TOLERANCE) { + Vector3f u = new Vector3f(); + Vector3f x = new Vector3f(); + float c1, c2, c3; /* coefficients for later use */ + int i, j; + + x.x = (start.x > 0.0) ? start.x : -start.x; + x.y = (start.y > 0.0) ? start.y : -start.y; + x.z = (start.z > 0.0) ? start.z : -start.z; + + if (x.x < x.y) { + if (x.x < x.z) { + x.x = 1.0f; + x.y = x.z = 0.0f; + } else { + x.z = 1.0f; + x.x = x.y = 0.0f; + } + } else { + if (x.y < x.z) { + x.y = 1.0f; + x.x = x.z = 0.0f; + } else { + x.z = 1.0f; + x.x = x.y = 0.0f; + } + } + + u.x = x.x - start.x; + u.y = x.y - start.y; + u.z = x.z - start.z; + v.x = x.x - end.x; + v.y = x.y - end.y; + v.z = x.z - end.z; + + c1 = 2.0f / u.dot(u); + c2 = 2.0f / v.dot(v); + c3 = c1 * c2 * u.dot(v); + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + float val = -c1 * u.get(i) * u.get(j) - c2 * v.get(i) + * v.get(j) + c3 * v.get(i) * u.get(j); + set(i, j, val); + } + float val = get(i, i); + set(i, i, val + 1.0f); + } + } else { + // the most common case, unless "start"="end", or "start"=-"end" + float hvx, hvz, hvxy, hvxz, hvyz; + h = 1.0f / (1.0f + e); + hvx = h * v.x; + hvz = h * v.z; + hvxy = hvx * v.y; + hvxz = hvx * v.z; + hvyz = hvz * v.y; + set(0, 0, e + hvx * v.x); + set(0, 1, hvxy - v.z); + set(0, 2, hvxz + v.y); + + set(1, 0, hvxy + v.z); + set(1, 1, e + h * v.y * v.y); + set(1, 2, hvyz - v.x); + + set(2, 0, hvxz - v.y); + set(2, 1, hvyz + v.x); + set(2, 2, e + hvz * v.z); + } + } + + /** + * scale scales the operation performed by this matrix on a + * per-component basis. + * + * @param scale + * The scale applied to each of the X, Y and Z output values. + */ + public void scale(Vector3f scale) { + m00 *= scale.x; + m10 *= scale.x; + m20 *= scale.x; + m01 *= scale.y; + m11 *= scale.y; + m21 *= scale.y; + m02 *= scale.z; + m12 *= scale.z; + m22 *= scale.z; + } + + static boolean equalIdentity(Matrix3f mat) { + if (Math.abs(mat.m00 - 1) > 1e-4) { + return false; + } + if (Math.abs(mat.m11 - 1) > 1e-4) { + return false; + } + if (Math.abs(mat.m22 - 1) > 1e-4) { + return false; + } + + if (Math.abs(mat.m01) > 1e-4) { + return false; + } + if (Math.abs(mat.m02) > 1e-4) { + return false; + } + + if (Math.abs(mat.m10) > 1e-4) { + return false; + } + if (Math.abs(mat.m12) > 1e-4) { + return false; + } + + if (Math.abs(mat.m20) > 1e-4) { + return false; + } + if (Math.abs(mat.m21) > 1e-4) { + return false; + } + + return true; + } + + @Override + public Matrix3f clone() { + try { + return (Matrix3f) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); // can not happen + } + } +}