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


// $Id: ceAABB.cpp,v 1.10 2005/08/10 20:13:08 kimmi Exp $ 
 
#include "Math/ceMath.h" 
#include  
 
namespace ZFXCE { 
	//------------------------------------------------------------------------------ 
	ceAABB::ceAABB(ceVec3f vMin, ceVec3f vMax) 
	{ 
		SetLimits(vMin, vMax); 
	} 
	//------------------------------------------------------------------------------ 
	ceAABB::ceAABB(ceAABB &AABB) 
	{ 
		ceVec3f vMin, vMax; 
		AABB.GetLimits(vMin, vMax); 
		m_vMin = vMin; 
		m_vMax = vMax; 
	} 
	//------------------------------------------------------------------------------ 
	void ceAABB::SetLimits(ceVec3f &vMin, ceVec3f &vMax) 
	{ 
		m_vMin = vMin; 
		m_vMax = vMax; 
		m_vCenter = (vMax - vMin) * 0.5f; 
	} 
	//------------------------------------------------------------------------------ 
	void ceAABB::GetLimits(ceVec3f &vMin, ceVec3f &vMax) 
	{ 
		vMin = m_vMin; 
		vMax = m_vMax; 
	} 
	//------------------------------------------------------------------------------ 
	void ceAABB::ConstructFromOBB(const ceOBB& OBB) 
	{ 
		ceVec3f vAxis0, vAxis1, vAxis2; 
 
		vAxis0 = OBB.m_vAxis0 * OBB.m_fAxis0; 
		vAxis1 = OBB.m_vAxis1 * OBB.m_fAxis1; 
		vAxis2 = OBB.m_vAxis2 * OBB.m_fAxis2; 
 
		// Computate extrem values 
		if (vAxis0.x > vAxis1.x) { 
			if(vAxis0.x > vAxis2.x) { 
				m_vMax.x = vAxis0.x; 
				m_vMin.x = -vAxis0.x; 
			} 
			else { 
				m_vMax.x = vAxis2.x; 
				m_vMin.x = -vAxis2.x; 
			} 
		} 
		else { 
			if(vAxis1.x > vAxis2.x) { 
				m_vMax.x = vAxis1.x; 
				m_vMin.x = -vAxis1.x; 
			} 
			else { 
				m_vMax.x = vAxis2.x; 
				m_vMin.x = -vAxis2.x; 
			} 
		} 
 
		if (vAxis0.y > vAxis1.y) { 
			if(vAxis0.y > vAxis2.y) { 
				m_vMax.y = vAxis0.y; 
				m_vMin.y = -vAxis0.y; 
			} 
			else { 
				m_vMax.y = vAxis2.y; 
				m_vMin.y = -vAxis2.y; 
			} 
		} 
		else { 
			if(vAxis1.y > vAxis2.y) { 
				m_vMax.y = vAxis1.y; 
				m_vMin.y = -vAxis1.y; 
			} 
			else { 
				m_vMax.y = vAxis2.y; 
				m_vMin.y = -vAxis2.y; 
			} 
		} 
 
		if (vAxis0.z > vAxis1.z) { 
			if (vAxis0.z > vAxis2.z) { 
				m_vMax.z = vAxis0.z; 
				m_vMin.z = -vAxis0.z; 
			} 
			else { 
				m_vMax.z = vAxis2.z; 
				m_vMin.z = -vAxis2.z; 
			} 
		} 
		else { 
			if(vAxis1.z > vAxis2.z) 
			{ 
				m_vMax.z = vAxis1.z; 
				m_vMin.z = -vAxis1.z; 
			} 
			else { 
				m_vMax.z = vAxis2.z; 
				m_vMin.z = -vAxis2.z; 
			} 
		} 
	} 
	//------------------------------------------------------------------------------ 
	INT ceAABB::Cull(const cePlane* pPlanes, UINT uiNumOfPlanes) 
	{ 
		ceVec3f vMin, vMax; 
		bool bIntersects = false; 
 
		// Berechnen und testen der Extrempunkte 
		for (UINT i=0; i < uiNumOfPlanes; i++) { 
			if(pPlanes[i].m_vNormal.x >= 0.0f) { 
				vMin.x = m_vMin.x; 
				vMax.x = m_vMax.x; 
			}	 
			else { 
 				vMin.x = m_vMax.x; 
				vMax.x = m_vMin.x; 
			} 
 
			if (pPlanes[i].m_vNormal.y >= 0.0f) { 
				vMin.y = m_vMin.y; 
				vMax.y = m_vMax.y; 
			} 
			else { 
				vMin.y = m_vMax.y; 
				vMax.y = m_vMin.y; 
			} 
 
			if(pPlanes[i].m_vNormal.z >= 0.0f) { 
				vMin.z = m_vMin.z; 
				vMax.z = m_vMax.z; 
			} 
			else { 
				vMin.z = m_vMax.z; 
				vMax.z = m_vMin.z; 
			} 
 
			if (((pPlanes[i].m_vNormal * vMin) + pPlanes[i].m_fDistance) > 0.0f) 
				return ceCulled; 
 
			if (((pPlanes[i].m_vNormal * vMax) + pPlanes[i].m_fDistance) >= 0.0f) 
				bIntersects = true; 
		} 
 
		if (bIntersects) 
			return ceClipped; 
 
		return ceVisible; 
	} 
	//------------------------------------------------------------------------------ 
	void ceAABB::GetPlanes(cePlane* pPlanes) const 
	{ 
		ceVec3f vNormal; 
		if (!pPlanes) 
			return; 
 
		// Rechts 
		vNormal.Set(1.0f, 0.0f, 0.0f); 
		pPlanes[0].Set(vNormal, m_vMax); 
 
		// links 
		vNormal.x = -1.0f; 
		pPlanes[1].Set(vNormal, m_vMin); 
 
		// vorne 
		vNormal.x = 0.0f; 
		vNormal.z = -1.0f; 
		pPlanes[2].Set(vNormal,m_vMin); 
 
		// hinten 
		vNormal.z = 1.0f; 
		pPlanes[3].Set(vNormal, m_vMax); 
 
		// oben 
		vNormal.y = 1.0f; 
		vNormal.z = 0.0f; 
		pPlanes[4].Set(vNormal, m_vMax); 
 
		// unten 
		vNormal.y = -1.0f; 
		pPlanes[5].Set(vNormal, m_vMin); 
	} 
	//------------------------------------------------------------------------------ 
	void ceAABB::GetVertices(std::vector &Vertices) 
	{ 
		PUSH_FUNCTION; 
 
		 
		//       8    7 
		//       x -- x 
		//   5 / | 6/ | 
		//   x   | x  | 
		//   |   x |- x  
		//   | / 4 | /3 
		//   x --- x 
		//   1     2 
		 
		// Vertice 1 
		m_Edges[0].x = m_vMin.x; 
		//Vertices[0].x = m_vMin.x; 
		m_Edges[0].y = m_vMin.y; 
		//Vertices[0].y = m_vMin.y; 
		m_Edges[0].z = m_vMin.z; 
		//Vertices[0].z = m_vMin.z; 
		Vertices.push_back(m_Edges[0]); 
 
		// Vertice 2 
		m_Edges[1].x = m_vMax.x; 
		//Vertices[1].x = m_vMax.x; 
		m_Edges[1].y = m_vMin.y; 
		//Vertices[1].y = m_vMin.y; 
		m_Edges[1].z = m_vMin.z; 
		//Vertices[1].z = m_vMin.z; 
		Vertices.push_back(m_Edges[1]); 
	 
		// Vertice 3 
		m_Edges[2].x = m_vMax.x; 
		//Vertices[2].x = m_vMax.x; 
		m_Edges[2].y = m_vMax.y; 
		//Vertices[2].y = m_vMax.y; 
		m_Edges[2].z = m_vMin.z; 
		//Vertices[2].z = m_vMin.z; 
		Vertices.push_back(m_Edges[2]); 
 
		// Vertice 4 
		m_Edges[3].x = m_vMin.x; 
		//Vertices[3].x = m_vMin.x; 
		m_Edges[3].y = m_vMax.y; 
		//Vertices[3].y = m_vMax.y; 
		m_Edges[3].z = m_vMin.z; 
		//Vertices[3].z = m_vMin.z; 
		Vertices.push_back(m_Edges[3]); 
 
		// Vertice 5 
		m_Edges[4].x = m_vMin.x; 
		//Vertices[0].x = m_vMin.x; 
		m_Edges[4].y = m_vMin.y; 
		//Vertices[0].y = m_vMin.y; 
		m_Edges[4].z = m_vMax.z; 
		//Vertices[0].z = m_vMax.z; 
		Vertices.push_back(m_Edges[4]); 
 
		// Vertice 6 
		m_Edges[5].x = m_vMax.x; 
		//Vertices[1].x = m_vMax.x; 
		m_Edges[5].y = m_vMin.y; 
		//Vertices[1].y = m_vMin.y; 
		m_Edges[5].z = m_vMax.z; 
		//Vertices[1].z = m_vMax.z; 
		Vertices.push_back(m_Edges[5]); 
	 
		// Vertice 7 
		m_Edges[6].x = m_vMax.x; 
		//Vertices[2].x = m_vMax.x; 
		m_Edges[6].y = m_vMax.y; 
		//Vertices[2].y = m_vMax.y; 
		m_Edges[6].z = m_vMax.z; 
		//Vertices[2].z = m_vMax.z; 
		Vertices.push_back(m_Edges[6]); 
 
		// Vertice 8 
		m_Edges[7].x = m_vMin.x; 
		//Vertices[3].x = m_vMin.x; 
		m_Edges[7].y = m_vMax.y; 
		//Vertices[3].y = m_vMax.y; 
		m_Edges[7].z = m_vMax.z; 
		//Vertices[3].z = m_vMax.z; 
		Vertices.push_back(m_Edges[7]); 
		 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Contains(const ceRay& Ray, FLOAT fL) const 
	{ 
		const ceVec3f vEnd = Ray.m_vOrigin + (Ray.m_vDir * fL); 
		return ( Intersects(Ray.m_vOrigin) && Intersects(vEnd) ); 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Intersects(const ceRay& Ray, FLOAT* pF) const 
	{ 
		FLOAT fT0, fT1, fTmp; 
		FLOAT fNear = -999999.9f; 
		FLOAT fFar = 999999.9f; 
		FLOAT fEpsilon = 0.00001f; 
 
		// Die ersten beiden Ebenen 
		if(_fabs(Ray.m_vDir.x) < fEpsilon) 
			if( Ray.m_vOrigin.x < m_vMin.x || Ray.m_vOrigin.x > m_vMax.x ) 
				return FALSE; 
 
		fT0 = (m_vMin.x - Ray.m_vOrigin.x) / Ray.m_vDir.x; 
		fT1 = (m_vMax.x - Ray.m_vOrigin.x) / Ray.m_vDir.x; 
	 
		if (fT0 > fT1) 
		{ 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
		if(fNear > fFar) 
			return FALSE; 
 
		if(fFar < 0) 
			return FALSE; 
 
		// Die nächsten beiden 
		if(_fabs(Ray.m_vDir.y) < fEpsilon) 
			if( Ray.m_vOrigin.y < m_vMin.y || Ray.m_vOrigin.y > m_vMax.y ) 
				return FALSE; 
 
		fT0 = (m_vMin.y - Ray.m_vOrigin.y) / Ray.m_vDir.y; 
		fT1 = (m_vMax.y - Ray.m_vOrigin.y) / Ray.m_vDir.y; 
	 
		if(fT0 > fT1) 
		{ 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
 
		if(fNear > fFar) 
			return false; 
 
		if(fFar < 0) 
			return false; 
 
		// und die letzten beiden 
		if(_fabs(Ray.m_vDir.z) < fEpsilon) 
			if( Ray.m_vOrigin.z < m_vMin.z || Ray.m_vOrigin.z > m_vMax.z ) 
				return false; 
 
		fT0 = (m_vMin.z - Ray.m_vOrigin.z) / Ray.m_vDir.z; 
		fT1 = (m_vMax.z - Ray.m_vOrigin.z) / Ray.m_vDir.z; 
	 
		if(fT0 > fT1) { 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if (fT0 > fNear) 
			fNear = fT0; 
		if (fT1 < fFar) 
			fFar = fT1; 
		if (fNear > fFar) 
			return false; 
 
		if (fFar < 0) 
			return false; 
 
		if (fNear > 0) { 
			if(pF) 
				(*pF) = fNear; 
 
		} 
		else { 
			if(pF) 
				(*pF) = fFar;  
		} 
 
		return true; 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Intersects(const ceRay& Ray, FLOAT fL, FLOAT* pF) const 
	{ 
		FLOAT fT0, fT1, fTmp; 
		FLOAT fNear = -999999.9f; 
		FLOAT fFar = 999999.9f; 
		FLOAT fEpsilon = 0.00001f; 
 
		// Die ersten beiden Ebenen 
		if(_fabs(Ray.m_vDir.x) < fEpsilon) 
			if( Ray.m_vOrigin.x < m_vMin.x || Ray.m_vOrigin.x > m_vMax.x ) 
				return FALSE; 
 
		const FLOAT fXVal = 1 /  Ray.m_vDir.x; 
		fT0 = (m_vMin.x - Ray.m_vOrigin.x) * fXVal; 
		fT1 = (m_vMax.x - Ray.m_vOrigin.x) * fXVal; 
	 
		if(fT0 > fT1) { 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
 
		if(fNear > fFar) 
			return false; 
 
		if(fFar < 0) 
			return false; 
 
		// Die nächsten beiden 
		if(_fabs(Ray.m_vDir.y) < fEpsilon) 
			if( Ray.m_vOrigin.y < m_vMin.y || Ray.m_vOrigin.y > m_vMax.y ) 
				return false; 
		const FLOAT fYVal = 1 / Ray.m_vDir.y; 
		fT0 = (m_vMin.y - Ray.m_vOrigin.y) * fYVal;  
		fT1 = (m_vMax.y - Ray.m_vOrigin.y) * fYVal; 
	 
		if(fT0 > fT1) { 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
 
		if(fNear > fFar) 
			return false; 
 
		if(fFar < 0) 
			return false; 
 
		// und die letzten beiden 
		if(_fabs(Ray.m_vDir.z) < fEpsilon) 
			if( Ray.m_vOrigin.z < m_vMin.z || Ray.m_vOrigin.z > m_vMax.z ) 
				return false; 
 
		const FLOAT fZVal = 1 / Ray.m_vDir.z; 
		fT0 = (m_vMin.z - Ray.m_vOrigin.z) * fZVal; 
		fT1 = (m_vMax.z - Ray.m_vOrigin.z) * fZVal; 
 
		if (fT0 > fT1) { 
			fTmp = fT0; 
			fT0 = fT1; 
			fT1 = fTmp; 
		} 
 
		if(fT0 > fNear) 
			fNear = fT0; 
		if(fT1 < fFar) 
			fFar = fT1; 
 
		if(fNear > fFar) 
			return false; 
 
		if(fFar < 0) 
			return false; 
 
		FLOAT fFinal = 0.0f; 
		if(fNear > 0) 
			fFinal = fNear; 
		else 
			fFinal = fFar; 
 
		if(fFinal > fL) 
			return false; 
 
		if (NULL != pF) 
			(*pF) = fFinal; 
 
		return true; 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Intersects(const ceAABB& AABB) const 
	{ 
		if( m_vMin.x > AABB.m_vMax.x || AABB.m_vMin.x > m_vMax.x) 
			return false; 
		if( m_vMin.y > AABB.m_vMax.y || AABB.m_vMin.y > m_vMax.y) 
			return false; 
		if( m_vMin.z > AABB.m_vMax.z || AABB.m_vMin.z > m_vMax.z) 
			return false; 
 
		return true; 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Intersects(const ceVec3f& v) const 
	{ 
		if(v.x > m_vMax.x) 
			return false; 
		if(v.y > m_vMax.y) 
			return false; 
		if(v.z > m_vMax.z) 
			return false; 
		if(v.x < m_vMin.x) 
			return false; 
		if(v.y < m_vMin.y) 
			return false; 
		if(v.z < m_vMin.z) 
			return false; 
 
		return true; 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Merge(ceAABB &AABB) 
	{ 
		ceVec3f vMin, vMax; 
		AABB.GetLimits(vMin, vMax); 
		if (m_vMin.x > vMin.x) 
			m_vMin.x = vMin.x; 
		if (m_vMin.y > vMin.y) 
			m_vMin.y = vMin.y; 
		if (m_vMin.z > vMin.z) 
			m_vMin.z = vMin.z; 
 
		if (m_vMax.x < vMax.x) 
			m_vMax.x = vMax.x; 
		if (m_vMax.y < vMax.y) 
			m_vMax.y = vMax.y; 
		if (m_vMax.z < vMax.z) 
			m_vMax.z = vMax.z; 
 
		return true; 
	} 
	//------------------------------------------------------------------------------ 
	bool ceAABB::Merge(ceOBB &OBB) 
	{ 
		return false; 
	} 
	//------------------------------------------------------------------------------ 
	void ceAABB::Transform(ceMatrix &Transform) 
	{ 
		ceVec3f vNew; 
		for (size_t i=0; i<8; ++i) { 
			vNew = Transform * this->m_Edges[i]; 
			if (m_vMin.x > vNew.x) 
				m_vMin.x = vNew.x; 
			if (m_vMin.y > vNew.y) 
				m_vMin.y = vNew.y; 
			if (m_vMin.z > vNew.z) 
				m_vMin.z = vNew.z; 
		 
			if (m_vMax.x < vNew.x) 
				m_vMax.x = vNew.x; 
			if (m_vMax.y < vNew.y) 
				m_vMax.y = vNew.y; 
			if (m_vMax.z < vNew.z) 
				m_vMax.z = vNew.z; 
		} 
	} 
	//------------------------------------------------------------------------------ 
	ceAABB& ceAABB::operator = (const ceAABB& AABB) 
	{ 
		m_vMin = AABB.m_vMin; 
		m_vMax = AABB.m_vMax; 
		m_bUpdate = AABB.m_bUpdate; 
		for (int i=0; i<8; ++i) { 
			this->m_Edges[i] = AABB.m_Edges[i]; 
		} 
		return *this; 
	} 
	//------------------------------------------------------------------------------ 
 
} // Namespace ZFXCE