frustum.cpp

Go to the documentation of this file.
00001 /* MAINTAINER: Martin */
00002 
00003 #include "frustum.h"
00004 
00005 
00006 Frustum::Frustum(const Frustum & f):mPlanes(6)
00007 {
00008         for (int i = 0; i < 6; ++i)
00009                 mPlanes[i] = f.mPlanes[i];
00010 }
00011 
00012 void Frustum::normalizePlane(TPlaneID planeID)
00013 {
00014         assertL(planeID >= 0 && planeID < (int)mPlanes.size() && "Bad frustum plane ID!");
00015         const GLVector3d &n = mPlanes[planeID].getNormal();
00016         double len = n.length();
00017         if (len) 
00018                 len = 1/len;
00019         mPlanes[planeID].setNormal(n * len);
00020         mPlanes[planeID].setD(mPlanes[planeID].getD() * len);
00021 }
00022 
00023 void Frustum::normalizeAllPlanes(void)
00024 {
00025         normalizePlane(PL_LEFT);
00026         normalizePlane(PL_TOP);
00027         normalizePlane(PL_RIGHT);
00028         normalizePlane(PL_BOTTOM);
00029         normalizePlane(PL_FAR);
00030         normalizePlane(PL_NEAR);
00031 }
00032 
00033 void Frustum::set(const GLMatrix4d &m, bool normalize)
00034 {
00035         // Left clipping plane
00036         mPlanes[PL_LEFT].setNormal(
00037                 GLVector3d(
00038                         m[mi(4, 1)] + m[mi(1, 1)],
00039                         m[mi(4, 2)] + m[mi(1, 2)],
00040                         m[mi(4, 3)] + m[mi(1, 3)]
00041                 ));
00042         mPlanes[PL_LEFT].setD(m[mi(4, 4)] + m[mi(1, 4)]);
00043         
00044         // Right clipping plane
00045         mPlanes[PL_RIGHT].setNormal(
00046                 GLVector3d(
00047                         m[mi(4, 1)] - m[mi(1, 1)],
00048                         m[mi(4, 2)] - m[mi(1, 2)],
00049                         m[mi(4, 3)] - m[mi(1, 3)]
00050                 ));
00051         mPlanes[PL_RIGHT].setD(m[mi(4, 4)] - m[mi(1, 4)]);
00052         
00053         // Top clipping plane
00054         mPlanes[PL_TOP].setNormal(
00055                 GLVector3d(
00056                         m[mi(4, 1)] - m[mi(2, 1)],
00057                         m[mi(4, 2)] - m[mi(2, 2)],
00058                         m[mi(4, 3)] - m[mi(2, 3)]
00059                 ));
00060         mPlanes[PL_TOP].setD(m[mi(4, 4)] - m[mi(2, 4)]);
00061         
00062         // Bottom clipping plane
00063         mPlanes[PL_BOTTOM].setNormal(
00064                 GLVector3d(
00065                         m[mi(4, 1)] + m[mi(2, 1)],
00066                         m[mi(4, 2)] + m[mi(2, 2)],
00067                         m[mi(4, 3)] + m[mi(2, 3)]
00068                 ));
00069         mPlanes[PL_BOTTOM].setD(m[mi(4, 4)] + m[mi(2, 4)]);
00070         
00071         // Near clipping plane
00072         mPlanes[PL_NEAR].setNormal(
00073                 GLVector3d(
00074                         m[mi(4, 1)] + m[mi(3, 1)],
00075                         m[mi(4, 2)] + m[mi(3, 2)],
00076                         m[mi(4, 3)] + m[mi(3, 3)]
00077                 ));
00078         mPlanes[PL_NEAR].setD(m[mi(4, 4)] + m[mi(3, 4)]);
00079         
00080         // Far clipping plane
00081         mPlanes[PL_FAR].setNormal(
00082                 GLVector3d(
00083                         m[mi(4, 1)] - m[mi(3, 1)],
00084                         m[mi(4, 2)] - m[mi(3, 2)],
00085                         m[mi(4, 3)] - m[mi(3, 3)]
00086                 ));
00087         mPlanes[PL_FAR].setD(m[mi(4, 4)] - m[mi(3, 4)]);
00088 
00089         if (normalize)
00090                 normalizeAllPlanes();
00091 }
00092 
00093 void Frustum::transform(const GLMatrix4d &m, bool normalize)
00094 {
00095         GLMatrix4d mt(m);
00096         mt.transpose();
00097 
00098         for (TPlaneContainer::iterator it = mPlanes.begin(), ite = mPlanes.end(); it != ite; ++it){
00099                 const GLVector3d &n = it->getNormal();
00100                 GLVector4d v(n.x, n.y, n.z, it->getD()), q;
00101                 q = mt * v;
00102                 it->setNormal(GLVector3d(q.x, q.y, q.z));
00103                 it->setD(q.w);
00104         }
00105         if (normalize)
00106                 normalizeAllPlanes();
00107 }
00108 
00109 Frustum::Halfspace Frustum::classifyPoint(const TPlane &plane, const GLVector3d &point, const double eps)
00110 {
00111         const double f(plane.getNormal().dot(point) + plane.getD());
00112 
00113         if (f < eps)
00114                 return NEGATIVE;
00115         else if (f > eps)
00116                 return POSITIVE;
00117         
00118         return ON_PLANE;
00119 }
00120 
00121 bool Frustum::testPoint(const GLVector3d &p)
00122 {
00123         Halfspace h[6];
00124         h[0] = classifyPoint(getPlane(PL_LEFT), p);
00125         h[1] = classifyPoint(getPlane(PL_TOP), p);
00126         h[2] = classifyPoint(getPlane(PL_RIGHT), p);
00127         h[3] = classifyPoint(getPlane(PL_BOTTOM), p);
00128         h[4] = classifyPoint(getPlane(PL_FAR), p);
00129         h[5] = classifyPoint(getPlane(PL_NEAR), p);
00130         
00131         bool inside = true;
00132         for (int i = 0; i < 6; ++i)
00133                 inside &= (h[i] >= 0);
00134 
00135         return inside;
00136 }
00137 
00138 Frustum::ClipState Frustum::testSphere(const GLVector3d &center, const double radius) const
00139 {
00140         double dist;
00141         int intersect(0);
00142 
00143         // for each plane ...
00144         for (TPlaneContainer::const_iterator it = mPlanes.begin(), ite = mPlanes.end(); it != ite; ++it) {
00145                 // the distance of center and the plane 
00146                 dist = it->distanceToPoint(center);
00147                 if (dist < -radius)
00148                         return Frustum::OUTSIDE;
00149                 if (fabs(dist) < radius)
00150                         ++intersect;
00151         }
00152         if (!intersect)
00153                 return Frustum::INSIDE;
00154         return Frustum::INTERSECT;
00155 }
00156 
00157 Frustum::ClipState Frustum::testBox(const GLVector3d &center, const GLVector3d &extent) const
00158 {
00159         const double eps = 0.0;
00160         
00161         GLVector3d v[8];
00162         
00163         v[0] = center + GLVector3d(extent.x, extent.y, extent.z);
00164         v[1] = center + GLVector3d(extent.x, extent.y, -extent.z);
00165         v[2] = center + GLVector3d(extent.x, -extent.y, extent.z);
00166         v[3] = center + GLVector3d(extent.x, -extent.y, -extent.z);
00167         v[4] = center + GLVector3d(-extent.x, extent.y, extent.z);
00168         v[5] = center + GLVector3d(-extent.x, extent.y, -extent.z);
00169         v[6] = center + GLVector3d(-extent.x, -extent.y, extent.z);
00170         v[7] = center + GLVector3d(-extent.x, -extent.y, -extent.z);
00171 
00172         // for each plane ...
00173         bool all_inside = true;
00174         for (TPlaneContainer::const_iterator it = mPlanes.begin(), ite = mPlanes.end(); it != ite; ++it) {
00175                 int outside_count = 0;
00176 
00177                 // test all points
00178                 for (int i = 0; i < 8; ++i) {
00179                         Halfspace hs = classifyPoint(*it, v[i], eps);
00180                         if (hs == NEGATIVE) {
00181                                 ++outside_count;
00182                                 all_inside = false;
00183                         }
00184                 }
00185 
00186                 if (outside_count == 8)
00187                         return OUTSIDE;
00188         }
00189 
00190         if (all_inside)
00191                 return Frustum::INSIDE;
00192 
00193         return Frustum::INTERSECT;
00194 }

Generated on Wed Apr 12 13:55:28 2006 for bjs by  doxygen 1.4.5