/*
|
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
|
*
|
* Bullet Continuous Collision Detection and Physics Library
|
* Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
|
*
|
* This software is provided 'as-is', without any express or implied warranty.
|
* In no event will the authors be held liable for any damages arising from
|
* the use of this software.
|
*
|
* Permission is granted to anyone to use this software for any purpose,
|
* including commercial applications, and to alter it and redistribute it
|
* freely, subject to the following restrictions:
|
*
|
* 1. The origin of this software must not be misrepresented; you must not
|
* claim that you wrote the original software. If you use this software
|
* in a product, an acknowledgment in the product documentation would be
|
* appreciated but is not required.
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
* misrepresented as being the original software.
|
* 3. This notice may not be removed or altered from any source distribution.
|
*/
|
|
package com.bulletphysics.linearmath;
|
|
import com.bulletphysics.BulletGlobals;
|
import com.bulletphysics.util.ArrayPool;
|
import cz.advel.stack.Stack;
|
import javax.vecmath.Matrix3f;
|
import javax.vecmath.Quat4f;
|
import javax.vecmath.Vector3f;
|
|
/**
|
* Utility functions for matrices.
|
*
|
* @author jezek2
|
*/
|
public class MatrixUtil {
|
|
public static void scale(Matrix3f dest, Matrix3f mat, Vector3f s) {
|
dest.m00 = mat.m00 * s.x; dest.m01 = mat.m01 * s.y; dest.m02 = mat.m02 * s.z;
|
dest.m10 = mat.m10 * s.x; dest.m11 = mat.m11 * s.y; dest.m12 = mat.m12 * s.z;
|
dest.m20 = mat.m20 * s.x; dest.m21 = mat.m21 * s.y; dest.m22 = mat.m22 * s.z;
|
}
|
|
public static void absolute(Matrix3f mat) {
|
mat.m00 = Math.abs(mat.m00);
|
mat.m01 = Math.abs(mat.m01);
|
mat.m02 = Math.abs(mat.m02);
|
mat.m10 = Math.abs(mat.m10);
|
mat.m11 = Math.abs(mat.m11);
|
mat.m12 = Math.abs(mat.m12);
|
mat.m20 = Math.abs(mat.m20);
|
mat.m21 = Math.abs(mat.m21);
|
mat.m22 = Math.abs(mat.m22);
|
}
|
|
public static void setFromOpenGLSubMatrix(Matrix3f mat, float[] m) {
|
mat.m00 = m[0]; mat.m01 = m[4]; mat.m02 = m[8];
|
mat.m10 = m[1]; mat.m11 = m[5]; mat.m12 = m[9];
|
mat.m20 = m[2]; mat.m21 = m[6]; mat.m22 = m[10];
|
}
|
|
public static void getOpenGLSubMatrix(Matrix3f mat, float[] m) {
|
m[0] = mat.m00;
|
m[1] = mat.m10;
|
m[2] = mat.m20;
|
m[3] = 0f;
|
m[4] = mat.m01;
|
m[5] = mat.m11;
|
m[6] = mat.m21;
|
m[7] = 0f;
|
m[8] = mat.m02;
|
m[9] = mat.m12;
|
m[10] = mat.m22;
|
m[11] = 0f;
|
}
|
|
/**
|
* Sets rotation matrix from euler angles. The euler angles are applied in ZYX
|
* order. This means a vector is first rotated about X then Y and then Z axis.
|
*/
|
public static void setEulerZYX(Matrix3f mat, float eulerX, float eulerY, float eulerZ) {
|
double ci = Math.cos(eulerX);
|
double cj = Math.cos(eulerY);
|
double ch = Math.cos(eulerZ);
|
double si = Math.sin(eulerX);
|
double sj = Math.sin(eulerY);
|
double sh = Math.sin(eulerZ);
|
double cc = ci * ch;
|
double cs = ci * sh;
|
double sc = si * ch;
|
double ss = si * sh;
|
|
mat.setRow(0, (float)(cj * ch), (float)(sj * sc - cs), (float)(sj * cc + ss));
|
mat.setRow(1, (float)(cj * sh), (float)(sj * ss + cc), (float)(sj * cs - sc));
|
mat.setRow(2, (float)(-sj), (float)(cj * si), (float)(cj * ci));
|
}
|
|
private static float tdotx(Matrix3f mat, Vector3f vec) {
|
return mat.m00 * vec.x + mat.m10 * vec.y + mat.m20 * vec.z;
|
}
|
|
private static float tdoty(Matrix3f mat, Vector3f vec) {
|
return mat.m01 * vec.x + mat.m11 * vec.y + mat.m21 * vec.z;
|
}
|
|
private static float tdotz(Matrix3f mat, Vector3f vec) {
|
return mat.m02 * vec.x + mat.m12 * vec.y + mat.m22 * vec.z;
|
}
|
|
public static void transposeTransform(Vector3f dest, Vector3f vec, Matrix3f mat) {
|
float x = tdotx(mat, vec);
|
float y = tdoty(mat, vec);
|
float z = tdotz(mat, vec);
|
dest.x = x;
|
dest.y = y;
|
dest.z = z;
|
}
|
|
public static void setRotation(Matrix3f dest, Quat4f q) {
|
float d = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
|
assert (d != 0f);
|
float s = 2f / d;
|
float xs = q.x * s, ys = q.y * s, zs = q.z * s;
|
float wx = q.w * xs, wy = q.w * ys, wz = q.w * zs;
|
float xx = q.x * xs, xy = q.x * ys, xz = q.x * zs;
|
float yy = q.y * ys, yz = q.y * zs, zz = q.z * zs;
|
dest.m00 = 1f - (yy + zz);
|
dest.m01 = xy - wz;
|
dest.m02 = xz + wy;
|
dest.m10 = xy + wz;
|
dest.m11 = 1f - (xx + zz);
|
dest.m12 = yz - wx;
|
dest.m20 = xz - wy;
|
dest.m21 = yz + wx;
|
dest.m22 = 1f - (xx + yy);
|
}
|
|
public static void getRotation(Matrix3f mat, Quat4f dest) {
|
ArrayPool<float[]> floatArrays = ArrayPool.get(float.class);
|
|
float trace = mat.m00 + mat.m11 + mat.m22;
|
float[] temp = floatArrays.getFixed(4);
|
|
if (trace > 0f) {
|
float s = (float) Math.sqrt(trace + 1f);
|
temp[3] = (s * 0.5f);
|
s = 0.5f / s;
|
|
temp[0] = ((mat.m21 - mat.m12) * s);
|
temp[1] = ((mat.m02 - mat.m20) * s);
|
temp[2] = ((mat.m10 - mat.m01) * s);
|
}
|
else {
|
int i = mat.m00 < mat.m11 ? (mat.m11 < mat.m22 ? 2 : 1) : (mat.m00 < mat.m22 ? 2 : 0);
|
int j = (i + 1) % 3;
|
int k = (i + 2) % 3;
|
|
float s = (float) Math.sqrt(mat.getElement(i, i) - mat.getElement(j, j) - mat.getElement(k, k) + 1f);
|
temp[i] = s * 0.5f;
|
s = 0.5f / s;
|
|
temp[3] = (mat.getElement(k, j) - mat.getElement(j, k)) * s;
|
temp[j] = (mat.getElement(j, i) + mat.getElement(i, j)) * s;
|
temp[k] = (mat.getElement(k, i) + mat.getElement(i, k)) * s;
|
}
|
dest.set(temp[0], temp[1], temp[2], temp[3]);
|
|
floatArrays.release(temp);
|
}
|
|
private static float cofac(Matrix3f mat, int r1, int c1, int r2, int c2) {
|
return mat.getElement(r1, c1) * mat.getElement(r2, c2) - mat.getElement(r1, c2) * mat.getElement(r2, c1);
|
}
|
|
public static void invert(Matrix3f mat) {
|
float co_x = cofac(mat, 1, 1, 2, 2);
|
float co_y = cofac(mat, 1, 2, 2, 0);
|
float co_z = cofac(mat, 1, 0, 2, 1);
|
|
float det = mat.m00*co_x + mat.m01*co_y + mat.m02*co_z;
|
assert (det != 0f);
|
|
float s = 1f / det;
|
float m00 = co_x * s;
|
float m01 = cofac(mat, 0, 2, 2, 1) * s;
|
float m02 = cofac(mat, 0, 1, 1, 2) * s;
|
float m10 = co_y * s;
|
float m11 = cofac(mat, 0, 0, 2, 2) * s;
|
float m12 = cofac(mat, 0, 2, 1, 0) * s;
|
float m20 = co_z * s;
|
float m21 = cofac(mat, 0, 1, 2, 0) * s;
|
float m22 = cofac(mat, 0, 0, 1, 1) * s;
|
|
mat.m00 = m00;
|
mat.m01 = m01;
|
mat.m02 = m02;
|
mat.m10 = m10;
|
mat.m11 = m11;
|
mat.m12 = m12;
|
mat.m20 = m20;
|
mat.m21 = m21;
|
mat.m22 = m22;
|
}
|
|
/**
|
* Diagonalizes this matrix by the Jacobi method. rot stores the rotation
|
* from the coordinate system in which the matrix is diagonal to the original
|
* coordinate system, i.e., old_this = rot * new_this * rot^T. The iteration
|
* stops when all off-diagonal elements are less than the threshold multiplied
|
* by the sum of the absolute values of the diagonal, or when maxSteps have
|
* been executed. Note that this matrix is assumed to be symmetric.
|
*/
|
// JAVA NOTE: diagonalize method from 2.71
|
public static void diagonalize(Matrix3f mat, Matrix3f rot, float threshold, int maxSteps) {
|
Vector3f row = Stack.alloc(Vector3f.class);
|
|
rot.setIdentity();
|
for (int step = maxSteps; step > 0; step--) {
|
// find off-diagonal element [p][q] with largest magnitude
|
int p = 0;
|
int q = 1;
|
int r = 2;
|
float max = Math.abs(mat.m01);
|
float v = Math.abs(mat.m02);
|
if (v > max) {
|
q = 2;
|
r = 1;
|
max = v;
|
}
|
v = Math.abs(mat.m12);
|
if (v > max) {
|
p = 1;
|
q = 2;
|
r = 0;
|
max = v;
|
}
|
|
float t = threshold * (Math.abs(mat.m00) + Math.abs(mat.m11) + Math.abs(mat.m22));
|
if (max <= t) {
|
if (max <= BulletGlobals.SIMD_EPSILON * t) {
|
return;
|
}
|
step = 1;
|
}
|
|
// compute Jacobi rotation J which leads to a zero for element [p][q]
|
float mpq = mat.getElement(p, q);
|
float theta = (mat.getElement(q, q) - mat.getElement(p, p)) / (2 * mpq);
|
float theta2 = theta * theta;
|
float cos;
|
float sin;
|
if ((theta2 * theta2) < (10f / BulletGlobals.SIMD_EPSILON)) {
|
t = (theta >= 0f) ? 1f / (theta + (float) Math.sqrt(1f + theta2))
|
: 1f / (theta - (float) Math.sqrt(1f + theta2));
|
cos = 1f / (float) Math.sqrt(1f + t * t);
|
sin = cos * t;
|
}
|
else {
|
// approximation for large theta-value, i.e., a nearly diagonal matrix
|
t = 1 / (theta * (2 + 0.5f / theta2));
|
cos = 1 - 0.5f * t * t;
|
sin = cos * t;
|
}
|
|
// apply rotation to matrix (this = J^T * this * J)
|
mat.setElement(p, q, 0f);
|
mat.setElement(q, p, 0f);
|
mat.setElement(p, p, mat.getElement(p, p) - t * mpq);
|
mat.setElement(q, q, mat.getElement(q, q) + t * mpq);
|
float mrp = mat.getElement(r, p);
|
float mrq = mat.getElement(r, q);
|
mat.setElement(r, p, cos * mrp - sin * mrq);
|
mat.setElement(p, r, cos * mrp - sin * mrq);
|
mat.setElement(r, q, cos * mrq + sin * mrp);
|
mat.setElement(q, r, cos * mrq + sin * mrp);
|
|
// apply rotation to rot (rot = rot * J)
|
for (int i=0; i<3; i++) {
|
rot.getRow(i, row);
|
|
mrp = VectorUtil.getCoord(row, p);
|
mrq = VectorUtil.getCoord(row, q);
|
VectorUtil.setCoord(row, p, cos * mrp - sin * mrq);
|
VectorUtil.setCoord(row, q, cos * mrq + sin * mrp);
|
rot.setRow(i, row);
|
}
|
}
|
}
|
|
}
|