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