diff options
Diffstat (limited to 'thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp')
-rw-r--r-- | thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp | 1183 |
1 files changed, 0 insertions, 1183 deletions
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp deleted file mode 100644 index 5af93cb2fb..0000000000 --- a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp +++ /dev/null @@ -1,1183 +0,0 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ - -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. -*/ - -#include "btGjkPairDetector.h" -#include "BulletCollision/CollisionShapes/btConvexShape.h" -#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" -#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" - -#if defined(DEBUG) || defined(_DEBUG) -//#define TEST_NON_VIRTUAL 1 -#include <stdio.h> //for debug printf -#ifdef __SPU__ -#include <spu_printf.h> -#define printf spu_printf -#endif //__SPU__ -#endif - -//must be above the machine epsilon -#ifdef BT_USE_DOUBLE_PRECISION -#define REL_ERROR2 btScalar(1.0e-12) -btScalar gGjkEpaPenetrationTolerance = 1.0e-12; -#else -#define REL_ERROR2 btScalar(1.0e-6) -btScalar gGjkEpaPenetrationTolerance = 0.001; -#endif - - -btGjkPairDetector::btGjkPairDetector(const btConvexShape *objectA, const btConvexShape *objectB, btSimplexSolverInterface *simplexSolver, btConvexPenetrationDepthSolver *penetrationDepthSolver) - : m_cachedSeparatingAxis(btScalar(0.), btScalar(1.), btScalar(0.)), - m_penetrationDepthSolver(penetrationDepthSolver), - m_simplexSolver(simplexSolver), - m_minkowskiA(objectA), - m_minkowskiB(objectB), - m_shapeTypeA(objectA->getShapeType()), - m_shapeTypeB(objectB->getShapeType()), - m_marginA(objectA->getMargin()), - m_marginB(objectB->getMargin()), - m_ignoreMargin(false), - m_lastUsedMethod(-1), - m_catchDegeneracies(1), - m_fixContactNormalDirection(1) -{ -} -btGjkPairDetector::btGjkPairDetector(const btConvexShape *objectA, const btConvexShape *objectB, int shapeTypeA, int shapeTypeB, btScalar marginA, btScalar marginB, btSimplexSolverInterface *simplexSolver, btConvexPenetrationDepthSolver *penetrationDepthSolver) - : m_cachedSeparatingAxis(btScalar(0.), btScalar(1.), btScalar(0.)), - m_penetrationDepthSolver(penetrationDepthSolver), - m_simplexSolver(simplexSolver), - m_minkowskiA(objectA), - m_minkowskiB(objectB), - m_shapeTypeA(shapeTypeA), - m_shapeTypeB(shapeTypeB), - m_marginA(marginA), - m_marginB(marginB), - m_ignoreMargin(false), - m_lastUsedMethod(-1), - m_catchDegeneracies(1), - m_fixContactNormalDirection(1) -{ -} - -void btGjkPairDetector::getClosestPoints(const ClosestPointInput &input, Result &output, class btIDebugDraw *debugDraw, bool swapResults) -{ - (void)swapResults; - - getClosestPointsNonVirtual(input, output, debugDraw); -} - -static void btComputeSupport(const btConvexShape *convexA, const btTransform &localTransA, const btConvexShape *convexB, const btTransform &localTransB, const btVector3 &dir, bool check2d, btVector3 &supAworld, btVector3 &supBworld, btVector3 &aMinb) -{ - btVector3 separatingAxisInA = (dir)*localTransA.getBasis(); - btVector3 separatingAxisInB = (-dir) * localTransB.getBasis(); - - btVector3 pInANoMargin = convexA->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInA); - btVector3 qInBNoMargin = convexB->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInB); - - btVector3 pInA = pInANoMargin; - btVector3 qInB = qInBNoMargin; - - supAworld = localTransA(pInA); - supBworld = localTransB(qInB); - - if (check2d) - { - supAworld[2] = 0.f; - supBworld[2] = 0.f; - } - - aMinb = supAworld - supBworld; -} - -struct btSupportVector -{ - btVector3 v; //!< Support point in minkowski sum - btVector3 v1; //!< Support point in obj1 - btVector3 v2; //!< Support point in obj2 -}; - -struct btSimplex -{ - btSupportVector ps[4]; - int last; //!< index of last added point -}; - -static btVector3 ccd_vec3_origin(0, 0, 0); - -inline void btSimplexInit(btSimplex *s) -{ - s->last = -1; -} - -inline int btSimplexSize(const btSimplex *s) -{ - return s->last + 1; -} - -inline const btSupportVector *btSimplexPoint(const btSimplex *s, int idx) -{ - // here is no check on boundaries - return &s->ps[idx]; -} -inline void btSupportCopy(btSupportVector *d, const btSupportVector *s) -{ - *d = *s; -} - -inline void btVec3Copy(btVector3 *v, const btVector3 *w) -{ - *v = *w; -} - -inline void ccdVec3Add(btVector3 *v, const btVector3 *w) -{ - v->m_floats[0] += w->m_floats[0]; - v->m_floats[1] += w->m_floats[1]; - v->m_floats[2] += w->m_floats[2]; -} - -inline void ccdVec3Sub(btVector3 *v, const btVector3 *w) -{ - *v -= *w; -} -inline void btVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w) -{ - *d = (*v) - (*w); -} -inline btScalar btVec3Dot(const btVector3 *a, const btVector3 *b) -{ - btScalar dot; - dot = a->dot(*b); - - return dot; -} - -inline btScalar ccdVec3Dist2(const btVector3 *a, const btVector3 *b) -{ - btVector3 ab; - btVec3Sub2(&ab, a, b); - return btVec3Dot(&ab, &ab); -} - -inline void btVec3Scale(btVector3 *d, btScalar k) -{ - d->m_floats[0] *= k; - d->m_floats[1] *= k; - d->m_floats[2] *= k; -} - -inline void btVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b) -{ - d->m_floats[0] = (a->m_floats[1] * b->m_floats[2]) - (a->m_floats[2] * b->m_floats[1]); - d->m_floats[1] = (a->m_floats[2] * b->m_floats[0]) - (a->m_floats[0] * b->m_floats[2]); - d->m_floats[2] = (a->m_floats[0] * b->m_floats[1]) - (a->m_floats[1] * b->m_floats[0]); -} - -inline void btTripleCross(const btVector3 *a, const btVector3 *b, - const btVector3 *c, btVector3 *d) -{ - btVector3 e; - btVec3Cross(&e, a, b); - btVec3Cross(d, &e, c); -} - -inline int ccdEq(btScalar _a, btScalar _b) -{ - btScalar ab; - btScalar a, b; - - ab = btFabs(_a - _b); - if (btFabs(ab) < SIMD_EPSILON) - return 1; - - a = btFabs(_a); - b = btFabs(_b); - if (b > a) - { - return ab < SIMD_EPSILON * b; - } - else - { - return ab < SIMD_EPSILON * a; - } -} - -btScalar ccdVec3X(const btVector3 *v) -{ - return v->x(); -} - -btScalar ccdVec3Y(const btVector3 *v) -{ - return v->y(); -} - -btScalar ccdVec3Z(const btVector3 *v) -{ - return v->z(); -} -inline int btVec3Eq(const btVector3 *a, const btVector3 *b) -{ - return ccdEq(ccdVec3X(a), ccdVec3X(b)) && ccdEq(ccdVec3Y(a), ccdVec3Y(b)) && ccdEq(ccdVec3Z(a), ccdVec3Z(b)); -} - -inline void btSimplexAdd(btSimplex *s, const btSupportVector *v) -{ - // here is no check on boundaries in sake of speed - ++s->last; - btSupportCopy(s->ps + s->last, v); -} - -inline void btSimplexSet(btSimplex *s, size_t pos, const btSupportVector *a) -{ - btSupportCopy(s->ps + pos, a); -} - -inline void btSimplexSetSize(btSimplex *s, int size) -{ - s->last = size - 1; -} - -inline const btSupportVector *ccdSimplexLast(const btSimplex *s) -{ - return btSimplexPoint(s, s->last); -} - -inline int ccdSign(btScalar val) -{ - if (btFuzzyZero(val)) - { - return 0; - } - else if (val < btScalar(0)) - { - return -1; - } - return 1; -} - -inline btScalar btVec3PointSegmentDist2(const btVector3 *P, - const btVector3 *x0, - const btVector3 *b, - btVector3 *witness) -{ - // The computation comes from solving equation of segment: - // S(t) = x0 + t.d - // where - x0 is initial point of segment - // - d is direction of segment from x0 (|d| > 0) - // - t belongs to <0, 1> interval - // - // Than, distance from a segment to some point P can be expressed: - // D(t) = |x0 + t.d - P|^2 - // which is distance from any point on segment. Minimization - // of this function brings distance from P to segment. - // Minimization of D(t) leads to simple quadratic equation that's - // solving is straightforward. - // - // Bonus of this method is witness point for free. - - btScalar dist, t; - btVector3 d, a; - - // direction of segment - btVec3Sub2(&d, b, x0); - - // precompute vector from P to x0 - btVec3Sub2(&a, x0, P); - - t = -btScalar(1.) * btVec3Dot(&a, &d); - t /= btVec3Dot(&d, &d); - - if (t < btScalar(0) || btFuzzyZero(t)) - { - dist = ccdVec3Dist2(x0, P); - if (witness) - btVec3Copy(witness, x0); - } - else if (t > btScalar(1) || ccdEq(t, btScalar(1))) - { - dist = ccdVec3Dist2(b, P); - if (witness) - btVec3Copy(witness, b); - } - else - { - if (witness) - { - btVec3Copy(witness, &d); - btVec3Scale(witness, t); - ccdVec3Add(witness, x0); - dist = ccdVec3Dist2(witness, P); - } - else - { - // recycling variables - btVec3Scale(&d, t); - ccdVec3Add(&d, &a); - dist = btVec3Dot(&d, &d); - } - } - - return dist; -} - -btScalar btVec3PointTriDist2(const btVector3 *P, - const btVector3 *x0, const btVector3 *B, - const btVector3 *C, - btVector3 *witness) -{ - // Computation comes from analytic expression for triangle (x0, B, C) - // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and - // Then equation for distance is: - // D(s, t) = | T(s, t) - P |^2 - // This leads to minimization of quadratic function of two variables. - // The solution from is taken only if s is between 0 and 1, t is - // between 0 and 1 and t + s < 1, otherwise distance from segment is - // computed. - - btVector3 d1, d2, a; - double u, v, w, p, q, r; - double s, t, dist, dist2; - btVector3 witness2; - - btVec3Sub2(&d1, B, x0); - btVec3Sub2(&d2, C, x0); - btVec3Sub2(&a, x0, P); - - u = btVec3Dot(&a, &a); - v = btVec3Dot(&d1, &d1); - w = btVec3Dot(&d2, &d2); - p = btVec3Dot(&a, &d1); - q = btVec3Dot(&a, &d2); - r = btVec3Dot(&d1, &d2); - - s = (q * r - w * p) / (w * v - r * r); - t = (-s * r - q) / w; - - if ((btFuzzyZero(s) || s > btScalar(0)) && (ccdEq(s, btScalar(1)) || s < btScalar(1)) && (btFuzzyZero(t) || t > btScalar(0)) && (ccdEq(t, btScalar(1)) || t < btScalar(1)) && (ccdEq(t + s, btScalar(1)) || t + s < btScalar(1))) - { - if (witness) - { - btVec3Scale(&d1, s); - btVec3Scale(&d2, t); - btVec3Copy(witness, x0); - ccdVec3Add(witness, &d1); - ccdVec3Add(witness, &d2); - - dist = ccdVec3Dist2(witness, P); - } - else - { - dist = s * s * v; - dist += t * t * w; - dist += btScalar(2.) * s * t * r; - dist += btScalar(2.) * s * p; - dist += btScalar(2.) * t * q; - dist += u; - } - } - else - { - dist = btVec3PointSegmentDist2(P, x0, B, witness); - - dist2 = btVec3PointSegmentDist2(P, x0, C, &witness2); - if (dist2 < dist) - { - dist = dist2; - if (witness) - btVec3Copy(witness, &witness2); - } - - dist2 = btVec3PointSegmentDist2(P, B, C, &witness2); - if (dist2 < dist) - { - dist = dist2; - if (witness) - btVec3Copy(witness, &witness2); - } - } - - return dist; -} - -static int btDoSimplex2(btSimplex *simplex, btVector3 *dir) -{ - const btSupportVector *A, *B; - btVector3 AB, AO, tmp; - btScalar dot; - - // get last added as A - A = ccdSimplexLast(simplex); - // get the other point - B = btSimplexPoint(simplex, 0); - // compute AB oriented segment - btVec3Sub2(&AB, &B->v, &A->v); - // compute AO vector - btVec3Copy(&AO, &A->v); - btVec3Scale(&AO, -btScalar(1)); - - // dot product AB . AO - dot = btVec3Dot(&AB, &AO); - - // check if origin doesn't lie on AB segment - btVec3Cross(&tmp, &AB, &AO); - if (btFuzzyZero(btVec3Dot(&tmp, &tmp)) && dot > btScalar(0)) - { - return 1; - } - - // check if origin is in area where AB segment is - if (btFuzzyZero(dot) || dot < btScalar(0)) - { - // origin is in outside are of A - btSimplexSet(simplex, 0, A); - btSimplexSetSize(simplex, 1); - btVec3Copy(dir, &AO); - } - else - { - // origin is in area where AB segment is - - // keep simplex untouched and set direction to - // AB x AO x AB - btTripleCross(&AB, &AO, &AB, dir); - } - - return 0; -} - -static int btDoSimplex3(btSimplex *simplex, btVector3 *dir) -{ - const btSupportVector *A, *B, *C; - btVector3 AO, AB, AC, ABC, tmp; - btScalar dot, dist; - - // get last added as A - A = ccdSimplexLast(simplex); - // get the other points - B = btSimplexPoint(simplex, 1); - C = btSimplexPoint(simplex, 0); - - // check touching contact - dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &B->v, &C->v, 0); - if (btFuzzyZero(dist)) - { - return 1; - } - - // check if triangle is really triangle (has area > 0) - // if not simplex can't be expanded and thus no itersection is found - if (btVec3Eq(&A->v, &B->v) || btVec3Eq(&A->v, &C->v)) - { - return -1; - } - - // compute AO vector - btVec3Copy(&AO, &A->v); - btVec3Scale(&AO, -btScalar(1)); - - // compute AB and AC segments and ABC vector (perpendircular to triangle) - btVec3Sub2(&AB, &B->v, &A->v); - btVec3Sub2(&AC, &C->v, &A->v); - btVec3Cross(&ABC, &AB, &AC); - - btVec3Cross(&tmp, &ABC, &AC); - dot = btVec3Dot(&tmp, &AO); - if (btFuzzyZero(dot) || dot > btScalar(0)) - { - dot = btVec3Dot(&AC, &AO); - if (btFuzzyZero(dot) || dot > btScalar(0)) - { - // C is already in place - btSimplexSet(simplex, 1, A); - btSimplexSetSize(simplex, 2); - btTripleCross(&AC, &AO, &AC, dir); - } - else - { - dot = btVec3Dot(&AB, &AO); - if (btFuzzyZero(dot) || dot > btScalar(0)) - { - btSimplexSet(simplex, 0, B); - btSimplexSet(simplex, 1, A); - btSimplexSetSize(simplex, 2); - btTripleCross(&AB, &AO, &AB, dir); - } - else - { - btSimplexSet(simplex, 0, A); - btSimplexSetSize(simplex, 1); - btVec3Copy(dir, &AO); - } - } - } - else - { - btVec3Cross(&tmp, &AB, &ABC); - dot = btVec3Dot(&tmp, &AO); - if (btFuzzyZero(dot) || dot > btScalar(0)) - { - dot = btVec3Dot(&AB, &AO); - if (btFuzzyZero(dot) || dot > btScalar(0)) - { - btSimplexSet(simplex, 0, B); - btSimplexSet(simplex, 1, A); - btSimplexSetSize(simplex, 2); - btTripleCross(&AB, &AO, &AB, dir); - } - else - { - btSimplexSet(simplex, 0, A); - btSimplexSetSize(simplex, 1); - btVec3Copy(dir, &AO); - } - } - else - { - dot = btVec3Dot(&ABC, &AO); - if (btFuzzyZero(dot) || dot > btScalar(0)) - { - btVec3Copy(dir, &ABC); - } - else - { - btSupportVector tmp; - btSupportCopy(&tmp, C); - btSimplexSet(simplex, 0, B); - btSimplexSet(simplex, 1, &tmp); - - btVec3Copy(dir, &ABC); - btVec3Scale(dir, -btScalar(1)); - } - } - } - - return 0; -} - -static int btDoSimplex4(btSimplex *simplex, btVector3 *dir) -{ - const btSupportVector *A, *B, *C, *D; - btVector3 AO, AB, AC, AD, ABC, ACD, ADB; - int B_on_ACD, C_on_ADB, D_on_ABC; - int AB_O, AC_O, AD_O; - btScalar dist; - - // get last added as A - A = ccdSimplexLast(simplex); - // get the other points - B = btSimplexPoint(simplex, 2); - C = btSimplexPoint(simplex, 1); - D = btSimplexPoint(simplex, 0); - - // check if tetrahedron is really tetrahedron (has volume > 0) - // if it is not simplex can't be expanded and thus no intersection is - // found - dist = btVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, 0); - if (btFuzzyZero(dist)) - { - return -1; - } - - // check if origin lies on some of tetrahedron's face - if so objects - // intersect - dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &B->v, &C->v, 0); - if (btFuzzyZero(dist)) - return 1; - dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &C->v, &D->v, 0); - if (btFuzzyZero(dist)) - return 1; - dist = btVec3PointTriDist2(&ccd_vec3_origin, &A->v, &B->v, &D->v, 0); - if (btFuzzyZero(dist)) - return 1; - dist = btVec3PointTriDist2(&ccd_vec3_origin, &B->v, &C->v, &D->v, 0); - if (btFuzzyZero(dist)) - return 1; - - // compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors - btVec3Copy(&AO, &A->v); - btVec3Scale(&AO, -btScalar(1)); - btVec3Sub2(&AB, &B->v, &A->v); - btVec3Sub2(&AC, &C->v, &A->v); - btVec3Sub2(&AD, &D->v, &A->v); - btVec3Cross(&ABC, &AB, &AC); - btVec3Cross(&ACD, &AC, &AD); - btVec3Cross(&ADB, &AD, &AB); - - // side (positive or negative) of B, C, D relative to planes ACD, ADB - // and ABC respectively - B_on_ACD = ccdSign(btVec3Dot(&ACD, &AB)); - C_on_ADB = ccdSign(btVec3Dot(&ADB, &AC)); - D_on_ABC = ccdSign(btVec3Dot(&ABC, &AD)); - - // whether origin is on same side of ACD, ADB, ABC as B, C, D - // respectively - AB_O = ccdSign(btVec3Dot(&ACD, &AO)) == B_on_ACD; - AC_O = ccdSign(btVec3Dot(&ADB, &AO)) == C_on_ADB; - AD_O = ccdSign(btVec3Dot(&ABC, &AO)) == D_on_ABC; - - if (AB_O && AC_O && AD_O) - { - // origin is in tetrahedron - return 1; - // rearrange simplex to triangle and call btDoSimplex3() - } - else if (!AB_O) - { - // B is farthest from the origin among all of the tetrahedron's - // points, so remove it from the list and go on with the triangle - // case - - // D and C are in place - btSimplexSet(simplex, 2, A); - btSimplexSetSize(simplex, 3); - } - else if (!AC_O) - { - // C is farthest - btSimplexSet(simplex, 1, D); - btSimplexSet(simplex, 0, B); - btSimplexSet(simplex, 2, A); - btSimplexSetSize(simplex, 3); - } - else - { // (!AD_O) - btSimplexSet(simplex, 0, C); - btSimplexSet(simplex, 1, B); - btSimplexSet(simplex, 2, A); - btSimplexSetSize(simplex, 3); - } - - return btDoSimplex3(simplex, dir); -} - -static int btDoSimplex(btSimplex *simplex, btVector3 *dir) -{ - if (btSimplexSize(simplex) == 2) - { - // simplex contains segment only one segment - return btDoSimplex2(simplex, dir); - } - else if (btSimplexSize(simplex) == 3) - { - // simplex contains triangle - return btDoSimplex3(simplex, dir); - } - else - { // btSimplexSize(simplex) == 4 - // tetrahedron - this is the only shape which can encapsule origin - // so btDoSimplex4() also contains test on it - return btDoSimplex4(simplex, dir); - } -} - -#ifdef __SPU__ -void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput &input, Result &output, class btIDebugDraw *debugDraw) -#else -void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput &input, Result &output, class btIDebugDraw *debugDraw) -#endif -{ - m_cachedSeparatingDistance = 0.f; - - btScalar distance = btScalar(0.); - btVector3 normalInB(btScalar(0.), btScalar(0.), btScalar(0.)); - - btVector3 pointOnA, pointOnB; - btTransform localTransA = input.m_transformA; - btTransform localTransB = input.m_transformB; - btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5); - localTransA.getOrigin() -= positionOffset; - localTransB.getOrigin() -= positionOffset; - - bool check2d = m_minkowskiA->isConvex2d() && m_minkowskiB->isConvex2d(); - - btScalar marginA = m_marginA; - btScalar marginB = m_marginB; - - - //for CCD we don't use margins - if (m_ignoreMargin) - { - marginA = btScalar(0.); - marginB = btScalar(0.); - } - - m_curIter = 0; - int gGjkMaxIter = 1000; //this is to catch invalid input, perhaps check for #NaN? - m_cachedSeparatingAxis.setValue(0, 1, 0); - - bool isValid = false; - bool checkSimplex = false; - bool checkPenetration = true; - m_degenerateSimplex = 0; - - m_lastUsedMethod = -1; - int status = -2; - btVector3 orgNormalInB(0, 0, 0); - btScalar margin = marginA + marginB; - - //we add a separate implementation to check if the convex shapes intersect - //See also "Real-time Collision Detection with Implicit Objects" by Leif Olvang - //Todo: integrate the simplex penetration check directly inside the Bullet btVoronoiSimplexSolver - //and remove this temporary code from libCCD - //this fixes issue https://github.com/bulletphysics/bullet3/issues/1703 - //note, for large differences in shapes, use double precision build! - { - btScalar squaredDistance = BT_LARGE_FLOAT; - btScalar delta = btScalar(0.); - - btSimplex simplex1; - btSimplex *simplex = &simplex1; - btSimplexInit(simplex); - - btVector3 dir(1, 0, 0); - - { - btVector3 lastSupV; - btVector3 supAworld; - btVector3 supBworld; - btComputeSupport(m_minkowskiA, localTransA, m_minkowskiB, localTransB, dir, check2d, supAworld, supBworld, lastSupV); - - btSupportVector last; - last.v = lastSupV; - last.v1 = supAworld; - last.v2 = supBworld; - - btSimplexAdd(simplex, &last); - - dir = -lastSupV; - - // start iterations - for (int iterations = 0; iterations < gGjkMaxIter; iterations++) - { - // obtain support point - btComputeSupport(m_minkowskiA, localTransA, m_minkowskiB, localTransB, dir, check2d, supAworld, supBworld, lastSupV); - - // check if farthest point in Minkowski difference in direction dir - // isn't somewhere before origin (the test on negative dot product) - // - because if it is, objects are not intersecting at all. - btScalar delta = lastSupV.dot(dir); - if (delta < 0) - { - //no intersection, besides margin - status = -1; - break; - } - - // add last support vector to simplex - last.v = lastSupV; - last.v1 = supAworld; - last.v2 = supBworld; - - btSimplexAdd(simplex, &last); - - // if btDoSimplex returns 1 if objects intersect, -1 if objects don't - // intersect and 0 if algorithm should continue - - btVector3 newDir; - int do_simplex_res = btDoSimplex(simplex, &dir); - - if (do_simplex_res == 1) - { - status = 0; // intersection found - break; - } - else if (do_simplex_res == -1) - { - // intersection not found - status = -1; - break; - } - - if (btFuzzyZero(btVec3Dot(&dir, &dir))) - { - // intersection not found - status = -1; - } - - if (dir.length2() < SIMD_EPSILON) - { - //no intersection, besides margin - status = -1; - break; - } - - if (dir.fuzzyZero()) - { - // intersection not found - status = -1; - break; - } - } - } - - m_simplexSolver->reset(); - if (status == 0) - { - //status = 0; - //printf("Intersect!\n"); - } - - if (status == -1) - { - //printf("not intersect\n"); - } - //printf("dir=%f,%f,%f\n",dir[0],dir[1],dir[2]); - if (1) - { - for (;;) - //while (true) - { - btVector3 separatingAxisInA = (-m_cachedSeparatingAxis) * localTransA.getBasis(); - btVector3 separatingAxisInB = m_cachedSeparatingAxis * localTransB.getBasis(); - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - - if (check2d) - { - pWorld[2] = 0.f; - qWorld[2] = 0.f; - } - - btVector3 w = pWorld - qWorld; - delta = m_cachedSeparatingAxis.dot(w); - - // potential exit, they don't overlap - if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared)) - { - m_degenerateSimplex = 10; - checkSimplex = true; - //checkPenetration = false; - break; - } - - //exit 0: the new point is already in the simplex, or we didn't come any closer - if (m_simplexSolver->inSimplex(w)) - { - m_degenerateSimplex = 1; - checkSimplex = true; - break; - } - // are we getting any closer ? - btScalar f0 = squaredDistance - delta; - btScalar f1 = squaredDistance * REL_ERROR2; - - if (f0 <= f1) - { - if (f0 <= btScalar(0.)) - { - m_degenerateSimplex = 2; - } - else - { - m_degenerateSimplex = 11; - } - checkSimplex = true; - break; - } - - //add current vertex to simplex - m_simplexSolver->addVertex(w, pWorld, qWorld); - btVector3 newCachedSeparatingAxis; - - //calculate the closest point to the origin (update vector v) - if (!m_simplexSolver->closest(newCachedSeparatingAxis)) - { - m_degenerateSimplex = 3; - checkSimplex = true; - break; - } - - if (newCachedSeparatingAxis.length2() < REL_ERROR2) - { - m_cachedSeparatingAxis = newCachedSeparatingAxis; - m_degenerateSimplex = 6; - checkSimplex = true; - break; - } - - btScalar previousSquaredDistance = squaredDistance; - squaredDistance = newCachedSeparatingAxis.length2(); -#if 0 - ///warning: this termination condition leads to some problems in 2d test case see Bullet/Demos/Box2dDemo - if (squaredDistance > previousSquaredDistance) - { - m_degenerateSimplex = 7; - squaredDistance = previousSquaredDistance; - checkSimplex = false; - break; - } -#endif // - - //redundant m_simplexSolver->compute_points(pointOnA, pointOnB); - - //are we getting any closer ? - if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) - { - // m_simplexSolver->backup_closest(m_cachedSeparatingAxis); - checkSimplex = true; - m_degenerateSimplex = 12; - - break; - } - - m_cachedSeparatingAxis = newCachedSeparatingAxis; - - //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject - if (m_curIter++ > gGjkMaxIter) - { -#if defined(DEBUG) || defined(_DEBUG) - - printf("btGjkPairDetector maxIter exceeded:%i\n", m_curIter); - printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n", - m_cachedSeparatingAxis.getX(), - m_cachedSeparatingAxis.getY(), - m_cachedSeparatingAxis.getZ(), - squaredDistance, - m_minkowskiA->getShapeType(), - m_minkowskiB->getShapeType()); - -#endif - break; - } - - bool check = (!m_simplexSolver->fullSimplex()); - //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex()); - - if (!check) - { - //do we need this backup_closest here ? - // m_simplexSolver->backup_closest(m_cachedSeparatingAxis); - m_degenerateSimplex = 13; - break; - } - } - - if (checkSimplex) - { - m_simplexSolver->compute_points(pointOnA, pointOnB); - normalInB = m_cachedSeparatingAxis; - - btScalar lenSqr = m_cachedSeparatingAxis.length2(); - - //valid normal - if (lenSqr < REL_ERROR2) - { - m_degenerateSimplex = 5; - } - if (lenSqr > SIMD_EPSILON * SIMD_EPSILON) - { - btScalar rlen = btScalar(1.) / btSqrt(lenSqr); - normalInB *= rlen; //normalize - - btScalar s = btSqrt(squaredDistance); - - btAssert(s > btScalar(0.0)); - pointOnA -= m_cachedSeparatingAxis * (marginA / s); - pointOnB += m_cachedSeparatingAxis * (marginB / s); - distance = ((btScalar(1.) / rlen) - margin); - isValid = true; - orgNormalInB = normalInB; - - m_lastUsedMethod = 1; - } - else - { - m_lastUsedMethod = 2; - } - } - } - - bool catchDegeneratePenetrationCase = - (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance + margin) < gGjkEpaPenetrationTolerance)); - - //if (checkPenetration && !isValid) - if ((checkPenetration && (!isValid || catchDegeneratePenetrationCase)) || (status == 0)) - { - //penetration case - - //if there is no way to handle penetrations, bail out - if (m_penetrationDepthSolver) - { - // Penetration depth case. - btVector3 tmpPointOnA, tmpPointOnB; - - m_cachedSeparatingAxis.setZero(); - - bool isValid2 = m_penetrationDepthSolver->calcPenDepth( - *m_simplexSolver, - m_minkowskiA, m_minkowskiB, - localTransA, localTransB, - m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB, - debugDraw); - - if (m_cachedSeparatingAxis.length2()) - { - if (isValid2) - { - btVector3 tmpNormalInB = tmpPointOnB - tmpPointOnA; - btScalar lenSqr = tmpNormalInB.length2(); - if (lenSqr <= (SIMD_EPSILON * SIMD_EPSILON)) - { - tmpNormalInB = m_cachedSeparatingAxis; - lenSqr = m_cachedSeparatingAxis.length2(); - } - - if (lenSqr > (SIMD_EPSILON * SIMD_EPSILON)) - { - tmpNormalInB /= btSqrt(lenSqr); - btScalar distance2 = -(tmpPointOnA - tmpPointOnB).length(); - m_lastUsedMethod = 3; - //only replace valid penetrations when the result is deeper (check) - if (!isValid || (distance2 < distance)) - { - distance = distance2; - pointOnA = tmpPointOnA; - pointOnB = tmpPointOnB; - normalInB = tmpNormalInB; - isValid = true; - } - else - { - m_lastUsedMethod = 8; - } - } - else - { - m_lastUsedMethod = 9; - } - } - else - - { - ///this is another degenerate case, where the initial GJK calculation reports a degenerate case - ///EPA reports no penetration, and the second GJK (using the supporting vector without margin) - ///reports a valid positive distance. Use the results of the second GJK instead of failing. - ///thanks to Jacob.Langford for the reproduction case - ///http://code.google.com/p/bullet/issues/detail?id=250 - - if (m_cachedSeparatingAxis.length2() > btScalar(0.)) - { - btScalar distance2 = (tmpPointOnA - tmpPointOnB).length() - margin; - //only replace valid distances when the distance is less - if (!isValid || (distance2 < distance)) - { - distance = distance2; - pointOnA = tmpPointOnA; - pointOnB = tmpPointOnB; - pointOnA -= m_cachedSeparatingAxis * marginA; - pointOnB += m_cachedSeparatingAxis * marginB; - normalInB = m_cachedSeparatingAxis; - normalInB.normalize(); - - isValid = true; - m_lastUsedMethod = 6; - } - else - { - m_lastUsedMethod = 5; - } - } - } - } - else - { - //printf("EPA didn't return a valid value\n"); - } - } - } - } - - if (isValid && ((distance < 0) || (distance * distance < input.m_maximumDistanceSquared))) - { - m_cachedSeparatingAxis = normalInB; - m_cachedSeparatingDistance = distance; - if (1) - { - ///todo: need to track down this EPA penetration solver degeneracy - ///the penetration solver reports penetration but the contact normal - ///connecting the contact points is pointing in the opposite direction - ///until then, detect the issue and revert the normal - - btScalar d2 = 0.f; - { - btVector3 separatingAxisInA = (-orgNormalInB) * localTransA.getBasis(); - btVector3 separatingAxisInB = orgNormalInB * localTransB.getBasis(); - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d2 = orgNormalInB.dot(w) - margin; - } - - btScalar d1 = 0; - { - btVector3 separatingAxisInA = (normalInB)*localTransA.getBasis(); - btVector3 separatingAxisInB = -normalInB * localTransB.getBasis(); - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d1 = (-normalInB).dot(w) - margin; - } - btScalar d0 = 0.f; - { - btVector3 separatingAxisInA = (-normalInB) * input.m_transformA.getBasis(); - btVector3 separatingAxisInB = normalInB * input.m_transformB.getBasis(); - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(separatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d0 = normalInB.dot(w) - margin; - } - - if (d1 > d0) - { - m_lastUsedMethod = 10; - normalInB *= -1; - } - - if (orgNormalInB.length2()) - { - if (d2 > d0 && d2 > d1 && d2 > distance) - { - normalInB = orgNormalInB; - distance = d2; - } - } - } - - output.addContactPoint( - normalInB, - pointOnB + positionOffset, - distance); - } - else - { - //printf("invalid gjk query\n"); - } -} |