osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/NodeUtils.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00020 #include <osgEarth/NodeUtils>
00021 #include <osg/TemplatePrimitiveFunctor>
00022 #include <osg/Geode>
00023 #include <osg/CullSettings>
00024 #include <vector>
00025 
00026 using namespace osgEarth;
00027 
00028 //------------------------------------------------------------------------
00029 
00030 namespace
00031 {
00032     struct ComputeMaxNormalLength
00033     {
00034         void set( const osg::Vec3& normalECEF, const osg::Matrixd& local2world, float* maxNormalLen )
00035         {
00036             _normal       = normalECEF;
00037             _local2world  = local2world;
00038             _maxNormalLen = maxNormalLen;
00039         }
00040 
00041         void operator()( const osg::Vec3 &v1, bool)
00042         {         
00043             compute( v1 );
00044         }
00045 
00046         void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, bool)
00047         {         
00048             compute( v1 );
00049             compute( v2 );
00050         }
00051 
00052         void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3& v3, bool)
00053         {         
00054             compute( v1 );
00055             compute( v2 );
00056             compute( v3 );
00057         }
00058 
00059         void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3& v3, const osg::Vec3& v4, bool)
00060         {         
00061             compute( v1 );
00062             compute( v2 );
00063             compute( v3 );
00064             compute( v4 );
00065         }
00066 
00067         void compute( const osg::Vec3& v )
00068         {
00069             osg::Vec3d vworld = v * _local2world;
00070             double vlen = vworld.length();
00071             vworld.normalize();
00072 
00073             // the dot product of the 2 vecs is the cos of the angle between them;
00074             // mult that be the vector length to get the new normal length.
00075             float normalLen = fabs(_normal * vworld) * vlen;
00076 
00077             if ( normalLen < *_maxNormalLen )
00078                 *_maxNormalLen = normalLen;
00079         }
00080 
00081         osg::Vec3 _normal;
00082         osg::Matrixd _local2world;
00083         float*    _maxNormalLen;
00084     };
00085 
00086     struct ComputeMaxRadius2
00087     {
00088         void set( const osg::Vec3& center, float* maxRadius2 )
00089         {
00090             _center = center;
00091             _maxRadius2 = maxRadius2;
00092         }
00093 
00094         void operator()( const osg::Vec3 &v1, bool )
00095         {            
00096             compute( v1 );
00097         }
00098 
00099         void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, bool )
00100         {            
00101             compute( v1 );
00102             compute( v2 );
00103         }
00104 
00105         void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, bool )
00106         {            
00107             compute( v1 );
00108             compute( v2 );
00109             compute( v3 );
00110         }        
00111 
00112         void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, const osg::Vec3& v4, bool )
00113         {            
00114             compute( v1 );
00115             compute( v2 );
00116             compute( v3 );
00117             compute( v4 );
00118         }
00119 
00120         void compute( const osg::Vec3& v )
00121         {
00122             float dist = (v - _center).length2();
00123             if ( dist > *_maxRadius2 )
00124                 *_maxRadius2 = dist;
00125         }
00126 
00127 
00128 
00129         osg::Vec3 _center;
00130         float*    _maxRadius2;
00131     };
00132 
00133     struct ComputeVisitor : public osg::NodeVisitor
00134     {
00135         ComputeVisitor()
00136             : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), 
00137               _maxRadius2(0.0f) { }
00138 
00139         void run( osg::Node* node, const osg::Vec3d& centerECEF )
00140         {
00141             _centerECEF = centerECEF;
00142             _normalECEF = _centerECEF;
00143             _normalECEF.normalize();
00144             _maxNormalLen = _centerECEF.length();
00145 
00146             _pass = 1;
00147             node->accept( *this );
00148 
00149             _centerECEF = _normalECEF * _maxNormalLen;
00150 
00151             _pass = 2;
00152             node->accept( *this );
00153         }
00154 
00155         void apply( osg::Geode& geode )
00156         {            
00157             if ( _pass == 1 )
00158             {
00159                 osg::Matrixd local2world;
00160                 if ( !_matrixStack.empty() )
00161                     local2world = _matrixStack.back();
00162 
00163                 osg::TemplatePrimitiveFunctor<ComputeMaxNormalLength> pass1;
00164                 pass1.set( _normalECEF, local2world, &_maxNormalLen );
00165 
00166                 for( unsigned i=0; i<geode.getNumDrawables(); ++i )
00167                     geode.getDrawable(i)->accept( pass1 );
00168             }
00169 
00170             else // if ( _pass == 2 )
00171             {
00172                 osg::Vec3d center = _matrixStack.empty() ? _centerECEF : _centerECEF * osg::Matrixd::inverse(_matrixStack.back());
00173 
00174                 osg::TemplatePrimitiveFunctor<ComputeMaxRadius2> pass2;
00175                 pass2.set( center, &_maxRadius2 );
00176                 for( unsigned i=0; i<geode.getNumDrawables(); ++i )
00177                     geode.getDrawable(i)->accept( pass2 );
00178             }
00179         }
00180 
00181         void apply( osg::Transform& xform )
00182         {
00183             osg::Matrixd matrix;
00184             if (!_matrixStack.empty()) matrix = _matrixStack.back();
00185             xform.computeLocalToWorldMatrix( matrix, this );
00186             _matrixStack.push_back( matrix );
00187             traverse(xform);
00188             _matrixStack.pop_back();
00189         }
00190         
00191         unsigned   _pass;
00192         osg::Vec3d _centerECEF;
00193         osg::Vec3f _normalECEF;
00194         float      _maxNormalLen;
00195         float      _maxRadius2;
00196         std::vector<osg::Matrixd> _matrixStack;
00197     };
00198 
00204     struct MyClusterCullingCallback : public osg::ClusterCullingCallback
00205     {
00206         bool cull(osg::NodeVisitor* nv, osg::Drawable* , osg::State*) const
00207         {
00208             osg::CullSettings* cs = dynamic_cast<osg::CullSettings*>(nv);
00209             if (cs && !(cs->getCullingMode() & osg::CullSettings::CLUSTER_CULLING))
00210             {
00211                 return false;
00212             }
00213 
00214             if (_deviation<=-1.0f)
00215             {
00216                 return false;
00217             }
00218 
00219             osg::Vec3 eye_cp = nv->getViewPoint() - _controlPoint;
00220             float radius = eye_cp.length();
00221 
00222             if (radius<_radius)
00223             {
00224                 return false;
00225             }
00226 
00227             float deviation = (eye_cp * _normal)/radius;
00228 
00229             return deviation < _deviation;
00230         }
00231     };
00232 }
00233 
00234 //------------------------------------------------------------------------
00235 
00236 osg::ClusterCullingCallback*
00237 ClusterCullerFactory::create( osg::Node* node, const osg::Vec3d& centerECEF )
00238 {
00239     // Cluster culling computer. This works in two passes.
00240     //
00241     // It starts with a control point provided by the caller. I the first pass it computes
00242     // a new control point that is along the same geocentric normal but at a lower Z. This 
00243     // corresponds to the lowest Z of a vertex with respect to that normal. This means we
00244     // can always use a "deviation" of 0 -- and it gets around the problem of the control
00245     // point being higher than a vertex and corrupting the deviation.
00246     //
00247     // In the second pass, we compute the radius based on the new control point.
00248 
00249     osg::ClusterCullingCallback* ccc = 0L;
00250     if ( node )
00251     {
00252         ComputeVisitor cv;
00253         cv.run( node, centerECEF );
00254 
00255         ccc = new MyClusterCullingCallback(); //osg::ClusterCullingCallback();
00256         ccc->set( cv._centerECEF, cv._normalECEF, 0.0f, sqrt(cv._maxRadius2) );
00257     }
00258     return ccc;
00259 }
00260 
00261 //------------------------------------------------------------------------
00262 
00263 RemoveEmptyGroupsVisitor::RemoveEmptyGroupsVisitor() :
00264 osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN )
00265 {
00266     //nop
00267 }
00268 
00269 void
00270 RemoveEmptyGroupsVisitor::apply( osg::Group& group )
00271 {
00272     bool removed = true;
00273     while( removed )
00274     {
00275         removed = false;
00276         for( unsigned i = 0; i < group.getNumChildren(); ++i )
00277         {
00278             osg::Group* child = group.getChild(i)->asGroup();
00279             if ( child )
00280             {
00281                 if (child->className() == "Group"         &&
00282                     child->getStateSet() == 0L            &&
00283                     child->getCullCallback() == 0L        &&
00284                     child->getUpdateCallback() == 0L      &&
00285                     child->getUserData() == 0L            &&
00286                     child->getName().empty()              &&
00287                     child->getDescriptions().size() == 0 )
00288                 {
00289                     for( unsigned j = 0; j < child->getNumChildren(); ++j )
00290                     {
00291                         group.addChild( child->getChild( j ) );
00292                     }
00293 
00294                     group.removeChild( i-- );
00295                     removed = true;
00296                 }                
00297             }
00298         }
00299     }
00300 
00301     traverse(group);
00302 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines