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 <osgEarth/TerrainLayer> 00020 #include <osgEarth/TileSource> 00021 #include <osgEarth/Registry> 00022 #include <osgEarth/StringUtils> 00023 #include <osgDB/WriteFile> 00024 #include <osg/Version> 00025 #include <OpenThreads/ScopedLock> 00026 #include <memory.h> 00027 00028 using namespace osgEarth; 00029 using namespace OpenThreads; 00030 00031 #define LC "[TerrainLayer] " 00032 00033 //------------------------------------------------------------------------ 00034 00035 TerrainLayerOptions::TerrainLayerOptions( const ConfigOptions& options ) : 00036 ConfigOptions( options ), 00037 _minLevel( 0 ), 00038 _maxLevel( 99 ), 00039 _cacheEnabled( true ), 00040 _cacheOnly( false ), 00041 _loadingWeight( 1.0f ), 00042 _exactCropping( false ), 00043 _enabled( true ), 00044 _reprojectedTileSize( 256 ) 00045 00046 { 00047 setDefaults(); 00048 fromConfig( _conf ); 00049 } 00050 00051 TerrainLayerOptions::TerrainLayerOptions( const std::string& name, const TileSourceOptions& driverOptions ) : 00052 ConfigOptions() 00053 { 00054 setDefaults(); 00055 fromConfig( _conf ); 00056 _name = name; 00057 _driver = driverOptions; 00058 } 00059 00060 void 00061 TerrainLayerOptions::setDefaults() 00062 { 00063 _enabled.init( true ); 00064 _exactCropping.init( false ); 00065 _reprojectedTileSize.init( 256 ); 00066 _cacheEnabled.init( true ); 00067 _cacheOnly.init( false ); 00068 _loadingWeight.init( 1.0f ); 00069 _minLevel.init( 0 ); 00070 _maxLevel.init( 99 ); 00071 } 00072 00073 Config 00074 TerrainLayerOptions::getConfig() const 00075 { 00076 Config conf = ConfigOptions::getConfig(); 00077 00078 conf.attr("name") = _name; 00079 conf.updateIfSet( "cacheid", _cacheId ); 00080 conf.updateIfSet( "min_level", _minLevel ); 00081 conf.updateIfSet( "max_level", _maxLevel ); 00082 conf.updateIfSet( "min_level_resolution", _minLevelResolution ); 00083 conf.updateIfSet( "max_level_resolution", _maxLevelResolution ); 00084 conf.updateIfSet( "cache_enabled", _cacheEnabled ); 00085 conf.updateIfSet( "cache_only", _cacheOnly ); 00086 conf.updateIfSet( "cache_format", _cacheFormat ); 00087 conf.updateIfSet( "loading_weight", _loadingWeight ); 00088 conf.updateIfSet( "enabled", _enabled ); 00089 conf.updateIfSet( "edge_buffer_ratio", _edgeBufferRatio); 00090 conf.updateObjIfSet( "profile", _profile ); 00091 conf.updateIfSet( "max_data_level", _maxDataLevel); 00092 conf.updateIfSet( "reprojected_tilesize", _reprojectedTileSize); 00093 00094 //Merge the TileSource options 00095 if (driver().isSet()) conf.merge( driver()->getConfig() ); 00096 00097 return conf; 00098 } 00099 00100 void 00101 TerrainLayerOptions::fromConfig( const Config& conf ) 00102 { 00103 _name = conf.value("name"); 00104 conf.getIfSet( "cacheid", _cacheId ); 00105 conf.getIfSet( "min_level", _minLevel ); 00106 conf.getIfSet( "max_level", _maxLevel ); 00107 conf.getIfSet( "min_level_resolution", _minLevelResolution ); 00108 conf.getIfSet( "max_level_resolution", _maxLevelResolution ); 00109 conf.getIfSet( "cache_enabled", _cacheEnabled ); 00110 conf.getIfSet( "cache_only", _cacheOnly ); 00111 conf.getIfSet( "cache_format", _cacheFormat ); 00112 conf.getIfSet( "loading_weight", _loadingWeight ); 00113 conf.getIfSet( "enabled", _enabled ); 00114 conf.getIfSet( "edge_buffer_ratio", _edgeBufferRatio); 00115 conf.getObjIfSet( "profile", _profile ); 00116 conf.getIfSet( "max_data_level", _maxDataLevel); 00117 conf.getIfSet( "reprojected_tilesize", _reprojectedTileSize); 00118 00119 00120 if ( conf.hasValue("driver") ) 00121 driver() = TileSourceOptions(conf); 00122 } 00123 00124 void 00125 TerrainLayerOptions::mergeConfig( const Config& conf ) 00126 { 00127 ConfigOptions::mergeConfig( conf ); 00128 fromConfig( conf ); 00129 } 00130 00131 //------------------------------------------------------------------------ 00132 00133 TerrainLayer::TerrainLayer( TerrainLayerOptions* options ) : 00134 _runtimeOptions( options ) 00135 { 00136 init(); 00137 } 00138 00139 TerrainLayer::TerrainLayer( TerrainLayerOptions* options, TileSource* tileSource ) : 00140 _runtimeOptions( options ), 00141 _tileSource ( tileSource ) 00142 { 00143 init(); 00144 } 00145 00146 void 00147 TerrainLayer::init() 00148 { 00149 _tileSourceInitialized = false; 00150 _tileSize = 256; 00151 } 00152 00153 void 00154 TerrainLayer::setCache(Cache* cache) 00155 { 00156 if (_cache.get() != cache) 00157 { 00158 _cache = cache; 00159 00160 // Read properties from the cache if not already set 00161 if ( _cache.valid() && _runtimeOptions->cacheEnabled() == true ) 00162 { 00163 // create the unique cache ID for the tile configuration. 00164 std::string cacheId; 00165 00166 if ( _runtimeOptions->cacheId().isSet() && !_runtimeOptions->cacheId()->empty() ) 00167 { 00168 // user expliticy set a cacheId in the terrain layer options. 00169 cacheId = *_runtimeOptions->cacheId(); 00170 } 00171 else 00172 { 00173 // system will generate a cacheId. 00174 Config hashConf = _runtimeOptions->driver()->getConfig(); 00175 00176 // remove cache-control properties before hashing. 00177 hashConf.remove( "cache_only" ); 00178 hashConf.remove( "cache_enabled" ); 00179 00180 std::stringstream buf; 00181 //OE_NOTICE << hashConf.toHashString() << std::endl; 00182 buf << std::fixed << std::setfill('0') << std::hex 00183 << osgEarth::hashString( hashConf.toHashString() ); 00184 cacheId = buf.str(); 00185 } 00186 00187 // try to load the properties from the cache; if that is unsuccesful, 00188 // create new properties. 00189 osg::ref_ptr<const Profile> profile; 00190 _cache->loadProperties( cacheId, _cacheSpec, profile, _tileSize ); 00191 00192 // Set the profile if it hasn't already been set 00193 if (!_profile.valid() && profile.valid()) 00194 { 00195 _profile = profile.get(); 00196 } 00197 00198 // Set the cache format if it hasn't been explicitly set 00199 if ( !_runtimeOptions->cacheFormat().isSet() ) 00200 { 00201 _runtimeOptions->cacheFormat() = _cacheSpec.format(); 00202 } 00203 00204 _cacheSpec = CacheSpec( cacheId, *_runtimeOptions->cacheFormat(), getName() ); 00205 } 00206 } 00207 } 00208 00209 void 00210 TerrainLayer::setTargetProfileHint( const Profile* profile ) 00211 { 00212 _targetProfileHint = profile; 00213 } 00214 00215 TileSource* 00216 TerrainLayer::getTileSource() const 00217 { 00218 if ((_tileSource.valid() && !_tileSourceInitialized) || 00219 (!_tileSource.valid() && _runtimeOptions->cacheOnly() == false) ) 00220 { 00221 OpenThreads::ScopedLock< OpenThreads::Mutex > lock(const_cast<TerrainLayer*>(this)->_initTileSourceMutex ); 00222 // double-check pattern 00223 if ((_tileSource.valid() && !_tileSourceInitialized) || 00224 (!_tileSource.valid() && _runtimeOptions->cacheOnly() == false)) 00225 { 00226 const_cast<TerrainLayer*>(this)->initTileSource(); 00227 } 00228 } 00229 00230 return _tileSource.get(); 00231 } 00232 00233 const Profile* 00234 TerrainLayer::getProfile() const 00235 { 00236 if ( !_profile.valid() ) 00237 { 00238 if ( _runtimeOptions->cacheOnly() == false && !_tileSourceInitialized ) 00239 { 00240 // Call getTileSource to make sure the TileSource is initialized 00241 getTileSource(); 00242 } 00243 00244 if ( _tileSource.valid() && !_profile.valid() ) 00245 { 00246 const_cast<TerrainLayer*>(this)->_profile = _tileSource->getProfile(); 00247 } 00248 } 00249 00250 return _profile.get(); 00251 } 00252 00253 unsigned int 00254 TerrainLayer::getMaxDataLevel() const 00255 { 00256 //Try the setting first 00257 00258 if ( _runtimeOptions->maxDataLevel().isSet() ) 00259 { 00260 return _runtimeOptions->maxDataLevel().get(); 00261 } 00262 00263 //Try the TileSource 00264 TileSource* ts = getTileSource(); 00265 if ( ts ) 00266 { 00267 return ts->getMaxDataLevel(); 00268 } 00269 00270 //Just default 00271 return 20; 00272 } 00273 00274 unsigned 00275 TerrainLayer::getTileSize() const 00276 { 00277 TileSource* ts = getTileSource(); 00278 return ts ? ts->getPixelsPerTile() : _tileSize; 00279 } 00280 00281 bool 00282 TerrainLayer::isDynamic() const 00283 { 00284 TileSource* ts = getTileSource(); 00285 return ts ? ts->isDynamic() : false; 00286 } 00287 00288 //TODO: move this to ImageLayer/ElevationLayer 00289 std::string 00290 TerrainLayer::suggestCacheFormat() const 00291 { 00292 std::string ext = _tileSource.valid() ? _tileSource->getExtension() : ""; 00293 return !ext.empty() ? ext : "png"; 00294 } 00295 00296 void 00297 TerrainLayer::initTileSource() 00298 { 00299 OE_DEBUG << LC << "Initializing tile source ..." << std::endl; 00300 00301 // instantiate it from driver options if it has not already been created: 00302 if ( !_tileSource.valid() ) 00303 { 00304 if ( _runtimeOptions->driver().isSet() ) 00305 { 00306 _tileSource = TileSourceFactory::create( *_runtimeOptions->driver() ); 00307 } 00308 } 00309 00310 // next check for an override-profile. The profile usually comes from the 00311 // TileSource itself, but you have the option of overriding: 00312 osg::ref_ptr<const Profile> overrideProfile; 00313 if ( _runtimeOptions->profile().isSet() ) 00314 { 00315 overrideProfile = Profile::create( *_runtimeOptions->profile() ); 00316 } 00317 00318 // Initialize the profile with the context information: 00319 if ( _tileSource.valid() ) 00320 { 00321 _tileSource->initialize( _referenceURI, overrideProfile.get() ); 00322 00323 if ( _tileSource->isOK() ) 00324 { 00325 _tileSize = _tileSource->getPixelsPerTile(); 00326 } 00327 else 00328 { 00329 OE_WARN << "Could not initialize TileSource for layer " << getName() << std::endl; 00330 _tileSource = NULL; 00331 } 00332 } 00333 00334 // Set the cache format to the native format of the TileSource if it isn't already set. 00335 if ( _runtimeOptions->cacheFormat()->empty() ) 00336 { 00337 _runtimeOptions->cacheFormat() = suggestCacheFormat(); 00338 _cacheSpec = CacheSpec( _cacheSpec.cacheId(), *_runtimeOptions->cacheFormat(), _cacheSpec.name() ); 00339 } 00340 00341 // Set the profile from the TileSource if possible: 00342 if ( _tileSource.valid() ) 00343 { 00344 _profile = _tileSource->getProfile(); 00345 } 00346 00347 // Otherwise, force cache-only mode (since there is no tilesource). The layer will try to 00348 // establish a profile from the metadata in the cache instead. 00349 else if (_cache.valid()) 00350 { 00351 OE_NOTICE << "Could not initialize TileSource " << _name << " but cache is valid. Setting layer to cache_only." << std::endl; 00352 _runtimeOptions->cacheOnly() = true; 00353 } 00354 00355 // check the environment to see if cache only should be enabled 00356 if ( _runtimeOptions->cacheOnly() == false && ::getenv("OSGEARTH_CACHE_ONLY") != 0 ) 00357 { 00358 _runtimeOptions->cacheOnly() = true; 00359 OE_INFO << "CACHE-ONLY mode enabled!!" << std::endl; 00360 } 00361 00362 _tileSourceInitialized = true; 00363 } 00364 00365 bool 00366 TerrainLayer::isKeyValid(const TileKey& key) const 00367 { 00368 if (!key.valid()) return false; 00369 00370 // Check to see if explicit levels of detail are set 00371 if ( _runtimeOptions->minLevel().isSet() && (int)key.getLevelOfDetail() < _runtimeOptions->minLevel().value() ) 00372 return false; 00373 if ( _runtimeOptions->maxLevel().isSet() && (int)key.getLevelOfDetail() > _runtimeOptions->maxLevel().value() ) 00374 return false; 00375 00376 // Check to see if levels of detail based on resolution are set 00377 if ( _runtimeOptions->minLevelResolution().isSet() ) 00378 { 00379 unsigned int minLevel = getProfile()->getLevelOfDetailForHorizResolution( 00380 _runtimeOptions->minLevelResolution().value(), getTileSize() ); 00381 OE_DEBUG << "Computed min level of " << minLevel << std::endl; 00382 if (key.getLevelOfDetail() < minLevel) return false; 00383 } 00384 00385 if (_runtimeOptions->maxLevelResolution().isSet()) 00386 { 00387 unsigned int maxLevel = getProfile()->getLevelOfDetailForHorizResolution( 00388 _runtimeOptions->maxLevelResolution().value(), getTileSize() ); 00389 OE_DEBUG << "Computed max level of " << maxLevel << std::endl; 00390 if (key.getLevelOfDetail() > maxLevel) return false; 00391 } 00392 00393 return true; 00394 } 00395 00396 void 00397 TerrainLayer::setEnabled( bool value ) 00398 { 00399 _runtimeOptions->enabled() = value; 00400 fireCallback( &TerrainLayerCallback::onEnabledChanged ); 00401 } 00402 00403 void 00404 TerrainLayer::setReferenceURI( const std::string& uri ) 00405 { 00406 _referenceURI = uri; 00407 } 00408 00409 void 00410 TerrainLayer::setCacheOnly( bool value ) 00411 { 00412 _runtimeOptions->cacheOnly() = value; 00413 }