Home | History | Annotate | Download | only in NarrowPhaseCollision
      1 
      2 /***
      3  * ---------------------------------
      4  * Copyright (c)2012 Daniel Fiser <danfis (at) danfis.cz>
      5  *
      6  *  This file was ported from mpr.c file, part of libccd.
      7  *  The Minkoski Portal Refinement implementation was ported
      8  *  to OpenCL by Erwin Coumans for the Bullet 3 Physics library.
      9  *  The original MPR idea and implementation is by Gary Snethen
     10  *  in XenoCollide, see http://github.com/erwincoumans/xenocollide
     11  *
     12  *  Distributed under the OSI-approved BSD License (the "License");
     13  *  see <http://www.opensource.org/licenses/bsd-license.php>.
     14  *  This software is distributed WITHOUT ANY WARRANTY; without even the
     15  *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     16  *  See the License for more information.
     17  */
     18 
     19 ///2014 Oct, Erwin Coumans, Use templates to avoid void* casts
     20 
     21 #ifndef BT_MPR_PENETRATION_H
     22 #define BT_MPR_PENETRATION_H
     23 
     24 #define BT_DEBUG_MPR1
     25 
     26 #include "LinearMath/btTransform.h"
     27 #include "LinearMath/btAlignedObjectArray.h"
     28 
     29 //#define MPR_AVERAGE_CONTACT_POSITIONS
     30 
     31 
     32 struct btMprCollisionDescription
     33 {
     34     btVector3	m_firstDir;
     35     int			m_maxGjkIterations;
     36     btScalar	m_maximumDistanceSquared;
     37     btScalar	m_gjkRelError2;
     38 
     39     btMprCollisionDescription()
     40     :	m_firstDir(0,1,0),
     41         m_maxGjkIterations(1000),
     42         m_maximumDistanceSquared(1e30f),
     43         m_gjkRelError2(1.0e-6)
     44     {
     45     }
     46     virtual ~btMprCollisionDescription()
     47     {
     48     }
     49 };
     50 
     51 struct btMprDistanceInfo
     52 {
     53     btVector3	m_pointOnA;
     54     btVector3	m_pointOnB;
     55     btVector3	m_normalBtoA;
     56     btScalar	m_distance;
     57 };
     58 
     59 #ifdef __cplusplus
     60 #define BT_MPR_SQRT sqrtf
     61 #else
     62 #define BT_MPR_SQRT sqrt
     63 #endif
     64 #define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y))
     65 #define BT_MPR_FABS fabs
     66 
     67 #define BT_MPR_TOLERANCE 1E-6f
     68 #define BT_MPR_MAX_ITERATIONS 1000
     69 
     70 struct _btMprSupport_t
     71 {
     72     btVector3 v;  //!< Support point in minkowski sum
     73     btVector3 v1; //!< Support point in obj1
     74     btVector3 v2; //!< Support point in obj2
     75 };
     76 typedef struct _btMprSupport_t btMprSupport_t;
     77 
     78 struct _btMprSimplex_t
     79 {
     80     btMprSupport_t ps[4];
     81     int last; //!< index of last added point
     82 };
     83 typedef struct _btMprSimplex_t btMprSimplex_t;
     84 
     85 inline btMprSupport_t* btMprSimplexPointW(btMprSimplex_t *s, int idx)
     86 {
     87     return &s->ps[idx];
     88 }
     89 
     90 inline void btMprSimplexSetSize(btMprSimplex_t *s, int size)
     91 {
     92     s->last = size - 1;
     93 }
     94 
     95 #ifdef DEBUG_MPR
     96 inline void btPrintPortalVertex(_btMprSimplex_t* portal, int index)
     97 {
     98     printf("portal[%d].v = %f,%f,%f, v1=%f,%f,%f, v2=%f,%f,%f\n", index, portal->ps[index].v.x(),portal->ps[index].v.y(),portal->ps[index].v.z(),
     99            portal->ps[index].v1.x(),portal->ps[index].v1.y(),portal->ps[index].v1.z(),
    100            portal->ps[index].v2.x(),portal->ps[index].v2.y(),portal->ps[index].v2.z());
    101 }
    102 #endif //DEBUG_MPR
    103 
    104 
    105 
    106 
    107 inline int btMprSimplexSize(const btMprSimplex_t *s)
    108 {
    109     return s->last + 1;
    110 }
    111 
    112 
    113 inline const btMprSupport_t* btMprSimplexPoint(const btMprSimplex_t* s, int idx)
    114 {
    115     // here is no check on boundaries
    116     return &s->ps[idx];
    117 }
    118 
    119 inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s)
    120 {
    121     *d = *s;
    122 }
    123 
    124 inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a)
    125 {
    126     btMprSupportCopy(s->ps + pos, a);
    127 }
    128 
    129 
    130 inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2)
    131 {
    132     btMprSupport_t supp;
    133 
    134     btMprSupportCopy(&supp, &s->ps[pos1]);
    135     btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]);
    136     btMprSupportCopy(&s->ps[pos2], &supp);
    137 }
    138 
    139 
    140 inline int btMprIsZero(float val)
    141 {
    142     return BT_MPR_FABS(val) < FLT_EPSILON;
    143 }
    144 
    145 
    146 
    147 inline int btMprEq(float _a, float _b)
    148 {
    149     float ab;
    150     float a, b;
    151 
    152     ab = BT_MPR_FABS(_a - _b);
    153     if (BT_MPR_FABS(ab) < FLT_EPSILON)
    154         return 1;
    155 
    156     a = BT_MPR_FABS(_a);
    157     b = BT_MPR_FABS(_b);
    158     if (b > a){
    159         return ab < FLT_EPSILON * b;
    160     }else{
    161         return ab < FLT_EPSILON * a;
    162     }
    163 }
    164 
    165 
    166 inline int btMprVec3Eq(const btVector3* a, const btVector3 *b)
    167 {
    168     return btMprEq((*a).x(), (*b).x())
    169             && btMprEq((*a).y(), (*b).y())
    170             && btMprEq((*a).z(), (*b).z());
    171 }
    172 
    173 
    174 
    175 
    176 
    177 
    178 
    179 
    180 
    181 
    182 
    183 template <typename btConvexTemplate>
    184 inline void btFindOrigin(const btConvexTemplate& a, const btConvexTemplate& b, const btMprCollisionDescription& colDesc,btMprSupport_t *center)
    185 {
    186 
    187 	center->v1 = a.getObjectCenterInWorld();
    188     center->v2 = b.getObjectCenterInWorld();
    189     center->v = center->v1 - center->v2;
    190 }
    191 
    192 inline void btMprVec3Set(btVector3 *v, float x, float y, float z)
    193 {
    194 	v->setValue(x,y,z);
    195 }
    196 
    197 inline void btMprVec3Add(btVector3 *v, const btVector3 *w)
    198 {
    199 	*v += *w;
    200 }
    201 
    202 inline void btMprVec3Copy(btVector3 *v, const btVector3 *w)
    203 {
    204     *v = *w;
    205 }
    206 
    207 inline void btMprVec3Scale(btVector3 *d, float k)
    208 {
    209     *d *= k;
    210 }
    211 
    212 inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b)
    213 {
    214     float dot;
    215 
    216 	dot = btDot(*a,*b);
    217     return dot;
    218 }
    219 
    220 
    221 inline float btMprVec3Len2(const btVector3 *v)
    222 {
    223     return btMprVec3Dot(v, v);
    224 }
    225 
    226 inline void btMprVec3Normalize(btVector3 *d)
    227 {
    228     float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d));
    229     btMprVec3Scale(d, k);
    230 }
    231 
    232 inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b)
    233 {
    234 	*d = btCross(*a,*b);
    235 
    236 }
    237 
    238 
    239 inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w)
    240 {
    241 	*d = *v - *w;
    242 }
    243 
    244 inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir)
    245 {
    246     btVector3 v2v1, v3v1;
    247 
    248     btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v,
    249                        &btMprSimplexPoint(portal, 1)->v);
    250     btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v,
    251                        &btMprSimplexPoint(portal, 1)->v);
    252     btMprVec3Cross(dir, &v2v1, &v3v1);
    253     btMprVec3Normalize(dir);
    254 }
    255 
    256 
    257 inline int portalEncapsulesOrigin(const btMprSimplex_t *portal,
    258                                        const btVector3 *dir)
    259 {
    260     float dot;
    261     dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v);
    262     return btMprIsZero(dot) || dot > 0.f;
    263 }
    264 
    265 inline int portalReachTolerance(const btMprSimplex_t *portal,
    266                                      const btMprSupport_t *v4,
    267                                      const btVector3 *dir)
    268 {
    269     float dv1, dv2, dv3, dv4;
    270     float dot1, dot2, dot3;
    271 
    272     // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}
    273 
    274     dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir);
    275     dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir);
    276     dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir);
    277     dv4 = btMprVec3Dot(&v4->v, dir);
    278 
    279     dot1 = dv4 - dv1;
    280     dot2 = dv4 - dv2;
    281     dot3 = dv4 - dv3;
    282 
    283     dot1 = BT_MPR_FMIN(dot1, dot2);
    284     dot1 = BT_MPR_FMIN(dot1, dot3);
    285 
    286     return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE;
    287 }
    288 
    289 inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal,
    290                                          const btMprSupport_t *v4,
    291                                          const btVector3 *dir)
    292 {
    293     float dot;
    294     dot = btMprVec3Dot(&v4->v, dir);
    295     return btMprIsZero(dot) || dot > 0.f;
    296 }
    297 
    298 inline void btExpandPortal(btMprSimplex_t *portal,
    299                               const btMprSupport_t *v4)
    300 {
    301     float dot;
    302     btVector3 v4v0;
    303 
    304     btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v);
    305     dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0);
    306     if (dot > 0.f){
    307         dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0);
    308         if (dot > 0.f){
    309             btMprSimplexSet(portal, 1, v4);
    310         }else{
    311             btMprSimplexSet(portal, 3, v4);
    312         }
    313     }else{
    314         dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0);
    315         if (dot > 0.f){
    316             btMprSimplexSet(portal, 2, v4);
    317         }else{
    318             btMprSimplexSet(portal, 1, v4);
    319         }
    320     }
    321 }
    322 template <typename btConvexTemplate>
    323 inline void btMprSupport(const btConvexTemplate& a, const btConvexTemplate& b,
    324                          const btMprCollisionDescription& colDesc,
    325 													const btVector3& dir, btMprSupport_t *supp)
    326 {
    327 	btVector3 seperatingAxisInA = dir* a.getWorldTransform().getBasis();
    328 	btVector3 seperatingAxisInB = -dir* b.getWorldTransform().getBasis();
    329 
    330 	btVector3 pInA = a.getLocalSupportWithMargin(seperatingAxisInA);
    331 	btVector3 qInB = b.getLocalSupportWithMargin(seperatingAxisInB);
    332 
    333 	supp->v1 = a.getWorldTransform()(pInA);
    334 	supp->v2 = b.getWorldTransform()(qInB);
    335 	supp->v = supp->v1 - supp->v2;
    336 }
    337 
    338 
    339 template <typename btConvexTemplate>
    340 static int btDiscoverPortal(const btConvexTemplate& a, const btConvexTemplate& b,
    341                             const btMprCollisionDescription& colDesc,
    342 													btMprSimplex_t *portal)
    343 {
    344     btVector3 dir, va, vb;
    345     float dot;
    346     int cont;
    347 
    348 
    349 
    350     // vertex 0 is center of portal
    351     btFindOrigin(a,b,colDesc, btMprSimplexPointW(portal, 0));
    352 
    353 
    354     // vertex 0 is center of portal
    355     btMprSimplexSetSize(portal, 1);
    356 
    357 
    358 
    359 	btVector3 zero = btVector3(0,0,0);
    360 	btVector3* org = &zero;
    361 
    362     if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org)){
    363         // Portal's center lies on origin (0,0,0) => we know that objects
    364         // intersect but we would need to know penetration info.
    365         // So move center little bit...
    366         btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f);
    367         btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va);
    368     }
    369 
    370 
    371     // vertex 1 = support in direction of origin
    372     btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v);
    373     btMprVec3Scale(&dir, -1.f);
    374     btMprVec3Normalize(&dir);
    375 
    376 
    377     btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 1));
    378 
    379     btMprSimplexSetSize(portal, 2);
    380 
    381     // test if origin isn't outside of v1
    382     dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir);
    383 
    384 
    385     if (btMprIsZero(dot) || dot < 0.f)
    386         return -1;
    387 
    388 
    389     // vertex 2
    390     btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v,
    391                        &btMprSimplexPoint(portal, 1)->v);
    392     if (btMprIsZero(btMprVec3Len2(&dir))){
    393         if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org)){
    394             // origin lies on v1
    395             return 1;
    396         }else{
    397             // origin lies on v0-v1 segment
    398             return 2;
    399         }
    400     }
    401 
    402     btMprVec3Normalize(&dir);
    403     btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 2));
    404 
    405 
    406 
    407     dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir);
    408     if (btMprIsZero(dot) || dot < 0.f)
    409         return -1;
    410 
    411     btMprSimplexSetSize(portal, 3);
    412 
    413     // vertex 3 direction
    414     btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
    415                      &btMprSimplexPoint(portal, 0)->v);
    416     btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
    417                      &btMprSimplexPoint(portal, 0)->v);
    418     btMprVec3Cross(&dir, &va, &vb);
    419     btMprVec3Normalize(&dir);
    420 
    421     // it is better to form portal faces to be oriented "outside" origin
    422     dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v);
    423     if (dot > 0.f){
    424         btMprSimplexSwap(portal, 1, 2);
    425         btMprVec3Scale(&dir, -1.f);
    426     }
    427 
    428     while (btMprSimplexSize(portal) < 4){
    429 		 btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 3));
    430 
    431         dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir);
    432         if (btMprIsZero(dot) || dot < 0.f)
    433             return -1;
    434 
    435         cont = 0;
    436 
    437         // test if origin is outside (v1, v0, v3) - set v2 as v3 and
    438         // continue
    439         btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v,
    440                           &btMprSimplexPoint(portal, 3)->v);
    441         dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
    442         if (dot < 0.f && !btMprIsZero(dot)){
    443             btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3));
    444             cont = 1;
    445         }
    446 
    447         if (!cont){
    448             // test if origin is outside (v3, v0, v2) - set v1 as v3 and
    449             // continue
    450             btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v,
    451                               &btMprSimplexPoint(portal, 2)->v);
    452             dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
    453             if (dot < 0.f && !btMprIsZero(dot)){
    454                 btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3));
    455                 cont = 1;
    456             }
    457         }
    458 
    459         if (cont){
    460             btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
    461                              &btMprSimplexPoint(portal, 0)->v);
    462             btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
    463                              &btMprSimplexPoint(portal, 0)->v);
    464             btMprVec3Cross(&dir, &va, &vb);
    465             btMprVec3Normalize(&dir);
    466         }else{
    467             btMprSimplexSetSize(portal, 4);
    468         }
    469     }
    470 
    471     return 0;
    472 }
    473 
    474 template <typename btConvexTemplate>
    475 static int btRefinePortal(const btConvexTemplate& a, const btConvexTemplate& b,const btMprCollisionDescription& colDesc,
    476 							btMprSimplex_t *portal)
    477 {
    478     btVector3 dir;
    479     btMprSupport_t v4;
    480 
    481 	for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
    482     //while (1)
    483 	{
    484         // compute direction outside the portal (from v0 throught v1,v2,v3
    485         // face)
    486         btPortalDir(portal, &dir);
    487 
    488         // test if origin is inside the portal
    489         if (portalEncapsulesOrigin(portal, &dir))
    490             return 0;
    491 
    492         // get next support point
    493 
    494 		 btMprSupport(a,b,colDesc, dir, &v4);
    495 
    496 
    497         // test if v4 can expand portal to contain origin and if portal
    498         // expanding doesn't reach given tolerance
    499         if (!portalCanEncapsuleOrigin(portal, &v4, &dir)
    500                 || portalReachTolerance(portal, &v4, &dir))
    501 		{
    502             return -1;
    503         }
    504 
    505         // v1-v2-v3 triangle must be rearranged to face outside Minkowski
    506         // difference (direction from v0).
    507         btExpandPortal(portal, &v4);
    508     }
    509 
    510     return -1;
    511 }
    512 
    513 static void btFindPos(const btMprSimplex_t *portal, btVector3 *pos)
    514 {
    515 
    516 	btVector3 zero = btVector3(0,0,0);
    517 	btVector3* origin = &zero;
    518 
    519     btVector3 dir;
    520     size_t i;
    521     float b[4], sum, inv;
    522     btVector3 vec, p1, p2;
    523 
    524     btPortalDir(portal, &dir);
    525 
    526     // use barycentric coordinates of tetrahedron to find origin
    527     btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
    528                        &btMprSimplexPoint(portal, 2)->v);
    529     b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
    530 
    531     btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
    532                        &btMprSimplexPoint(portal, 2)->v);
    533     b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
    534 
    535     btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v,
    536                        &btMprSimplexPoint(portal, 1)->v);
    537     b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
    538 
    539     btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
    540                        &btMprSimplexPoint(portal, 1)->v);
    541     b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
    542 
    543 	sum = b[0] + b[1] + b[2] + b[3];
    544 
    545     if (btMprIsZero(sum) || sum < 0.f){
    546 		b[0] = 0.f;
    547 
    548         btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
    549                            &btMprSimplexPoint(portal, 3)->v);
    550         b[1] = btMprVec3Dot(&vec, &dir);
    551         btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
    552                            &btMprSimplexPoint(portal, 1)->v);
    553         b[2] = btMprVec3Dot(&vec, &dir);
    554         btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
    555                            &btMprSimplexPoint(portal, 2)->v);
    556         b[3] = btMprVec3Dot(&vec, &dir);
    557 
    558 		sum = b[1] + b[2] + b[3];
    559 	}
    560 
    561 	inv = 1.f / sum;
    562 
    563     btMprVec3Copy(&p1, origin);
    564     btMprVec3Copy(&p2, origin);
    565     for (i = 0; i < 4; i++){
    566         btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1);
    567         btMprVec3Scale(&vec, b[i]);
    568         btMprVec3Add(&p1, &vec);
    569 
    570         btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2);
    571         btMprVec3Scale(&vec, b[i]);
    572         btMprVec3Add(&p2, &vec);
    573     }
    574     btMprVec3Scale(&p1, inv);
    575     btMprVec3Scale(&p2, inv);
    576 #ifdef MPR_AVERAGE_CONTACT_POSITIONS
    577     btMprVec3Copy(pos, &p1);
    578     btMprVec3Add(pos, &p2);
    579     btMprVec3Scale(pos, 0.5);
    580 #else
    581     btMprVec3Copy(pos, &p2);
    582 #endif//MPR_AVERAGE_CONTACT_POSITIONS
    583 }
    584 
    585 inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b)
    586 {
    587     btVector3 ab;
    588     btMprVec3Sub2(&ab, a, b);
    589     return btMprVec3Len2(&ab);
    590 }
    591 
    592 inline float _btMprVec3PointSegmentDist2(const btVector3 *P,
    593                                                   const btVector3 *x0,
    594                                                   const btVector3 *b,
    595                                                   btVector3 *witness)
    596 {
    597     // The computation comes from solving equation of segment:
    598     //      S(t) = x0 + t.d
    599     //          where - x0 is initial point of segment
    600     //                - d is direction of segment from x0 (|d| > 0)
    601     //                - t belongs to <0, 1> interval
    602     //
    603     // Than, distance from a segment to some point P can be expressed:
    604     //      D(t) = |x0 + t.d - P|^2
    605     //          which is distance from any point on segment. Minimization
    606     //          of this function brings distance from P to segment.
    607     // Minimization of D(t) leads to simple quadratic equation that's
    608     // solving is straightforward.
    609     //
    610     // Bonus of this method is witness point for free.
    611 
    612     float dist, t;
    613     btVector3 d, a;
    614 
    615     // direction of segment
    616     btMprVec3Sub2(&d, b, x0);
    617 
    618     // precompute vector from P to x0
    619     btMprVec3Sub2(&a, x0, P);
    620 
    621     t  = -1.f * btMprVec3Dot(&a, &d);
    622     t /= btMprVec3Len2(&d);
    623 
    624     if (t < 0.f || btMprIsZero(t)){
    625         dist = btMprVec3Dist2(x0, P);
    626         if (witness)
    627             btMprVec3Copy(witness, x0);
    628     }else if (t > 1.f || btMprEq(t, 1.f)){
    629         dist = btMprVec3Dist2(b, P);
    630         if (witness)
    631             btMprVec3Copy(witness, b);
    632     }else{
    633         if (witness){
    634             btMprVec3Copy(witness, &d);
    635             btMprVec3Scale(witness, t);
    636             btMprVec3Add(witness, x0);
    637             dist = btMprVec3Dist2(witness, P);
    638         }else{
    639             // recycling variables
    640             btMprVec3Scale(&d, t);
    641             btMprVec3Add(&d, &a);
    642             dist = btMprVec3Len2(&d);
    643         }
    644     }
    645 
    646     return dist;
    647 }
    648 
    649 
    650 
    651 inline float btMprVec3PointTriDist2(const btVector3 *P,
    652                                 const btVector3 *x0, const btVector3 *B,
    653                                 const btVector3 *C,
    654                                 btVector3 *witness)
    655 {
    656     // Computation comes from analytic expression for triangle (x0, B, C)
    657     //      T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
    658     // Then equation for distance is:
    659     //      D(s, t) = | T(s, t) - P |^2
    660     // This leads to minimization of quadratic function of two variables.
    661     // The solution from is taken only if s is between 0 and 1, t is
    662     // between 0 and 1 and t + s < 1, otherwise distance from segment is
    663     // computed.
    664 
    665     btVector3 d1, d2, a;
    666     float u, v, w, p, q, r;
    667     float s, t, dist, dist2;
    668     btVector3 witness2;
    669 
    670     btMprVec3Sub2(&d1, B, x0);
    671     btMprVec3Sub2(&d2, C, x0);
    672     btMprVec3Sub2(&a, x0, P);
    673 
    674     u = btMprVec3Dot(&a, &a);
    675     v = btMprVec3Dot(&d1, &d1);
    676     w = btMprVec3Dot(&d2, &d2);
    677     p = btMprVec3Dot(&a, &d1);
    678     q = btMprVec3Dot(&a, &d2);
    679     r = btMprVec3Dot(&d1, &d2);
    680 
    681 	btScalar div = (w * v - r * r);
    682 	if (btMprIsZero(div))
    683 	{
    684 		s=-1;
    685 	} else
    686 	{
    687 		s = (q * r - w * p) / div;
    688 		t = (-s * r - q) / w;
    689 	}
    690 
    691     if ((btMprIsZero(s) || s > 0.f)
    692             && (btMprEq(s, 1.f) || s < 1.f)
    693             && (btMprIsZero(t) || t > 0.f)
    694             && (btMprEq(t, 1.f) || t < 1.f)
    695             && (btMprEq(t + s, 1.f) || t + s < 1.f)){
    696 
    697         if (witness){
    698             btMprVec3Scale(&d1, s);
    699             btMprVec3Scale(&d2, t);
    700             btMprVec3Copy(witness, x0);
    701             btMprVec3Add(witness, &d1);
    702             btMprVec3Add(witness, &d2);
    703 
    704             dist = btMprVec3Dist2(witness, P);
    705         }else{
    706             dist  = s * s * v;
    707             dist += t * t * w;
    708             dist += 2.f * s * t * r;
    709             dist += 2.f * s * p;
    710             dist += 2.f * t * q;
    711             dist += u;
    712         }
    713     }else{
    714         dist = _btMprVec3PointSegmentDist2(P, x0, B, witness);
    715 
    716         dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2);
    717         if (dist2 < dist){
    718             dist = dist2;
    719             if (witness)
    720                 btMprVec3Copy(witness, &witness2);
    721         }
    722 
    723         dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2);
    724         if (dist2 < dist){
    725             dist = dist2;
    726             if (witness)
    727                 btMprVec3Copy(witness, &witness2);
    728         }
    729     }
    730 
    731     return dist;
    732 }
    733 
    734 template <typename btConvexTemplate>
    735 static void btFindPenetr(const btConvexTemplate& a, const btConvexTemplate& b,
    736                          const btMprCollisionDescription& colDesc,
    737                          btMprSimplex_t *portal,
    738                          float *depth, btVector3 *pdir, btVector3 *pos)
    739 {
    740     btVector3 dir;
    741     btMprSupport_t v4;
    742     unsigned long iterations;
    743 
    744 	btVector3 zero = btVector3(0,0,0);
    745 	btVector3* origin = &zero;
    746 
    747 
    748     iterations = 1UL;
    749 	for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
    750     //while (1)
    751 	{
    752         // compute portal direction and obtain next support point
    753         btPortalDir(portal, &dir);
    754 
    755 		 btMprSupport(a,b,colDesc, dir, &v4);
    756 
    757 
    758         // reached tolerance -> find penetration info
    759         if (portalReachTolerance(portal, &v4, &dir)
    760                 || iterations ==BT_MPR_MAX_ITERATIONS)
    761 		{
    762             *depth = btMprVec3PointTriDist2(origin,&btMprSimplexPoint(portal, 1)->v,&btMprSimplexPoint(portal, 2)->v,&btMprSimplexPoint(portal, 3)->v,pdir);
    763             *depth = BT_MPR_SQRT(*depth);
    764 
    765 			if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z()))
    766 			{
    767 
    768 				*pdir = dir;
    769 			}
    770 			btMprVec3Normalize(pdir);
    771 
    772             // barycentric coordinates:
    773             btFindPos(portal, pos);
    774 
    775 
    776             return;
    777         }
    778 
    779         btExpandPortal(portal, &v4);
    780 
    781         iterations++;
    782     }
    783 }
    784 
    785 static void btFindPenetrTouch(btMprSimplex_t *portal,float *depth, btVector3 *dir, btVector3 *pos)
    786 {
    787     // Touching contact on portal's v1 - so depth is zero and direction
    788     // is unimportant and pos can be guessed
    789     *depth = 0.f;
    790     btVector3 zero = btVector3(0,0,0);
    791 	btVector3* origin = &zero;
    792 
    793 
    794 	btMprVec3Copy(dir, origin);
    795 #ifdef MPR_AVERAGE_CONTACT_POSITIONS
    796     btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
    797     btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
    798     btMprVec3Scale(pos, 0.5);
    799 #else
    800      btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
    801 #endif
    802 }
    803 
    804 static void btFindPenetrSegment(btMprSimplex_t *portal,
    805                               float *depth, btVector3 *dir, btVector3 *pos)
    806 {
    807 
    808     // Origin lies on v0-v1 segment.
    809     // Depth is distance to v1, direction also and position must be
    810     // computed
    811 #ifdef MPR_AVERAGE_CONTACT_POSITIONS
    812     btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
    813     btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
    814     btMprVec3Scale(pos, 0.5f);
    815 #else
    816      btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
    817 #endif//MPR_AVERAGE_CONTACT_POSITIONS
    818 
    819     btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v);
    820     *depth = BT_MPR_SQRT(btMprVec3Len2(dir));
    821     btMprVec3Normalize(dir);
    822 
    823 
    824 }
    825 
    826 
    827 template <typename btConvexTemplate>
    828 inline int btMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b,
    829                             const btMprCollisionDescription& colDesc,
    830 					float *depthOut, btVector3* dirOut, btVector3* posOut)
    831 {
    832 
    833 	 btMprSimplex_t portal;
    834 
    835 
    836     // Phase 1: Portal discovery
    837     int result = btDiscoverPortal(a,b,colDesc, &portal);
    838 
    839 
    840 	//sepAxis[pairIndex] = *pdir;//or -dir?
    841 
    842 	switch (result)
    843 	{
    844 	case 0:
    845 		{
    846 			// Phase 2: Portal refinement
    847 
    848 			result = btRefinePortal(a,b,colDesc, &portal);
    849 			if (result < 0)
    850 				return -1;
    851 
    852 			// Phase 3. Penetration info
    853 			btFindPenetr(a,b,colDesc, &portal, depthOut, dirOut, posOut);
    854 
    855 
    856 			break;
    857 		}
    858 	case 1:
    859 		{
    860 			 // Touching contact on portal's v1.
    861 			btFindPenetrTouch(&portal, depthOut, dirOut, posOut);
    862 			result=0;
    863 			break;
    864 		}
    865 	case 2:
    866 		{
    867 
    868 			btFindPenetrSegment( &portal, depthOut, dirOut, posOut);
    869 			result=0;
    870 			break;
    871 		}
    872 	default:
    873 		{
    874 			//if (res < 0)
    875 			//{
    876 				// Origin isn't inside portal - no collision.
    877 				result = -1;
    878 			//}
    879 		}
    880 	};
    881 
    882 	return result;
    883 };
    884 
    885 
    886 template<typename btConvexTemplate, typename btMprDistanceTemplate>
    887 inline int	btComputeMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, const
    888                                     btMprCollisionDescription& colDesc, btMprDistanceTemplate* distInfo)
    889 {
    890 	btVector3 dir,pos;
    891 	float depth;
    892 
    893 	int res = btMprPenetration(a,b,colDesc,&depth, &dir, &pos);
    894 	if (res==0)
    895 	{
    896 		distInfo->m_distance = -depth;
    897 		distInfo->m_pointOnB = pos;
    898 		distInfo->m_normalBtoA = -dir;
    899 		distInfo->m_pointOnA = pos-distInfo->m_distance*dir;
    900 		return 0;
    901 	}
    902 
    903 	return -1;
    904 }
    905 
    906 
    907 
    908 #endif //BT_MPR_PENETRATION_H
    909