diff options
Diffstat (limited to 'thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp')
| -rw-r--r-- | thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp | 308 | 
1 files changed, 308 insertions, 0 deletions
diff --git a/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp new file mode 100644 index 0000000000..23aaece22b --- /dev/null +++ b/thirdparty/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp @@ -0,0 +1,308 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose,  +including commercial applications, and to alter it and redistribute it freely,  +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btPersistentManifold.h" +#include "LinearMath/btTransform.h" + + +btScalar					gContactBreakingThreshold = btScalar(0.02); +ContactDestroyedCallback	gContactDestroyedCallback = 0; +ContactProcessedCallback	gContactProcessedCallback = 0; +ContactStartedCallback		gContactStartedCallback = 0; +ContactEndedCallback		gContactEndedCallback = 0; +///gContactCalcArea3Points will approximate the convex hull area using 3 points +///when setting it to false, it will use 4 points to compute the area: it is more accurate but slower +bool						gContactCalcArea3Points = true; + + +btPersistentManifold::btPersistentManifold() +:btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE), +m_body0(0), +m_body1(0), +m_cachedPoints (0), +m_index1a(0) +{ +} + + + + +#ifdef DEBUG_PERSISTENCY +#include <stdio.h> +void	btPersistentManifold::DebugPersistency() +{ +	int i; +	printf("DebugPersistency : numPoints %d\n",m_cachedPoints); +	for (i=0;i<m_cachedPoints;i++) +	{ +		printf("m_pointCache[%d].m_userPersistentData = %x\n",i,m_pointCache[i].m_userPersistentData); +	} +} +#endif //DEBUG_PERSISTENCY + +void btPersistentManifold::clearUserCache(btManifoldPoint& pt) +{ + +	void* oldPtr = pt.m_userPersistentData; +	if (oldPtr) +	{ +#ifdef DEBUG_PERSISTENCY +		int i; +		int occurance = 0; +		for (i=0;i<m_cachedPoints;i++) +		{ +			if (m_pointCache[i].m_userPersistentData == oldPtr) +			{ +				occurance++; +				if (occurance>1) +					printf("error in clearUserCache\n"); +			} +		} +		btAssert(occurance<=0); +#endif //DEBUG_PERSISTENCY + +		if (pt.m_userPersistentData && gContactDestroyedCallback) +		{ +			(*gContactDestroyedCallback)(pt.m_userPersistentData); +			pt.m_userPersistentData = 0; +		} +		 +#ifdef DEBUG_PERSISTENCY +		DebugPersistency(); +#endif +	} + +	 +} + +static inline btScalar calcArea4Points(const btVector3 &p0,const btVector3 &p1,const btVector3 &p2,const btVector3 &p3) +{ +	// It calculates possible 3 area constructed from random 4 points and returns the biggest one. + +	btVector3 a[3],b[3]; +	a[0] = p0 - p1; +	a[1] = p0 - p2; +	a[2] = p0 - p3; +	b[0] = p2 - p3; +	b[1] = p1 - p3; +	b[2] = p1 - p2; + +	//todo: Following 3 cross production can be easily optimized by SIMD. +	btVector3 tmp0 = a[0].cross(b[0]); +	btVector3 tmp1 = a[1].cross(b[1]); +	btVector3 tmp2 = a[2].cross(b[2]); + +	return btMax(btMax(tmp0.length2(),tmp1.length2()),tmp2.length2()); +} + +int btPersistentManifold::sortCachedPoints(const btManifoldPoint& pt)  +{ +		//calculate 4 possible cases areas, and take biggest area +		//also need to keep 'deepest' +		 +		int maxPenetrationIndex = -1; +#define KEEP_DEEPEST_POINT 1 +#ifdef KEEP_DEEPEST_POINT +		btScalar maxPenetration = pt.getDistance(); +		for (int i=0;i<4;i++) +		{ +			if (m_pointCache[i].getDistance() < maxPenetration) +			{ +				maxPenetrationIndex = i; +				maxPenetration = m_pointCache[i].getDistance(); +			} +		} +#endif //KEEP_DEEPEST_POINT +		 +		btScalar res0(btScalar(0.)),res1(btScalar(0.)),res2(btScalar(0.)),res3(btScalar(0.)); + +	if (gContactCalcArea3Points) +	{ +		if (maxPenetrationIndex != 0) +		{ +			btVector3 a0 = pt.m_localPointA-m_pointCache[1].m_localPointA; +			btVector3 b0 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; +			btVector3 cross = a0.cross(b0); +			res0 = cross.length2(); +		} +		if (maxPenetrationIndex != 1) +		{ +			btVector3 a1 = pt.m_localPointA-m_pointCache[0].m_localPointA; +			btVector3 b1 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; +			btVector3 cross = a1.cross(b1); +			res1 = cross.length2(); +		} + +		if (maxPenetrationIndex != 2) +		{ +			btVector3 a2 = pt.m_localPointA-m_pointCache[0].m_localPointA; +			btVector3 b2 = m_pointCache[3].m_localPointA-m_pointCache[1].m_localPointA; +			btVector3 cross = a2.cross(b2); +			res2 = cross.length2(); +		} + +		if (maxPenetrationIndex != 3) +		{ +			btVector3 a3 = pt.m_localPointA-m_pointCache[0].m_localPointA; +			btVector3 b3 = m_pointCache[2].m_localPointA-m_pointCache[1].m_localPointA; +			btVector3 cross = a3.cross(b3); +			res3 = cross.length2(); +		} +	}  +	else +	{ +		if(maxPenetrationIndex != 0) { +			res0 = calcArea4Points(pt.m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA); +		} + +		if(maxPenetrationIndex != 1) { +			res1 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA); +		} + +		if(maxPenetrationIndex != 2) { +			res2 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[3].m_localPointA); +		} + +		if(maxPenetrationIndex != 3) { +			res3 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA); +		} +	} +	btVector4 maxvec(res0,res1,res2,res3); +	int biggestarea = maxvec.closestAxis4(); +	return biggestarea; +	 +} + + +int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const +{ +	btScalar shortestDist =  getContactBreakingThreshold() * getContactBreakingThreshold(); +	int size = getNumContacts(); +	int nearestPoint = -1; +	for( int i = 0; i < size; i++ ) +	{ +		const btManifoldPoint &mp = m_pointCache[i]; + +		btVector3 diffA =  mp.m_localPointA- newPoint.m_localPointA; +		const btScalar distToManiPoint = diffA.dot(diffA); +		if( distToManiPoint < shortestDist ) +		{ +			shortestDist = distToManiPoint; +			nearestPoint = i; +		} +	} +	return nearestPoint; +} + +int btPersistentManifold::addManifoldPoint(const btManifoldPoint& newPoint, bool isPredictive) +{ +	if (!isPredictive) +	{ +		btAssert(validContactDistance(newPoint)); +	} +	 +	int insertIndex = getNumContacts(); +	if (insertIndex == MANIFOLD_CACHE_SIZE) +	{ +#if MANIFOLD_CACHE_SIZE >= 4 +		//sort cache so best points come first, based on area +		insertIndex = sortCachedPoints(newPoint); +#else +		insertIndex = 0; +#endif +		clearUserCache(m_pointCache[insertIndex]); +		 +	} else +	{ +		m_cachedPoints++; + +		 +	} +	if (insertIndex<0) +		insertIndex=0; + +	btAssert(m_pointCache[insertIndex].m_userPersistentData==0); +	m_pointCache[insertIndex] = newPoint; +	return insertIndex; +} + +btScalar	btPersistentManifold::getContactBreakingThreshold() const +{ +	return m_contactBreakingThreshold; +} + + + +void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btTransform& trB) +{ +	int i; +#ifdef DEBUG_PERSISTENCY +	printf("refreshContactPoints posA = (%f,%f,%f) posB = (%f,%f,%f)\n", +		trA.getOrigin().getX(), +		trA.getOrigin().getY(), +		trA.getOrigin().getZ(), +		trB.getOrigin().getX(), +		trB.getOrigin().getY(), +		trB.getOrigin().getZ()); +#endif //DEBUG_PERSISTENCY +	/// first refresh worldspace positions and distance +	for (i=getNumContacts()-1;i>=0;i--) +	{ +		btManifoldPoint &manifoldPoint = m_pointCache[i]; +		manifoldPoint.m_positionWorldOnA = trA( manifoldPoint.m_localPointA ); +		manifoldPoint.m_positionWorldOnB = trB( manifoldPoint.m_localPointB ); +		manifoldPoint.m_distance1 = (manifoldPoint.m_positionWorldOnA -  manifoldPoint.m_positionWorldOnB).dot(manifoldPoint.m_normalWorldOnB); +		manifoldPoint.m_lifeTime++; +	} + +	/// then  +	btScalar distance2d; +	btVector3 projectedDifference,projectedPoint; +	for (i=getNumContacts()-1;i>=0;i--) +	{ +		 +		btManifoldPoint &manifoldPoint = m_pointCache[i]; +		//contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction) +		if (!validContactDistance(manifoldPoint)) +		{ +			removeContactPoint(i); +		} else +		{ +            //todo: friction anchor may require the contact to be around a bit longer +			//contact also becomes invalid when relative movement orthogonal to normal exceeds margin +			projectedPoint = manifoldPoint.m_positionWorldOnA - manifoldPoint.m_normalWorldOnB * manifoldPoint.m_distance1; +			projectedDifference = manifoldPoint.m_positionWorldOnB - projectedPoint; +			distance2d = projectedDifference.dot(projectedDifference); +			if (distance2d  > getContactBreakingThreshold()*getContactBreakingThreshold() ) +			{ +				removeContactPoint(i); +			} else +			{ +				//contact point processed callback +				if (gContactProcessedCallback) +					(*gContactProcessedCallback)(manifoldPoint,(void*)m_body0,(void*)m_body1); +			} +		} +	} +#ifdef DEBUG_PERSISTENCY +	DebugPersistency(); +#endif // +} + + + + +  |