osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/CompositeTileSource.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 #include <osgEarth/CompositeTileSource>
00020 #include <osgEarth/ImageUtils>
00021 #include <osgDB/FileNameUtils>
00022 
00023 #define LC "[CompositeTileSource] "
00024 
00025 using namespace osgEarth;
00026 
00027 //------------------------------------------------------------------------
00028 
00029 CompositeTileSourceOptions::CompositeTileSourceOptions( const TileSourceOptions& options ) :
00030 TileSourceOptions( options )
00031 {
00032     setDriver( "composite" );
00033     fromConfig( _conf );
00034 }
00035 
00036 void
00037 CompositeTileSourceOptions::add( const TileSourceOptions& options )
00038 {
00039     Component c;
00040     c._tileSourceOptions = options;
00041     _components.push_back( c );
00042 }
00043 
00044 void
00045 CompositeTileSourceOptions::add( TileSource* source )
00046 {
00047     Component c;
00048     c._tileSourceInstance = source;
00049     _components.push_back( c );
00050 }
00051 
00052 void
00053 CompositeTileSourceOptions::add( const ImageLayerOptions& options )
00054 {
00055     Component c;
00056     c._imageLayerOptions = options;
00057     _components.push_back( c );
00058 }
00059 
00060 void
00061 CompositeTileSourceOptions::add( TileSource* source, const ImageLayerOptions& options )
00062 {
00063     Component c;
00064     c._tileSourceInstance = source;
00065     c._imageLayerOptions = options;
00066     _components.push_back( c );
00067 }
00068 
00069 Config 
00070 CompositeTileSourceOptions::getConfig() const
00071 {
00072     Config conf = TileSourceOptions::getConfig();
00073 
00074     for( ComponentVector::const_iterator i = _components.begin(); i != _components.end(); ++i )
00075     {
00076         if ( i->_imageLayerOptions.isSet() )
00077             conf.add( "image", i->_imageLayerOptions->getConfig() );
00078         else if ( i->_tileSourceOptions.isSet() )
00079             conf.add( "image", i->_tileSourceOptions->getConfig() );
00080     }
00081 
00082     return conf;
00083 }
00084 
00085 void 
00086 CompositeTileSourceOptions::mergeConfig( const Config& conf )
00087 {
00088     TileSourceOptions::mergeConfig( conf );
00089     fromConfig( conf );
00090 }
00091 
00092 void 
00093 CompositeTileSourceOptions::fromConfig( const Config& conf )
00094 {
00095     const ConfigSet& children = conf.children("image");
00096     for( ConfigSet::const_iterator i = children.begin(); i != children.end(); ++i )
00097     {
00098         add( ImageLayerOptions( *i ) );
00099     }
00100 
00101     if (conf.children("elevation").size() > 0 || conf.children("heightfield").size() > 0 ||
00102         conf.children("model").size() > 0 || conf.children("overlay").size() > 0 )
00103     {
00104         OE_WARN << LC << "Illegal - composite driver only supports image layers" << std::endl;
00105     }
00106 }
00107 
00108 //------------------------------------------------------------------------
00109 
00110 namespace
00111 {
00112     // some helper types.
00113     typedef std::pair< osg::ref_ptr<osg::Image>, float> ImageOpacityPair;
00114     typedef std::vector<ImageOpacityPair> ImageMixVector;
00115 
00116     // same op that occurs in ImageLayer.cpp ... maybe consilidate
00117     struct ImageLayerPreCacheOperation : public TileSource::ImageOperation
00118     {
00119         void operator()( osg::ref_ptr<osg::Image>& image )
00120         {
00121             _processor.process( image );
00122         }
00123 
00124         ImageLayerTileProcessor _processor;
00125     };
00126 }
00127 
00128 //-----------------------------------------------------------------------
00129 
00130 CompositeTileSource::CompositeTileSource( const TileSourceOptions& options ) :
00131 _options( options ),
00132 _initialized( false ),
00133 _dynamic( false )
00134 {
00135     for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); 
00136         i != _options._components.end(); )
00137 
00138     {
00139         if ( i->_imageLayerOptions.isSet() )
00140         {
00141             if ( i->_imageLayerOptions->driver().isSet() )
00142                 i->_tileSourceOptions = i->_imageLayerOptions->driver().value();
00143         }
00144 
00145         if ( i->_tileSourceOptions.isSet() )
00146         {
00147             if ( !i->_tileSourceInstance->valid() )
00148                 i->_tileSourceInstance = TileSourceFactory::create( i->_tileSourceOptions.value() );
00149             
00150             if ( !i->_tileSourceInstance->valid() )
00151                 OE_WARN << LC << "Could not find a TileSource for driver [" << i->_tileSourceOptions->getDriver() << "]" << std::endl;
00152         }
00153 
00154         if ( !i->_tileSourceInstance->valid() )
00155         {
00156             OE_WARN << LC << "A component has no valid TileSource ... removing." << std::endl;
00157             i = _options._components.erase( i );
00158         }
00159         else
00160         {
00161             ++i;
00162         }
00163     }
00164 }
00165 
00166 osg::Image*
00167 CompositeTileSource::createImage( const TileKey& key, ProgressCallback* progress )
00168 {
00169     ImageMixVector images;
00170     images.reserve( _options._components.size() );
00171 
00172     for(CompositeTileSourceOptions::ComponentVector::const_iterator i = _options._components.begin();
00173         i != _options._components.end();
00174         ++i )
00175     {
00176         if ( progress && progress->isCanceled() )
00177             return 0L;
00178 
00179         TileSource* source = i->_tileSourceInstance->get();
00180         if ( source )
00181         {
00182 
00183             //TODO:  This duplicates code in ImageLayer::isKeyValid.  Maybe should move that to TileSource::isKeyValid instead
00184             int minLevel = 0;
00185             int maxLevel = INT_MAX;
00186             if (i->_imageLayerOptions->minLevel().isSet())
00187             {
00188                 minLevel = i->_imageLayerOptions->minLevel().value();
00189             }
00190             else if (i->_imageLayerOptions->minLevelResolution().isSet())
00191             {
00192                 minLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->minLevelResolution().value(), source->getPixelsPerTile());            
00193             }
00194 
00195             if (i->_imageLayerOptions->maxLevel().isSet())
00196             {
00197                 maxLevel = i->_imageLayerOptions->maxLevel().value();
00198             }
00199             else if (i->_imageLayerOptions->maxLevelResolution().isSet())
00200             {
00201                 maxLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->maxLevelResolution().value(), source->getPixelsPerTile());            
00202             }
00203 
00204 
00205 
00206 
00207             // check that this source is within the level bounds:
00208             if (minLevel > key.getLevelOfDetail() ||
00209                 maxLevel < key.getLevelOfDetail() )
00210             {
00211                 continue;
00212             }
00213 
00214 
00215 
00216 
00217 
00218             if ( !source->getBlacklist()->contains( key.getTileId() ) )
00219             {
00220                 //Only try to get data if the source actually has data
00221                 if ( source->hasData( key ) )
00222                 {
00223                     osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp;
00224                     if ( i->_imageLayerOptions.isSet() )
00225                     {
00226                         preCacheOp = new ImageLayerPreCacheOperation();
00227                         preCacheOp->_processor.init( i->_imageLayerOptions.value(), true );                        
00228                     }
00229 
00230 
00231 
00232                     ImageOpacityPair imagePair(
00233                         source->createImage( key, preCacheOp.get(), progress ),
00234                         1.0f );
00235 
00236                     //If the image is not valid and the progress was not cancelled, blacklist
00237                     if (!imagePair.first.valid() && (!progress || !progress->isCanceled()))
00238                     {
00239                         //Add the tile to the blacklist
00240                         OE_DEBUG << LC << "Adding tile " << key.str() << " to the blacklist" << std::endl;
00241                         source->getBlacklist()->add( key.getTileId() );
00242                     }
00243 
00244                     if ( imagePair.first.valid() )
00245                     {
00246                         // check for opacity:
00247                         imagePair.second = i->_imageLayerOptions.isSet() ? i->_imageLayerOptions->opacity().value() : 1.0f;
00248 
00249                         images.push_back( imagePair );
00250                     }
00251                 }
00252                 else
00253                 {
00254                     OE_DEBUG << LC << "Source has no data at " << key.str() << std::endl;
00255                 }
00256             }
00257             else
00258             {
00259                 OE_DEBUG << LC << "Tile " << key.str() << " is blacklisted, not checking" << std::endl;
00260             }
00261         }
00262     }
00263 
00264     if ( progress && progress->isCanceled() )
00265     {
00266         return 0L;
00267     }
00268     else if ( images.size() == 0 )
00269     {
00270         return 0L;
00271     }
00272     else if ( images.size() == 1 )
00273     {
00274         return images[0].first.release();
00275     }
00276     else
00277     {
00278         osg::Image* result = new osg::Image( *images[0].first.get() );
00279         for( unsigned int i=1; i<images.size(); ++i )
00280         {
00281             ImageOpacityPair& pair = images[i];
00282             if ( pair.first.valid() )
00283             {
00284                 ImageUtils::mix( result, pair.first.get(), pair.second );
00285             }
00286         }
00287         return result;
00288     }
00289 }
00290 
00291 void
00292 CompositeTileSource::initialize( const std::string& referenceURI, const Profile* overrideProfile )
00293 {
00294     osg::ref_ptr<const Profile> profile = overrideProfile;
00295 
00296     for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin();
00297         i != _options._components.end();
00298         ++i)
00299     {
00300         TileSource* source = i->_tileSourceInstance->get(); //.get();
00301         if ( source )
00302         {
00303             osg::ref_ptr<const Profile> localOverrideProfile = overrideProfile;
00304 
00305             const TileSourceOptions& opt = source->getOptions();
00306             if ( opt.profile().isSet() )
00307                 localOverrideProfile = Profile::create( opt.profile().value() );
00308 
00309             source->initialize( referenceURI, localOverrideProfile.get() );
00310 
00311             if ( !profile.valid() )
00312             {
00313                 // assume the profile of the first source to be the overall profile.
00314                 profile = source->getProfile();
00315             }
00316             else if ( !profile->isEquivalentTo( source->getProfile() ) )
00317             {
00318                 // if sub-sources have different profiles, print a warning because this is
00319                 // not supported!
00320                 OE_WARN << LC << "Components with differing profiles are not supported. " 
00321                     << "Visual anomalies may result." << std::endl;
00322             }
00323             
00324             _dynamic = _dynamic || source->isDynamic();
00325 
00326             // gather extents
00327             const DataExtentList& extents = source->getDataExtents();
00328             for( DataExtentList::const_iterator j = extents.begin(); j != extents.end(); ++j )
00329             {
00330                 getDataExtents().push_back( *j );
00331             }
00332         }
00333     }
00334 
00335     setProfile( profile.get() );
00336 
00337     _initialized = true;
00338 }
00339 
00340 //------------------------------------------------------------------------
00341 
00342 namespace
00343 {
00344     struct CompositeTileSourceDriver : public TileSourceDriver
00345     {
00346         CompositeTileSourceDriver()
00347         {
00348             supportsExtension( "osgearth_composite", "Composite tile source driver" );
00349         }
00350 
00351         virtual const char* className()
00352         {
00353             return "CompositeTileSourceDriver";
00354         }
00355 
00356         virtual ReadResult readObject(const std::string& file_name, const Options* options) const
00357         {
00358             if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name )))
00359                 return ReadResult::FILE_NOT_HANDLED;
00360 
00361             return new CompositeTileSource( getTileSourceOptions(options) );
00362         }
00363     };
00364 }
00365 REGISTER_OSGPLUGIN(osgearth_composite, CompositeTileSourceDriver)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines