/*
|
* 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 cz.advel.stack.Stack;
|
import cz.advel.stack.StaticAlloc;
|
import javax.vecmath.Matrix3f;
|
import javax.vecmath.Quat4f;
|
import javax.vecmath.Vector3f;
|
|
/**
|
* Utility functions for transforms.
|
*
|
* @author jezek2
|
*/
|
public class TransformUtil {
|
|
public static final float SIMDSQRT12 = 0.7071067811865475244008443621048490f;
|
public static final float ANGULAR_MOTION_THRESHOLD = 0.5f*BulletGlobals.SIMD_HALF_PI;
|
|
public static float recipSqrt(float x) {
|
return 1f / (float)Math.sqrt(x); /* reciprocal square root */
|
}
|
|
public static void planeSpace1(Vector3f n, Vector3f p, Vector3f q) {
|
if (Math.abs(n.z) > SIMDSQRT12) {
|
// choose p in y-z plane
|
float a = n.y * n.y + n.z * n.z;
|
float k = recipSqrt(a);
|
p.set(0, -n.z * k, n.y * k);
|
// set q = n x p
|
q.set(a * k, -n.x * p.z, n.x * p.y);
|
}
|
else {
|
// choose p in x-y plane
|
float a = n.x * n.x + n.y * n.y;
|
float k = recipSqrt(a);
|
p.set(-n.y * k, n.x * k, 0);
|
// set q = n x p
|
q.set(-n.z * p.y, n.z * p.x, a * k);
|
}
|
}
|
|
@StaticAlloc
|
public static void integrateTransform(Transform curTrans, Vector3f linvel, Vector3f angvel, float timeStep, Transform predictedTransform) {
|
predictedTransform.origin.scaleAdd(timeStep, linvel, curTrans.origin);
|
// //#define QUATERNION_DERIVATIVE
|
// #ifdef QUATERNION_DERIVATIVE
|
// btQuaternion predictedOrn = curTrans.getRotation();
|
// predictedOrn += (angvel * predictedOrn) * (timeStep * btScalar(0.5));
|
// predictedOrn.normalize();
|
// #else
|
// Exponential map
|
// google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
|
|
Vector3f axis = Stack.alloc(Vector3f.class);
|
float fAngle = angvel.length();
|
|
// limit the angular motion
|
if (fAngle * timeStep > ANGULAR_MOTION_THRESHOLD) {
|
fAngle = ANGULAR_MOTION_THRESHOLD / timeStep;
|
}
|
|
if (fAngle < 0.001f) {
|
// use Taylor's expansions of sync function
|
axis.scale(0.5f * timeStep - (timeStep * timeStep * timeStep) * (0.020833333333f) * fAngle * fAngle, angvel);
|
}
|
else {
|
// sync(fAngle) = sin(c*fAngle)/t
|
axis.scale((float) Math.sin(0.5f * fAngle * timeStep) / fAngle, angvel);
|
}
|
Quat4f dorn = Stack.alloc(Quat4f.class);
|
dorn.set(axis.x, axis.y, axis.z, (float) Math.cos(fAngle * timeStep * 0.5f));
|
Quat4f orn0 = curTrans.getRotation(Stack.alloc(Quat4f.class));
|
|
Quat4f predictedOrn = Stack.alloc(Quat4f.class);
|
predictedOrn.mul(dorn, orn0);
|
predictedOrn.normalize();
|
// #endif
|
predictedTransform.setRotation(predictedOrn);
|
}
|
|
public static void calculateVelocity(Transform transform0, Transform transform1, float timeStep, Vector3f linVel, Vector3f angVel) {
|
linVel.sub(transform1.origin, transform0.origin);
|
linVel.scale(1f / timeStep);
|
|
Vector3f axis = Stack.alloc(Vector3f.class);
|
float[] angle = new float[1];
|
calculateDiffAxisAngle(transform0, transform1, axis, angle);
|
angVel.scale(angle[0] / timeStep, axis);
|
}
|
|
public static void calculateDiffAxisAngle(Transform transform0, Transform transform1, Vector3f axis, float[] angle) {
|
// #ifdef USE_QUATERNION_DIFF
|
// btQuaternion orn0 = transform0.getRotation();
|
// btQuaternion orn1a = transform1.getRotation();
|
// btQuaternion orn1 = orn0.farthest(orn1a);
|
// btQuaternion dorn = orn1 * orn0.inverse();
|
// #else
|
Matrix3f tmp = Stack.alloc(Matrix3f.class);
|
tmp.set(transform0.basis);
|
MatrixUtil.invert(tmp);
|
|
Matrix3f dmat = Stack.alloc(Matrix3f.class);
|
dmat.mul(transform1.basis, tmp);
|
|
Quat4f dorn = Stack.alloc(Quat4f.class);
|
MatrixUtil.getRotation(dmat, dorn);
|
// #endif
|
|
// floating point inaccuracy can lead to w component > 1..., which breaks
|
|
dorn.normalize();
|
|
angle[0] = QuaternionUtil.getAngle(dorn);
|
axis.set(dorn.x, dorn.y, dorn.z);
|
// TODO: probably not needed
|
//axis[3] = btScalar(0.);
|
|
// check for axis length
|
float len = axis.lengthSquared();
|
if (len < BulletGlobals.FLT_EPSILON * BulletGlobals.FLT_EPSILON) {
|
axis.set(1f, 0f, 0f);
|
}
|
else {
|
axis.scale(1f / (float) Math.sqrt(len));
|
}
|
}
|
|
}
|