osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/TileSource.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 <limits.h>
00020 
00021 #include <osgEarth/TileSource>
00022 #include <osgEarth/ImageToHeightFieldConverter>
00023 #include <osgEarth/ImageUtils>
00024 #include <osgEarth/FileUtils>
00025 #include <osgEarth/Registry>
00026 #include <osgEarth/ThreadingUtils>
00027 #include <osgDB/FileUtils>
00028 #include <osgDB/FileNameUtils>
00029 #include <osgDB/ReadFile>
00030 #include <osgDB/WriteFile>
00031 
00032 #define LC "[TileSource] "
00033 
00034 using namespace osgEarth;
00035 
00036 //------------------------------------------------------------------------
00037 
00038 TileBlacklist::TileBlacklist()
00039 {
00040     //NOP
00041 }
00042 
00043 void
00044 TileBlacklist::add(const osgTerrain::TileID &tile)
00045 {
00046     Threading::ScopedWriteLock lock(_mutex);
00047     _tiles.insert(tile);
00048     OE_DEBUG << "Added " << tile.level << " (" << tile.x << ", " << tile.y << ") to blacklist" << std::endl;
00049 }
00050 
00051 void
00052 TileBlacklist::remove(const osgTerrain::TileID &tile)
00053 {
00054     Threading::ScopedWriteLock lock(_mutex);
00055     _tiles.erase(tile);
00056     OE_DEBUG << "Removed " << tile.level << " (" << tile.x << ", " << tile.y << ") from blacklist" << std::endl;
00057 }
00058 
00059 void
00060 TileBlacklist::clear()
00061 {
00062     Threading::ScopedWriteLock lock(_mutex);
00063     _tiles.clear();
00064     OE_DEBUG << "Cleared blacklist" << std::endl;
00065 }
00066 
00067 bool
00068 TileBlacklist::contains(const osgTerrain::TileID &tile) const
00069 {
00070     Threading::ScopedReadLock lock(const_cast<TileBlacklist*>(this)->_mutex);
00071     return _tiles.find(tile) != _tiles.end();
00072 }
00073 
00074 unsigned int
00075 TileBlacklist::size() const
00076 {
00077     Threading::ScopedReadLock lock(const_cast<TileBlacklist*>(this)->_mutex);
00078     return _tiles.size();
00079 }
00080 
00081 TileBlacklist*
00082 TileBlacklist::read(std::istream &in)
00083 {
00084     osg::ref_ptr< TileBlacklist > result = new TileBlacklist();
00085 
00086 
00087     while (!in.eof())
00088     {
00089         std::string line;
00090         std::getline(in, line);
00091         if (!line.empty())
00092         {
00093             int z, x, y;
00094             if (sscanf(line.c_str(), "%d %d %d", &z, &x, &y) == 3)
00095             {
00096                 result->add(osgTerrain::TileID(z, x, y ));
00097             }
00098 
00099         }
00100     }
00101 
00102     return result.release();
00103 }
00104 
00105 TileBlacklist*
00106 TileBlacklist::read(const std::string &filename)
00107 {
00108     if (osgDB::fileExists(filename) && (osgDB::fileType(filename) == osgDB::REGULAR_FILE))
00109     {
00110         std::ifstream in( filename.c_str() );
00111         return read( in );
00112     }
00113     return NULL;
00114 }
00115 
00116 void
00117 TileBlacklist::write(const std::string &filename) const
00118 { 
00119     std::string path = osgDB::getFilePath(filename);
00120     if (!path.empty() && !osgDB::fileExists(path) && !osgDB::makeDirectory(path))
00121     {
00122         OE_NOTICE << "Couldn't create path " << path << std::endl;
00123         return;
00124     }
00125     std::ofstream out(filename.c_str());
00126     write(out);
00127 }
00128 
00129 void
00130 TileBlacklist::write(std::ostream &output) const
00131 {
00132     Threading::ScopedReadLock lock(const_cast<TileBlacklist*>(this)->_mutex);
00133     for (BlacklistedTiles::const_iterator itr = _tiles.begin(); itr != _tiles.end(); ++itr)
00134     {
00135         output << itr->level << " " << itr->x << " " << itr->y << std::endl;
00136     }
00137 }
00138 
00139 //------------------------------------------------------------------------
00140 
00141 TileSource::TileSource( const TileSourceOptions& options ) :
00142 _options( options )
00143 {
00144     this->setThreadSafeRefUnref( true );
00145 
00146     if ( *options.L2CacheSize() > 0 )
00147     {
00148         _memCache = new MemCache( *options.L2CacheSize() );
00149     }
00150     else
00151     {
00152         OE_INFO << LC << "L2 Cache disabled" << std::endl;
00153     }
00154 
00155     if (_options.blacklistFilename().isSet())
00156     {
00157         _blacklistFilename = _options.blacklistFilename().value();
00158     }
00159 
00160     
00161     if (!_blacklistFilename.empty() && osgDB::fileExists(_blacklistFilename))
00162     {
00163         _blacklist = TileBlacklist::read(_blacklistFilename);
00164         if (_blacklist.valid())
00165         {
00166             OE_INFO << "Read blacklist from file" << _blacklistFilename << std::endl;
00167         }
00168     }
00169 
00170     if (!_blacklist.valid())
00171     {
00172         //Initialize the blacklist if we couldn't read it.
00173         _blacklist = new TileBlacklist();
00174     }
00175 }
00176 
00177 TileSource::~TileSource()
00178 {
00179     if (_blacklist.valid() && !_blacklistFilename.empty())
00180     {
00181         _blacklist->write(_blacklistFilename);
00182     }
00183 }
00184 
00185 int
00186 TileSource::getPixelsPerTile() const
00187 {
00188     return _options.tileSize().value();
00189 }
00190 
00191 osg::Image*
00192 TileSource::createImage(const TileKey& key, ImageOperation* prepOp, ProgressCallback* progress)
00193 {
00194     // Try to get it from the memcache fist
00195     if (_memCache.valid())
00196     {
00197         osg::ref_ptr<const osg::Image> cachedImage;
00198         if ( _memCache->getImage( key, CacheSpec(), cachedImage ) )
00199         {
00200             return ImageUtils::cloneImage(cachedImage.get());
00201         }
00202     }
00203 
00204     osg::ref_ptr<osg::Image> newImage = createImage(key, progress);
00205 
00206     if ( prepOp )
00207         (*prepOp)( newImage );
00208 
00209     if ( newImage.valid() && _memCache.valid() )
00210     {
00211         // cache it to the memory cache.
00212         _memCache->setImage( key, CacheSpec(), newImage.get() );
00213     }
00214 
00215     return newImage.release();
00216 }
00217 
00218 osg::HeightField*
00219 TileSource::createHeightField(const TileKey& key, HeightFieldOperation* prepOp, ProgressCallback* progress )
00220 {
00221     // Try to get it from the memcache first:
00222         if (_memCache.valid())
00223         {
00224         osg::ref_ptr<const osg::HeightField> cachedHF;
00225                 if ( _memCache->getHeightField( key, CacheSpec(), cachedHF ) )
00226         {
00227             return new osg::HeightField( *cachedHF.get() );
00228         }
00229         }
00230 
00231     osg::ref_ptr<osg::HeightField> newHF = createHeightField( key, progress );
00232 
00233     if ( prepOp )
00234         (*prepOp)( newHF );
00235 
00236     if ( newHF.valid() && _memCache.valid() )
00237     {
00238         _memCache->setHeightField( key, CacheSpec(), newHF.get() );
00239     }
00240 
00241     //TODO: why not just newHF.release()? -gw
00242     return newHF.valid() ? new osg::HeightField( *newHF.get() ) : 0L;
00243 }
00244 
00245 osg::HeightField*
00246 TileSource::createHeightField( const TileKey& key,
00247                                ProgressCallback* progress)
00248 {
00249     osg::ref_ptr<osg::Image> image = createImage(key, progress);
00250     osg::HeightField* hf = 0;
00251     if (image.valid())
00252     {
00253         ImageToHeightFieldConverter conv;
00254         hf = conv.convert( image.get() );
00255     }      
00256     return hf;
00257 }
00258 
00259 bool
00260 TileSource::isOK() const 
00261 {
00262     return getProfile() != NULL;
00263 }
00264 
00265 void
00266 TileSource::setProfile( const Profile* profile )
00267 {
00268     _profile = profile;
00269 }
00270 
00271 const Profile*
00272 TileSource::getProfile() const
00273 {
00274     return _profile.get();
00275 }
00276 
00277 unsigned int
00278 TileSource::getMaxDataLevel() const
00279 {
00280     //If we have no data extents, just use a reasonably high number
00281     if (_dataExtents.size() == 0) return 35;
00282 
00283     unsigned int maxDataLevel = 0;
00284     for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr)
00285     {
00286         if (itr->getMaxLevel() > maxDataLevel) maxDataLevel = itr->getMaxLevel();
00287     }
00288     return maxDataLevel;
00289 }
00290 
00291 unsigned int
00292 TileSource::getMinDataLevel() const
00293 {
00294     //If we have no data extents, just use 0
00295     if (_dataExtents.size() == 0) return 0;
00296 
00297     unsigned int minDataLevel = INT_MAX;
00298     for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr)
00299     {
00300         if (itr->getMinLevel() < minDataLevel) minDataLevel = itr->getMinLevel();
00301     }
00302     return minDataLevel;
00303 }
00304 
00305 bool
00306 TileSource::hasDataAtLOD( unsigned lod ) const
00307 {
00308     //If no data extents are provided, just return true
00309     if ( _dataExtents.size() == 0 )
00310         return true;
00311 
00312     bool intersects = false;
00313 
00314     for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr)
00315     {
00316         if ( itr->getMinLevel() <= lod && lod <= itr->getMaxLevel() )
00317         {
00318             intersects = true;
00319             break;
00320         }
00321     }
00322     return intersects;
00323 }
00324 
00325 bool
00326 TileSource::hasDataInExtent( const GeoExtent& extent ) const
00327 {
00328     //If no data extents are provided, just return true
00329     if ( _dataExtents.size() == 0 )
00330         return true;
00331 
00332     bool intersects = false;
00333 
00334     for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr)
00335     {
00336         if ( extent.intersects( *itr ) )
00337         {
00338             intersects = true;
00339             break;
00340         }
00341     }
00342     return intersects;
00343 }
00344 
00345 
00346 bool
00347 TileSource::hasData(const osgEarth::TileKey& key) const
00348 {
00349     //If no data extents are provided, just return true
00350     if (_dataExtents.size() == 0) return true;
00351 
00352     const osgEarth::GeoExtent& keyExtent = key.getExtent();
00353     bool intersectsData = false;
00354 
00355     for (DataExtentList::const_iterator itr = _dataExtents.begin(); itr != _dataExtents.end(); ++itr)
00356     {
00357         if (keyExtent.intersects( *itr ) && key.getLevelOfDetail() >= itr->getMinLevel() && key.getLevelOfDetail() <= itr->getMaxLevel())
00358         {
00359             intersectsData = true;
00360             break;
00361         }
00362     }
00363 
00364     return intersectsData;
00365 }
00366 
00367 bool
00368 TileSource::supportsPersistentCaching() const
00369 {
00370     return true;
00371 }
00372 
00373 TileBlacklist*
00374 TileSource::getBlacklist()
00375 {
00376     return _blacklist.get();
00377 }
00378 
00379 const TileBlacklist*
00380 TileSource::getBlacklist() const
00381 {
00382     return _blacklist.get();
00383 }
00384 
00385 //------------------------------------------------------------------------
00386 
00387 #undef  LC
00388 #define LC "[TileSourceFactory] "
00389 #define TILESOURCEOPTIONS_TAG "__osgEarth::TileSourceOptions"
00390 
00391 TileSource*
00392 TileSourceFactory::create( const TileSourceOptions& options )
00393 {
00394     TileSource* result = 0L;
00395 
00396     std::string driver = options.getDriver();
00397     if ( driver.empty() )
00398     {
00399         OE_WARN << "ILLEGAL- no driver set for tile source" << std::endl;
00400         return 0L;
00401     }
00402 
00403     osg::ref_ptr<osgDB::ReaderWriter::Options> rwopt = new osgDB::ReaderWriter::Options();
00404     rwopt->setPluginData( TILESOURCEOPTIONS_TAG, (void*)&options );
00405 
00406     std::string driverExt = std::string( ".osgearth_" ) + driver;
00407     result = dynamic_cast<TileSource*>( osgDB::readObjectFile( driverExt, rwopt.get() ) );
00408     if ( !result )
00409     {
00410         OE_WARN << "WARNING: Failed to load TileSource driver for \"" << driver << "\"" << std::endl;
00411     }
00412 
00413     return result;
00414 }
00415 
00416 //------------------------------------------------------------------------
00417 
00418 const TileSourceOptions&
00419 TileSourceDriver::getTileSourceOptions( const osgDB::ReaderWriter::Options* rwopt ) const
00420 {
00421     return *static_cast<const TileSourceOptions*>( rwopt->getPluginData( TILESOURCEOPTIONS_TAG ) );
00422 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines