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