/*
|
* 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.collision.narrowphase;
|
|
import com.bulletphysics.BulletGlobals;
|
import com.bulletphysics.collision.shapes.ConvexShape;
|
import com.bulletphysics.linearmath.MatrixUtil;
|
import com.bulletphysics.linearmath.Transform;
|
import com.bulletphysics.linearmath.VectorUtil;
|
import cz.advel.stack.Stack;
|
import javax.vecmath.Vector3f;
|
|
/**
|
* SubsimplexConvexCast implements Gino van den Bergens' paper
|
* "Ray Casting against bteral Convex Objects with Application to Continuous Collision Detection"
|
* GJK based Ray Cast, optimized version
|
* Objects should not start in overlap, otherwise results are not defined.
|
*
|
* @author jezek2
|
*/
|
public class SubsimplexConvexCast extends ConvexCast {
|
|
//protected final BulletStack stack = BulletStack.get();
|
|
// Typically the conservative advancement reaches solution in a few iterations, clip it to 32 for degenerate cases.
|
// See discussion about this here http://www.bulletphysics.com/phpBB2/viewtopic.php?t=565
|
//#ifdef BT_USE_DOUBLE_PRECISION
|
//#define MAX_ITERATIONS 64
|
//#else
|
//#define MAX_ITERATIONS 32
|
//#endif
|
|
private static final int MAX_ITERATIONS = 32;
|
|
private SimplexSolverInterface simplexSolver;
|
private ConvexShape convexA;
|
private ConvexShape convexB;
|
|
public SubsimplexConvexCast(ConvexShape shapeA, ConvexShape shapeB, SimplexSolverInterface simplexSolver) {
|
this.convexA = shapeA;
|
this.convexB = shapeB;
|
this.simplexSolver = simplexSolver;
|
}
|
|
public boolean calcTimeOfImpact(Transform fromA, Transform toA, Transform fromB, Transform toB, CastResult result) {
|
Vector3f tmp = Stack.alloc(Vector3f.class);
|
|
simplexSolver.reset();
|
|
Vector3f linVelA = Stack.alloc(Vector3f.class);
|
Vector3f linVelB = Stack.alloc(Vector3f.class);
|
linVelA.sub(toA.origin, fromA.origin);
|
linVelB.sub(toB.origin, fromB.origin);
|
|
float lambda = 0f;
|
|
Transform interpolatedTransA = (Transform) Stack.alloc(fromA);
|
Transform interpolatedTransB = (Transform) Stack.alloc(fromB);
|
|
// take relative motion
|
Vector3f r = Stack.alloc(Vector3f.class);
|
r.sub(linVelA, linVelB);
|
|
Vector3f v = Stack.alloc(Vector3f.class);
|
|
tmp.negate(r);
|
MatrixUtil.transposeTransform(tmp, tmp, fromA.basis);
|
Vector3f supVertexA = convexA.localGetSupportingVertex(tmp, Stack.alloc(Vector3f.class));
|
fromA.transform(supVertexA);
|
|
MatrixUtil.transposeTransform(tmp, r, fromB.basis);
|
Vector3f supVertexB = convexB.localGetSupportingVertex(tmp, Stack.alloc(Vector3f.class));
|
fromB.transform(supVertexB);
|
|
v.sub(supVertexA, supVertexB);
|
|
int maxIter = MAX_ITERATIONS;
|
|
Vector3f n = Stack.alloc(Vector3f.class);
|
n.set(0f, 0f, 0f);
|
boolean hasResult = false;
|
Vector3f c = Stack.alloc(Vector3f.class);
|
|
float lastLambda = lambda;
|
|
float dist2 = v.lengthSquared();
|
//#ifdef BT_USE_DOUBLE_PRECISION
|
// btScalar epsilon = btScalar(0.0001);
|
//#else
|
float epsilon = 0.0001f;
|
//#endif
|
Vector3f w = Stack.alloc(Vector3f.class), p = Stack.alloc(Vector3f.class);
|
float VdotR;
|
|
while ((dist2 > epsilon) && (maxIter--) != 0) {
|
tmp.negate(v);
|
MatrixUtil.transposeTransform(tmp, tmp, interpolatedTransA.basis);
|
convexA.localGetSupportingVertex(tmp, supVertexA);
|
interpolatedTransA.transform(supVertexA);
|
|
MatrixUtil.transposeTransform(tmp, v, interpolatedTransB.basis);
|
convexB.localGetSupportingVertex(tmp, supVertexB);
|
interpolatedTransB.transform(supVertexB);
|
|
w.sub(supVertexA, supVertexB);
|
|
float VdotW = v.dot(w);
|
|
if (lambda > 1f) {
|
return false;
|
}
|
|
if (VdotW > 0f) {
|
VdotR = v.dot(r);
|
|
if (VdotR >= -(BulletGlobals.FLT_EPSILON * BulletGlobals.FLT_EPSILON)) {
|
return false;
|
}
|
else {
|
lambda = lambda - VdotW / VdotR;
|
|
// interpolate to next lambda
|
// x = s + lambda * r;
|
VectorUtil.setInterpolate3(interpolatedTransA.origin, fromA.origin, toA.origin, lambda);
|
VectorUtil.setInterpolate3(interpolatedTransB.origin, fromB.origin, toB.origin, lambda);
|
//m_simplexSolver->reset();
|
// check next line
|
w.sub(supVertexA, supVertexB);
|
lastLambda = lambda;
|
n.set(v);
|
hasResult = true;
|
}
|
}
|
simplexSolver.addVertex(w, supVertexA , supVertexB);
|
if (simplexSolver.closest(v)) {
|
dist2 = v.lengthSquared();
|
hasResult = true;
|
// todo: check this normal for validity
|
//n.set(v);
|
//printf("V=%f , %f, %f\n",v[0],v[1],v[2]);
|
//printf("DIST2=%f\n",dist2);
|
//printf("numverts = %i\n",m_simplexSolver->numVertices());
|
}
|
else {
|
dist2 = 0f;
|
}
|
}
|
|
//int numiter = MAX_ITERATIONS - maxIter;
|
// printf("number of iterations: %d", numiter);
|
|
// don't report a time of impact when moving 'away' from the hitnormal
|
|
result.fraction = lambda;
|
if (n.lengthSquared() >= BulletGlobals.SIMD_EPSILON * BulletGlobals.SIMD_EPSILON) {
|
result.normal.normalize(n);
|
}
|
else {
|
result.normal.set(0f, 0f, 0f);
|
}
|
|
// don't report time of impact for motion away from the contact normal (or causes minor penetration)
|
if (result.normal.dot(r) >= -result.allowedPenetration)
|
return false;
|
|
Vector3f hitA = Stack.alloc(Vector3f.class);
|
Vector3f hitB = Stack.alloc(Vector3f.class);
|
simplexSolver.compute_points(hitA,hitB);
|
result.hitPoint.set(hitB);
|
return true;
|
}
|
|
}
|