osgEarth 2.1.1
|
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 }