2017-08-01 14:30:58 +02:00
|
|
|
/*
|
|
|
|
Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef B3_TRANSFORM_UTIL_H
|
|
|
|
#define B3_TRANSFORM_UTIL_H
|
|
|
|
|
|
|
|
#include "b3Transform.h"
|
2019-01-03 14:26:51 +01:00
|
|
|
#define B3_ANGULAR_MOTION_THRESHOLD b3Scalar(0.5) * B3_HALF_PI
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
B3_FORCE_INLINE b3Vector3 b3AabbSupport(const b3Vector3& halfExtents, const b3Vector3& supportDir)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
return b3MakeVector3(supportDir.getX() < b3Scalar(0.0) ? -halfExtents.getX() : halfExtents.getX(),
|
2019-01-03 14:26:51 +01:00
|
|
|
supportDir.getY() < b3Scalar(0.0) ? -halfExtents.getY() : halfExtents.getY(),
|
|
|
|
supportDir.getZ() < b3Scalar(0.0) ? -halfExtents.getZ() : halfExtents.getZ());
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Utils related to temporal transforms
|
|
|
|
class b3TransformUtil
|
|
|
|
{
|
|
|
|
public:
|
2019-01-03 14:26:51 +01:00
|
|
|
static void integrateTransform(const b3Transform& curTrans, const b3Vector3& linvel, const b3Vector3& angvel, b3Scalar timeStep, b3Transform& predictedTransform)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep);
|
2019-01-03 14:26:51 +01:00
|
|
|
// #define QUATERNION_DERIVATIVE
|
|
|
|
#ifdef QUATERNION_DERIVATIVE
|
2017-08-01 14:30:58 +02:00
|
|
|
b3Quaternion predictedOrn = curTrans.getRotation();
|
|
|
|
predictedOrn += (angvel * predictedOrn) * (timeStep * b3Scalar(0.5));
|
|
|
|
predictedOrn.normalize();
|
2019-01-03 14:26:51 +01:00
|
|
|
#else
|
2017-08-01 14:30:58 +02:00
|
|
|
//Exponential map
|
|
|
|
//google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
|
|
|
|
|
|
|
|
b3Vector3 axis;
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Scalar fAngle = angvel.length();
|
2017-08-01 14:30:58 +02:00
|
|
|
//limit the angular motion
|
2019-01-03 14:26:51 +01:00
|
|
|
if (fAngle * timeStep > B3_ANGULAR_MOTION_THRESHOLD)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
fAngle = B3_ANGULAR_MOTION_THRESHOLD / timeStep;
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
if (fAngle < b3Scalar(0.001))
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
// use Taylor's expansions of sync function
|
2019-01-03 14:26:51 +01:00
|
|
|
axis = angvel * (b3Scalar(0.5) * timeStep - (timeStep * timeStep * timeStep) * (b3Scalar(0.020833333333)) * fAngle * fAngle);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// sync(fAngle) = sin(c*fAngle)/t
|
2019-01-03 14:26:51 +01:00
|
|
|
axis = angvel * (b3Sin(b3Scalar(0.5) * fAngle * timeStep) / fAngle);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Quaternion dorn(axis.getX(), axis.getY(), axis.getZ(), b3Cos(fAngle * timeStep * b3Scalar(0.5)));
|
2017-08-01 14:30:58 +02:00
|
|
|
b3Quaternion orn0 = curTrans.getRotation();
|
|
|
|
|
|
|
|
b3Quaternion predictedOrn = dorn * orn0;
|
|
|
|
predictedOrn.normalize();
|
2019-01-03 14:26:51 +01:00
|
|
|
#endif
|
2017-08-01 14:30:58 +02:00
|
|
|
predictedTransform.setRotation(predictedOrn);
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
static void calculateVelocityQuaternion(const b3Vector3& pos0, const b3Vector3& pos1, const b3Quaternion& orn0, const b3Quaternion& orn1, b3Scalar timeStep, b3Vector3& linVel, b3Vector3& angVel)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
linVel = (pos1 - pos0) / timeStep;
|
|
|
|
b3Vector3 axis;
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Scalar angle;
|
2017-08-01 14:30:58 +02:00
|
|
|
if (orn0 != orn1)
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
calculateDiffAxisAngleQuaternion(orn0, orn1, axis, angle);
|
2017-08-01 14:30:58 +02:00
|
|
|
angVel = axis * angle / timeStep;
|
2019-01-03 14:26:51 +01:00
|
|
|
}
|
|
|
|
else
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
angVel.setValue(0, 0, 0);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
static void calculateDiffAxisAngleQuaternion(const b3Quaternion& orn0, const b3Quaternion& orn1a, b3Vector3& axis, b3Scalar& angle)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
b3Quaternion orn1 = orn0.nearest(orn1a);
|
|
|
|
b3Quaternion dorn = orn1 * orn0.inverse();
|
|
|
|
angle = dorn.getAngle();
|
2019-01-03 14:26:51 +01:00
|
|
|
axis = b3MakeVector3(dorn.getX(), dorn.getY(), dorn.getZ());
|
2017-08-01 14:30:58 +02:00
|
|
|
axis[3] = b3Scalar(0.);
|
|
|
|
//check for axis length
|
|
|
|
b3Scalar len = axis.length2();
|
2019-01-03 14:26:51 +01:00
|
|
|
if (len < B3_EPSILON * B3_EPSILON)
|
|
|
|
axis = b3MakeVector3(b3Scalar(1.), b3Scalar(0.), b3Scalar(0.));
|
2017-08-01 14:30:58 +02:00
|
|
|
else
|
|
|
|
axis /= b3Sqrt(len);
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
static void calculateVelocity(const b3Transform& transform0, const b3Transform& transform1, b3Scalar timeStep, b3Vector3& linVel, b3Vector3& angVel)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
linVel = (transform1.getOrigin() - transform0.getOrigin()) / timeStep;
|
|
|
|
b3Vector3 axis;
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Scalar angle;
|
|
|
|
calculateDiffAxisAngle(transform0, transform1, axis, angle);
|
2017-08-01 14:30:58 +02:00
|
|
|
angVel = axis * angle / timeStep;
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
static void calculateDiffAxisAngle(const b3Transform& transform0, const b3Transform& transform1, b3Vector3& axis, b3Scalar& angle)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
b3Matrix3x3 dmat = transform1.getBasis() * transform0.getBasis().inverse();
|
|
|
|
b3Quaternion dorn;
|
|
|
|
dmat.getRotation(dorn);
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
///floating point inaccuracy can lead to w component > 1..., which breaks
|
2017-08-01 14:30:58 +02:00
|
|
|
dorn.normalize();
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
angle = dorn.getAngle();
|
2019-01-03 14:26:51 +01:00
|
|
|
axis = b3MakeVector3(dorn.getX(), dorn.getY(), dorn.getZ());
|
2017-08-01 14:30:58 +02:00
|
|
|
axis[3] = b3Scalar(0.);
|
|
|
|
//check for axis length
|
|
|
|
b3Scalar len = axis.length2();
|
2019-01-03 14:26:51 +01:00
|
|
|
if (len < B3_EPSILON * B3_EPSILON)
|
|
|
|
axis = b3MakeVector3(b3Scalar(1.), b3Scalar(0.), b3Scalar(0.));
|
2017-08-01 14:30:58 +02:00
|
|
|
else
|
|
|
|
axis /= b3Sqrt(len);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
///The b3ConvexSeparatingDistanceUtil can help speed up convex collision detection
|
2017-08-01 14:30:58 +02:00
|
|
|
///by conservatively updating a cached separating distance/vector instead of re-calculating the closest distance
|
2019-01-03 14:26:51 +01:00
|
|
|
class b3ConvexSeparatingDistanceUtil
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Quaternion m_ornA;
|
|
|
|
b3Quaternion m_ornB;
|
|
|
|
b3Vector3 m_posA;
|
|
|
|
b3Vector3 m_posB;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Vector3 m_separatingNormal;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Scalar m_boundingRadiusA;
|
|
|
|
b3Scalar m_boundingRadiusB;
|
|
|
|
b3Scalar m_separatingDistance;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
public:
|
|
|
|
b3ConvexSeparatingDistanceUtil(b3Scalar boundingRadiusA, b3Scalar boundingRadiusB)
|
|
|
|
: m_boundingRadiusA(boundingRadiusA),
|
|
|
|
m_boundingRadiusB(boundingRadiusB),
|
|
|
|
m_separatingDistance(0.f)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Scalar getConservativeSeparatingDistance()
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
return m_separatingDistance;
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
void updateSeparatingDistance(const b3Transform& transA, const b3Transform& transB)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
const b3Vector3& toPosA = transA.getOrigin();
|
|
|
|
const b3Vector3& toPosB = transB.getOrigin();
|
|
|
|
b3Quaternion toOrnA = transA.getRotation();
|
|
|
|
b3Quaternion toOrnB = transB.getRotation();
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
if (m_separatingDistance > 0.f)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Vector3 linVelA, angVelA, linVelB, angVelB;
|
|
|
|
b3TransformUtil::calculateVelocityQuaternion(m_posA, toPosA, m_ornA, toOrnA, b3Scalar(1.), linVelA, angVelA);
|
|
|
|
b3TransformUtil::calculateVelocityQuaternion(m_posB, toPosB, m_ornB, toOrnB, b3Scalar(1.), linVelB, angVelB);
|
2017-08-01 14:30:58 +02:00
|
|
|
b3Scalar maxAngularProjectedVelocity = angVelA.length() * m_boundingRadiusA + angVelB.length() * m_boundingRadiusB;
|
2019-01-03 14:26:51 +01:00
|
|
|
b3Vector3 relLinVel = (linVelB - linVelA);
|
2017-08-01 14:30:58 +02:00
|
|
|
b3Scalar relLinVelocLength = relLinVel.dot(m_separatingNormal);
|
2019-01-03 14:26:51 +01:00
|
|
|
if (relLinVelocLength < 0.f)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
relLinVelocLength = 0.f;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
|
|
|
b3Scalar projectedMotion = maxAngularProjectedVelocity + relLinVelocLength;
|
2017-08-01 14:30:58 +02:00
|
|
|
m_separatingDistance -= projectedMotion;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
m_posA = toPosA;
|
|
|
|
m_posB = toPosB;
|
|
|
|
m_ornA = toOrnA;
|
|
|
|
m_ornB = toOrnB;
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
void initSeparatingDistance(const b3Vector3& separatingVector, b3Scalar separatingDistance, const b3Transform& transA, const b3Transform& transB)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_separatingDistance = separatingDistance;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
if (m_separatingDistance > 0.f)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_separatingNormal = separatingVector;
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
const b3Vector3& toPosA = transA.getOrigin();
|
|
|
|
const b3Vector3& toPosB = transB.getOrigin();
|
|
|
|
b3Quaternion toOrnA = transA.getRotation();
|
|
|
|
b3Quaternion toOrnB = transB.getRotation();
|
|
|
|
m_posA = toPosA;
|
|
|
|
m_posB = toPosB;
|
|
|
|
m_ornA = toOrnA;
|
|
|
|
m_ornB = toOrnB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
#endif //B3_TRANSFORM_UTIL_H
|