www.pudn.com > zfxcengine-0.1.0.zip > cePlane.cpp


// $Id: cePlane.cpp,v 1.6 2005/07/10 18:53:23 kimmi Exp $ 
#include "Math/ceMath.h" 
 
namespace ZFXCE { 
	//////////////////////////////////////////////////////////////////////////////// 
	void cePlane::Set(const ceVec3f& vNormal, const ceVec3f& vPoint) 
	{ 
		m_fDistance = - (vNormal * vPoint); 
		m_vNormal = vNormal; 
		m_vPointOnPlane = vPoint; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	void cePlane::Set(const ceVec3f& vNormal, const ceVec3f& vPoint, FLOAT fD) 
	{ 
		m_fDistance = fD; 
		m_vNormal = vNormal; 
		m_vPointOnPlane = vPoint; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	void cePlane::Set(const ceVec3f& v0, const ceVec3f& v1, const ceVec3f& v2) 
	{ 
		const ceVec3f vEdge1 = v1 - v0; 
		const ceVec3f vEdge2 = v2 - v0; 
 
		m_vNormal.Cross(vEdge1, vEdge2); 
		m_vNormal.Normalize(); 
		m_fDistance = - (m_vNormal * v0); 
		m_vPointOnPlane = v0; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	FLOAT cePlane::Distance(const ceVec3f& v) const 
	{ 
		return _fabs( (m_vNormal * v) - m_fDistance); 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	ceHalfSpace cePlane::Classify(const ceVec3f& v) const 
	{ 
		const FLOAT f = (v * m_vNormal) + m_fDistance; 
 
		if (f > 0.00001)  
			return PLANE_POSITIVE; 
		if (f < -0.00001) 
			return PLANE_NEGATIVE; 
 
		return PLANE_ONPLANE; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	ceHalfSpace cePlane::Classify(const cePolygon& p) const 
	{ 
		INT iNumInFront=0, iNumInBack=0, iNumOfPlanar=0; 
		INT iClass = 0; 
		const INT iNumOfPoints = p.GetNumOfPoints(); 
 
		// Do for all edges of polygon 
		for (INT i=0; i < iNumOfPoints; ++i) { 
			iClass = Classify(p.m_pPoints[i]); 
		 
			if(iClass == ceFront) 
				++iNumInFront; 
			else if(iClass == ceBack) 
				++iNumInBack; 
			else 
			{ 
				++iNumInBack; 
				++iNumInFront; 
				++iNumOfPlanar; 
			} 
		} 
 
		// Wenn alle Punkte planar sind... 
		if(iNumOfPlanar == iNumOfPoints) 
			return PLANE_ONPLANE; 
		 
		// Alle Punkte vor der Ebene 
		if(iNumInFront == iNumOfPoints) 
			return PLANE_POSITIVE; 
		 
		// Alle Punkte hinter der Ebene 
		if(iNumInBack == iNumOfPoints) 
			return PLANE_NEGATIVE; 
	 
		// Und wenn das alles nicht zutrifft, dann schneidet das Polygon die Ebene 
		return PLANE_CLIPPED; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	bool cePlane::Clip(const ceRay* pRay, FLOAT fL, ceRay* pA, ceRay* pB) const 
	{ 
		ceVec3f vHit(0.0f, 0.0f, 0.0f); 
		ceRay* pWorkRay = (ceRay*) pRay; 
 
		// Schneidet der Strahl die Ebene überhaupt? 
		if( !pWorkRay->Intersects(*this, false, fL, 0, &vHit) ) 
			return false; 
 
		const INT iClass = Classify(pRay->m_vOrigin); 
 
		// Der Strahlenursprung liegt hinter der Ebene 
		if(iClass == ceBack) { 
			if(pA) 
				pA->Set(vHit, pRay->m_vDir); 
			if(pB) 
				pB->Set(pWorkRay->m_vOrigin, pWorkRay->m_vDir); 
		} 
		else if(iClass == ceFront) { 
			if(pA) 
				pA->Set(pWorkRay->m_vOrigin, pWorkRay->m_vDir); 
			if(pB) 
				pB->Set(vHit, pRay->m_vDir); 
		} 
 
		return true; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	bool cePlane::Intersects(const ceVec3f& v0, const ceVec3f& v1,  
					const ceVec3f& v2) const 
	{ 
		const INT iClass = Classify(v0); 
		return !((iClass == Classify(v1)) && (iClass == Classify(v2))); 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	bool cePlane::Intersects(const cePlane& Plane, ceRay* prIntersection) const 
	{ 
		ceVec3f vCross; 
 
		vCross.Cross(m_vNormal, Plane.m_vNormal); 
		const FLOAT fSqrLength = vCross.GetSqrLength(); 
 
		if (fSqrLength < 1e-08f) 
			return FALSE; 
 
		// Schnittlinie 
		if(prIntersection) 
		{ 
			const FLOAT fN00 = m_vNormal.GetSqrLength(); 
			const FLOAT fN01 = m_vNormal * Plane.m_vNormal; 
			ceVec3f vT = Plane.m_vNormal; 
			const FLOAT fN11 = vT.GetSqrLength(); 
			const FLOAT fDet = fN00*fN11 - fN01*fN01; 
 
			if( _fabs(fDet) < 1e-08f) 
				return false; 
		 
			const FLOAT fInverseDet = 1.0f / fDet; 
			const FLOAT fC0 = (fN11 * m_fDistance - fN01 * Plane.m_fDistance) * fInverseDet; 
			const FLOAT fC1 = (fN00 * Plane.m_fDistance - fN01 * m_fDistance) * fInverseDet; 
 
			(*prIntersection).m_vDir = vCross; 
			vT = m_vNormal * fC0; 
			ceVec3f vT1 = Plane.m_vNormal * fC1; 
			(*prIntersection).m_vOrigin = vT + vT1; 
		} 
 
		return true; 
	} 
	//////////////////////////////////////////////////////////////////////////////// 
	bool cePlane::Intersects(const ceAABB& AABB) const 
	{ 
		ceVec3f vMin, vMax; 
 
		if(m_vNormal.x >= 0.0f) { 
			vMin.x = AABB.m_vMin.x; 
			vMax.x = AABB.m_vMax.x; 
		} 
		else { 
			vMin.x = AABB.m_vMax.x; 
			vMax.x = AABB.m_vMin.x; 
		} 
 
		if(m_vNormal.y >= 0.0f) { 
			vMin.y = AABB.m_vMin.y; 
			vMax.y = AABB.m_vMax.y; 
		} 
		else { 
			vMin.y = AABB.m_vMax.y; 
			vMax.y = AABB.m_vMin.y; 
		} 
 
		if(m_vNormal.z >= 0.0f) { 
			vMin.z = AABB.m_vMin.z; 
			vMax.z = AABB.m_vMax.z; 
		} 
		else { 
			vMin.z = AABB.m_vMax.z; 
			vMax.z = AABB.m_vMin.z; 
		} 
 
		if( ((m_vNormal * vMin) + m_fDistance) > 0.0f) 
			return false; 
 
		if( ((m_vNormal * vMax) + m_fDistance) >= 0.0f) 
			return true; 
 
		return false; 
	}	 
	//////////////////////////////////////////////////////////////////////////////// 
	bool cePlane::Intersects(const ceOBB& OBB) const 
	{ 
		const FLOAT fRadius = _fabs(OBB.m_fAxis0 * (m_vNormal * OBB.m_vAxis0) ) 
						+ _fabs(OBB.m_fAxis1 * (m_vNormal * OBB.m_vAxis1) ) 
						+ _fabs(OBB.m_fAxis2 * (m_vNormal * OBB.m_vAxis2) ); 
		const FLOAT fDistance = Distance(OBB.m_vCenter); 
 
		return (fDistance <= fRadius); 
	} 
} // Namespace ZFXCE