1036 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1036 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Bullet Continuous Collision Detection and Physics Library
 | 
						|
Copyright (c) 2003-2014 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.
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
Initial GJK-EPA collision solver by Nathanael Presson, 2008
 | 
						|
Improvements and refactoring by Erwin Coumans, 2008-2014
 | 
						|
*/
 | 
						|
#ifndef BT_GJK_EPA3_H
 | 
						|
#define BT_GJK_EPA3_H
 | 
						|
 | 
						|
#include "LinearMath/btTransform.h"
 | 
						|
#include "btGjkCollisionDescription.h"
 | 
						|
 | 
						|
 | 
						|
 | 
						|
struct	btGjkEpaSolver3
 | 
						|
{
 | 
						|
struct	sResults
 | 
						|
	{
 | 
						|
	enum eStatus
 | 
						|
		{
 | 
						|
		Separated,		/* Shapes doesnt penetrate												*/ 
 | 
						|
		Penetrating,	/* Shapes are penetrating												*/ 
 | 
						|
		GJK_Failed,		/* GJK phase fail, no big issue, shapes are probably just 'touching'	*/ 
 | 
						|
		EPA_Failed		/* EPA phase fail, bigger problem, need to save parameters, and debug	*/ 
 | 
						|
		}		status;
 | 
						|
	btVector3	witnesses[2];
 | 
						|
	btVector3	normal;
 | 
						|
	btScalar	distance;
 | 
						|
	};
 | 
						|
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#if defined(DEBUG) || defined (_DEBUG)
 | 
						|
#include <stdio.h> //for debug printf
 | 
						|
#ifdef __SPU__
 | 
						|
#include <spu_printf.h>
 | 
						|
#define printf spu_printf
 | 
						|
#endif //__SPU__
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
    
 | 
						|
    // Config
 | 
						|
    
 | 
						|
    /* GJK	*/
 | 
						|
#define GJK_MAX_ITERATIONS	128
 | 
						|
#define GJK_ACCURARY		((btScalar)0.0001)
 | 
						|
#define GJK_MIN_DISTANCE	((btScalar)0.0001)
 | 
						|
#define GJK_DUPLICATED_EPS	((btScalar)0.0001)
 | 
						|
#define GJK_SIMPLEX2_EPS	((btScalar)0.0)
 | 
						|
#define GJK_SIMPLEX3_EPS	((btScalar)0.0)
 | 
						|
#define GJK_SIMPLEX4_EPS	((btScalar)0.0)
 | 
						|
    
 | 
						|
    /* EPA	*/
 | 
						|
#define EPA_MAX_VERTICES	64
 | 
						|
#define EPA_MAX_FACES		(EPA_MAX_VERTICES*2)
 | 
						|
#define EPA_MAX_ITERATIONS	255
 | 
						|
#define EPA_ACCURACY		((btScalar)0.0001)
 | 
						|
#define EPA_FALLBACK		(10*EPA_ACCURACY)
 | 
						|
#define EPA_PLANE_EPS		((btScalar)0.00001)
 | 
						|
#define EPA_INSIDE_EPS		((btScalar)0.01)
 | 
						|
    
 | 
						|
    
 | 
						|
    // Shorthands
 | 
						|
    typedef unsigned int	U;
 | 
						|
    typedef unsigned char	U1;
 | 
						|
    
 | 
						|
    // MinkowskiDiff
 | 
						|
    template <typename btConvexTemplate>
 | 
						|
    struct	MinkowskiDiff
 | 
						|
    {
 | 
						|
        const btConvexTemplate* m_convexAPtr;
 | 
						|
        const btConvexTemplate* m_convexBPtr;
 | 
						|
        
 | 
						|
        btMatrix3x3				m_toshape1;
 | 
						|
        btTransform				m_toshape0;
 | 
						|
        
 | 
						|
        bool					m_enableMargin;
 | 
						|
        
 | 
						|
        
 | 
						|
        MinkowskiDiff(const btConvexTemplate& a, const btConvexTemplate& b)
 | 
						|
        :m_convexAPtr(&a),
 | 
						|
        m_convexBPtr(&b)
 | 
						|
        {
 | 
						|
        }
 | 
						|
        
 | 
						|
        void					EnableMargin(bool enable)
 | 
						|
        {
 | 
						|
            m_enableMargin = enable;
 | 
						|
        }
 | 
						|
        inline btVector3		Support0(const btVector3& d) const
 | 
						|
        {
 | 
						|
            return m_convexAPtr->getLocalSupportWithMargin(d);
 | 
						|
        }
 | 
						|
        inline btVector3		Support1(const btVector3& d) const
 | 
						|
        {
 | 
						|
            return m_toshape0*m_convexBPtr->getLocalSupportWithMargin(m_toshape1*d);
 | 
						|
        }
 | 
						|
        
 | 
						|
        
 | 
						|
        inline btVector3		Support(const btVector3& d) const
 | 
						|
        {
 | 
						|
            return(Support0(d)-Support1(-d));
 | 
						|
        }
 | 
						|
        btVector3				Support(const btVector3& d,U index) const
 | 
						|
        {
 | 
						|
            if(index)
 | 
						|
                return(Support1(d));
 | 
						|
            else
 | 
						|
                return(Support0(d));
 | 
						|
        }
 | 
						|
    };
 | 
						|
    
 | 
						|
enum	eGjkStatus
 | 
						|
{
 | 
						|
    eGjkValid,
 | 
						|
    eGjkInside,
 | 
						|
    eGjkFailed
 | 
						|
};
 | 
						|
 | 
						|
    // GJK
 | 
						|
    template <typename btConvexTemplate>
 | 
						|
    struct	GJK
 | 
						|
    {
 | 
						|
        /* Types		*/
 | 
						|
        struct	sSV
 | 
						|
        {
 | 
						|
            btVector3	d,w;
 | 
						|
        };
 | 
						|
        struct	sSimplex
 | 
						|
        {
 | 
						|
            sSV*		c[4];
 | 
						|
            btScalar	p[4];
 | 
						|
            U			rank;
 | 
						|
        };
 | 
						|
        
 | 
						|
        /* Fields		*/
 | 
						|
        
 | 
						|
        MinkowskiDiff<btConvexTemplate>			m_shape;
 | 
						|
        btVector3		m_ray;
 | 
						|
        btScalar		m_distance;
 | 
						|
        sSimplex		m_simplices[2];
 | 
						|
        sSV				m_store[4];
 | 
						|
        sSV*			m_free[4];
 | 
						|
        U				m_nfree;
 | 
						|
        U				m_current;
 | 
						|
        sSimplex*		m_simplex;
 | 
						|
        eGjkStatus      m_status;
 | 
						|
        /* Methods		*/
 | 
						|
        
 | 
						|
        GJK(const btConvexTemplate& a, const btConvexTemplate& b)
 | 
						|
        :m_shape(a,b)
 | 
						|
        {
 | 
						|
            Initialize();
 | 
						|
        }
 | 
						|
        void				Initialize()
 | 
						|
        {
 | 
						|
            m_ray		=	btVector3(0,0,0);
 | 
						|
            m_nfree		=	0;
 | 
						|
            m_status	=	eGjkFailed;
 | 
						|
            m_current	=	0;
 | 
						|
            m_distance	=	0;
 | 
						|
        }
 | 
						|
        eGjkStatus			Evaluate(const MinkowskiDiff<btConvexTemplate>& shapearg,const btVector3& guess)
 | 
						|
        {
 | 
						|
            U			iterations=0;
 | 
						|
            btScalar	sqdist=0;
 | 
						|
            btScalar	alpha=0;
 | 
						|
            btVector3	lastw[4];
 | 
						|
            U			clastw=0;
 | 
						|
            /* Initialize solver		*/
 | 
						|
            m_free[0]			=	&m_store[0];
 | 
						|
            m_free[1]			=	&m_store[1];
 | 
						|
            m_free[2]			=	&m_store[2];
 | 
						|
            m_free[3]			=	&m_store[3];
 | 
						|
            m_nfree				=	4;
 | 
						|
            m_current			=	0;
 | 
						|
            m_status			=	eGjkValid;
 | 
						|
            m_shape				=	shapearg;
 | 
						|
            m_distance			=	0;
 | 
						|
            /* Initialize simplex		*/
 | 
						|
            m_simplices[0].rank	=	0;
 | 
						|
            m_ray				=	guess;
 | 
						|
            const btScalar	sqrl=	m_ray.length2();
 | 
						|
            appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0));
 | 
						|
            m_simplices[0].p[0]	=	1;
 | 
						|
            m_ray				=	m_simplices[0].c[0]->w;
 | 
						|
            sqdist				=	sqrl;
 | 
						|
            lastw[0]			=
 | 
						|
            lastw[1]			=
 | 
						|
            lastw[2]			=
 | 
						|
            lastw[3]			=	m_ray;
 | 
						|
            /* Loop						*/
 | 
						|
            do	{
 | 
						|
                const U		next=1-m_current;
 | 
						|
                sSimplex&	cs=m_simplices[m_current];
 | 
						|
                sSimplex&	ns=m_simplices[next];
 | 
						|
                /* Check zero							*/
 | 
						|
                const btScalar	rl=m_ray.length();
 | 
						|
                if(rl<GJK_MIN_DISTANCE)
 | 
						|
                {/* Touching or inside				*/
 | 
						|
                    m_status=eGjkInside;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                /* Append new vertice in -'v' direction	*/
 | 
						|
                appendvertice(cs,-m_ray);
 | 
						|
                const btVector3&	w=cs.c[cs.rank-1]->w;
 | 
						|
                bool				found=false;
 | 
						|
                for(U i=0;i<4;++i)
 | 
						|
                {
 | 
						|
                    if((w-lastw[i]).length2()<GJK_DUPLICATED_EPS)
 | 
						|
                    { found=true;break; }
 | 
						|
                }
 | 
						|
                if(found)
 | 
						|
                {/* Return old simplex				*/
 | 
						|
                    removevertice(m_simplices[m_current]);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {/* Update lastw					*/
 | 
						|
                    lastw[clastw=(clastw+1)&3]=w;
 | 
						|
                }
 | 
						|
                /* Check for termination				*/
 | 
						|
                const btScalar	omega=btDot(m_ray,w)/rl;
 | 
						|
                alpha=btMax(omega,alpha);
 | 
						|
                if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
 | 
						|
                {/* Return old simplex				*/
 | 
						|
                    removevertice(m_simplices[m_current]);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                /* Reduce simplex						*/
 | 
						|
                btScalar	weights[4];
 | 
						|
                U			mask=0;
 | 
						|
                switch(cs.rank)
 | 
						|
                {
 | 
						|
                    case	2:	sqdist=projectorigin(	cs.c[0]->w,
 | 
						|
                                                     cs.c[1]->w,
 | 
						|
                                                     weights,mask);break;
 | 
						|
                    case	3:	sqdist=projectorigin(	cs.c[0]->w,
 | 
						|
                                                     cs.c[1]->w,
 | 
						|
                                                     cs.c[2]->w,
 | 
						|
                                                     weights,mask);break;
 | 
						|
                    case	4:	sqdist=projectorigin(	cs.c[0]->w,
 | 
						|
                                                     cs.c[1]->w,
 | 
						|
                                                     cs.c[2]->w,
 | 
						|
                                                     cs.c[3]->w,
 | 
						|
                                                     weights,mask);break;
 | 
						|
                }
 | 
						|
                if(sqdist>=0)
 | 
						|
                {/* Valid	*/
 | 
						|
                    ns.rank		=	0;
 | 
						|
                    m_ray		=	btVector3(0,0,0);
 | 
						|
                    m_current	=	next;
 | 
						|
                    for(U i=0,ni=cs.rank;i<ni;++i)
 | 
						|
                    {
 | 
						|
                        if(mask&(1<<i))
 | 
						|
                        {
 | 
						|
                            ns.c[ns.rank]		=	cs.c[i];
 | 
						|
                            ns.p[ns.rank++]		=	weights[i];
 | 
						|
                            m_ray				+=	cs.c[i]->w*weights[i];
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            m_free[m_nfree++]	=	cs.c[i];
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if(mask==15) m_status=eGjkInside;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {/* Return old simplex				*/
 | 
						|
                    removevertice(m_simplices[m_current]);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eGjkFailed;
 | 
						|
            } while(m_status==eGjkValid);
 | 
						|
            m_simplex=&m_simplices[m_current];
 | 
						|
            switch(m_status)
 | 
						|
            {
 | 
						|
                case	eGjkValid:		m_distance=m_ray.length();break;
 | 
						|
                case	eGjkInside:	m_distance=0;break;
 | 
						|
                default:
 | 
						|
                {
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return(m_status);
 | 
						|
        }
 | 
						|
        bool					EncloseOrigin()
 | 
						|
        {
 | 
						|
            switch(m_simplex->rank)
 | 
						|
            {
 | 
						|
                case	1:
 | 
						|
                {
 | 
						|
                    for(U i=0;i<3;++i)
 | 
						|
                    {
 | 
						|
                        btVector3		axis=btVector3(0,0,0);
 | 
						|
                        axis[i]=1;
 | 
						|
                        appendvertice(*m_simplex, axis);
 | 
						|
                        if(EncloseOrigin())	return(true);
 | 
						|
                        removevertice(*m_simplex);
 | 
						|
                        appendvertice(*m_simplex,-axis);
 | 
						|
                        if(EncloseOrigin())	return(true);
 | 
						|
                        removevertice(*m_simplex);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                    break;
 | 
						|
                case	2:
 | 
						|
                {
 | 
						|
                    const btVector3	d=m_simplex->c[1]->w-m_simplex->c[0]->w;
 | 
						|
                    for(U i=0;i<3;++i)
 | 
						|
                    {
 | 
						|
                        btVector3		axis=btVector3(0,0,0);
 | 
						|
                        axis[i]=1;
 | 
						|
                        const btVector3	p=btCross(d,axis);
 | 
						|
                        if(p.length2()>0)
 | 
						|
                        {
 | 
						|
                            appendvertice(*m_simplex, p);
 | 
						|
                            if(EncloseOrigin())	return(true);
 | 
						|
                            removevertice(*m_simplex);
 | 
						|
                            appendvertice(*m_simplex,-p);
 | 
						|
                            if(EncloseOrigin())	return(true);
 | 
						|
                            removevertice(*m_simplex);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                    break;
 | 
						|
                case	3:
 | 
						|
                {
 | 
						|
                    const btVector3	n=btCross(m_simplex->c[1]->w-m_simplex->c[0]->w,
 | 
						|
                                              m_simplex->c[2]->w-m_simplex->c[0]->w);
 | 
						|
                    if(n.length2()>0)
 | 
						|
                    {
 | 
						|
                        appendvertice(*m_simplex,n);
 | 
						|
                        if(EncloseOrigin())	return(true);
 | 
						|
                        removevertice(*m_simplex);
 | 
						|
                        appendvertice(*m_simplex,-n);
 | 
						|
                        if(EncloseOrigin())	return(true);
 | 
						|
                        removevertice(*m_simplex);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                    break;
 | 
						|
                case	4:
 | 
						|
                {
 | 
						|
                    if(btFabs(det(	m_simplex->c[0]->w-m_simplex->c[3]->w,
 | 
						|
                                  m_simplex->c[1]->w-m_simplex->c[3]->w,
 | 
						|
                                  m_simplex->c[2]->w-m_simplex->c[3]->w))>0)
 | 
						|
                        return(true);
 | 
						|
                }
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
            return(false);
 | 
						|
        }
 | 
						|
        /* Internals	*/
 | 
						|
        void				getsupport(const btVector3& d,sSV& sv) const
 | 
						|
        {
 | 
						|
            sv.d	=	d/d.length();
 | 
						|
            sv.w	=	m_shape.Support(sv.d);
 | 
						|
        }
 | 
						|
        void				removevertice(sSimplex& simplex)
 | 
						|
        {
 | 
						|
            m_free[m_nfree++]=simplex.c[--simplex.rank];
 | 
						|
        }
 | 
						|
        void				appendvertice(sSimplex& simplex,const btVector3& v)
 | 
						|
        {
 | 
						|
            simplex.p[simplex.rank]=0;
 | 
						|
            simplex.c[simplex.rank]=m_free[--m_nfree];
 | 
						|
            getsupport(v,*simplex.c[simplex.rank++]);
 | 
						|
        }
 | 
						|
        static btScalar		det(const btVector3& a,const btVector3& b,const btVector3& c)
 | 
						|
        {
 | 
						|
            return(	a.y()*b.z()*c.x()+a.z()*b.x()*c.y()-
 | 
						|
                   a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+
 | 
						|
                   a.x()*b.y()*c.z()-a.z()*b.y()*c.x());
 | 
						|
        }
 | 
						|
        static btScalar		projectorigin(	const btVector3& a,
 | 
						|
                                          const btVector3& b,
 | 
						|
                                          btScalar* w,U& m)
 | 
						|
        {
 | 
						|
            const btVector3	d=b-a;
 | 
						|
            const btScalar	l=d.length2();
 | 
						|
            if(l>GJK_SIMPLEX2_EPS)
 | 
						|
            {
 | 
						|
                const btScalar	t(l>0?-btDot(a,d)/l:0);
 | 
						|
                if(t>=1)		{ w[0]=0;w[1]=1;m=2;return(b.length2()); }
 | 
						|
                else if(t<=0)	{ w[0]=1;w[1]=0;m=1;return(a.length2()); }
 | 
						|
                else			{ w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); }
 | 
						|
            }
 | 
						|
            return(-1);
 | 
						|
        }
 | 
						|
        static btScalar		projectorigin(	const btVector3& a,
 | 
						|
                                          const btVector3& b,
 | 
						|
                                          const btVector3& c,
 | 
						|
                                          btScalar* w,U& m)
 | 
						|
        {
 | 
						|
            static const U		imd3[]={1,2,0};
 | 
						|
            const btVector3*	vt[]={&a,&b,&c};
 | 
						|
            const btVector3		dl[]={a-b,b-c,c-a};
 | 
						|
            const btVector3		n=btCross(dl[0],dl[1]);
 | 
						|
            const btScalar		l=n.length2();
 | 
						|
            if(l>GJK_SIMPLEX3_EPS)
 | 
						|
            {
 | 
						|
                btScalar	mindist=-1;
 | 
						|
                btScalar	subw[2]={0.f,0.f};
 | 
						|
                U			subm(0);
 | 
						|
                for(U i=0;i<3;++i)
 | 
						|
                {
 | 
						|
                    if(btDot(*vt[i],btCross(dl[i],n))>0)
 | 
						|
                    {
 | 
						|
                        const U			j=imd3[i];
 | 
						|
                        const btScalar	subd(projectorigin(*vt[i],*vt[j],subw,subm));
 | 
						|
                        if((mindist<0)||(subd<mindist))
 | 
						|
                        {
 | 
						|
                            mindist		=	subd;
 | 
						|
                            m			=	static_cast<U>(((subm&1)?1<<i:0)+((subm&2)?1<<j:0));
 | 
						|
                            w[i]		=	subw[0];
 | 
						|
                            w[j]		=	subw[1];
 | 
						|
                            w[imd3[j]]	=	0;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if(mindist<0)
 | 
						|
                {
 | 
						|
                    const btScalar	d=btDot(a,n);
 | 
						|
                    const btScalar	s=btSqrt(l);
 | 
						|
                    const btVector3	p=n*(d/l);
 | 
						|
                    mindist	=	p.length2();
 | 
						|
                    m		=	7;
 | 
						|
                    w[0]	=	(btCross(dl[1],b-p)).length()/s;
 | 
						|
                    w[1]	=	(btCross(dl[2],c-p)).length()/s;
 | 
						|
                    w[2]	=	1-(w[0]+w[1]);
 | 
						|
                }
 | 
						|
                return(mindist);
 | 
						|
            }
 | 
						|
            return(-1);
 | 
						|
        }
 | 
						|
        static btScalar		projectorigin(	const btVector3& a,
 | 
						|
                                          const btVector3& b,
 | 
						|
                                          const btVector3& c,
 | 
						|
                                          const btVector3& d,
 | 
						|
                                          btScalar* w,U& m)
 | 
						|
        {
 | 
						|
            static const U		imd3[]={1,2,0};
 | 
						|
            const btVector3*	vt[]={&a,&b,&c,&d};
 | 
						|
            const btVector3		dl[]={a-d,b-d,c-d};
 | 
						|
            const btScalar		vl=det(dl[0],dl[1],dl[2]);
 | 
						|
            const bool			ng=(vl*btDot(a,btCross(b-c,a-b)))<=0;
 | 
						|
            if(ng&&(btFabs(vl)>GJK_SIMPLEX4_EPS))
 | 
						|
            {
 | 
						|
                btScalar	mindist=-1;
 | 
						|
                btScalar	subw[3]={0.f,0.f,0.f};
 | 
						|
                U			subm(0);
 | 
						|
                for(U i=0;i<3;++i)
 | 
						|
                {
 | 
						|
                    const U			j=imd3[i];
 | 
						|
                    const btScalar	s=vl*btDot(d,btCross(dl[i],dl[j]));
 | 
						|
                    if(s>0)
 | 
						|
                    {
 | 
						|
                        const btScalar	subd=projectorigin(*vt[i],*vt[j],d,subw,subm);
 | 
						|
                        if((mindist<0)||(subd<mindist))
 | 
						|
                        {
 | 
						|
                            mindist		=	subd;
 | 
						|
                            m			=	static_cast<U>((subm&1?1<<i:0)+
 | 
						|
                                                           (subm&2?1<<j:0)+
 | 
						|
                                                           (subm&4?8:0));
 | 
						|
                            w[i]		=	subw[0];
 | 
						|
                            w[j]		=	subw[1];
 | 
						|
                            w[imd3[j]]	=	0;
 | 
						|
                            w[3]		=	subw[2];
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if(mindist<0)
 | 
						|
                {
 | 
						|
                    mindist	=	0;
 | 
						|
                    m		=	15;
 | 
						|
                    w[0]	=	det(c,b,d)/vl;
 | 
						|
                    w[1]	=	det(a,c,d)/vl;
 | 
						|
                    w[2]	=	det(b,a,d)/vl;
 | 
						|
                    w[3]	=	1-(w[0]+w[1]+w[2]);
 | 
						|
                }
 | 
						|
                return(mindist);
 | 
						|
            }
 | 
						|
            return(-1);
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
 | 
						|
enum	eEpaStatus
 | 
						|
{
 | 
						|
    eEpaValid,
 | 
						|
    eEpaTouching,
 | 
						|
    eEpaDegenerated,
 | 
						|
    eEpaNonConvex,
 | 
						|
    eEpaInvalidHull,
 | 
						|
    eEpaOutOfFaces,
 | 
						|
    eEpaOutOfVertices,
 | 
						|
    eEpaAccuraryReached,
 | 
						|
    eEpaFallBack,
 | 
						|
    eEpaFailed
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
    // EPA
 | 
						|
template <typename btConvexTemplate>
 | 
						|
    struct	EPA
 | 
						|
    {
 | 
						|
        /* Types		*/
 | 
						|
       
 | 
						|
        struct	sFace
 | 
						|
        {
 | 
						|
            btVector3	n;
 | 
						|
            btScalar	d;
 | 
						|
            typename GJK<btConvexTemplate>::sSV*		c[3];
 | 
						|
            sFace*		f[3];
 | 
						|
            sFace*		l[2];
 | 
						|
            U1			e[3];
 | 
						|
            U1			pass;
 | 
						|
        };
 | 
						|
        struct	sList
 | 
						|
        {
 | 
						|
            sFace*		root;
 | 
						|
            U			count;
 | 
						|
            sList() : root(0),count(0)	{}
 | 
						|
        };
 | 
						|
        struct	sHorizon
 | 
						|
        {
 | 
						|
            sFace*		cf;
 | 
						|
            sFace*		ff;
 | 
						|
            U			nf;
 | 
						|
            sHorizon() : cf(0),ff(0),nf(0)	{}
 | 
						|
        };
 | 
						|
       
 | 
						|
        /* Fields		*/
 | 
						|
        eEpaStatus		m_status;
 | 
						|
        typename GJK<btConvexTemplate>::sSimplex	m_result;
 | 
						|
        btVector3		m_normal;
 | 
						|
        btScalar		m_depth;
 | 
						|
        typename GJK<btConvexTemplate>::sSV				m_sv_store[EPA_MAX_VERTICES];
 | 
						|
        sFace			m_fc_store[EPA_MAX_FACES];
 | 
						|
        U				m_nextsv;
 | 
						|
        sList			m_hull;
 | 
						|
        sList			m_stock;
 | 
						|
        /* Methods		*/
 | 
						|
        EPA()
 | 
						|
        {
 | 
						|
            Initialize();
 | 
						|
        }
 | 
						|
        
 | 
						|
        
 | 
						|
        static inline void		bind(sFace* fa,U ea,sFace* fb,U eb)
 | 
						|
        {
 | 
						|
            fa->e[ea]=(U1)eb;fa->f[ea]=fb;
 | 
						|
            fb->e[eb]=(U1)ea;fb->f[eb]=fa;
 | 
						|
        }
 | 
						|
        static inline void		append(sList& list,sFace* face)
 | 
						|
        {
 | 
						|
            face->l[0]	=	0;
 | 
						|
            face->l[1]	=	list.root;
 | 
						|
            if(list.root) list.root->l[0]=face;
 | 
						|
            list.root	=	face;
 | 
						|
            ++list.count;
 | 
						|
        }
 | 
						|
        static inline void		remove(sList& list,sFace* face)
 | 
						|
        {
 | 
						|
            if(face->l[1]) face->l[1]->l[0]=face->l[0];
 | 
						|
            if(face->l[0]) face->l[0]->l[1]=face->l[1];
 | 
						|
            if(face==list.root) list.root=face->l[1];
 | 
						|
            --list.count;
 | 
						|
        }
 | 
						|
        
 | 
						|
        
 | 
						|
        void				Initialize()
 | 
						|
        {
 | 
						|
            m_status	=	eEpaFailed;
 | 
						|
            m_normal	=	btVector3(0,0,0);
 | 
						|
            m_depth		=	0;
 | 
						|
            m_nextsv	=	0;
 | 
						|
            for(U i=0;i<EPA_MAX_FACES;++i)
 | 
						|
            {
 | 
						|
                append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        eEpaStatus			Evaluate(GJK<btConvexTemplate>& gjk,const btVector3& guess)
 | 
						|
        {
 | 
						|
            typename GJK<btConvexTemplate>::sSimplex&	simplex=*gjk.m_simplex;
 | 
						|
            if((simplex.rank>1)&&gjk.EncloseOrigin())
 | 
						|
            {
 | 
						|
                
 | 
						|
                /* Clean up				*/
 | 
						|
                while(m_hull.root)
 | 
						|
                {
 | 
						|
                    sFace*	f = m_hull.root;
 | 
						|
                    remove(m_hull,f);
 | 
						|
                    append(m_stock,f);
 | 
						|
                }
 | 
						|
                m_status	=	eEpaValid;
 | 
						|
                m_nextsv	=	0;
 | 
						|
                /* Orient simplex		*/
 | 
						|
                if(gjk.det(	simplex.c[0]->w-simplex.c[3]->w,
 | 
						|
                           simplex.c[1]->w-simplex.c[3]->w,
 | 
						|
                           simplex.c[2]->w-simplex.c[3]->w)<0)
 | 
						|
                {
 | 
						|
                    btSwap(simplex.c[0],simplex.c[1]);
 | 
						|
                    btSwap(simplex.p[0],simplex.p[1]);
 | 
						|
                }
 | 
						|
                /* Build initial hull	*/
 | 
						|
                sFace*	tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),
 | 
						|
                    newface(simplex.c[1],simplex.c[0],simplex.c[3],true),
 | 
						|
                    newface(simplex.c[2],simplex.c[1],simplex.c[3],true),
 | 
						|
                    newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};
 | 
						|
                if(m_hull.count==4)
 | 
						|
                {
 | 
						|
                    sFace*		best=findbest();
 | 
						|
                    sFace		outer=*best;
 | 
						|
                    U			pass=0;
 | 
						|
                    U			iterations=0;
 | 
						|
                    bind(tetra[0],0,tetra[1],0);
 | 
						|
                    bind(tetra[0],1,tetra[2],0);
 | 
						|
                    bind(tetra[0],2,tetra[3],0);
 | 
						|
                    bind(tetra[1],1,tetra[3],2);
 | 
						|
                    bind(tetra[1],2,tetra[2],1);
 | 
						|
                    bind(tetra[2],2,tetra[3],1);
 | 
						|
                    m_status=eEpaValid;
 | 
						|
                    for(;iterations<EPA_MAX_ITERATIONS;++iterations)
 | 
						|
                    {
 | 
						|
                        if(m_nextsv<EPA_MAX_VERTICES)
 | 
						|
                        {
 | 
						|
                            sHorizon		horizon;
 | 
						|
                            typename GJK<btConvexTemplate>::sSV*			w=&m_sv_store[m_nextsv++];
 | 
						|
                            bool			valid=true;
 | 
						|
                            best->pass	=	(U1)(++pass);
 | 
						|
                            gjk.getsupport(best->n,*w);
 | 
						|
                            const btScalar	wdist=btDot(best->n,w->w)-best->d;
 | 
						|
                            if(wdist>EPA_ACCURACY)
 | 
						|
                            {
 | 
						|
                                for(U j=0;(j<3)&&valid;++j)
 | 
						|
                                {
 | 
						|
                                    valid&=expand(	pass,w,
 | 
						|
                                                  best->f[j],best->e[j],
 | 
						|
                                                  horizon);
 | 
						|
                                }
 | 
						|
                                if(valid&&(horizon.nf>=3))
 | 
						|
                                {
 | 
						|
                                    bind(horizon.cf,1,horizon.ff,2);
 | 
						|
                                    remove(m_hull,best);
 | 
						|
                                    append(m_stock,best);
 | 
						|
                                    best=findbest();
 | 
						|
                                    outer=*best;
 | 
						|
                                } else { m_status=eEpaInvalidHull;break; }
 | 
						|
                            } else { m_status=eEpaAccuraryReached;break; }
 | 
						|
                        } else { m_status=eEpaOutOfVertices;break; }
 | 
						|
                    }
 | 
						|
                    const btVector3	projection=outer.n*outer.d;
 | 
						|
                    m_normal	=	outer.n;
 | 
						|
                    m_depth		=	outer.d;
 | 
						|
                    m_result.rank	=	3;
 | 
						|
                    m_result.c[0]	=	outer.c[0];
 | 
						|
                    m_result.c[1]	=	outer.c[1];
 | 
						|
                    m_result.c[2]	=	outer.c[2];
 | 
						|
                    m_result.p[0]	=	btCross(	outer.c[1]->w-projection,
 | 
						|
                                                outer.c[2]->w-projection).length();
 | 
						|
                    m_result.p[1]	=	btCross(	outer.c[2]->w-projection,
 | 
						|
                                                outer.c[0]->w-projection).length();
 | 
						|
                    m_result.p[2]	=	btCross(	outer.c[0]->w-projection,
 | 
						|
                                                outer.c[1]->w-projection).length();
 | 
						|
                    const btScalar	sum=m_result.p[0]+m_result.p[1]+m_result.p[2];
 | 
						|
                    m_result.p[0]	/=	sum;
 | 
						|
                    m_result.p[1]	/=	sum;
 | 
						|
                    m_result.p[2]	/=	sum;
 | 
						|
                    return(m_status);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            /* Fallback		*/
 | 
						|
            m_status	=	eEpaFallBack;
 | 
						|
            m_normal	=	-guess;
 | 
						|
            const btScalar	nl=m_normal.length();
 | 
						|
            if(nl>0)
 | 
						|
                m_normal	=	m_normal/nl;
 | 
						|
            else
 | 
						|
                m_normal	=	btVector3(1,0,0);
 | 
						|
            m_depth	=	0;
 | 
						|
            m_result.rank=1;
 | 
						|
            m_result.c[0]=simplex.c[0];
 | 
						|
            m_result.p[0]=1;
 | 
						|
            return(m_status);
 | 
						|
        }
 | 
						|
        bool getedgedist(sFace* face, typename GJK<btConvexTemplate>::sSV* a, typename GJK<btConvexTemplate>::sSV* b, btScalar& dist)
 | 
						|
        {
 | 
						|
            const btVector3 ba = b->w - a->w;
 | 
						|
            const btVector3 n_ab = btCross(ba, face->n); // Outward facing edge normal direction, on triangle plane
 | 
						|
            const btScalar a_dot_nab = btDot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required
 | 
						|
            
 | 
						|
            if(a_dot_nab < 0)
 | 
						|
            {
 | 
						|
                // Outside of edge a->b
 | 
						|
                
 | 
						|
                const btScalar ba_l2 = ba.length2();
 | 
						|
                const btScalar a_dot_ba = btDot(a->w, ba);
 | 
						|
                const btScalar b_dot_ba = btDot(b->w, ba);
 | 
						|
                
 | 
						|
                if(a_dot_ba > 0)
 | 
						|
                {
 | 
						|
                    // Pick distance vertex a
 | 
						|
                    dist = a->w.length();
 | 
						|
                }
 | 
						|
                else if(b_dot_ba < 0)
 | 
						|
                {
 | 
						|
                    // Pick distance vertex b
 | 
						|
                    dist = b->w.length();
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    // Pick distance to edge a->b
 | 
						|
                    const btScalar a_dot_b = btDot(a->w, b->w);
 | 
						|
                    dist = btSqrt(btMax((a->w.length2() * b->w.length2() - a_dot_b * a_dot_b) / ba_l2, (btScalar)0));
 | 
						|
                }
 | 
						|
                
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        sFace*				newface(typename GJK<btConvexTemplate>::sSV* a,typename GJK<btConvexTemplate>::sSV* b,typename GJK<btConvexTemplate>::sSV* c,bool forced)
 | 
						|
        {
 | 
						|
            if(m_stock.root)
 | 
						|
            {
 | 
						|
                sFace*	face=m_stock.root;
 | 
						|
                remove(m_stock,face);
 | 
						|
                append(m_hull,face);
 | 
						|
                face->pass	=	0;
 | 
						|
                face->c[0]	=	a;
 | 
						|
                face->c[1]	=	b;
 | 
						|
                face->c[2]	=	c;
 | 
						|
                face->n		=	btCross(b->w-a->w,c->w-a->w);
 | 
						|
                const btScalar	l=face->n.length();
 | 
						|
                const bool		v=l>EPA_ACCURACY;
 | 
						|
                
 | 
						|
                if(v)
 | 
						|
                {
 | 
						|
                    if(!(getedgedist(face, a, b, face->d) ||
 | 
						|
                         getedgedist(face, b, c, face->d) ||
 | 
						|
                         getedgedist(face, c, a, face->d)))
 | 
						|
                    {
 | 
						|
                        // Origin projects to the interior of the triangle
 | 
						|
                        // Use distance to triangle plane
 | 
						|
                        face->d = btDot(a->w, face->n) / l;
 | 
						|
                    }
 | 
						|
                    
 | 
						|
                    face->n /= l;
 | 
						|
                    if(forced || (face->d >= -EPA_PLANE_EPS))
 | 
						|
                    {
 | 
						|
                        return face;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                        m_status=eEpaNonConvex;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                    m_status=eEpaDegenerated;
 | 
						|
                
 | 
						|
                remove(m_hull, face);
 | 
						|
                append(m_stock, face);
 | 
						|
                return 0;
 | 
						|
                
 | 
						|
            }
 | 
						|
            m_status = m_stock.root ? eEpaOutOfVertices : eEpaOutOfFaces;
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        sFace*				findbest()
 | 
						|
        {
 | 
						|
            sFace*		minf=m_hull.root;
 | 
						|
            btScalar	mind=minf->d*minf->d;
 | 
						|
            for(sFace* f=minf->l[1];f;f=f->l[1])
 | 
						|
            {
 | 
						|
                const btScalar	sqd=f->d*f->d;
 | 
						|
                if(sqd<mind)
 | 
						|
                {
 | 
						|
                    minf=f;
 | 
						|
                    mind=sqd;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return(minf);
 | 
						|
        }
 | 
						|
        bool				expand(U pass,typename GJK<btConvexTemplate>::sSV* w,sFace* f,U e,sHorizon& horizon)
 | 
						|
        {
 | 
						|
            static const U	i1m3[]={1,2,0};
 | 
						|
            static const U	i2m3[]={2,0,1};
 | 
						|
            if(f->pass!=pass)
 | 
						|
            {
 | 
						|
                const U	e1=i1m3[e];
 | 
						|
                if((btDot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)
 | 
						|
                {
 | 
						|
                    sFace*	nf=newface(f->c[e1],f->c[e],w,false);
 | 
						|
                    if(nf)
 | 
						|
                    {
 | 
						|
                        bind(nf,0,f,e);
 | 
						|
                        if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf;
 | 
						|
                        horizon.cf=nf;
 | 
						|
                        ++horizon.nf;
 | 
						|
                        return(true);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    const U	e2=i2m3[e];
 | 
						|
                    f->pass		=	(U1)pass;
 | 
						|
                    if(	expand(pass,w,f->f[e1],f->e[e1],horizon)&&
 | 
						|
                       expand(pass,w,f->f[e2],f->e[e2],horizon))
 | 
						|
                    {
 | 
						|
                        remove(m_hull,f);
 | 
						|
                        append(m_stock,f);
 | 
						|
                        return(true);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return(false);
 | 
						|
        }
 | 
						|
        
 | 
						|
    };
 | 
						|
    
 | 
						|
    template <typename btConvexTemplate>
 | 
						|
    static void	Initialize(	const btConvexTemplate& a, const btConvexTemplate& b,
 | 
						|
                           btGjkEpaSolver3::sResults& results,
 | 
						|
                           MinkowskiDiff<btConvexTemplate>& shape)
 | 
						|
    {
 | 
						|
        /* Results		*/ 
 | 
						|
        results.witnesses[0]	=
 | 
						|
        results.witnesses[1]	=	btVector3(0,0,0);
 | 
						|
        results.status			=	btGjkEpaSolver3::sResults::Separated;
 | 
						|
        /* Shape		*/ 
 | 
						|
       
 | 
						|
        shape.m_toshape1		=	b.getWorldTransform().getBasis().transposeTimes(a.getWorldTransform().getBasis());
 | 
						|
        shape.m_toshape0		=	a.getWorldTransform().inverseTimes(b.getWorldTransform());
 | 
						|
        
 | 
						|
    }
 | 
						|
    
 | 
						|
 | 
						|
//
 | 
						|
// Api
 | 
						|
//
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//
 | 
						|
template <typename btConvexTemplate>
 | 
						|
bool		btGjkEpaSolver3_Distance(const btConvexTemplate& a, const btConvexTemplate& b,
 | 
						|
                                      const btVector3& guess,
 | 
						|
                                      btGjkEpaSolver3::sResults& results)
 | 
						|
{
 | 
						|
    MinkowskiDiff<btConvexTemplate>			shape(a,b);
 | 
						|
    Initialize(a,b,results,shape);
 | 
						|
    GJK<btConvexTemplate>				gjk(a,b);
 | 
						|
    eGjkStatus	gjk_status=gjk.Evaluate(shape,guess);
 | 
						|
    if(gjk_status==eGjkValid)
 | 
						|
    {
 | 
						|
        btVector3	w0=btVector3(0,0,0);
 | 
						|
        btVector3	w1=btVector3(0,0,0);
 | 
						|
        for(U i=0;i<gjk.m_simplex->rank;++i)
 | 
						|
        {
 | 
						|
            const btScalar	p=gjk.m_simplex->p[i];
 | 
						|
            w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
 | 
						|
            w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
 | 
						|
        }
 | 
						|
        results.witnesses[0]	=	a.getWorldTransform()*w0;
 | 
						|
        results.witnesses[1]	=	a.getWorldTransform()*w1;
 | 
						|
        results.normal			=	w0-w1;
 | 
						|
        results.distance		=	results.normal.length();
 | 
						|
        results.normal			/=	results.distance>GJK_MIN_DISTANCE?results.distance:1;
 | 
						|
        return(true);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        results.status	=	gjk_status==eGjkInside?
 | 
						|
        btGjkEpaSolver3::sResults::Penetrating	:
 | 
						|
        btGjkEpaSolver3::sResults::GJK_Failed	;
 | 
						|
        return(false);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template <typename btConvexTemplate>
 | 
						|
bool	btGjkEpaSolver3_Penetration(const btConvexTemplate& a,
 | 
						|
                                     const btConvexTemplate& b,
 | 
						|
                                     const btVector3& guess,
 | 
						|
                                     btGjkEpaSolver3::sResults& results)
 | 
						|
{
 | 
						|
    MinkowskiDiff<btConvexTemplate>			shape(a,b);
 | 
						|
    Initialize(a,b,results,shape);
 | 
						|
    GJK<btConvexTemplate>				gjk(a,b);
 | 
						|
    eGjkStatus	gjk_status=gjk.Evaluate(shape,-guess);
 | 
						|
    switch(gjk_status)
 | 
						|
    {
 | 
						|
        case	eGjkInside:
 | 
						|
        {
 | 
						|
            EPA<btConvexTemplate>				epa;
 | 
						|
            eEpaStatus	epa_status=epa.Evaluate(gjk,-guess);
 | 
						|
            if(epa_status!=eEpaFailed)
 | 
						|
            {
 | 
						|
                btVector3	w0=btVector3(0,0,0);
 | 
						|
                for(U i=0;i<epa.m_result.rank;++i)
 | 
						|
                {
 | 
						|
                    w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];
 | 
						|
                }
 | 
						|
                results.status			=	btGjkEpaSolver3::sResults::Penetrating;
 | 
						|
                results.witnesses[0]	=	a.getWorldTransform()*w0;
 | 
						|
                results.witnesses[1]	=	a.getWorldTransform()*(w0-epa.m_normal*epa.m_depth);
 | 
						|
                results.normal			=	-epa.m_normal;
 | 
						|
                results.distance		=	-epa.m_depth;
 | 
						|
                return(true);
 | 
						|
            } else results.status=btGjkEpaSolver3::sResults::EPA_Failed;
 | 
						|
        }
 | 
						|
            break;
 | 
						|
        case	eGjkFailed:
 | 
						|
            results.status=btGjkEpaSolver3::sResults::GJK_Failed;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
        {
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return(false);
 | 
						|
}
 | 
						|
 | 
						|
#if 0
 | 
						|
int	btComputeGjkEpaPenetration2(const btCollisionDescription& colDesc, btDistanceInfo* distInfo)
 | 
						|
{
 | 
						|
    btGjkEpaSolver3::sResults results;
 | 
						|
    btVector3 guess = colDesc.m_firstDir;
 | 
						|
    
 | 
						|
    bool res = btGjkEpaSolver3::Penetration(colDesc.m_objA,colDesc.m_objB,
 | 
						|
                                            colDesc.m_transformA,colDesc.m_transformB,
 | 
						|
                                            colDesc.m_localSupportFuncA,colDesc.m_localSupportFuncB,
 | 
						|
                                            guess,
 | 
						|
                                            results);
 | 
						|
    if (res)
 | 
						|
    {
 | 
						|
        if ((results.status==btGjkEpaSolver3::sResults::Penetrating) || results.status==GJK::eStatus::Inside)
 | 
						|
        {
 | 
						|
            //normal could be 'swapped'
 | 
						|
            
 | 
						|
            distInfo->m_distance = results.distance;
 | 
						|
            distInfo->m_normalBtoA = results.normal;
 | 
						|
            btVector3 tmpNormalInB = results.witnesses[1]-results.witnesses[0];
 | 
						|
            btScalar lenSqr = tmpNormalInB.length2();
 | 
						|
            if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
 | 
						|
            {
 | 
						|
                tmpNormalInB = results.normal;
 | 
						|
                lenSqr = results.normal.length2();
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
 | 
						|
            {
 | 
						|
                tmpNormalInB /= btSqrt(lenSqr);
 | 
						|
                btScalar distance2 = -(results.witnesses[0]-results.witnesses[1]).length();
 | 
						|
                //only replace valid penetrations when the result is deeper (check)
 | 
						|
                //if ((distance2 < results.distance))
 | 
						|
                {
 | 
						|
                    distInfo->m_distance = distance2;
 | 
						|
                    distInfo->m_pointOnA= results.witnesses[0];
 | 
						|
                    distInfo->m_pointOnB= results.witnesses[1];
 | 
						|
                    distInfo->m_normalBtoA= tmpNormalInB;
 | 
						|
                    return 0;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
    }
 | 
						|
    
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
template <typename btConvexTemplate, typename btDistanceInfoTemplate>
 | 
						|
int	btComputeGjkDistance(const btConvexTemplate& a, const btConvexTemplate& b,
 | 
						|
                         const btGjkCollisionDescription& colDesc, btDistanceInfoTemplate* distInfo)
 | 
						|
{
 | 
						|
    btGjkEpaSolver3::sResults results;
 | 
						|
    btVector3 guess = colDesc.m_firstDir;
 | 
						|
    
 | 
						|
    bool isSeparated = btGjkEpaSolver3_Distance(	a,b,
 | 
						|
                                                 guess,
 | 
						|
                                                 results);
 | 
						|
    if (isSeparated)
 | 
						|
    {
 | 
						|
        distInfo->m_distance = results.distance;
 | 
						|
        distInfo->m_pointOnA= results.witnesses[0];
 | 
						|
        distInfo->m_pointOnB= results.witnesses[1];
 | 
						|
        distInfo->m_normalBtoA= results.normal;
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
/* Symbols cleanup		*/ 
 | 
						|
 | 
						|
#undef GJK_MAX_ITERATIONS
 | 
						|
#undef GJK_ACCURARY
 | 
						|
#undef GJK_MIN_DISTANCE
 | 
						|
#undef GJK_DUPLICATED_EPS
 | 
						|
#undef GJK_SIMPLEX2_EPS
 | 
						|
#undef GJK_SIMPLEX3_EPS
 | 
						|
#undef GJK_SIMPLEX4_EPS
 | 
						|
 | 
						|
#undef EPA_MAX_VERTICES
 | 
						|
#undef EPA_MAX_FACES
 | 
						|
#undef EPA_MAX_ITERATIONS
 | 
						|
#undef EPA_ACCURACY
 | 
						|
#undef EPA_FALLBACK
 | 
						|
#undef EPA_PLANE_EPS
 | 
						|
#undef EPA_INSIDE_EPS
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#endif //BT_GJK_EPA3_H
 | 
						|
 |