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 00020 #include <osgEarth/Registry> 00021 #include <osgEarth/TileSource> 00022 #include <osgEarth/HTTPClient> 00023 #include <osgEarth/FileUtils> 00024 #include <osgEarth/ThreadingUtils> 00025 00026 #include <osg/Notify> 00027 #include <osg/io_utils> 00028 #include <osg/Version> 00029 #include <osgTerrain/Terrain> 00030 00031 #include <osgDB/FileNameUtils> 00032 #include <osgDB/FileUtils> 00033 #include <osgDB/Registry> 00034 #include <osgDB/ReadFile> 00035 #include <osgDB/WriteFile> 00036 00037 #include <sstream> 00038 00039 #include "VPBOptions" 00040 00041 #define LC "[VPB] " 00042 00043 using namespace osgEarth; 00044 using namespace osgEarth::Drivers; 00045 00046 //#define PROPERTY_URL "url" 00047 //#define PROPERTY_PRIMARY_SPLIT_LEVEL "primary_split_level" 00048 //#define PROPERTY_SECONDARY_SPLIT_LEVEL "secondary_split_level" 00049 //#define PROPERTY_DIRECTORY_STRUCTURE "directory_structure" 00050 //#define PROPERTY_LAYER_NUM "layer" 00051 //#define PROPERTY_NUM_TILES_WIDE_AT_LOD0 "num_tiles_wide_at_lod0" 00052 //#define PROPERTY_NUM_TILES_HIGH_AT_LOD0 "num_tiles_high_at_lod0" 00053 //#define PROPERTY_BASE_NAME "base_name" 00054 00055 00056 class CollectTiles : public osg::NodeVisitor 00057 { 00058 public: 00059 00060 CollectTiles(): 00061 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) 00062 { 00063 } 00064 00065 void reset() 00066 { 00067 _terrainTiles.clear(); 00068 } 00069 00070 void apply(osg::Group& group) 00071 { 00072 osgTerrain::TerrainTile* terrainTile = dynamic_cast<osgTerrain::TerrainTile*>(&group); 00073 if (terrainTile) 00074 { 00075 OE_DEBUG<<"VPB: Found terrain tile TileID("<< 00076 TileKey::getLOD(terrainTile->getTileID())<<", "<< 00077 terrainTile->getTileID().x<<", "<< 00078 terrainTile->getTileID().y<<")"<<std::endl; 00079 00080 _terrainTiles.push_back(terrainTile); 00081 } 00082 else 00083 { 00084 traverse(group); 00085 } 00086 } 00087 00088 osgTerrain::Locator* getLocator() 00089 { 00090 for(unsigned int i=0; i<_terrainTiles.size(); ++i) 00091 { 00092 osgTerrain::TerrainTile* tile = _terrainTiles[i].get(); 00093 osgTerrain::Locator* locator = tile->getLocator(); 00094 if (locator) return locator; 00095 } 00096 return 0; 00097 } 00098 00099 bool getRange(double& min_x, double& min_y, double& max_x, double& max_y) const 00100 { 00101 min_x = DBL_MAX; 00102 max_x = -DBL_MAX; 00103 min_y = DBL_MAX; 00104 max_y = -DBL_MAX; 00105 00106 typedef std::vector<osg::Vec3d> Corners; 00107 Corners corners; 00108 corners.push_back(osg::Vec3d(0.0f,0.0f,0.0f)); 00109 corners.push_back(osg::Vec3d(1.0f,0.0f,0.0f)); 00110 corners.push_back(osg::Vec3d(1.0f,1.0f,0.0f)); 00111 corners.push_back(osg::Vec3d(1.0f,1.0f,0.0f)); 00112 00113 for(unsigned int i=0; i<_terrainTiles.size(); ++i) 00114 { 00115 osgTerrain::TerrainTile* tile = _terrainTiles[i].get(); 00116 osgTerrain::Locator* locator = tile->getLocator(); 00117 if (locator) 00118 { 00119 for(Corners::iterator itr = corners.begin(); 00120 itr != corners.end(); 00121 ++itr) 00122 { 00123 osg::Vec3d& local = *itr; 00124 osg::Vec3d projected = local * locator->getTransform(); 00125 00126 if (projected.x()<min_x) min_x = projected.x(); 00127 if (projected.x()>max_x) max_x = projected.x(); 00128 00129 if (projected.y()<min_y) min_y = projected.y(); 00130 if (projected.y()>max_y) max_y = projected.y(); 00131 } 00132 } 00133 } 00134 00135 return min_x <= max_x; 00136 } 00137 00138 typedef std::vector< osg::ref_ptr<osgTerrain::TerrainTile> > TerrainTiles; 00139 TerrainTiles _terrainTiles; 00140 }; 00141 00142 00143 class VPBDatabase : public osg::Referenced 00144 { 00145 public: 00146 VPBDatabase( const VPBOptions& in_options ) : 00147 _options( in_options ), 00148 //_directory_structure( FLAT_TASK_DIRECTORIES ), 00149 _profile( osgEarth::Registry::instance()->getGlobalGeodeticProfile() ), 00150 _maxNumTilesInCache( 128 ), 00151 _initialized( false ) 00152 { 00153 } 00154 00155 void initialize( const std::string& referenceURI) 00156 { 00157 Threading::ScopedMutexLock lock( _initializeMutex ); 00158 00159 if ( _initialized ) 00160 return; 00161 00162 unsigned int numTilesWideAtLod0, numTilesHighAtLod0; 00163 _profile->getNumTiles(0, numTilesWideAtLod0, numTilesHighAtLod0); 00164 00165 // validate dataset 00166 _url = _options.url().value(); 00167 00168 if ( !_url.empty() ) 00169 { 00170 //If the path doesn't contain a server address, get the full path to the file. 00171 if (!osgDB::containsServerAddress( *_url )) 00172 { 00173 //todo: obselete..? 00174 _url = URI(_url.full(), referenceURI); 00175 //_url = osgEarth::getFullPath(referenceURI, _url); 00176 } 00177 00178 osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions = new osgDB::ReaderWriter::Options; 00179 localOptions->setPluginData("osgearth_vpb Plugin",(void*)(1)); 00180 //_rootNode = osgDB::readNodeFile( _url, localOptions.get() ); 00181 00182 HTTPClient::ResultCode rc = HTTPClient::readNodeFile( _url.full(), _rootNode, localOptions.get() ); 00183 00184 if ( rc == HTTPClient::RESULT_OK && _rootNode.valid() ) 00185 { 00186 _baseNameToUse = _options.baseName().value(); 00187 00188 _path = osgDB::getFilePath( *_url ); 00189 if ( _baseNameToUse.empty() ) 00190 _baseNameToUse = osgDB::getStrippedName( *_url ); 00191 _extension = osgDB::getFileExtension( *_url ); 00192 00193 OE_INFO << LC << "Loaded root "<< _url.full() <<", path="<<_path<<" base_name="<<_baseNameToUse<<" extension="<<_extension<<std::endl; 00194 00195 std::string srs = _profile->getSRS()->getInitString(); //.srs(); 00196 00197 osg::CoordinateSystemNode* csn = dynamic_cast<osg::CoordinateSystemNode*>(_rootNode.get()); 00198 if (csn) 00199 { 00200 OE_INFO << LC << "CSN found: "<<csn->getCoordinateSystem()<<std::endl; 00201 00202 srs = csn->getCoordinateSystem(); 00203 } 00204 00205 CollectTiles ct; 00206 _rootNode->accept(ct); 00207 00208 00209 osgTerrain::Locator* locator = ct.getLocator(); 00210 if (locator) 00211 { 00212 double min_x, max_x, min_y, max_y; 00213 ct.getRange(min_x, min_y, max_x, max_y); 00214 00215 OE_DEBUG << LC << "range("<<min_x<<", "<<min_y<<", "<<max_x<<", "<<max_y<< ")" <<std::endl; 00216 OE_DEBUG << LC << "range("<<osg::RadiansToDegrees(min_x)<<", "<<osg::RadiansToDegrees(min_y)<<", " 00217 <<osg::RadiansToDegrees(max_x)<<", "<<osg::RadiansToDegrees(max_y)<< ")" <<std::endl; 00218 00219 srs = locator->getCoordinateSystem(); 00220 00221 double aspectRatio = (max_x-min_x)/(max_y-min_y); 00222 00223 OE_DEBUG << LC << "aspectRatio = "<<aspectRatio<<std::endl; 00224 00225 if (aspectRatio>1.0) 00226 { 00227 numTilesWideAtLod0 = static_cast<unsigned int>(floor(aspectRatio+0.499999)); 00228 numTilesHighAtLod0 = 1; 00229 } 00230 else 00231 { 00232 numTilesWideAtLod0 = 1; 00233 numTilesHighAtLod0 = static_cast<unsigned int>(floor(1.0/aspectRatio+0.499999)); 00234 } 00235 00236 OE_DEBUG << LC << "computed numTilesWideAtLod0 = "<<numTilesWideAtLod0<<std::endl; 00237 OE_DEBUG << LC << "computed numTilesHightAtLod0 = "<<numTilesHighAtLod0<<std::endl; 00238 00239 //if ( _options.valid() ) 00240 { 00241 if ( _options.numTilesWideAtLod0().isSet() ) 00242 numTilesWideAtLod0 = _options.numTilesWideAtLod0().value(); 00243 00244 if ( _options.numTilesHighAtLod0().isSet() ) 00245 numTilesHighAtLod0 = _options.numTilesHighAtLod0().value(); 00246 } 00247 00248 OE_DEBUG << LC << "final numTilesWideAtLod0 = "<<numTilesWideAtLod0<<std::endl; 00249 OE_DEBUG << LC << "final numTilesHightAtLod0 = "<<numTilesHighAtLod0<<std::endl; 00250 00251 _profile = osgEarth::Profile::create( 00252 srs, 00253 osg::RadiansToDegrees(min_x), 00254 osg::RadiansToDegrees(min_y), 00255 osg::RadiansToDegrees(max_x), 00256 osg::RadiansToDegrees(max_y), 00257 "", 00258 numTilesWideAtLod0, 00259 numTilesHighAtLod0 ); 00260 } 00261 00262 } 00263 else 00264 { 00265 OE_WARN << LC << HTTPClient::getResultCodeString(rc) << ": " << *_url << std::endl; 00266 _url = URI(); 00267 } 00268 } 00269 else 00270 { 00271 OE_WARN<<"VPB: No data referenced "<<std::endl; 00272 } 00273 00274 _initialized = true; 00275 } 00276 00277 std::string createTileName( int level, int tile_x, int tile_y ) 00278 { 00279 std::stringstream buf; 00280 if ( _options.directoryStructure() == VPBOptions::DS_FLAT ) 00281 { 00282 buf<<_path<<"/"<<_baseNameToUse<<"_L"<<level<<"_X"<<tile_x/2<<"_Y"<<tile_y/2<<"_subtile."<<_extension; 00283 } 00284 else 00285 { 00286 int psl = _options.primarySplitLevel().value(); 00287 int ssl = _options.secondarySplitLevel().value(); 00288 00289 if (level<psl) 00290 { 00291 buf<<_path<<"/"<<_baseNameToUse<<"_root_L0_X0_Y0/"<< 00292 _baseNameToUse<<"_L"<<level<<"_X"<<tile_x/2<<"_Y"<<tile_y/2<<"_subtile."<<_extension; 00293 00294 } 00295 else if (level<ssl) 00296 { 00297 tile_x /= 2; 00298 tile_y /= 2; 00299 00300 int split_x = tile_x >> (level - psl); 00301 int split_y = tile_y >> (level - psl); 00302 00303 buf<<_path<<"/"<<_baseNameToUse<<"_subtile_L"<<psl<<"_X"<<split_x<<"_Y"<<split_y<<"/"<< 00304 _baseNameToUse<<"_L"<<level<<"_X"<<tile_x<<"_Y"<<tile_y<<"_subtile."<<_extension; 00305 } 00306 else if ( _options.directoryStructure() == VPBOptions::DS_TASK ) 00307 { 00308 tile_x /= 2; 00309 tile_y /= 2; 00310 00311 int split_x = tile_x >> (level - psl); 00312 int split_y = tile_y >> (level - psl); 00313 00314 int secondary_split_x = tile_x >> (level - ssl); 00315 int secondary_split_y = tile_y >> (level - ssl); 00316 00317 buf<<_path<<"/"<<_baseNameToUse<<"_subtile_L"<<psl<<"_X"<<split_x<<"_Y"<<split_y<<"/"<< 00318 _baseNameToUse<<"_subtile_L"<<ssl<<"_X"<<secondary_split_x<<"_Y"<<secondary_split_y<<"/"<< 00319 _baseNameToUse<<"_L"<<level<<"_X"<<tile_x<<"_Y"<<tile_y<<"_subtile."<<_extension; 00320 } 00321 else 00322 { 00323 tile_x /= 2; 00324 tile_y /= 2; 00325 00326 int split_x = tile_x >> (level - ssl); 00327 int split_y = tile_y >> (level - ssl); 00328 00329 buf<<_path<<"/"<<_baseNameToUse<<"_subtile_L"<<ssl<<"_X"<<split_x<<"_Y"<<split_y<<"/"<< 00330 _baseNameToUse<<"_L"<<level<<"_X"<<tile_x<<"_Y"<<tile_y<<"_subtile."<<_extension; 00331 } 00332 } 00333 00334 std::string bufStr; 00335 bufStr = buf.str(); 00336 OE_DEBUG<<"VPB: VPBDatabase::createTileName(), buf.str()=="<< bufStr <<std::endl; 00337 00338 return bufStr; 00339 } 00340 00341 void getTerrainTile( const TileKey& key, ProgressCallback* progress, osg::ref_ptr<osgTerrain::TerrainTile>& out_tile ) 00342 { 00343 int level = key.getLevelOfDetail(); 00344 unsigned int tile_x, tile_y; 00345 key.getTileXY( tile_x, tile_y ); 00346 00347 //int max_x = (2 << level) - 1; 00348 int max_y = (1 << level) - 1; 00349 00350 tile_y = max_y - tile_y; 00351 00352 osgTerrain::TileID tileID(level, tile_x, tile_y); 00353 00354 findTile(tileID, false, out_tile); 00355 if (out_tile.valid()) 00356 return; 00357 00358 std::string filename = createTileName(level, tile_x, tile_y); 00359 00360 bool foundInBlacklist = false; 00361 { 00362 Threading::ScopedReadLock sharedLock( _blacklistMutex ); 00363 foundInBlacklist = _blacklistedFilenames.count(filename) == 1; 00364 } 00365 if ( foundInBlacklist ) 00366 { 00367 OE_DEBUG << LC << "file has been found in black list : "<<filename<<std::endl; 00368 insertTile(tileID, 0); 00369 return; //return 0; 00370 } 00371 00372 // OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_blacklistMutex); 00373 // if (_blacklistedFilenames.count(filename)==1) 00374 // { 00375 // OE_DEBUG<<"VPB: file has been found in black list : "<<filename<<std::endl; 00376 // insertTile(tileID, 0); 00377 // return 0; 00378 // } 00379 //} 00380 00381 00382 osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions = new osgDB::ReaderWriter::Options; 00383 localOptions->setPluginData("osgearth_vpb Plugin",(void*)(1)); 00384 00385 00386 //osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filename, localOptions.get()); 00387 osg::ref_ptr<osg::Node> node; 00388 HTTPClient::ResultCode result = HTTPClient::readNodeFile( filename, node, localOptions.get(), progress ); 00389 if ( result == HTTPClient::RESULT_OK && node.valid() ) 00390 { 00391 //OE_INFO << LC << "Loaded model "<<filename<<std::endl; 00392 CollectTiles ct; 00393 node->accept(ct); 00394 00395 int base_x = (tile_x / 2) * 2; 00396 int base_y = (tile_y / 2) * 2; 00397 00398 double min_x, max_x, min_y, max_y; 00399 ct.getRange(min_x, min_y, max_x, max_y); 00400 00401 double center_x = (min_x + max_x)*0.5; 00402 double center_y = (min_y + max_y)*0.5; 00403 00404 osg::Vec3d local(0.5,0.5,0.0); 00405 for(unsigned int i=0; i<ct._terrainTiles.size(); ++i) 00406 { 00407 osgTerrain::TerrainTile* tile = ct._terrainTiles[i].get(); 00408 osgTerrain::Locator* locator = tile->getLocator(); 00409 if (locator) 00410 { 00411 osg::Vec3d projected = local * locator->getTransform(); 00412 00413 int local_x = base_x + ((projected.x() > center_x) ? 1 : 0); 00414 int local_y = base_y + ((projected.y() > center_y) ? 1 : 0); 00415 osgTerrain::TileID local_tileID(level, local_x, local_y); 00416 00417 tile->setTileID(local_tileID); 00418 insertTile(local_tileID, tile); 00419 00420 if ( local_tileID == tileID ) 00421 out_tile = tile; 00422 } 00423 00424 } 00425 00426 } 00427 else 00428 { 00429 // in the case of an "unrecoverable" error, black-list the URL for this tile. 00430 if ( ! HTTPClient::isRecoverable( result ) ) 00431 { 00432 Threading::ScopedWriteLock exclusiveLock( _blacklistMutex ); 00433 _blacklistedFilenames.insert( filename ); 00434 } 00435 } 00436 00437 //TODO: just return it instead... 00438 //findTile(tileID, false, out_tile); 00439 } 00440 00441 void insertTile(const osgTerrain::TileID& tileID, osgTerrain::TerrainTile* tile) 00442 { 00443 Threading::ScopedWriteLock exclusiveLock( _tileMapMutex ); 00444 00445 if ( _tileMap.find(tileID) == _tileMap.end() ) 00446 { 00447 _tileMap[tileID] = tile; 00448 00449 _tileFIFO.push_back(tileID); 00450 00451 if (_tileFIFO.size() > _maxNumTilesInCache) 00452 { 00453 osgTerrain::TileID tileToRemove = _tileFIFO.front(); 00454 _tileFIFO.pop_front(); 00455 _tileMap.erase(tileToRemove); 00456 00457 OE_DEBUG << LC << "Pruned tileID ("<<TileKey::getLOD(tileID)<<", "<<tileID.x<<", "<<tileID.y<<")"<<std::endl; 00458 } 00459 00460 OE_DEBUG << LC << "insertTile (" 00461 << TileKey::getLOD(tileID)<<", "<<tileID.x<<", "<<tileID.y<<") " 00462 << " tileFIFO.size()=="<<_tileFIFO.size()<<std::endl; 00463 } 00464 else 00465 { 00466 OE_DEBUG << LC << "insertTile (" 00467 << TileKey::getLOD(tileID)<<", "<<tileID.x<<", "<<tileID.y<<") " 00468 << " ...already in cache!"<<std::endl; 00469 } 00470 } 00471 00472 void findTile(const osgTerrain::TileID& tileID, bool insertBlankTileIfNotFound, osg::ref_ptr<osgTerrain::TerrainTile>& out_tile) 00473 { 00474 // read with a shared lock 00475 { 00476 Threading::ScopedReadLock sharedLock( _tileMapMutex ); 00477 TileMap::iterator itr = _tileMap.find(tileID); 00478 if (itr != _tileMap.end()) 00479 out_tile = itr->second.get(); 00480 } 00481 00482 // upgrade lock and write: 00483 if (insertBlankTileIfNotFound) 00484 insertTile(tileID, 0); 00485 00486 //return 0; 00487 } 00488 00489 const VPBOptions _options; 00490 URI _url; 00491 std::string _path; 00492 std::string _extension; 00493 00494 std::string _baseNameToUse; 00495 00496 osg::ref_ptr<const Profile> _profile; 00497 osg::ref_ptr<osg::Node> _rootNode; 00498 00499 unsigned int _maxNumTilesInCache; 00500 00501 typedef std::map<osgTerrain::TileID, osg::ref_ptr<osgTerrain::TerrainTile> > TileMap; 00502 TileMap _tileMap; 00503 Threading::ReadWriteMutex _tileMapMutex; 00504 00505 typedef std::list<osgTerrain::TileID> TileIDList; 00506 TileIDList _tileFIFO; 00507 00508 typedef std::set<std::string> StringSet; 00509 StringSet _blacklistedFilenames; 00510 Threading::ReadWriteMutex _blacklistMutex; 00511 00512 bool _initialized; 00513 Threading::Mutex _initializeMutex; 00514 00515 }; 00516 00517 class VPBSource : public TileSource 00518 { 00519 public: 00520 VPBSource( VPBDatabase* vpbDatabase, const VPBOptions& in_options ) : 00521 TileSource(in_options), 00522 _vpbDatabase(vpbDatabase), 00523 _options( in_options ), 00524 _referenceUri() 00525 { 00526 //nop 00527 } 00528 00529 void initialize( const std::string& referenceURI, const Profile* overrideProfile) 00530 { 00531 _referenceUri = referenceURI; 00532 00533 _vpbDatabase->initialize(referenceURI); 00534 00535 if ( overrideProfile) 00536 { 00537 setProfile( overrideProfile ); 00538 } 00539 else 00540 { 00541 setProfile(_vpbDatabase->_profile.get()); 00542 } 00543 } 00544 00545 osg::Image* createImage( const TileKey& key, ProgressCallback* progress) 00546 { 00547 osg::Image * ret = NULL; 00548 //TODO: Make VPB driver use progress callback 00549 osg::ref_ptr<osgTerrain::TerrainTile> tile; 00550 _vpbDatabase->getTerrainTile(key, progress, tile); 00551 if (tile.valid()) 00552 { 00553 int layerNum = _options.layer().value(); 00554 const optional<std::string> & layerSetName = _options.layerSetName(); 00555 00556 int numColorLayers = (int)tile->getNumColorLayers(); 00557 if(layerNum > numColorLayers) 00558 layerNum = 0; 00559 if (layerNum < numColorLayers) 00560 { 00561 osgTerrain::Layer* layer = tile->getColorLayer(layerNum); 00562 00563 osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(layer); 00564 if (imageLayer) 00565 { 00566 OE_DEBUG << LC << "createImage(" << key.str() << " layerNum=" << layerNum << ") successful." <<std::endl; 00567 ret = new osg::Image( *imageLayer->getImage() ); 00568 } 00569 else 00570 { 00571 osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(layer); 00572 if (switchLayer && layerSetName.isSet()) 00573 { 00574 for(unsigned int si=0; !imageLayer && si<switchLayer->getNumLayers(); ++si) 00575 { 00576 if(switchLayer->getSetName(si) == layerSetName.value()) 00577 { 00578 imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(switchLayer->getLayer(si)); 00579 } 00580 } 00581 } 00582 if(imageLayer) 00583 { 00584 OE_DEBUG << LC << "createImage(" << key.str() << " layerSet=" << layerSetName.value() << ") successful." <<std::endl; 00585 ret = new osg::Image( *imageLayer->getImage() ); 00586 } 00587 } 00588 } 00589 if(!ret) 00590 { 00591 OE_DEBUG << LC << "createImage(" << key.str() << " layerSet=" << layerSetName.value() << " layerNum=" << layerNum << "/" << numColorLayers << ") failed." <<std::endl; 00592 } 00593 } 00594 else 00595 { 00596 OE_DEBUG << LC << "createImage(" << key.str() << ") database retrieval failed." <<std::endl; 00597 } 00598 return ret; 00599 } 00600 00601 osg::HeightField* createHeightField( const TileKey& key, 00602 ProgressCallback* progress 00603 ) 00604 { 00605 osg::ref_ptr<osgTerrain::TerrainTile> tile; 00606 _vpbDatabase->getTerrainTile(key, progress, tile); 00607 if (tile.valid()) 00608 { 00609 osgTerrain::Layer* elevationLayer = tile->getElevationLayer(); 00610 osgTerrain::HeightFieldLayer* hfLayer = dynamic_cast<osgTerrain::HeightFieldLayer*>(elevationLayer); 00611 if (hfLayer) 00612 { 00613 //return hfLayer->getHeightField(); 00614 return new osg::HeightField(*hfLayer->getHeightField()); 00615 } 00616 } 00617 00618 return 0; 00619 } 00620 00621 virtual std::string getExtension() const 00622 { 00623 //All VPB tiles are in IVE format 00624 return _vpbDatabase->_extension; 00625 } 00626 00627 private: 00628 osg::ref_ptr<VPBDatabase> _vpbDatabase; 00629 const VPBOptions _options; 00630 std::string _referenceUri; 00631 }; 00632 00633 00634 class VPBSourceFactory : public TileSourceDriver 00635 { 00636 public: 00637 VPBSourceFactory() 00638 { 00639 supportsExtension( "osgearth_vpb", "VirtualPlanetBuilder data" ); 00640 } 00641 00642 virtual const char* className() 00643 { 00644 return "VirtualPlanetBuilder ReaderWriter"; 00645 } 00646 00647 virtual ReadResult readObject(const std::string& file_name, const Options* options) const 00648 { 00649 if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name ))) 00650 return ReadResult::FILE_NOT_HANDLED; 00651 00652 VPBOptions vpbOptions( getTileSourceOptions(options) ); 00653 00654 URI url = vpbOptions.url().value(); 00655 if ( !url.empty() ) 00656 { 00657 OpenThreads::ScopedLock<OpenThreads::Mutex> lock(vpbDatabaseMapMutex); 00658 osg::observer_ptr<VPBDatabase>& db_ptr = vpbDatabaseMap[*url]; //get or create 00659 00660 if (!db_ptr) db_ptr = new VPBDatabase( vpbOptions ); 00661 00662 if (db_ptr.valid()) 00663 return new VPBSource( db_ptr.get(), vpbOptions ); 00664 else 00665 return ReadResult::FILE_NOT_FOUND; 00666 } 00667 else 00668 { 00669 return ReadResult::FILE_NOT_HANDLED; 00670 } 00671 } 00672 00673 typedef std::map<std::string, osg::observer_ptr<VPBDatabase> > VPBDatabaseMap; 00674 mutable OpenThreads::Mutex vpbDatabaseMapMutex; 00675 mutable VPBDatabaseMap vpbDatabaseMap; 00676 }; 00677 00678 REGISTER_OSGPLUGIN(osgearth_vpb, VPBSourceFactory) 00679