OSGTileGeometryLoad.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 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  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 
00039 //---------------------------------------------------------------------------
00040 //  Includes
00041 //---------------------------------------------------------------------------
00042 
00043 #include <stdlib.h>
00044 #include <stdio.h>
00045 #include <math.h>
00046 
00047 #include "OSGConfig.h"
00048 #include "OSGBaseFunctions.h"
00049 #include "OSGTriangleIterator.h"
00050 #include "OSGTileGeometryLoad.h"
00051 
00052 OSG_USING_NAMESPACE
00053 
00060 /*-------------------------------------------------------------------------*/
00061 /*                            Constructors                                 */
00062 
00066 TileGeometryLoad::TileGeometryLoad(UInt32 nodeId,
00067                                    bool useFaceDistribution):
00068     _nodeId(nodeId),
00069     _faces(0),
00070     _useFaceDistribution(useFaceDistribution),
00071     _valid(false)
00072 {
00073     if(_directions.size()==0)
00074     {
00075         // create directions for face distribution
00076         _directions.push_back(
00077             Plane(Vec3f( 1, 0, 0)              ,Pnt3f(0,0,0)));
00078         _directions.push_back(
00079             Plane(Vec3f( 0, 1, 0)              ,Pnt3f(0,0,0)));
00080         _directions.push_back(
00081             Plane(Vec3f( 0, 0, 1)              ,Pnt3f(0,0,0)));
00082 
00083         _directions.push_back(
00084             Plane(Vec3f( 1, 1, 1)*(1/osgSqrt(3.0f)),Pnt3f(0,0,0)));
00085         _directions.push_back(
00086             Plane(Vec3f(-1, 1, 1)*(1/osgSqrt(3.0f)),Pnt3f(1,0,0)));
00087         _directions.push_back(
00088             Plane(Vec3f( 1,-1, 1)*(1/osgSqrt(3.0f)),Pnt3f(0,1,0)));
00089         _directions.push_back(
00090             Plane(Vec3f( 1, 1,-1)*(1/osgSqrt(3.0f)),Pnt3f(0,0,1)));
00091 
00092         _directions.push_back(
00093             Plane(Vec3f( 1, 1, 0)*(1/osgSqrt(2.0f)),Pnt3f(0,0,0)));
00094         _directions.push_back(
00095             Plane(Vec3f( 1,-1, 0)*(1/osgSqrt(2.0f)),Pnt3f(0,1,0)));
00096         _directions.push_back(
00097             Plane(Vec3f( 0, 1, 1)*(1/osgSqrt(2.0f)),Pnt3f(0,0,0)));
00098         _directions.push_back(
00099             Plane(Vec3f( 0,-1, 1)*(1/osgSqrt(2.0f)),Pnt3f(0,1,0)));
00100         _directions.push_back(
00101             Plane(Vec3f( 1, 0, 1)*(1/osgSqrt(2.0f)),Pnt3f(0,0,0)));
00102         _directions.push_back(
00103             Plane(Vec3f(-1, 0, 1)*(1/osgSqrt(2.0f)),Pnt3f(1,0,0)));
00104 
00105 
00106     }
00107     updateGeometry();
00108 }
00109 
00113 TileGeometryLoad::TileGeometryLoad(const TileGeometryLoad &source):
00114     _nodeId(source._nodeId),
00115     _useFaceDistribution(source._useFaceDistribution),
00116     _valid(source._valid)
00117 {
00118     _min[0]           = source._min[0];
00119     _min[1]           = source._min[1];
00120     _max[0]           = source._max[0];
00121     _max[1]           = source._max[1];
00122     _faces            = source._faces;
00123     _visible          = source._visible;
00124     _faceDistribution = source._faceDistribution;
00125     _areaSize         = source._areaSize;
00126 }
00127 
00128 /*-------------------------------------------------------------------------*/
00129 /*                             Destructor                                  */
00130 
00133 TileGeometryLoad::~TileGeometryLoad(void)
00134 {
00135 }
00136 
00140 void TileGeometryLoad::updateView(Matrix &viewing,
00141                                   Matrix &projection,
00142                                   Real32 rNear,
00143                                   UInt32 width,
00144                                   UInt32 height)
00145 {
00146     Vec3f                        vol[2];
00147     Pnt3f                        pnt;
00148     Real32                       minx = 0.0,miny = 0.0;
00149     Real32                       maxx = 0.0,maxy = 0.0;
00150     Matrix                      *p;
00151     Real32                       bestScalX;
00152     UInt32                       bestDirX = 0;
00153     Real32                       bestScalY;
00154     UInt32                       bestDirY = 0;
00155 
00156     NodePtr node = dynamic_cast<NodePtr>(FieldContainerFactory::the()->getContainer(_nodeId));
00157     if(node == NullFC)
00158         return;
00159 
00160     // get whole transformation
00161     Matrix m=node->getToWorld();
00162     m.multLeft(viewing);
00163     // get transformed volume
00164     node->updateVolume();
00165     DynamicVolume volume=node->getVolume();
00166     // bug in osg base
00167     /*
00168     if(volume.isEmpty())
00169     {
00170         _visible=false;
00171         return;
00172     }
00173     */
00174     volume.transform(m);
00175     // get min,max
00176     volume.getBounds(vol[0], vol[1]);
00177     // min < rNear
00178     if(vol[0][2] > -rNear)
00179     {
00180         _visible=false;
00181         return;
00182     }
00183 
00184     // find best directon for face distribution
00185     if(_useFaceDistribution)
00186     {
00187         Real32 scal;
00188         Vec3f xdir(m[0][0],m[1][0],m[2][0]);
00189         Vec3f ydir(m[0][1],m[1][1],m[2][1]);
00190         xdir.normalize();
00191         ydir.normalize();
00192         bestScalX=bestScalY=0;
00193         for(UInt32 dir=0;dir<_directions.size();++dir)
00194         {
00195             scal=_directions[dir].getNormal()*xdir;
00196             if(scal>bestScalX)
00197             {
00198                 bestScalX=scal;
00199                 bestDirX =dir*2;
00200             }
00201             if((-scal)>bestScalX)
00202             {
00203                 bestScalX=-scal;
00204                 bestDirX =dir*2+1;
00205             }
00206             scal=_directions[dir].getNormal()*ydir;
00207             if(scal>bestScalY)
00208             {
00209                 bestScalY=scal;
00210                 bestDirY =dir*2;
00211             }
00212             if((-scal)>bestScalY)
00213             {
00214                 bestScalY=-scal;
00215                 bestDirY =dir*2+1;
00216             }
00217         }
00218         // cout << "x " << xdir << " " << _directions[bestDirX>>1].getNormal() << endl;
00219         // cout << "y " << ydir << " " << _directions[bestDirY>>1].getNormal() << endl;
00220         _faceDistDirX=bestDirX;
00221         _faceDistDirY=bestDirY;
00222         // cout << "best X:" << bestDirX << endl;
00223         // cout << "best Y:" << bestDirY << endl;
00224     }
00225 
00226     if(vol[1][2] > -rNear)
00227     {
00228         // volume lays on the fron clipping plane
00229         vol[1][2] = -rNear;
00230         p=&projection;
00231     }
00232     else
00233     {
00234         // volume lays on the visible side of the clipping plane
00235         node->getVolume().getBounds(vol[0], vol[1]);
00236         m.multLeft(projection);
00237         p=&m;
00238     }
00239     // create corners of a bounding box
00240     for(int i=0;i<8;++i)
00241     {
00242         p->multFullMatrixPnt(Pnt3f( vol[ (i   )&1 ][0] ,
00243                                     vol[ (i>>1)&1 ][1] ,
00244                                     vol[ (i>>2)&1 ][2]) , pnt);
00245         if(i>0)
00246         {
00247             if(minx > pnt[0]) minx = pnt[0];
00248             if(miny > pnt[1]) miny = pnt[1];
00249             if(maxx < pnt[0]) maxx = pnt[0];
00250             if(maxy < pnt[1]) maxy = pnt[1];
00251         }
00252         else
00253         {
00254             maxx = minx = pnt[0];
00255             maxy = miny = pnt[1];
00256         }
00257     }
00258     // visible ?
00259     if(maxx<-1 || maxy<-1 ||
00260        minx> 1 || miny> 1)
00261     {
00262         _visible = false;
00263     }
00264     else
00265     {
00266         minx=width  * ( minx + 1.0f ) / 2.0f - .5f;
00267         maxx=width  * ( maxx + 1.0f ) / 2.0f + .5f;
00268         miny=height * ( miny + 1.0f ) / 2.0f - .5f;
00269         maxy=height * ( maxy + 1.0f ) / 2.0f + .5f;
00270         _min[0]=(Int32)minx;
00271         _max[0]=(Int32)maxx;
00272         _min[1]=(Int32)miny;
00273         _max[1]=(Int32)maxy;
00274 
00275         _areaSize =
00276             (Real32)( _max[0] - _min[0] + 1 ) *
00277             (Real32)( _max[1] - _min[1] + 1 );
00278         /* Don't clip!
00279         if(_min[0]<0) _min[0]=0;
00280         if(_min[1]<0) _min[1]=0;
00281         if(_max[0]>=width ) _max[0]=width-1;
00282         if(_max[1]>=height) _max[1]=height-1;
00283         */
00284         _visible = true;
00285     }
00286 }
00287 
00296 void TileGeometryLoad::updateGeometry()
00297 {
00298     NodePtr node = dynamic_cast<NodePtr>(FieldContainerFactory::the()->getContainer(_nodeId));
00299     if(node == NullFC)
00300         return;
00301 
00302     const OSG::Volume *volume = &(node->getVolume().getInstance());
00303     TriangleIterator   f;
00304     int                p,s;
00305     Vec3f              vmin,vmax;
00306     Pnt3f              pos;
00307     Real32             min = 0.0,max = 0.0;
00308     PrimitiveIterator  it;
00309     NodeCorePtr        core;
00310     GeometryPtr        geo;
00311     const Real32       sq2 = osgSqrt(2.0f);
00312     const Real32       sq3 = osgSqrt(3.0f);
00313 
00314     _faces = 0;
00315     core=node->getCore();
00316     if(node->getCore() == NullFC)
00317         return;
00318     geo=dynamic_cast<GeometryPtr>(core);
00319     if(geo == NullFC)
00320         return;
00321 
00322     // get volume min,max
00323     volume->getBounds(vmin,vmax);
00324 
00325     // count faces
00326     for(f=geo->beginTriangles() ; f!=geo->endTriangles() ; ++f)
00327     {
00328         ++_faces;
00329     }
00330     if(_useFaceDistribution)
00331     {
00332         _faceDistribution.resize(_directions.size()*2);
00333         // loop through all directions
00334         for(UInt32 d=0;d<_directions.size();++d)
00335         {
00336             // init dist
00337             _faceDistribution[d*2  ].resize(FACE_DISTRIBUTION_SAMPLING_COUNT);
00338             _faceDistribution[d*2+1].resize(FACE_DISTRIBUTION_SAMPLING_COUNT);
00339             for(s=0;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
00340             {
00341                 _faceDistribution[d*2  ][s]=0;
00342                 _faceDistribution[d*2+1][s]=0;
00343             }
00344             // loop over all faces
00345             for(f=geo->beginTriangles() ;
00346                 f!=geo->endTriangles() ;
00347                 ++f)
00348             {
00349                 for(p=0;p<3;++p)
00350                 {
00351                     // get point and rescale
00352                     pos=(f.getPosition(p) - vmin);
00353                     pos[0]/=vmax[0]-vmin[0];
00354                     pos[1]/=vmax[1]-vmin[1];
00355                     pos[2]/=vmax[2]-vmin[2];
00356                     if(p==0)
00357                     {
00358                         max=min=_directions[d].distance(pos);
00359                     }
00360                     else
00361                     {
00362                         max=osgMax(max,_directions[d].distance(pos));
00363                         min=osgMin(min,_directions[d].distance(pos));
00364                     }
00365                 }
00366                 if(d>=7)
00367                 {
00368                     min/=sq2;
00369                     max/=sq2;
00370                 }
00371                 else if(d>=3)
00372                 {
00373                     min/=sq3;
00374                     max/=sq3;
00375                 }
00376                 _faceDistribution
00377                     [d*2  ]
00378                     [(int)(ceil(min*
00379                                 (FACE_DISTRIBUTION_SAMPLING_COUNT-1)))]++;
00380                 _faceDistribution
00381                     [d*2+1]
00382                     [(int)(ceil((1-max)*
00383                                 (FACE_DISTRIBUTION_SAMPLING_COUNT-1)))]++;
00384             }
00385         }
00386         for(UInt32 d=0;d<_directions.size();++d)
00387         {
00388             _faceDistribution[d*2  ][0]/=_faces;
00389             _faceDistribution[d*2+1][0]/=_faces;
00390             for(s=1;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
00391             {
00392                 _faceDistribution[d*2  ][s]/=_faces;
00393                 _faceDistribution[d*2+1][s]/=_faces;
00394                 _faceDistribution[d*2  ][s]+=_faceDistribution[d*2  ][s-1];
00395                 _faceDistribution[d*2+1][s]+=_faceDistribution[d*2+1][s-1];
00396             }
00397 #if 0
00398             printf("--> ");
00399             for(s=0;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
00400                 printf("%4.3f ",_faceDistribution[d*2  ][s]);
00401             printf("\n<-- ");
00402             for(s=0;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
00403                 printf("%4.3f ",_faceDistribution[d*2+1][s]);
00404             printf("\n");
00405 #endif
00406         }
00407     }
00408 }
00409 
00410 /*-------------------------------------------------------------------------*/
00411 /*                             Assignment                                  */
00412 
00415 TileGeometryLoad& TileGeometryLoad::operator=(const TileGeometryLoad &source)
00416 {
00417     if(this == &source)
00418         return *this;
00419     _min[0]              = source._min[0];
00420     _min[1]              = source._min[1];
00421     _max[0]              = source._max[0];
00422     _max[1]              = source._max[1];
00423     _faces               = source._faces;
00424     _visible             = source._visible;
00425     _faceDistribution    = source._faceDistribution;
00426     _faceDistDirX        = source._faceDistDirX;
00427     _faceDistDirY        = source._faceDistDirY;
00428     _nodeId              = source._nodeId;
00429     _useFaceDistribution = source._useFaceDistribution;
00430     _areaSize            = source._areaSize;
00431 
00432     return *this;
00433 }
00434 
00435 /*-------------------------------------------------------------------------*/
00436 /*                             dump                                        */
00437 
00438 void TileGeometryLoad::dump(void)
00439 {
00440     if(_visible)
00441     {
00442         SLOG << "Min/Max     :"
00443              << _min[0] << " " << _min[1] << " / "
00444              << _max[0] << " " << _max[1] << std::endl;
00445     }
00446     else
00447     {
00448         SLOG << "invisible " << std::endl;
00449     }
00450     SLOG << "Faces       :" << _faces << std::endl;
00451 }
00452 
00453 /*-------------------------------------------------------------------------*/
00454 /*                             get                                         */
00455 
00458 const Int32 *TileGeometryLoad::getMin()
00459 {
00460     return _min;
00461 }
00462 
00465 const Int32 *TileGeometryLoad::getMax()
00466 {
00467     return _max;
00468 }
00469 
00472 bool TileGeometryLoad::isVisible() const
00473 {
00474     return _visible;
00475 }
00476 
00479 NodePtr TileGeometryLoad::getNode() const
00480 {
00481     return dynamic_cast<NodePtr>(FieldContainerFactory::the()->getContainer(_nodeId));
00482 }
00483 
00486 UInt32 TileGeometryLoad::getFaces()
00487 {
00488     return _faces;
00489 }
00490 
00493 Real32 TileGeometryLoad::getVisibleFraction( const Int32 wmin[2],
00494                                              const Int32 wmax[2],
00495                                                    Int32 viswmin[2],
00496                                                    Int32 viswmax[2] )
00497 {
00498     Real32 x,y;
00499 
00500     if(_visible==false)
00501         return 0;
00502 
00503     // get visible area
00504     if(!getVisibleArea(wmin,wmax,viswmin,viswmax))
00505     {
00506         // not in region
00507         return 0;
00508     }
00509     // geometry complete in region?
00510     if(viswmin[0] == _min[0] &&
00511        viswmin[1] == _min[1] &&
00512        viswmax[0] == _max[0] &&
00513        viswmax[1] == _max[1])
00514     {
00515         return 1;
00516     }
00517 
00518     if(_useFaceDistribution)
00519     {
00520         x=1.0f/(_max[0]-_min[0]+1);
00521         y=1.0f/(_max[1]-_min[1]+1);
00522         return
00523             (getFaceDistribution(_faceDistDirX^1,
00524                                  1.0f - (viswmin[0] - _min[0]    ) * x) +
00525              getFaceDistribution(_faceDistDirX,
00526                                        (viswmax[0] - _min[0] + 1) * x) - 1)
00527             *
00528             (getFaceDistribution(_faceDistDirY^1,
00529                                  1.0f - (viswmin[1] - _min[1]    ) * y) +
00530              getFaceDistribution(_faceDistDirY,
00531                                        (viswmax[1] - _min[1] + 1) * y) - 1);
00532     }
00533     else
00534     {
00535         return
00536             ((Real32)(viswmax[0] - viswmin[0] + 1) *
00537              (Real32)(viswmax[1] - viswmin[1] + 1)) / _areaSize;
00538     }
00539 }
00540 
00543 bool TileGeometryLoad::getVisibleArea( const Int32 wmin[2],
00544                                        const Int32 wmax[2],
00545                                              Int32 viswmin[2],
00546                                              Int32 viswmax[2]      )
00547 {
00548     viswmin[0] = osgMax(wmin[0],_min[0]);
00549     viswmin[1] = osgMax(wmin[1],_min[1]);
00550     viswmax[0] = osgMin(wmax[0],_max[0]);
00551     viswmax[1] = osgMin(wmax[1],_max[1]);
00552     // not in region
00553     if(viswmin[0] > viswmax[0] ||
00554        viswmin[1] > viswmax[1])
00555         return false;
00556     else
00557         return true;
00558 }
00559 
00566 bool TileGeometryLoad::checkRegion( Int32 min[2],
00567                                     Int32 max[2] )
00568 {
00569     if(min[0] > _max[0] ||
00570        max[0] < _min[0] ||
00571        min[1] > _max[1] ||
00572        max[1] < _min[1])
00573         return false;
00574     else
00575         return true;
00576 }
00577 
00578 void TileGeometryLoad::setValid(bool s)
00579 {
00580     _valid = s;
00581 }
00582 
00583 bool TileGeometryLoad::isInvalid(void)
00584 {
00585     return !_valid;
00586 }
00587 
00588 /*-------------------------------------------------------------------------*/
00589 /*                              static                                     */
00590 
00591 std::vector<Plane>    TileGeometryLoad::_directions;