OSGFrustumVolume.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *                 Copyright (C) 2003 by the OpenSG Forum                    *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028  *                                                                           *
00029 \*---------------------------------------------------------------------------*/
00030 /*---------------------------------------------------------------------------*\
00031  *                                Changes                                    *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037  *                                                                           *
00038 \*---------------------------------------------------------------------------*/
00039
00040 //---------------------------------------------------------------------------
00041 //  Includes
00042 //---------------------------------------------------------------------------
00043
00044 #include "OSGConfig.h"
00045
00046 #include <iostream>
00047
00048 #include <cassert>
00049
00050 #include "OSGFrustumVolume.h"
00051 #include "OSGLog.h"
00052 #include "OSGMatrix.h"
00053 #include "OSGLine.h"
00054
00055
00062 OSG_BEGIN_NAMESPACE
00063
00064 /*-------------------------------- get ------------------------------------*/
00065
00066 void FrustumVolume::getCenter(Pnt3r &center) const
00067 {
00068     Pnt3r vertices[8];
00069     Line  lines   [4];
00070
00071     _planeVec[5].intersect(_planeVec[3],lines[3]);
00072     _planeVec[3].intersect(_planeVec[4],lines[2]);
00073     _planeVec[4].intersect(_planeVec[2],lines[0]);
00074     _planeVec[2].intersect(_planeVec[5],lines[1]);
00075
00076     for(Int32 i = 0; i < 4; i++)
00077     {
00078         _planeVec[0].intersectInfinite(lines[i],vertices[    i]);
00079         _planeVec[1].intersectInfinite(lines[i],vertices[4 + i]);
00080     }
00081
00082     center = Pnt3r(0.f, 0.f ,0.f);
00083
00084     for(Int32 i = 0; i < 8; i++)
00085     {
00086         center = center + vertices[i].subZero();
00087     }
00088
00089     center /= 8.f;
00090 }
00091
00092
00093 Real FrustumVolume::getScalarVolume() const
00094 {
00095     const Int32 faces[6][4] =
00096     {
00097         {0,1,3,2},
00098         {4,5,7,6},
00099         {0,4,5,1},
00100         {2,6,7,3},
00101         {2,6,4,0},
00102         {1,5,7,3}
00103     };
00104
00105     Pnt3r vertices[8];
00106     Line  lines   [4];
00107
00108     _planeVec[5].intersect(_planeVec[3], lines[3]);
00109     _planeVec[3].intersect(_planeVec[4], lines[2]);
00110     _planeVec[4].intersect(_planeVec[2], lines[0]);
00111     _planeVec[2].intersect(_planeVec[5], lines[1]);
00112
00113     for(Int32 i = 0; i < 4; i++)
00114     {
00115         _planeVec[0].intersectInfinite(lines[i], vertices[    i]);
00116         _planeVec[1].intersectInfinite(lines[i], vertices[4 + i]);
00117     }
00118
00119
00120     Pnt3r center = Pnt3r(0.f, 0.f, 0.f);
00121
00122     for(Int32 i = 0; i < 8; i++)
00123     {
00124         center = center + vertices[i].subZero();
00125     }
00126
00127     center /= 8.f;
00128
00129     Real volume = .0f;
00130
00131     for(Int32 i = 0; i < 6; i++)
00132     {
00133         Real height;
00134         Real area;
00135
00136         height =
00137             _planeVec[i].getNormal().dot(center) -
00138             _planeVec[i].getDistanceFromOrigin();
00139
00140         Vec3r main_diag = vertices[faces[i][0]] - vertices[faces[i][2]];
00141         Vec3r sec_diag  = vertices[faces[i][1]] - vertices[faces[i][3]];
00142
00143         area = osgAbs((main_diag.cross(sec_diag)).length() / 2.f);
00144
00145         volume += osgAbs((height*area)) / 3.f;
00146     }
00147
00148     return volume;
00149 }
00150
00151
00155 void FrustumVolume::getBounds(Pnt3r &minPnt,
00156                               Pnt3r &maxPnt ) const
00157 {
00158     Pnt3r corners[8];
00159
00160     this->getCorners(corners[0], corners[1], corners[2], corners[3],
00161                      corners[4], corners[5], corners[6], corners[7] );
00162
00163     minPnt[0] = TypeTraits<Pnt3r::ValueType>::getMax();
00164     minPnt[1] = TypeTraits<Pnt3r::ValueType>::getMax();
00165     minPnt[2] = TypeTraits<Pnt3r::ValueType>::getMax();
00166
00167     maxPnt[0] = TypeTraits<Pnt3r::ValueType>::getMin();
00168     maxPnt[1] = TypeTraits<Pnt3r::ValueType>::getMin();
00169     maxPnt[2] = TypeTraits<Pnt3r::ValueType>::getMin();
00170
00171     for(UInt32 i = 0; i < 8; ++i)
00172     {
00173         minPnt[0] = osgMin(minPnt[0], corners[i][0]);
00174         minPnt[1] = osgMin(minPnt[1], corners[i][1]);
00175         minPnt[2] = osgMin(minPnt[2], corners[i][2]);
00176
00177         maxPnt[0] = osgMax(maxPnt[0], corners[i][0]);
00178         maxPnt[1] = osgMax(maxPnt[1], corners[i][1]);
00179         maxPnt[2] = osgMax(maxPnt[2], corners[i][2]);
00180     }
00181 }
00182
00185 void FrustumVolume::getCorners(Pnt3r &nlt, Pnt3r &nlb,
00186                                Pnt3r &nrt, Pnt3r &nrb,
00187                                Pnt3r &flt, Pnt3r &flb,
00188                                Pnt3r &frt, Pnt3r &frb ) const
00189 {
00190     Line edges[4];
00191
00192     _planeVec[PLANE_BOTTOM].intersect(_planeVec[PLANE_RIGHT ], edges[3]);
00193     _planeVec[PLANE_RIGHT ].intersect(_planeVec[PLANE_TOP   ], edges[2]);
00194     _planeVec[PLANE_TOP   ].intersect(_planeVec[PLANE_LEFT  ], edges[0]);
00195     _planeVec[PLANE_LEFT  ].intersect(_planeVec[PLANE_BOTTOM], edges[1]);
00196
00197     _planeVec[PLANE_NEAR].intersectInfinite(edges[0], nlt);
00198     _planeVec[PLANE_FAR ].intersectInfinite(edges[0], flt);
00199     _planeVec[PLANE_NEAR].intersectInfinite(edges[1], nlb);
00200     _planeVec[PLANE_FAR ].intersectInfinite(edges[1], flb);
00201     _planeVec[PLANE_NEAR].intersectInfinite(edges[2], nrt);
00202     _planeVec[PLANE_FAR ].intersectInfinite(edges[2], frt);
00203     _planeVec[PLANE_NEAR].intersectInfinite(edges[3], nrb);
00204     _planeVec[PLANE_FAR ].intersectInfinite(edges[3], frb);
00205 }
00206
00207 /*------------------------------ feature ----------------------------------*/
00208
00209 void FrustumVolume::setPlanes(const Plane &pnear, const Plane &pfar,
00210                               const Plane &left,  const Plane &right,
00211                               const Plane &top,   const Plane &bottom)
00212 {
00213     _planeVec[0] = pnear;
00214     _planeVec[1] = pfar;
00215     _planeVec[2] = left;
00216     _planeVec[3] = right;
00217     _planeVec[4] = top;
00218     _planeVec[5] = bottom;
00219 }
00220
00221
00222 void FrustumVolume::setPlanes(const Pnt3r &nlt, const Pnt3r &nlb,
00223                               const Pnt3r &nrt, const Pnt3r &nrb,
00224                               const Pnt3r &flt, const Pnt3r &flb,
00225                               const Pnt3r &frt, const Pnt3r &frb)
00226 {
00227
00228     Plane pnear  (nlb,nlt,nrb);
00229     Plane pfar   (frb,frt,flb);
00230     Plane pleft  (flb,flt,nlb);
00231     Plane pright (nrb,nrt,frb);
00232     Plane ptop   (frt,nrt,flt);
00233     Plane pbottom(nlb,nrb,flb);
00234
00235
00236     _planeVec[0] = pnear;
00237     _planeVec[1] = pfar;
00238     _planeVec[2] = pleft;
00239     _planeVec[3] = pright;
00240     _planeVec[4] = ptop;
00241     _planeVec[5] = pbottom;
00242
00243 }
00244
00245
00246 void FrustumVolume::setPlanes(const Matrixr &objectClipMat)
00247 {
00248     Vec4r planeEquation[6];
00249     Real  vectorLength;
00250     Vec3r normal;
00251
00252     planeEquation[0][0] = objectClipMat[0][3] - objectClipMat[0][0];
00253     planeEquation[0][1] = objectClipMat[1][3] - objectClipMat[1][0];
00254     planeEquation[0][2] = objectClipMat[2][3] - objectClipMat[2][0];
00255     planeEquation[0][3] = objectClipMat[3][3] - objectClipMat[3][0];
00256
00257     planeEquation[1][0] = objectClipMat[0][3] + objectClipMat[0][0];
00258     planeEquation[1][1] = objectClipMat[1][3] + objectClipMat[1][0];
00259     planeEquation[1][2] = objectClipMat[2][3] + objectClipMat[2][0];
00260     planeEquation[1][3] = objectClipMat[3][3] + objectClipMat[3][0];
00261
00262     planeEquation[2][0] = objectClipMat[0][3] + objectClipMat[0][1];
00263     planeEquation[2][1] = objectClipMat[1][3] + objectClipMat[1][1];
00264     planeEquation[2][2] = objectClipMat[2][3] + objectClipMat[2][1];
00265     planeEquation[2][3] = objectClipMat[3][3] + objectClipMat[3][1];
00266
00267     planeEquation[3][0] = objectClipMat[0][3] - objectClipMat[0][1];
00268     planeEquation[3][1] = objectClipMat[1][3] - objectClipMat[1][1];
00269     planeEquation[3][2] = objectClipMat[2][3] - objectClipMat[2][1];
00270     planeEquation[3][3] = objectClipMat[3][3] - objectClipMat[3][1];
00271
00272     planeEquation[4][0] = objectClipMat[0][3] + objectClipMat[0][2];
00273     planeEquation[4][1] = objectClipMat[1][3] + objectClipMat[1][2];
00274     planeEquation[4][2] = objectClipMat[2][3] + objectClipMat[2][2];
00275     planeEquation[4][3] = objectClipMat[3][3] + objectClipMat[3][2];
00276
00277     planeEquation[5][0] = objectClipMat[0][3] - objectClipMat[0][2];
00278     planeEquation[5][1] = objectClipMat[1][3] - objectClipMat[1][2];
00279     planeEquation[5][2] = objectClipMat[2][3] - objectClipMat[2][2];
00280     planeEquation[5][3] = objectClipMat[3][3] - objectClipMat[3][2];
00281
00282     for(Int32  i = 0; i < 6; i++)
00283     {
00284         vectorLength =
00285             osgSqrt(planeEquation[i][0] * planeEquation[i][0] +
00286                     planeEquation[i][1] * planeEquation[i][1] +
00287                     planeEquation[i][2] * planeEquation[i][2]);
00288
00289         planeEquation[i][0] /=  vectorLength;
00290         planeEquation[i][1] /=  vectorLength;
00291         planeEquation[i][2] /=  vectorLength;
00292         planeEquation[i][3] /= -vectorLength;
00293     }
00294
00295   // right
00296   _planeVec[3].set(planeEquation[0]);
00297
00298   // left
00299   _planeVec[2].set(planeEquation[1]);
00300
00301   // bottom
00302   _planeVec[5].set(planeEquation[2]);
00303
00304   // top
00305   _planeVec[4].set(planeEquation[3]);
00306
00307   // near
00308   _planeVec[0].set(planeEquation[4]);
00309
00310   // far
00311   _planeVec[1].set(planeEquation[5]);
00312 }
00313
00314
00315
00316 /*-------------------------- extending ------------------------------------*/
00317
00323 void FrustumVolume::extendBy(const Pnt3r &OSG_CHECK_ARG(pt))
00324 {
00325 }
00326
00331 void FrustumVolume::extendBy(const Volume &volume)
00332 {
00333     OSG::extend(*this, volume);
00334 }
00335
00336
00337 /*-------------------------- intersection ---------------------------------*/
00338
00339 bool FrustumVolume::intersect(const Pnt3r &point) const
00340 {
00341     bool retCode = true;
00342
00343     for(Int32 i = 0; i < 6; i++)
00344     {
00345         if((_planeVec[i].getNormal().x() * point.x() +
00346             _planeVec[i].getNormal().y() * point.y() +
00347             _planeVec[i].getNormal().z() * point.z() -
00348             _planeVec[i].getDistanceFromOrigin()     ) < 0.f)
00349         {
00350             retCode = false;
00351             break;
00352         }
00353     }
00354
00355     return retCode;
00356 }
00357
00358
00359 bool FrustumVolume::intersect(const Line &line) const
00360 {
00361     return line.intersect(*this);
00362 }
00363
00364
00365 bool FrustumVolume::intersect(const Line        &line,
00366                                     Real &minDist,
00367                                     Real &maxDist) const
00368 {
00369     return line.intersect(*this, minDist, maxDist);
00370 }
00371
00372
00373 bool FrustumVolume::intersect(const Volume &volume) const
00374 {
00375     return OSG::intersect(*this, volume);
00376 }
00377
00383 bool FrustumVolume::isOnSurface(const Pnt3r &OSG_CHECK_ARG(point)) const
00384 {
00385     FWARNING(("FrustumVolume::isOnSurface: NYI!\n"));
00386     return false;
00387 }
00388
00389 void FrustumVolume::transform(const Matrixr &m)
00390 {
00391     _planeVec[0].transform(m);
00392     _planeVec[1].transform(m);
00393     _planeVec[2].transform(m);
00394     _planeVec[3].transform(m);
00395     _planeVec[4].transform(m);
00396     _planeVec[5].transform(m);
00397 }
00398
00399 FrustumVolume &FrustumVolume::operator =(const FrustumVolume &rhs)
00400 {
00401     if(this == &rhs)
00402         return *this;
00403
00404     for(Int32 i = 0; i < 6; i++)
00405     {
00406         _planeVec[i] = rhs._planeVec[i];
00407     }
00408
00409     _state = rhs._state;
00410
00411     return *this;
00412 }
00413
00414 bool FrustumVolume::operator ==(const FrustumVolume &rhs) const
00415 {
00416     return ((static_cast<const Volume &>(*this) == rhs) &&
00417             (_planeVec[0] == rhs._planeVec[0]         ) &&
00418             (_planeVec[1] == rhs._planeVec[1]         ) &&
00419             (_planeVec[2] == rhs._planeVec[2]         ) &&
00420             (_planeVec[3] == rhs._planeVec[3]         ) &&
00421             (_planeVec[4] == rhs._planeVec[4]         ) &&
00422             (_planeVec[5] == rhs._planeVec[5]         ));
00423 }
00424
00425 void FrustumVolume::dump(      UInt32    OSG_CHECK_ARG(uiIndent),
00426                          const BitVector OSG_CHECK_ARG(bvFlags )) const
00427 {
00428 #if 1
00429     fprintf(stderr,"Frustum:(%f %f %f:%f)(%f %f %f:%f)(%f %f %f:%f)"
00430                 "(%f %f %f:%f)(%f %f %f:%f)(%f %f %f:%f)\n",
00431                 _planeVec[0].getNormal()[0],
00432                 _planeVec[0].getNormal()[1],
00433                 _planeVec[0].getNormal()[2],
00434                 _planeVec[0].getDistanceFromOrigin(),
00435                 _planeVec[1].getNormal()[0],
00436                 _planeVec[1].getNormal()[1],
00437                 _planeVec[1].getNormal()[2],
00438                 _planeVec[1].getDistanceFromOrigin(),
00439                 _planeVec[2].getNormal()[0],
00440                 _planeVec[2].getNormal()[1],
00441                 _planeVec[2].getNormal()[2],
00442                 _planeVec[2].getDistanceFromOrigin(),
00443                 _planeVec[3].getNormal()[0],
00444                 _planeVec[3].getNormal()[1],
00445                 _planeVec[3].getNormal()[2],
00446                 _planeVec[3].getDistanceFromOrigin(),
00447                 _planeVec[4].getNormal()[0],
00448                 _planeVec[4].getNormal()[1],
00449                 _planeVec[4].getNormal()[2],
00450                 _planeVec[4].getDistanceFromOrigin(),
00451                 _planeVec[5].getNormal()[0],
00452                 _planeVec[5].getNormal()[1],
00453                 _planeVec[5].getNormal()[2],
00454                 _planeVec[5].getDistanceFromOrigin() );
00455
00456
00457 #else 
00458     print(PLOG);
00459 #endif
00460 }
00461
00462 void FrustumVolume::print(std::ostream &os) const
00463 {
00464     os << "Frustum ("
00465        << _planeVec[0].getNormal()             << ":"
00466        << _planeVec[0].getDistanceFromOrigin() << "|"
00467        << _planeVec[1].getNormal()             << ":"
00468        << _planeVec[1].getDistanceFromOrigin() << "|"
00469        << _planeVec[2].getNormal()             << ":"
00470        << _planeVec[2].getDistanceFromOrigin() << "|"
00471        << _planeVec[3].getNormal()             << ":"
00472        << _planeVec[3].getDistanceFromOrigin() << "|"
00473        << _planeVec[4].getNormal()             << ":"
00474        << _planeVec[4].getDistanceFromOrigin() << "|"
00475        << _planeVec[5].getNormal()             << ":"
00476        << _planeVec[5].getDistanceFromOrigin()
00477        << ") ";
00478     printState(os);
00479 }
00480
00481
00492 OSG_BASE_DLLMAPPING
00493 bool intersect(const OSG::FrustumVolume           &frustum,
00494                const OSG::Volume                  &vol,
00495                      OSG::FrustumVolume::PlaneSet &inplanes)
00496 {
00497     // it's probably safe to assume the frustum is not empty and finite
00498     // so we only check vol for these conditions
00499
00500     if(vol.isEmpty() == true)
00501     {
00502         return false;
00503     }
00504     else if(vol.isInfinite() == true)
00505     {
00506         return true;
00507     }
00508     else
00509     {
00510         Pnt3r min, max;
00511
00512         vol.getBounds(min, max);
00513
00514         const Plane             *frust = frustum.getPlanes();
00515         FrustumVolume::PlaneSet  mask  = 0x1;
00516
00517         // check the box against the 6 planes, adjust the inplanes set
00518         // accordingly
00519
00520         for(Int32 i = 0; i < 6; i++, mask <<= 1)
00521         {
00522             if((inplanes & mask) != 0)
00523                 continue;
00524
00525             if(frust[i].isOutHalfSpace(min, max))
00526                 return false;
00527
00528             if(frust[i].isInHalfSpace(min, max))
00529                 inplanes |= mask;
00530         }
00531     }
00532
00533     return true;
00534 }
00535
00536 OSG_END_NAMESPACE