Config EarthFileSerializer2::serialize( MapNode* input ) const { Config mapConf("map"); mapConf.attr("version") = "2"; if ( !input || !input->getMap() ) return mapConf; Map* map = input->getMap(); MapFrame mapf( map, Map::ENTIRE_MODEL ); // the map and node options: Config optionsConf = map->getMapOptions().getConfig(); optionsConf.merge( input->getMapNodeOptions().getConfig() ); mapConf.add( "options", optionsConf ); // the layers for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); Config layerConf = layer->getImageLayerOptions().getConfig(); layerConf.attr("name") = layer->getName(); layerConf.attr("driver") = layer->getImageLayerOptions().driver()->getDriver(); mapConf.add( "image", layerConf ); } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); ++i ) { ElevationLayer* layer = i->get(); Config layerConf = layer->getElevationLayerOptions().getConfig(); layerConf.attr("name") = layer->getName(); layerConf.attr("driver") = layer->getElevationLayerOptions().driver()->getDriver(); mapConf.add( "elevation", layerConf ); } for( ModelLayerVector::const_iterator i = mapf.modelLayers().begin(); i != mapf.modelLayers().end(); ++i ) { ModelLayer* layer = i->get(); Config layerConf = layer->getModelLayerOptions().getConfig(); //layer->getDriverConfig(); layerConf.attr("name") = layer->getName(); //layerConf.attr("driver") = layer->getDriverConfig().value("driver"); layerConf.attr("driver") = layer->getModelLayerOptions().driver()->getDriver(); mapConf.add( "model", layerConf ); } Config ext = input->externalConfig(); if ( !ext.empty() ) { ext.key() = "external"; mapConf.addChild( ext ); } return mapConf; }
void TerrainEngineNode::updateImageUniforms() { // don't bother if this is a hurting old card if ( !Registry::instance()->getCapabilities().supportsGLSL() ) return; // update the layer uniform arrays: osg::StateSet* stateSet = this->getOrCreateStateSet(); // get a copy of the image layer stack: MapFrame mapf( _map.get(), Map::IMAGE_LAYERS ); _imageLayerController->_layerVisibleUniform.detach(); _imageLayerController->_layerOpacityUniform.detach(); _imageLayerController->_layerRangeUniform.detach(); if ( mapf.imageLayers().size() > 0 ) { // the "enabled" uniform is fixed size. this is handy to account for layers that are in flux...i.e., their source // layer count has changed, but the shader has not yet caught up. In the future we might use this to disable // "ghost" layers that used to exist at a given index, but no longer do. _imageLayerController->_layerVisibleUniform.attach( "osgearth_ImageLayerVisible", osg::Uniform::BOOL, stateSet, MAX_IMAGE_LAYERS ); _imageLayerController->_layerOpacityUniform.attach( "osgearth_ImageLayerOpacity", osg::Uniform::FLOAT, stateSet, mapf.imageLayers().size() ); _imageLayerController->_layerRangeUniform.attach ( "osgearth_ImageLayerRange", osg::Uniform::FLOAT, stateSet, 2 * mapf.imageLayers().size() ); for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); int index = (int)(i - mapf.imageLayers().begin()); _imageLayerController->_layerVisibleUniform.setElement( index, layer->getVisible() ); _imageLayerController->_layerOpacityUniform.setElement( index, layer->getOpacity() ); _imageLayerController->_layerRangeUniform.setElement( (2*index), layer->getImageLayerOptions().minVisibleRange().value() ); _imageLayerController->_layerRangeUniform.setElement( (2*index)+1, layer->getImageLayerOptions().maxVisibleRange().value() ); } // set the remainder of the layers to disabled for( int j=mapf.imageLayers().size(); j<_imageLayerController->_layerVisibleUniform.getNumElements(); ++j) { _imageLayerController->_layerVisibleUniform.setElement( j, false ); } } dirty(); }
/** Packages an image layer as a TMS folder. */ int makeTMS( osg::ArgumentParser& args ) { // see if the user wants to override the type extension (imagery only) std::string extension; args.read( "--ext", extension ); // verbosity? bool verbose = !args.read( "--quiet" ); // find a .earth file on the command line std::string earthFile = findArgumentWithExtension( args, ".earth" ); /* if ( earthFile.empty() ) return usage( "Missing required .earth file" ); */ // folder to which to write the TMS archive. std::string rootFolder; if( !args.read( "--out", rootFolder ) ) rootFolder = Stringify() << earthFile << ".tms_repo"; // whether to overwrite existing tile files bool overwrite = false; if( args.read( "--overwrite" ) ) overwrite = true; // write out an earth file std::string outEarth; args.read( "--out-earth", outEarth ); std::string dbOptions; args.read( "--db-options", dbOptions ); std::string::size_type n = 0; while( (n = dbOptions.find( '"', n )) != dbOptions.npos ) { dbOptions.erase( n, 1 ); } osg::ref_ptr<osgDB::Options> options = new osgDB::Options( dbOptions ); std::vector< Bounds > bounds; // restrict packaging to user-specified bounds. double xmin = DBL_MAX, ymin = DBL_MAX, xmax = DBL_MIN, ymax = DBL_MIN; while( args.read( "--bounds", xmin, ymin, xmax, ymax ) ) { Bounds b; b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax; bounds.push_back( b ); } // max level to which to generate unsigned maxLevel = ~0; args.read( "--max-level", maxLevel ); // whether to keep 'empty' tiles bool keepEmpties = args.read( "--keep-empties" ); bool continueSingleColor = args.read( "--continue-single-color" ); // max level to which to generate unsigned elevationPixelDepth = 32; args.read( "--elevation-pixel-depth", elevationPixelDepth ); // load up the map osg::ref_ptr<MapNode> mapNode = MapNode::load( args ); if( !mapNode.valid() ) return usage( "Failed to load a valid .earth file" ); // create a folder for the output osgDB::makeDirectory( rootFolder ); if( !osgDB::fileExists( rootFolder ) ) return usage( "Failed to create root output folder" ); Map* map = mapNode->getMap(); // fire up a packager: TMSPackager packager( map->getProfile(), options ); packager.setVerbose( verbose ); packager.setOverwrite( overwrite ); packager.setKeepEmptyImageTiles( keepEmpties ); packager.setSubdivideSingleColorImageTiles( continueSingleColor ); packager.setElevationPixelDepth( elevationPixelDepth ); if( maxLevel != ~0 ) packager.setMaxLevel( maxLevel ); if( bounds.size() > 0 ) { for( unsigned int i = 0; i < bounds.size(); ++i ) { Bounds b = bounds[i]; if( b.isValid() ) packager.addExtent( GeoExtent( map->getProfile()->getSRS(), b ) ); } } // new map for an output earth file if necessary. osg::ref_ptr<Map> outMap = 0L; if( !outEarth.empty() ) { // copy the options from the source map first outMap = new Map( map->getInitialMapOptions() ); } // establish the output path of the earth file, if applicable: std::string outEarthFile = osgDB::concatPaths( rootFolder, osgDB::getSimpleFileName( outEarth ) ); // package any image layers that are enabled: ImageLayerVector imageLayers; map->getImageLayers( imageLayers ); unsigned counter = 0; for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter ) { ImageLayer* layer = i->get(); if( layer->getImageLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if( layerFolder.empty() ) layerFolder = Stringify() << "image_layer_" << counter; if( verbose ) { OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl; } osg::ref_ptr< ConsoleProgressCallback > progress = new ConsoleProgressCallback(); std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot, progress, extension ); if( r.ok ) { // save to the output map if requested: if( outMap.valid() ) { // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths( layerFolder, "tms.xml" ), outEarthFile ); ImageLayerOptions layerOptions( layer->getName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addImageLayer( new ImageLayer( layerOptions ) ); } } else { OE_WARN << LC << r.message << std::endl; } } else if( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // package any elevation layers that are enabled: counter = 0; ElevationLayerVector elevationLayers; map->getElevationLayers( elevationLayers ); for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter ) { ElevationLayer* layer = i->get(); if( layer->getElevationLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if( layerFolder.empty() ) layerFolder = Stringify() << "elevation_layer_" << counter; if( verbose ) { OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot ); if( r.ok ) { // save to the output map if requested: if( outMap.valid() ) { // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths( layerFolder, "tms.xml" ), outEarthFile ); ElevationLayerOptions layerOptions( layer->getName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addElevationLayer( new ElevationLayer( layerOptions ) ); } } else { OE_WARN << LC << r.message << std::endl; } } else if( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // Finally, write an earth file if requested: if( outMap.valid() ) { MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions(); osg::ref_ptr<MapNode> outMapNode = new MapNode( outMap.get(), outNodeOptions ); if( !osgDB::writeNodeFile( *outMapNode.get(), outEarthFile ) ) { OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl; } else if( verbose ) { OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl; } } return 0; }
void CacheSeed::seed( Map* map ) { // We must do this to avoid an error message in OpenSceneGraph b/c the findWrapper method doesn't appear to be threadsafe. // This really isn't a big deal b/c this only effects data that is already cached. osgDB::ObjectWrapper* wrapper = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper( "osg::Image" ); osg::Timer_t startTime = osg::Timer::instance()->tick(); if ( !map->getCache() ) { OE_WARN << LC << "Warning: No cache defined; aborting." << std::endl; return; } std::vector<TileKey> keys; map->getProfile()->getRootKeys(keys); //Add the map's entire extent if we don't have one specified. if (_extents.empty()) { addExtent( map->getProfile()->getExtent() ); } bool hasCaches = false; int src_min_level = INT_MAX; unsigned int src_max_level = 0; MapFrame mapf( map, Map::TERRAIN_LAYERS, "CacheSeed::seed" ); //Assumes the the TileSource will perform the caching for us when we call createImage for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ ) { ImageLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ImageLayerOptions& opt = layer->getImageLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if ( !src ) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } //else if ( src->getCachePolicyHint(0L) == CachePolicy::NO_CACHE ) //{ // OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; //} else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); i++ ) { ElevationLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ElevationLayerOptions& opt = layer->getElevationLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if (!src) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } //else if ( src->getCachePolicyHint(0L) == CachePolicy::NO_CACHE ) //{ // OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; //} else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } if ( !hasCaches ) { OE_WARN << LC << "There are either no caches defined in the map, or no sources to cache; aborting." << std::endl; return; } if ( src_max_level > 0 && src_max_level < _maxLevel ) { _maxLevel = src_max_level; } OE_NOTICE << LC << "Maximum cache level will be " << _maxLevel << std::endl; //Estimate the number of tiles _total = 0; CacheEstimator est; est.setMinLevel( _minLevel ); est.setMaxLevel( _maxLevel ); est.setProfile( map->getProfile() ); for (unsigned int i = 0; i < _extents.size(); i++) { est.addExtent( _extents[ i ] ); } _total = est.getNumTiles(); OE_INFO << "Processing ~" << _total << " tiles" << std::endl; // Initialize the operations queue _queue = new osg::OperationQueue; osg::Timer_t endTime = osg::Timer::instance()->tick(); // Start the threads std::vector< osg::ref_ptr< osg::OperationsThread > > threads; for (unsigned int i = 0; i < _numThreads; i++) { osg::OperationsThread* thread = new osg::OperationsThread(); thread->setOperationQueue(_queue.get()); thread->start(); threads.push_back( thread ); } OE_NOTICE << "Startup time " << osg::Timer::instance()->delta_s( startTime, endTime ) << std::endl; // Add the root keys to the queue for (unsigned int i = 0; i < keys.size(); ++i) { //processKey( mapf, keys[i] ); _queue.get()->add( new CacheTileOperation( mapf, *this, keys[i]) ); } bool done = false; while (!done) { OpenThreads::Thread::microSleep(500000); // sleep for half a second done = true; if (_queue->getNumOperationsInQueue() > 0) { done = false; continue; } else { // Make sure no threads are currently working on an operation, which actually might add MORE operations since we are doing a quadtree traversal for (unsigned int i = 0; i < threads.size(); i++) { if (threads[i]->getCurrentOperation()) { done = false; continue; } } } } _total = _completed; if ( _progress.valid()) _progress->reportProgress(_completed, _total, 0, 1, "Finished"); }
void CacheSeed::seed( Map* map ) { if ( !map->getCache() ) { OE_WARN << LC << "Warning: No cache defined; aborting." << std::endl; return; } std::vector<TileKey> keys; map->getProfile()->getRootKeys(keys); //Add the map's entire extent if we don't have one specified. if (_extents.empty()) { addExtent( map->getProfile()->getExtent() ); } bool hasCaches = false; int src_min_level = INT_MAX; unsigned int src_max_level = 0; MapFrame mapf( map, Map::TERRAIN_LAYERS, "CacheSeed::seed" ); //Assumes the the TileSource will perform the caching for us when we call createImage for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ ) { ImageLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ImageLayerOptions& opt = layer->getImageLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if ( !src ) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } //else if ( src->getCachePolicyHint(0L) == CachePolicy::NO_CACHE ) //{ // OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; //} else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); i++ ) { ElevationLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ElevationLayerOptions& opt = layer->getElevationLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if (!src) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } //else if ( src->getCachePolicyHint(0L) == CachePolicy::NO_CACHE ) //{ // OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; //} else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } if ( !hasCaches ) { OE_WARN << LC << "There are either no caches defined in the map, or no sources to cache; aborting." << std::endl; return; } if ( src_max_level > 0 && src_max_level < _maxLevel ) { _maxLevel = src_max_level; } OE_NOTICE << LC << "Maximum cache level will be " << _maxLevel << std::endl; //Estimate the number of tiles _total = 0; CacheEstimator est; est.setMinLevel( _minLevel ); est.setMaxLevel( _maxLevel ); est.setProfile( map->getProfile() ); for (unsigned int i = 0; i < _extents.size(); i++) { est.addExtent( _extents[ i ] ); } _total = est.getNumTiles(); OE_INFO << "Processing ~" << _total << " tiles" << std::endl; for (unsigned int i = 0; i < keys.size(); ++i) { processKey( mapf, keys[i] ); } _total = _completed; if ( _progress.valid()) _progress->reportProgress(_completed, _total, 0, 1, "Finished"); }
Config EarthFileSerializer2::serialize(const MapNode* input, const std::string& referrer) const { Config mapConf("map"); mapConf.set("version", "2"); if ( !input || !input->getMap() ) return mapConf; const Map* map = input->getMap(); MapFrame mapf( map, Map::ENTIRE_MODEL ); // the map and node options: Config optionsConf = map->getInitialMapOptions().getConfig(); optionsConf.merge( input->getMapNodeOptions().getConfig() ); mapConf.add( "options", optionsConf ); // the layers for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); //Config layerConf = layer->getInitialOptions().getConfig(); Config layerConf = layer->getImageLayerOptions().getConfig(); layerConf.set("name", layer->getName()); layerConf.set("driver", layer->getInitialOptions().driver()->getDriver()); mapConf.add( "image", layerConf ); } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); ++i ) { ElevationLayer* layer = i->get(); //Config layerConf = layer->getInitialOptions().getConfig(); Config layerConf = layer->getElevationLayerOptions().getConfig(); layerConf.set("name", layer->getName()); layerConf.set("driver", layer->getInitialOptions().driver()->getDriver()); mapConf.add( "elevation", layerConf ); } for( ModelLayerVector::const_iterator i = mapf.modelLayers().begin(); i != mapf.modelLayers().end(); ++i ) { ModelLayer* layer = i->get(); Config layerConf = layer->getModelLayerOptions().getConfig(); layerConf.set("name", layer->getName()); layerConf.set("driver", layer->getModelLayerOptions().driver()->getDriver()); mapConf.add( "model", layerConf ); } Config ext = input->externalConfig(); if ( !ext.empty() ) { ext.key() = "extensions"; mapConf.add( ext ); } #if 1 // removed until it can be debugged. // Re-write pathnames in the Config so they are relative to the new referrer. if ( _rewritePaths && !referrer.empty() ) { RewritePaths rewritePaths( referrer ); rewritePaths.setRewriteAbsolutePaths( _rewriteAbsolutePaths ); rewritePaths.apply( mapConf ); } #endif return mapConf; }
void TileBuilder::createTile(const TileKey& key, bool parallelize, osg::ref_ptr<Tile>& out_tile, bool& out_hasRealData, bool& out_hasLodBlendedLayers ) { MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS ); SourceRepo repo; // init this to false, then search for real data. "Real data" is data corresponding // directly to the key, as opposed to fallback data, which is derived from a lower // LOD key. out_hasRealData = false; out_hasLodBlendedLayers = false; const MapInfo& mapInfo = mapf.getMapInfo(); // If we need more than one layer, fetch them in parallel. // TODO: change the test based on isKeyValid total. if ( parallelize && (mapf.imageLayers().size() + mapf.elevationLayers().size() > 1) ) { // count the valid layers. int jobCount = 0; for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { if ( i->get()->isKeyValid( key ) ) ++jobCount; if ( i->get()->getImageLayerOptions().lodBlending() == true ) out_hasLodBlendedLayers = true; } if ( mapf.elevationLayers().size() > 0 ) ++jobCount; // A thread job monitoring event: Threading::MultiEvent semaphore( jobCount ); // Start the image layer jobs: for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->isKeyValid(key) ) { ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore ); j->init( key, layer, mapInfo, _terrainOptions, repo ); j->setPriority( -(float)key.getLevelOfDetail() ); _service->add( j ); } } // If we have elevation layers, start an elevation job as well. Otherwise just create an // empty one while we're waiting for the images to load. if ( mapf.elevationLayers().size() > 0 ) { ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore ); ej->init( key, mapf, _terrainOptions, repo ); ej->setPriority( -(float)key.getLevelOfDetail() ); _service->add( ej ); } else { BuildElevLayer build; build.init( key, mapf, _terrainOptions, repo ); build.execute(); } // Wait for all the jobs to finish. semaphore.wait(); } // Fetch the image data serially: else { // gather all the image layers serially. for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); //if ( layer->isKeyValid(key) ) // Wrong. no guarantee key is in the same profile. if ( layer->getEnabled() ) { BuildColorLayer build; build.init( key, layer, mapInfo, _terrainOptions, repo ); build.execute(); if ( layer->getImageLayerOptions().lodBlending() == true ) out_hasLodBlendedLayers = true; } } // make an elevation layer. BuildElevLayer build; build.init( key, mapf, _terrainOptions, repo ); build.execute(); } // Bail out now if there's no data to be had. if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one. if ( !repo._elevLayer.getHFLayer() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 ); //osg::HeightField* hf = key.getProfile()->getVerticalSRS()->createReferenceHeightField( key.getExtent(), 8, 8 ); osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf ); hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) ); repo._elevLayer = CustomElevLayer( hfLayer, true ); } // Now, if there are any color layers that did not get built, create them with an empty // image so the shaders have something to draw. osg::ref_ptr<osg::Image> emptyImage; osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator(); for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() && !layer->isKeyValid(key) ) { if ( !emptyImage.valid() ) emptyImage = ImageUtils::createEmptyImage(); repo.add( CustomColorLayer( layer, emptyImage.get(), locator, key.getLevelOfDetail(), key, true ) ); } } //osg::Vec3dArray* maskBounds = 0L; //osgEarth::MaskLayer* mask = mapf.getTerrainMaskLayer(); //if (mask) // maskBounds = mask->getOrCreateBoundary(); // Ready to create the actual tile. AssembleTile assemble; assemble.init( key, mapInfo, _terrainOptions, repo, mapf.terrainMaskLayers() ); assemble.execute(); if (!out_hasRealData) { // Check the results and see if we have any real data. for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i ) { if ( !i->second.isFallbackData() ) { out_hasRealData = true; break; } } } if ( !out_hasRealData && !repo._elevLayer.isFallbackData() ) { out_hasRealData = true; } out_tile = assemble._tile; }
void CacheSeed::seed( Map* map ) { if ( !map->getCache() ) { OE_WARN << LC << "Warning: No cache defined; aborting." << std::endl; return; } std::vector<TileKey> keys; map->getProfile()->getRootKeys(keys); //Add the map's entire extent if we don't have one specified. if (_extents.empty()) { addExtent( map->getProfile()->getExtent() ); } bool hasCaches = false; int src_min_level = INT_MAX; unsigned int src_max_level = 0; MapFrame mapf( map, Map::TERRAIN_LAYERS, "CacheSeed::seed" ); //Assumes the the TileSource will perform the caching for us when we call createImage for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ ) { ImageLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ImageLayerOptions& opt = layer->getImageLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if ( !src ) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } //else if ( src->getCachePolicyHint(0L) == CachePolicy::NO_CACHE ) //{ // OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; //} else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); i++ ) { ElevationLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ElevationLayerOptions& opt = layer->getElevationLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if (!src) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } //else if ( src->getCachePolicyHint(0L) == CachePolicy::NO_CACHE ) //{ // OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; //} else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } if ( !hasCaches ) { OE_WARN << LC << "There are either no caches defined in the map, or no sources to cache; aborting." << std::endl; return; } if ( src_max_level > 0 && src_max_level < _maxLevel ) { _maxLevel = src_max_level; } OE_NOTICE << LC << "Maximum cache level will be " << _maxLevel << std::endl; osg::Timer_t startTime = osg::Timer::instance()->tick(); //Estimate the number of tiles _total = 0; for (unsigned int level = _minLevel; level <= _maxLevel; level++) { double coverageRatio = 0.0; if (_extents.empty()) { unsigned int wide, high; map->getProfile()->getNumTiles( level, wide, high ); _total += (wide * high); } else { for (std::vector< GeoExtent >::const_iterator itr = _extents.begin(); itr != _extents.end(); itr++) { const GeoExtent& extent = *itr; double boundsArea = extent.area(); TileKey ll = map->getProfile()->createTileKey(extent.xMin(), extent.yMin(), level); TileKey ur = map->getProfile()->createTileKey(extent.xMax(), extent.yMax(), level); if (!ll.valid() || !ur.valid()) continue; int tilesWide = ur.getTileX() - ll.getTileX() + 1; int tilesHigh = ll.getTileY() - ur.getTileY() + 1; int tilesAtLevel = tilesWide * tilesHigh; //OE_NOTICE << "Tiles at level " << level << "=" << tilesAtLevel << std::endl; /* bool hasData = false; for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); itr++) { TileSource* src = itr->get()->getTileSource(); if (src) { if (src->hasDataAtLOD( level )) { //Compute the percent coverage of this dataset on the current extent if (src->getDataExtents().size() > 0) { double cov = 0.0; for (unsigned int j = 0; j < src->getDataExtents().size(); j++) { GeoExtent b = src->getDataExtents()[j].transform( extent.getSRS()); GeoExtent intersection = b.intersectionSameSRS( extent ); if (intersection.isValid()) { double coverage = intersection.area() / boundsArea; cov += coverage; //Assumes the extents aren't overlapping } } if (coverageRatio < cov) coverageRatio = cov; } else { //We have no way of knowing how much coverage we have coverageRatio = 1.0; } hasData = true; break; } } } for (ElevationLayerVector::const_iterator itr = mapf.elevationLayers().begin(); itr != mapf.elevationLayers().end(); itr++) { TileSource* src = itr->get()->getTileSource(); if (src) { if (src->hasDataAtLOD( level )) { //Compute the percent coverage of this dataset on the current extent if (src->getDataExtents().size() > 0) { double cov = 0.0; for (unsigned int j = 0; j < src->getDataExtents().size(); j++) { GeoExtent b = src->getDataExtents()[j].transform( extent.getSRS()); GeoExtent intersection = b.intersectionSameSRS( extent ); if (intersection.isValid()) { double coverage = intersection.area() / boundsArea; cov += coverage; //Assumes the extents aren't overlapping } } if (coverageRatio < cov) coverageRatio = cov; } else { //We have no way of knowing how much coverage we have coverageRatio = 1.0; } hasData = true; break; } } } //Adjust the coverage ratio by a fudge factor to try to keep it from being too small, //tiles are either processed or not and the ratio is exact so will cover tiles partially //and potentially be too small double adjust = 4.0; coverageRatio = osg::clampBetween(coverageRatio * adjust, 0.0, 1.0); //OE_NOTICE << level << " CoverageRatio = " << coverageRatio << std::endl; if (hasData) { _total += (int)ceil(coverageRatio * (double)tilesAtLevel ); } */ _total += tilesAtLevel; } } } osg::Timer_t endTime = osg::Timer::instance()->tick(); //OE_NOTICE << "Counted tiles in " << osg::Timer::instance()->delta_s(startTime, endTime) << " s" << std::endl; OE_INFO << "Processing ~" << _total << " tiles" << std::endl; for (unsigned int i = 0; i < keys.size(); ++i) { processKey( mapf, keys[i] ); } _total = _completed; if ( _progress.valid()) _progress->reportProgress(_completed, _total, 0, 1, "Finished"); }
void TileModelFactory::createTileModel(const TileKey& key, osg::ref_ptr<TileModel>& out_model, bool& out_hasRealData, bool& out_hasLodBlendedLayers ) { MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS ); const MapInfo& mapInfo = mapf.getMapInfo(); osg::ref_ptr<TileModel> model = new TileModel(); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, mapInfo); // init this to false, then search for real data. "Real data" is data corresponding // directly to the key, as opposed to fallback data, which is derived from a lower // LOD key. out_hasRealData = false; out_hasLodBlendedLayers = false; // Fetch the image data and make color layers. for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() ) { BuildColorData build; build.init( key, layer, mapInfo, _terrainOptions, model.get() ); build.execute(); if ( layer->getImageLayerOptions().lodBlending() == true ) { out_hasLodBlendedLayers = true; } } } // make an elevation layer. BuildElevationData build; build.init( key, mapf, _terrainOptions, model.get(), _hfCache ); build.execute(); // Bail out now if there's no data to be had. if ( model->_colorData.size() == 0 && !model->_elevationData.getHFLayer() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one. if ( !model->_elevationData.getHFLayer() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 ); osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf ); hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) ); model->_elevationData = TileModel::ElevationData( hfLayer, true ); } // Now, if there are any color layers that did not get built, create them with an empty // image so the shaders have something to draw. osg::ref_ptr<osg::Image> emptyImage; osgTerrain::Locator* locator = model->_elevationData.getHFLayer()->getLocator(); for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() && !layer->isKeyValid(key) ) { if ( !emptyImage.valid() ) emptyImage = ImageUtils::createEmptyImage(); model->_colorData[i->get()->getUID()] = TileModel::ColorData( layer, emptyImage.get(), locator, key.getLevelOfDetail(), key, true ); } } // Ready to create the actual tile. //AssembleTile assemble; //assemble.init( key, mapInfo, _terrainOptions, model.get(), mapf.terrainMaskLayers() ); //assemble.execute(); // if we're using LOD blending, find and add the parent's state set. if ( out_hasLodBlendedLayers && key.getLevelOfDetail() > 0 && _liveTiles.valid() ) { osg::ref_ptr<TileNode> parent; if ( _liveTiles->get( key.createParentKey(), parent ) ) { model->_parentStateSet = parent->getPublicStateSet(); } } if (!out_hasRealData) { // Check the results and see if we have any real data. for( TileModel::ColorDataByUID::const_iterator i = model->_colorData.begin(); i != model->_colorData.end(); ++i ) { if ( !i->second.isFallbackData() ) { out_hasRealData = true; break; } } } if ( !out_hasRealData && !model->_elevationData.isFallbackData() ) { out_hasRealData = true; } out_model = model.release(); //out_tile = assemble._node; }
/** Packages an image layer as a TMS folder. */ int makeTMS( osg::ArgumentParser& args ) { // see if the user wants to override the type extension (imagery only) std::string extension = "png"; args.read( "--ext", extension ); // verbosity? bool verbose = !args.read( "--quiet" ); // find a .earth file on the command line std::string earthFile = findArgumentWithExtension(args, ".earth"); if ( earthFile.empty() ) return usage( "Missing required .earth file" ); // folder to which to write the TMS archive. std::string rootFolder; if ( !args.read( "--out", rootFolder ) ) rootFolder = Stringify() << earthFile << ".tms_repo"; // max level to which to generate unsigned maxLevel = ~0; args.read( "--max-level", maxLevel ); // load up the map osg::ref_ptr<MapNode> mapNode = MapNode::load( args ); if ( !mapNode.valid() ) return usage( "Failed to load a valid .earth file" ); // create a folder for the output osgDB::makeDirectory(rootFolder); if ( !osgDB::fileExists(rootFolder) ) return usage("Failed to create root output folder" ); Map* map = mapNode->getMap(); // fire up a packager: TMSPackager packager( map->getProfile() ); packager.setVerbose( verbose ); if ( maxLevel != ~0 ) packager.setMaxLevel( maxLevel ); // package any image layers that are enabled: ImageLayerVector imageLayers; map->getImageLayers( imageLayers ); unsigned counter = 0; for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter ) { ImageLayer* layer = i->get(); if ( layer->getImageLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if ( layerFolder.empty() ) layerFolder = Stringify() << "image_layer_" << counter; if ( verbose ) { OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot, extension ); if ( !r.ok ) { OE_WARN << LC << r.message << std::endl; } } else if ( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // package any elevation layers that are enabled: counter = 0; ElevationLayerVector elevationLayers; map->getElevationLayers( elevationLayers ); for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter ) { ElevationLayer* layer = i->get(); if ( layer->getElevationLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if ( layerFolder.empty() ) layerFolder = Stringify() << "elevation_layer_" << counter; if ( verbose ) { OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); packager.package( layer, layerRoot ); } else if ( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } return 0; }