// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.math; import org.pmw.tinylog.Logger; import java.nio.FloatBuffer; /** * 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. */ public class Matrix3f { public float m00, m01, m02; public float m10, m11, m12; public float m20, m21, m22; /** * 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) { copy(mat); } 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; return !(Math.abs(mat.m21) > 1e-4); } /** * 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. */ public void copy(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; } } /** * get retrieves a value from the matrix at the given position. * If the position is invalid a Exception is thrown. * * @param i the row index. * @param j the column index. * @return the value at (i, j). * @throws Exception */ public float get(int i, int j) throws Exception { 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; } } throw new Exception("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). * @throws Exception */ public void get(float[] data, boolean rowMajor) throws Exception { 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 Exception("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. * @throws Exception */ public Vector3f getColumn(int i) throws Exception { 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. * @throws Exception */ public Vector3f getColumn(int i, Vector3f store) throws Exception { 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: throw new Exception("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. * @throws Exception */ public Vector3f getRow(int i) throws Exception { 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. * @throws Exception */ public Vector3f getRow(int i, Vector3f store) throws Exception { 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: throw new Exception("Invalid row index. " + i); } return store; } /** * 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) { fb.put(m00).put(m01).put(m02); fb.put(m10).put(m11).put(m12); fb.put(m20).put(m21).put(m22); return fb; } /** * 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. * @throws Exception */ public void setColumn(int i, Vector3f column) throws Exception { if (column == null) { return; } 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: throw new Exception("Invalid column index. " + i); } } /** * 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. * @throws Exception */ public void setRow(int i, Vector3f row) throws Exception { if (row == null) { return; } 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: throw new Exception("Invalid row index. " + i); } } /** * set places a given value into the matrix at the given * position. If the position is invalid a Exception is thrown. * * @param i the row index. * @param j the column index. * @param value the value for (i, j). * @throws Exception */ public void set(int i, int j, float value) throws Exception { switch (i) { case 0: switch (j) { case 0: m00 = value; return; case 1: m01 = value; return; case 2: m02 = value; return; } case 1: switch (j) { case 0: m10 = value; return; case 1: m11 = value; return; case 2: m12 = value; return; } case 2: switch (j) { case 0: m20 = value; return; case 1: m21 = value; return; case 2: m22 = value; return; } } throw new Exception("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 Exception if the array is not of size 9. */ public void set(float[][] matrix) throws Exception { if (matrix.length != 3 || matrix[0].length != 3) { throw new Exception("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]; } /** * 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. * @throws Exception */ public void set(float[] matrix) throws Exception { 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. */ public void set(float[] matrix, boolean rowMajor) throws Exception { if (matrix.length != 9) throw new Exception("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]; } } /** * 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. */ public void set(Quaternion quaternion) { 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 * @throws Exception */ public Matrix3f transposeLocal() throws Exception { float[] tmp = new float[9]; get(tmp, false); set(tmp, true); 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) <= 0) 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) <= FastMath.FLT_EPSILON) 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; return m00 * fCo00 + m01 * fCo10 + m02 * fCo20; } /** * 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; } /** * add adds the values of a parameter matrix to this matrix. * * @param mat the matrix to add to this. */ public void add(Matrix3f mat) { m00 += mat.m00; m01 += mat.m01; m02 += mat.m02; m10 += mat.m10; m11 += mat.m11; m12 += mat.m12; m20 += mat.m20; m21 += mat.m21; m22 += mat.m22; } /** * 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. * @throws Exception */ public Matrix3f transpose() throws Exception { return transposeLocal(); } /** * transposeNew returns a transposed version of this matrix. * * @return The new Matrix3f object. */ public Matrix3f transposeNew() { return new Matrix3f(m00, m10, m20, m01, m11, m21, m02, m12, m22); } /** * 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() { StringBuffer result = new StringBuffer("com.jme.math.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; return Float.compare(m22, comp.m22) == 0; } /** * 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 * @throws Exception * @see "Tomas Miller, 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) throws Exception { 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; } @Override public Matrix3f clone() { try { return (Matrix3f) super.clone(); } catch (CloneNotSupportedException e) { Logger.error(e); throw new AssertionError(); // can not happen } } }