613 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			613 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | 
 | ||
|  | /*
 | ||
|  | 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. | ||
|  | 	 | ||
|  | 	Elsevier CDROM license agreements grants nonexclusive license to use the software | ||
|  | 	for any purpose, commercial or non-commercial as long as the following credit is included | ||
|  | 	identifying the original source of the software: | ||
|  | 
 | ||
|  | 	Parts of the source are "from the book Real-Time Collision Detection by | ||
|  | 	Christer Ericson, published by Morgan Kaufmann Publishers, | ||
|  | 	(c) 2005 Elsevier Inc." | ||
|  | 		 | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | #include "btVoronoiSimplexSolver.h"
 | ||
|  | 
 | ||
|  | #define VERTA  0
 | ||
|  | #define VERTB  1
 | ||
|  | #define VERTC  2
 | ||
|  | #define VERTD  3
 | ||
|  | 
 | ||
|  | #define CATCH_DEGENERATE_TETRAHEDRON 1
 | ||
|  | void	btVoronoiSimplexSolver::removeVertex(int index) | ||
|  | { | ||
|  | 	 | ||
|  | 	btAssert(m_numVertices>0); | ||
|  | 	m_numVertices--; | ||
|  | 	m_simplexVectorW[index] = m_simplexVectorW[m_numVertices]; | ||
|  | 	m_simplexPointsP[index] = m_simplexPointsP[m_numVertices]; | ||
|  | 	m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices]; | ||
|  | } | ||
|  | 
 | ||
|  | void	btVoronoiSimplexSolver::reduceVertices (const btUsageBitfield& usedVerts) | ||
|  | { | ||
|  | 	if ((numVertices() >= 4) && (!usedVerts.usedVertexD)) | ||
|  | 		removeVertex(3); | ||
|  | 
 | ||
|  | 	if ((numVertices() >= 3) && (!usedVerts.usedVertexC)) | ||
|  | 		removeVertex(2); | ||
|  | 
 | ||
|  | 	if ((numVertices() >= 2) && (!usedVerts.usedVertexB)) | ||
|  | 		removeVertex(1); | ||
|  | 	 | ||
|  | 	if ((numVertices() >= 1) && (!usedVerts.usedVertexA)) | ||
|  | 		removeVertex(0); | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | //clear the simplex, remove all the vertices
 | ||
|  | void btVoronoiSimplexSolver::reset() | ||
|  | { | ||
|  | 	m_cachedValidClosest = false; | ||
|  | 	m_numVertices = 0; | ||
|  | 	m_needsUpdate = true; | ||
|  | 	m_lastW = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  | 	m_cachedBC.reset(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 	//add a vertex
 | ||
|  | void btVoronoiSimplexSolver::addVertex(const btVector3& w, const btVector3& p, const btVector3& q) | ||
|  | { | ||
|  | 	m_lastW = w; | ||
|  | 	m_needsUpdate = true; | ||
|  | 
 | ||
|  | 	m_simplexVectorW[m_numVertices] = w; | ||
|  | 	m_simplexPointsP[m_numVertices] = p; | ||
|  | 	m_simplexPointsQ[m_numVertices] = q; | ||
|  | 
 | ||
|  | 	m_numVertices++; | ||
|  | } | ||
|  | 
 | ||
|  | bool	btVoronoiSimplexSolver::updateClosestVectorAndPoints() | ||
|  | { | ||
|  | 	 | ||
|  | 	if (m_needsUpdate) | ||
|  | 	{ | ||
|  | 		m_cachedBC.reset(); | ||
|  | 
 | ||
|  | 		m_needsUpdate = false; | ||
|  | 
 | ||
|  | 		switch (numVertices()) | ||
|  | 		{ | ||
|  | 		case 0: | ||
|  | 				m_cachedValidClosest = false; | ||
|  | 				break; | ||
|  | 		case 1: | ||
|  | 			{ | ||
|  | 				m_cachedP1 = m_simplexPointsP[0]; | ||
|  | 				m_cachedP2 = m_simplexPointsQ[0]; | ||
|  | 				m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0]
 | ||
|  | 				m_cachedBC.reset(); | ||
|  | 				m_cachedBC.setBarycentricCoordinates(btScalar(1.),btScalar(0.),btScalar(0.),btScalar(0.)); | ||
|  | 				m_cachedValidClosest = m_cachedBC.isValid(); | ||
|  | 				break; | ||
|  | 			}; | ||
|  | 		case 2: | ||
|  | 			{ | ||
|  | 			//closest point origin from line segment
 | ||
|  | 					const btVector3& from = m_simplexVectorW[0]; | ||
|  | 					const btVector3& to = m_simplexVectorW[1]; | ||
|  | 					btVector3 nearest; | ||
|  | 
 | ||
|  | 					btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); | ||
|  | 					btVector3 diff = p - from; | ||
|  | 					btVector3 v = to - from; | ||
|  | 					btScalar t = v.dot(diff); | ||
|  | 					 | ||
|  | 					if (t > 0) { | ||
|  | 						btScalar dotVV = v.dot(v); | ||
|  | 						if (t < dotVV) { | ||
|  | 							t /= dotVV; | ||
|  | 							diff -= t*v; | ||
|  | 							m_cachedBC.m_usedVertices.usedVertexA = true; | ||
|  | 							m_cachedBC.m_usedVertices.usedVertexB = true; | ||
|  | 						} else { | ||
|  | 							t = 1; | ||
|  | 							diff -= v; | ||
|  | 							//reduce to 1 point
 | ||
|  | 							m_cachedBC.m_usedVertices.usedVertexB = true; | ||
|  | 						} | ||
|  | 					} else | ||
|  | 					{ | ||
|  | 						t = 0; | ||
|  | 						//reduce to 1 point
 | ||
|  | 						m_cachedBC.m_usedVertices.usedVertexA = true; | ||
|  | 					} | ||
|  | 					m_cachedBC.setBarycentricCoordinates(1-t,t); | ||
|  | 					nearest = from + t*v; | ||
|  | 
 | ||
|  | 					m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]); | ||
|  | 					m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]); | ||
|  | 					m_cachedV = m_cachedP1 - m_cachedP2; | ||
|  | 					 | ||
|  | 					reduceVertices(m_cachedBC.m_usedVertices); | ||
|  | 
 | ||
|  | 					m_cachedValidClosest = m_cachedBC.isValid(); | ||
|  | 					break; | ||
|  | 			} | ||
|  | 		case 3:  | ||
|  | 			{  | ||
|  | 				//closest point origin from triangle 
 | ||
|  | 				btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.));  | ||
|  | 
 | ||
|  | 				const btVector3& a = m_simplexVectorW[0];  | ||
|  | 				const btVector3& b = m_simplexVectorW[1];  | ||
|  | 				const btVector3& c = m_simplexVectorW[2];  | ||
|  | 
 | ||
|  | 				closestPtPointTriangle(p,a,b,c,m_cachedBC);  | ||
|  | 				m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +  | ||
|  | 				m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +  | ||
|  | 				m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2];  | ||
|  | 
 | ||
|  | 				m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +  | ||
|  | 				m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +  | ||
|  | 				m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2];  | ||
|  | 
 | ||
|  | 				m_cachedV = m_cachedP1-m_cachedP2;  | ||
|  | 
 | ||
|  | 				reduceVertices (m_cachedBC.m_usedVertices);  | ||
|  | 				m_cachedValidClosest = m_cachedBC.isValid();  | ||
|  | 
 | ||
|  | 				break;  | ||
|  | 			} | ||
|  | 		case 4: | ||
|  | 			{ | ||
|  | 
 | ||
|  | 				 | ||
|  | 				btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); | ||
|  | 				 | ||
|  | 				const btVector3& a = m_simplexVectorW[0]; | ||
|  | 				const btVector3& b = m_simplexVectorW[1]; | ||
|  | 				const btVector3& c = m_simplexVectorW[2]; | ||
|  | 				const btVector3& d = m_simplexVectorW[3]; | ||
|  | 
 | ||
|  | 				bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC); | ||
|  | 
 | ||
|  | 				if (hasSeperation) | ||
|  | 				{ | ||
|  | 
 | ||
|  | 					m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + | ||
|  | 						m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + | ||
|  | 						m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] + | ||
|  | 						m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3]; | ||
|  | 
 | ||
|  | 					m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + | ||
|  | 						m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + | ||
|  | 						m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] + | ||
|  | 						m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3]; | ||
|  | 
 | ||
|  | 					m_cachedV = m_cachedP1-m_cachedP2; | ||
|  | 					reduceVertices (m_cachedBC.m_usedVertices); | ||
|  | 				} else | ||
|  | 				{ | ||
|  | //					printf("sub distance got penetration\n");
 | ||
|  | 
 | ||
|  | 					if (m_cachedBC.m_degenerate) | ||
|  | 					{ | ||
|  | 						m_cachedValidClosest = false; | ||
|  | 					} else | ||
|  | 					{ | ||
|  | 						m_cachedValidClosest = true; | ||
|  | 						//degenerate case == false, penetration = true + zero
 | ||
|  | 						m_cachedV.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); | ||
|  | 					} | ||
|  | 					break; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				m_cachedValidClosest = m_cachedBC.isValid(); | ||
|  | 
 | ||
|  | 				//closest point origin from tetrahedron
 | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			{ | ||
|  | 				m_cachedValidClosest = false; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return m_cachedValidClosest; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | //return/calculate the closest vertex
 | ||
|  | bool btVoronoiSimplexSolver::closest(btVector3& v) | ||
|  | { | ||
|  | 	bool succes = updateClosestVectorAndPoints(); | ||
|  | 	v = m_cachedV; | ||
|  | 	return succes; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btScalar btVoronoiSimplexSolver::maxVertex() | ||
|  | { | ||
|  | 	int i, numverts = numVertices(); | ||
|  | 	btScalar maxV = btScalar(0.); | ||
|  | 	for (i=0;i<numverts;i++) | ||
|  | 	{ | ||
|  | 		btScalar curLen2 = m_simplexVectorW[i].length2(); | ||
|  | 		if (maxV < curLen2) | ||
|  | 			maxV = curLen2; | ||
|  | 	} | ||
|  | 	return maxV; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 	//return the current simplex
 | ||
|  | int btVoronoiSimplexSolver::getSimplex(btVector3 *pBuf, btVector3 *qBuf, btVector3 *yBuf) const | ||
|  | { | ||
|  | 	int i; | ||
|  | 	for (i=0;i<numVertices();i++) | ||
|  | 	{ | ||
|  | 		yBuf[i] = m_simplexVectorW[i]; | ||
|  | 		pBuf[i] = m_simplexPointsP[i]; | ||
|  | 		qBuf[i] = m_simplexPointsQ[i]; | ||
|  | 	} | ||
|  | 	return numVertices(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | bool btVoronoiSimplexSolver::inSimplex(const btVector3& w) | ||
|  | { | ||
|  | 	bool found = false; | ||
|  | 	int i, numverts = numVertices(); | ||
|  | 	//btScalar maxV = btScalar(0.);
 | ||
|  | 	 | ||
|  | 	//w is in the current (reduced) simplex
 | ||
|  | 	for (i=0;i<numverts;i++) | ||
|  | 	{ | ||
|  | #ifdef BT_USE_EQUAL_VERTEX_THRESHOLD
 | ||
|  | 		if ( m_simplexVectorW[i].distance2(w) <= m_equalVertexThreshold) | ||
|  | #else
 | ||
|  | 		if (m_simplexVectorW[i] == w) | ||
|  | #endif
 | ||
|  | 		{ | ||
|  | 			found = true; | ||
|  | 			break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	//check in case lastW is already removed
 | ||
|  | 	if (w == m_lastW) | ||
|  | 		return true; | ||
|  |     	 | ||
|  | 	return found; | ||
|  | } | ||
|  | 
 | ||
|  | void btVoronoiSimplexSolver::backup_closest(btVector3& v)  | ||
|  | { | ||
|  | 	v = m_cachedV; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | bool btVoronoiSimplexSolver::emptySimplex() const  | ||
|  | { | ||
|  | 	return (numVertices() == 0); | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | void btVoronoiSimplexSolver::compute_points(btVector3& p1, btVector3& p2)  | ||
|  | { | ||
|  | 	updateClosestVectorAndPoints(); | ||
|  | 	p1 = m_cachedP1; | ||
|  | 	p2 = m_cachedP2; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | bool	btVoronoiSimplexSolver::closestPtPointTriangle(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c,btSubSimplexClosestResult& result) | ||
|  | { | ||
|  | 	result.m_usedVertices.reset(); | ||
|  | 
 | ||
|  |     // Check if P in vertex region outside A
 | ||
|  |     btVector3 ab = b - a; | ||
|  |     btVector3 ac = c - a; | ||
|  |     btVector3 ap = p - a; | ||
|  |     btScalar d1 = ab.dot(ap); | ||
|  |     btScalar d2 = ac.dot(ap); | ||
|  |     if (d1 <= btScalar(0.0) && d2 <= btScalar(0.0))  | ||
|  | 	{ | ||
|  | 		result.m_closestPointOnSimplex = a; | ||
|  | 		result.m_usedVertices.usedVertexA = true; | ||
|  | 		result.setBarycentricCoordinates(1,0,0); | ||
|  | 		return true;// a; // barycentric coordinates (1,0,0)
 | ||
|  | 	} | ||
|  | 
 | ||
|  |     // Check if P in vertex region outside B
 | ||
|  |     btVector3 bp = p - b; | ||
|  |     btScalar d3 = ab.dot(bp); | ||
|  |     btScalar d4 = ac.dot(bp); | ||
|  |     if (d3 >= btScalar(0.0) && d4 <= d3)  | ||
|  | 	{ | ||
|  | 		result.m_closestPointOnSimplex = b; | ||
|  | 		result.m_usedVertices.usedVertexB = true; | ||
|  | 		result.setBarycentricCoordinates(0,1,0); | ||
|  | 
 | ||
|  | 		return true; // b; // barycentric coordinates (0,1,0)
 | ||
|  | 	} | ||
|  |     // Check if P in edge region of AB, if so return projection of P onto AB
 | ||
|  |     btScalar vc = d1*d4 - d3*d2; | ||
|  |     if (vc <= btScalar(0.0) && d1 >= btScalar(0.0) && d3 <= btScalar(0.0)) { | ||
|  |         btScalar v = d1 / (d1 - d3); | ||
|  | 		result.m_closestPointOnSimplex = a + v * ab; | ||
|  | 		result.m_usedVertices.usedVertexA = true; | ||
|  | 		result.m_usedVertices.usedVertexB = true; | ||
|  | 		result.setBarycentricCoordinates(1-v,v,0); | ||
|  | 		return true; | ||
|  |         //return a + v * ab; // barycentric coordinates (1-v,v,0)
 | ||
|  |     } | ||
|  | 
 | ||
|  |     // Check if P in vertex region outside C
 | ||
|  |     btVector3 cp = p - c; | ||
|  |     btScalar d5 = ab.dot(cp); | ||
|  |     btScalar d6 = ac.dot(cp); | ||
|  |     if (d6 >= btScalar(0.0) && d5 <= d6)  | ||
|  | 	{ | ||
|  | 		result.m_closestPointOnSimplex = c; | ||
|  | 		result.m_usedVertices.usedVertexC = true; | ||
|  | 		result.setBarycentricCoordinates(0,0,1); | ||
|  | 		return true;//c; // barycentric coordinates (0,0,1)
 | ||
|  | 	} | ||
|  | 
 | ||
|  |     // Check if P in edge region of AC, if so return projection of P onto AC
 | ||
|  |     btScalar vb = d5*d2 - d1*d6; | ||
|  |     if (vb <= btScalar(0.0) && d2 >= btScalar(0.0) && d6 <= btScalar(0.0)) { | ||
|  |         btScalar w = d2 / (d2 - d6); | ||
|  | 		result.m_closestPointOnSimplex = a + w * ac; | ||
|  | 		result.m_usedVertices.usedVertexA = true; | ||
|  | 		result.m_usedVertices.usedVertexC = true; | ||
|  | 		result.setBarycentricCoordinates(1-w,0,w); | ||
|  | 		return true; | ||
|  |         //return a + w * ac; // barycentric coordinates (1-w,0,w)
 | ||
|  |     } | ||
|  | 
 | ||
|  |     // Check if P in edge region of BC, if so return projection of P onto BC
 | ||
|  |     btScalar va = d3*d6 - d5*d4; | ||
|  |     if (va <= btScalar(0.0) && (d4 - d3) >= btScalar(0.0) && (d5 - d6) >= btScalar(0.0)) { | ||
|  |         btScalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); | ||
|  | 		 | ||
|  | 		result.m_closestPointOnSimplex = b + w * (c - b); | ||
|  | 		result.m_usedVertices.usedVertexB = true; | ||
|  | 		result.m_usedVertices.usedVertexC = true; | ||
|  | 		result.setBarycentricCoordinates(0,1-w,w); | ||
|  | 		return true;		 | ||
|  |        // return b + w * (c - b); // barycentric coordinates (0,1-w,w)
 | ||
|  |     } | ||
|  | 
 | ||
|  |     // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
 | ||
|  |     btScalar denom = btScalar(1.0) / (va + vb + vc); | ||
|  |     btScalar v = vb * denom; | ||
|  |     btScalar w = vc * denom; | ||
|  |      | ||
|  | 	result.m_closestPointOnSimplex = a + ab * v + ac * w; | ||
|  | 	result.m_usedVertices.usedVertexA = true; | ||
|  | 	result.m_usedVertices.usedVertexB = true; | ||
|  | 	result.m_usedVertices.usedVertexC = true; | ||
|  | 	result.setBarycentricCoordinates(1-v-w,v,w); | ||
|  | 	 | ||
|  | 	return true; | ||
|  | //	return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w
 | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /// Test if point p and d lie on opposite sides of plane through abc
 | ||
|  | int btVoronoiSimplexSolver::pointOutsideOfPlane(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d) | ||
|  | { | ||
|  | 	btVector3 normal = (b-a).cross(c-a); | ||
|  | 
 | ||
|  |     btScalar signp = (p - a).dot(normal); // [AP AB AC]
 | ||
|  |     btScalar signd = (d - a).dot( normal); // [AD AB AC]
 | ||
|  | 
 | ||
|  | #ifdef CATCH_DEGENERATE_TETRAHEDRON
 | ||
|  | #ifdef BT_USE_DOUBLE_PRECISION
 | ||
|  | if (signd * signd < (btScalar(1e-8) * btScalar(1e-8))) | ||
|  | 	{ | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | #else
 | ||
|  | 	if (signd * signd < (btScalar(1e-4) * btScalar(1e-4))) | ||
|  | 	{ | ||
|  | //		printf("affine dependent/degenerate\n");//
 | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 	// Points on opposite sides if expression signs are opposite
 | ||
|  |     return signp * signd < btScalar(0.); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | bool	btVoronoiSimplexSolver::closestPtPointTetrahedron(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, btSubSimplexClosestResult& finalResult) | ||
|  | { | ||
|  | 	btSubSimplexClosestResult tempResult; | ||
|  | 
 | ||
|  |     // Start out assuming point inside all halfspaces, so closest to itself
 | ||
|  | 	finalResult.m_closestPointOnSimplex = p; | ||
|  | 	finalResult.m_usedVertices.reset(); | ||
|  |     finalResult.m_usedVertices.usedVertexA = true; | ||
|  | 	finalResult.m_usedVertices.usedVertexB = true; | ||
|  | 	finalResult.m_usedVertices.usedVertexC = true; | ||
|  | 	finalResult.m_usedVertices.usedVertexD = true; | ||
|  | 
 | ||
|  |     int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d); | ||
|  | 	int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b); | ||
|  |   	int	pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c); | ||
|  | 	int	pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a); | ||
|  | 
 | ||
|  |    if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0) | ||
|  |    { | ||
|  | 	   finalResult.m_degenerate = true; | ||
|  | 	   return false; | ||
|  |    } | ||
|  | 
 | ||
|  |    if (!pointOutsideABC  && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC) | ||
|  | 	 { | ||
|  | 		 return false; | ||
|  | 	 } | ||
|  | 
 | ||
|  | 
 | ||
|  |     btScalar bestSqDist = FLT_MAX; | ||
|  |     // If point outside face abc then compute closest point on abc
 | ||
|  | 	if (pointOutsideABC)  | ||
|  | 	{ | ||
|  |         closestPtPointTriangle(p, a, b, c,tempResult); | ||
|  | 		btVector3 q = tempResult.m_closestPointOnSimplex; | ||
|  | 		 | ||
|  |         btScalar sqDist = (q - p).dot( q - p); | ||
|  |         // Update best closest point if (squared) distance is less than current best
 | ||
|  |         if (sqDist < bestSqDist) { | ||
|  | 			bestSqDist = sqDist; | ||
|  | 			finalResult.m_closestPointOnSimplex = q; | ||
|  | 			//convert result bitmask!
 | ||
|  | 			finalResult.m_usedVertices.reset(); | ||
|  | 			finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; | ||
|  | 			finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB; | ||
|  | 			finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; | ||
|  | 			finalResult.setBarycentricCoordinates( | ||
|  | 					tempResult.m_barycentricCoords[VERTA], | ||
|  | 					tempResult.m_barycentricCoords[VERTB], | ||
|  | 					tempResult.m_barycentricCoords[VERTC], | ||
|  | 					0 | ||
|  | 			); | ||
|  | 
 | ||
|  | 		} | ||
|  |     } | ||
|  |    | ||
|  | 
 | ||
|  | 	// Repeat test for face acd
 | ||
|  | 	if (pointOutsideACD)  | ||
|  | 	{ | ||
|  |         closestPtPointTriangle(p, a, c, d,tempResult); | ||
|  | 		btVector3 q = tempResult.m_closestPointOnSimplex; | ||
|  | 		//convert result bitmask!
 | ||
|  | 
 | ||
|  |         btScalar sqDist = (q - p).dot( q - p); | ||
|  |         if (sqDist < bestSqDist)  | ||
|  | 		{ | ||
|  | 			bestSqDist = sqDist; | ||
|  | 			finalResult.m_closestPointOnSimplex = q; | ||
|  | 			finalResult.m_usedVertices.reset(); | ||
|  | 			finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; | ||
|  | 
 | ||
|  | 			finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB; | ||
|  | 			finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC; | ||
|  | 			finalResult.setBarycentricCoordinates( | ||
|  | 					tempResult.m_barycentricCoords[VERTA], | ||
|  | 					0, | ||
|  | 					tempResult.m_barycentricCoords[VERTB], | ||
|  | 					tempResult.m_barycentricCoords[VERTC] | ||
|  | 			); | ||
|  | 
 | ||
|  | 		} | ||
|  |     } | ||
|  |     // Repeat test for face adb
 | ||
|  | 
 | ||
|  | 	 | ||
|  | 	if (pointOutsideADB) | ||
|  | 	{ | ||
|  | 		closestPtPointTriangle(p, a, d, b,tempResult); | ||
|  | 		btVector3 q = tempResult.m_closestPointOnSimplex; | ||
|  | 		//convert result bitmask!
 | ||
|  | 
 | ||
|  |         btScalar sqDist = (q - p).dot( q - p); | ||
|  |         if (sqDist < bestSqDist)  | ||
|  | 		{ | ||
|  | 			bestSqDist = sqDist; | ||
|  | 			finalResult.m_closestPointOnSimplex = q; | ||
|  | 			finalResult.m_usedVertices.reset(); | ||
|  | 			finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; | ||
|  | 			finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC; | ||
|  | 			 | ||
|  | 			finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; | ||
|  | 			finalResult.setBarycentricCoordinates( | ||
|  | 					tempResult.m_barycentricCoords[VERTA], | ||
|  | 					tempResult.m_barycentricCoords[VERTC], | ||
|  | 					0, | ||
|  | 					tempResult.m_barycentricCoords[VERTB] | ||
|  | 			); | ||
|  | 
 | ||
|  | 		} | ||
|  |     } | ||
|  |     // Repeat test for face bdc
 | ||
|  |      | ||
|  | 
 | ||
|  | 	if (pointOutsideBDC) | ||
|  | 	{ | ||
|  |         closestPtPointTriangle(p, b, d, c,tempResult); | ||
|  | 		btVector3 q = tempResult.m_closestPointOnSimplex; | ||
|  | 		//convert result bitmask!
 | ||
|  |         btScalar sqDist = (q - p).dot( q - p); | ||
|  |         if (sqDist < bestSqDist)  | ||
|  | 		{ | ||
|  | 			bestSqDist = sqDist; | ||
|  | 			finalResult.m_closestPointOnSimplex = q; | ||
|  | 			finalResult.m_usedVertices.reset(); | ||
|  | 			//
 | ||
|  | 			finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA; | ||
|  | 			finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; | ||
|  | 			finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; | ||
|  | 
 | ||
|  | 			finalResult.setBarycentricCoordinates( | ||
|  | 					0, | ||
|  | 					tempResult.m_barycentricCoords[VERTA], | ||
|  | 					tempResult.m_barycentricCoords[VERTC], | ||
|  | 					tempResult.m_barycentricCoords[VERTB] | ||
|  | 			); | ||
|  | 
 | ||
|  | 		} | ||
|  |     } | ||
|  | 
 | ||
|  | 	//help! we ended up full !
 | ||
|  | 	 | ||
|  | 	if (finalResult.m_usedVertices.usedVertexA && | ||
|  | 		finalResult.m_usedVertices.usedVertexB && | ||
|  | 		finalResult.m_usedVertices.usedVertexC && | ||
|  | 		finalResult.m_usedVertices.usedVertexD)  | ||
|  | 	{ | ||
|  | 		return true; | ||
|  | 	} | ||
|  | 
 | ||
|  |     return true; | ||
|  | } | ||
|  | 
 |