void CompositeTileSource::initialize( const std::string& referenceURI, const Profile* overrideProfile ) { osg::ref_ptr<const Profile> profile = overrideProfile; for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); i != _options._components.end(); ++i) { TileSource* source = i->_tileSourceInstance.get(); if ( source ) { osg::ref_ptr<const Profile> localOverrideProfile = overrideProfile; const TileSourceOptions& opt = source->getOptions(); if ( opt.profile().isSet() ) localOverrideProfile = Profile::create( opt.profile().value() ); source->initialize( referenceURI, localOverrideProfile.get() ); if ( !profile.valid() ) { // assume the profile of the first source to be the overall profile. profile = source->getProfile(); } else if ( !profile->isEquivalentTo( source->getProfile() ) ) { // if sub-sources have different profiles, print a warning because this is // not supported! OE_WARN << LC << "Components with differing profiles are not supported. " << "Visual anomalies may result." << std::endl; } _dynamic = _dynamic || source->isDynamic(); // gather extents const DataExtentList& extents = source->getDataExtents(); for( DataExtentList::const_iterator j = extents.begin(); j != extents.end(); ++j ) { getDataExtents().push_back( *j ); } } } setProfile( profile.get() ); _initialized = true; }
TileSource* TileSourceFactory::create(const TileSourceOptions& options) { TileSource* result = 0L; std::string driver = options.getDriver(); if ( driver.empty() ) { OE_WARN << LC << "ILLEGAL- no driver set for tile source" << std::endl; return 0L; } osg::ref_ptr<osgDB::Options> dbopt = Registry::instance()->cloneOrCreateOptions(); dbopt->setPluginData ( TILESOURCE_OPTIONS_TAG, (void*)&options ); dbopt->setPluginStringData( TILESOURCE_INTERFACE_TAG, TileSource::INTERFACE_NAME ); std::string driverExt = std::string( ".osgearth_" ) + driver; result = dynamic_cast<TileSource*>( osgDB::readObjectFile( driverExt, dbopt.get() ) ); if ( !result ) { OE_WARN << LC << "Failed to load TileSource driver \"" << driver << "\"" << std::endl; } OE_DEBUG << LC << "Tile source Profile = " << (result->getProfile() ? result->getProfile()->toString() : "NULL") << std::endl; // apply an Override Profile if provided. if ( result && options.profile().isSet() ) { const Profile* profile = Profile::create(*options.profile()); if ( profile ) { result->setProfile( profile ); } } return result; }
Status CompositeTileSource::initialize(const osgDB::Options* dbOptions) { _dbOptions = Registry::instance()->cloneOrCreateOptions(dbOptions); osg::ref_ptr<const Profile> profile = getProfile(); for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); i != _options._components.end(); ) { if ( i->_imageLayerOptions.isSet() && !i->_layer.valid() ) { // Disable the l2 cache for composite layers so that we don't get run out of memory on very large datasets. i->_imageLayerOptions->driver()->L2CacheSize() = 0; osg::ref_ptr< ImageLayer > layer = new ImageLayer(*i->_imageLayerOptions); layer->setReadOptions(_dbOptions.get()); Status status = layer->open(); if (status.isOK()) { i->_layer = layer; _imageLayers.push_back( layer ); OE_INFO << LC << " .. added image layer " << layer->getName() << " (" << i->_imageLayerOptions->driver()->getDriver() << ")\n"; } else { OE_WARN << LC << "Could not open image layer (" << layer->getName() << ") ... " << status.message() << std::endl; } } else if (i->_elevationLayerOptions.isSet() && !i->_layer.valid()) { // Disable the l2 cache for composite layers so that we don't get run out of memory on very large datasets. i->_elevationLayerOptions->driver()->L2CacheSize() = 0; osg::ref_ptr< ElevationLayer > layer = new ElevationLayer(*i->_elevationLayerOptions); layer->setReadOptions(_dbOptions.get()); Status status = layer->open(); if (status.isOK()) { i->_layer = layer; _elevationLayers.push_back( layer.get() ); } else { OE_WARN << LC << "Could not open elevation layer (" << layer->getName() << ") ... " << status.message() << std::endl; } } if ( !i->_layer.valid() ) { OE_WARN << LC << "A component has no valid TerrainLayer ... removing." << std::endl; i = _options._components.erase( i ); } else { TileSource* source = i->_layer->getTileSource(); // If no profile is specified assume they want to use the profile of the first layer in the list. if (!profile.valid()) { profile = source->getProfile(); } _dynamic = _dynamic || source->isDynamic(); // gather extents const DataExtentList& extents = source->getDataExtents(); for( DataExtentList::const_iterator j = extents.begin(); j != extents.end(); ++j ) { // Convert the data extent to the profile that is actually used by this TileSource DataExtent dataExtent = *j; GeoExtent ext = dataExtent.transform(profile->getSRS()); unsigned int minLevel = 0; unsigned int maxLevel = profile->getEquivalentLOD( source->getProfile(), *dataExtent.maxLevel() ); dataExtent = DataExtent(ext, minLevel, maxLevel); getDataExtents().push_back( dataExtent ); } } ++i; } // set the new profile that was derived from the components setProfile( profile.get() ); _initialized = true; return STATUS_OK; }
TileSource::Status CompositeTileSource::initialize(const osgDB::Options* dbOptions) { _dbOptions = Registry::instance()->cloneOrCreateOptions(dbOptions); osg::ref_ptr<const Profile> profile = getProfile(); for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); i != _options._components.end(); ) { if ( i->_imageLayerOptions.isSet() ) { if ( !i->_tileSourceInstance.valid() ) { i->_tileSourceInstance = TileSourceFactory::create( i->_imageLayerOptions->driver().value() ); if ( !i->_tileSourceInstance.valid() ) { OE_WARN << LC << "Could not find a TileSource for driver [" << i->_imageLayerOptions->driver()->getDriver() << "]" << std::endl; } } } if ( !i->_tileSourceInstance.valid() ) { OE_WARN << LC << "A component has no valid TileSource ... removing." << std::endl; i = _options._components.erase( i ); } else { TileSource* source = i->_tileSourceInstance.get(); if ( source ) { osg::ref_ptr<const Profile> localOverrideProfile = profile.get(); const TileSourceOptions& opt = source->getOptions(); if ( opt.profile().isSet() ) { localOverrideProfile = Profile::create( opt.profile().value() ); source->setProfile( localOverrideProfile.get() ); } // initialize the component tile source: TileSource::Status compStatus = source->startup( _dbOptions.get() ); if ( compStatus == TileSource::STATUS_OK ) { if ( !profile.valid() ) { // assume the profile of the first source to be the overall profile. profile = source->getProfile(); } else if ( !profile->isEquivalentTo( source->getProfile() ) ) { // if sub-sources have different profiles, print a warning because this is // not supported! OE_WARN << LC << "Components with differing profiles are not supported. " << "Visual anomalies may result." << std::endl; } _dynamic = _dynamic || source->isDynamic(); // gather extents const DataExtentList& extents = source->getDataExtents(); for( DataExtentList::const_iterator j = extents.begin(); j != extents.end(); ++j ) { getDataExtents().push_back( *j ); } } else { // if even one of the components fails to initialize, the entire // composite tile source is invalid. return Status::Error("At least one component is invalid"); } } } ++i; } // set the new profile that was derived from the components setProfile( profile.get() ); _initialized = true; return STATUS_OK; }
osg::Image* CompositeTileSource::createImage(const TileKey& key, ProgressCallback* progress ) { ImageMixVector images; images.reserve( _options._components.size() ); for(CompositeTileSourceOptions::ComponentVector::const_iterator i = _options._components.begin(); i != _options._components.end(); ++i ) { if ( progress && progress->isCanceled() ) return 0L; ImageInfo imageInfo; imageInfo.dataInExtents = false; TileSource* source = i->_tileSourceInstance.get(); if ( source ) { //TODO: This duplicates code in ImageLayer::isKeyValid. Maybe should move that to TileSource::isKeyValid instead int minLevel = 0; int maxLevel = INT_MAX; if (i->_imageLayerOptions->minLevel().isSet()) { minLevel = i->_imageLayerOptions->minLevel().value(); } else if (i->_imageLayerOptions->minResolution().isSet()) { minLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->minResolution().value(), source->getPixelsPerTile()); } if (i->_imageLayerOptions->maxLevel().isSet()) { maxLevel = i->_imageLayerOptions->maxLevel().value(); } else if (i->_imageLayerOptions->maxResolution().isSet()) { maxLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->maxResolution().value(), source->getPixelsPerTile()); } // check that this source is within the level bounds: if (minLevel > (int)key.getLevelOfDetail() || maxLevel < (int)key.getLevelOfDetail() ) { continue; } //Only try to get data if the source actually has data if (source->hasDataInExtent( key.getExtent() ) ) { //We have data within these extents imageInfo.dataInExtents = true; if ( !source->getBlacklist()->contains( key.getTileId() ) ) { osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp; if ( i->_imageLayerOptions.isSet() ) { preCacheOp = new ImageLayerPreCacheOperation(); preCacheOp->_processor.init( i->_imageLayerOptions.value(), _dbOptions.get(), true ); } imageInfo.image = source->createImage( key, preCacheOp.get(), progress ); imageInfo.opacity = 1.0f; //If the image is not valid and the progress was not cancelled, blacklist if (!imageInfo.image.valid() && (!progress || !progress->isCanceled())) { //Add the tile to the blacklist OE_DEBUG << LC << "Adding tile " << key.str() << " to the blacklist" << std::endl; source->getBlacklist()->add( key.getTileId() ); } imageInfo.opacity = i->_imageLayerOptions.isSet() ? i->_imageLayerOptions->opacity().value() : 1.0f; } } else { OE_DEBUG << LC << "Source has no data at " << key.str() << std::endl; } } //Add the ImageInfo to the list images.push_back( imageInfo ); } unsigned numValidImages = 0; osg::Vec2s textureSize; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) { if (numValidImages == 0) { textureSize.set( info.image->s(), info.image->t()); } numValidImages++; } } //Try to fallback on any empty images if we have some valid images but not valid images for ALL layers if (numValidImages > 0 && numValidImages < images.size()) { for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (!info.image.valid() && info.dataInExtents) { TileKey parentKey = key.createParentKey(); TileSource* source = _options._components[i]._tileSourceInstance; if (source) { osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp; if ( _options._components[i]._imageLayerOptions.isSet() ) { preCacheOp = new ImageLayerPreCacheOperation(); preCacheOp->_processor.init( _options._components[i]._imageLayerOptions.value(), _dbOptions.get(), true ); } osg::ref_ptr< osg::Image > image; while (!image.valid() && parentKey.valid()) { image = source->createImage( parentKey, preCacheOp.get(), progress ); if (image.valid()) { break; } parentKey = parentKey.createParentKey(); } if (image.valid()) { //We got an image, but now we need to crop it to match the incoming key's extents GeoImage geoImage( image.get(), parentKey.getExtent()); GeoImage cropped = geoImage.crop( key.getExtent(), true, textureSize.x(), textureSize.y(), *source->_options.bilinearReprojection()); image = cropped.getImage(); } info.image = image.get(); } } } } //Recompute the number of valid images numValidImages = 0; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) numValidImages++; } if ( progress && progress->isCanceled() ) { return 0L; } else if ( numValidImages == 0 ) { return 0L; } else if ( numValidImages == 1 ) { //We only have one valid image, so just return it and don't bother with compositing for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) return info.image.release(); } return 0L; } else { osg::Image* result = 0; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& imageInfo = images[i]; if (!result) { if (imageInfo.image.valid()) { result = new osg::Image( *imageInfo.image.get()); } } else { if (imageInfo.image.valid()) { ImageUtils::mix( result, imageInfo.image, imageInfo.opacity ); } } } return result; } }
osg::Image* CompositeTileSource::createImage( const TileKey& key, ProgressCallback* progress ) { ImageMixVector images; images.reserve( _options._components.size() ); for(CompositeTileSourceOptions::ComponentVector::const_iterator i = _options._components.begin(); i != _options._components.end(); ++i ) { if ( progress && progress->isCanceled() ) return 0L; TileSource* source = i->_tileSourceInstance->get(); if ( source ) { //TODO: This duplicates code in ImageLayer::isKeyValid. Maybe should move that to TileSource::isKeyValid instead int minLevel = 0; int maxLevel = INT_MAX; if (i->_imageLayerOptions->minLevel().isSet()) { minLevel = i->_imageLayerOptions->minLevel().value(); } else if (i->_imageLayerOptions->minLevelResolution().isSet()) { minLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->minLevelResolution().value(), source->getPixelsPerTile()); } if (i->_imageLayerOptions->maxLevel().isSet()) { maxLevel = i->_imageLayerOptions->maxLevel().value(); } else if (i->_imageLayerOptions->maxLevelResolution().isSet()) { maxLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->maxLevelResolution().value(), source->getPixelsPerTile()); } // check that this source is within the level bounds: if (minLevel > key.getLevelOfDetail() || maxLevel < key.getLevelOfDetail() ) { continue; } if ( !source->getBlacklist()->contains( key.getTileId() ) ) { //Only try to get data if the source actually has data if ( source->hasData( key ) ) { osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp; if ( i->_imageLayerOptions.isSet() ) { preCacheOp = new ImageLayerPreCacheOperation(); preCacheOp->_processor.init( i->_imageLayerOptions.value(), true ); } ImageOpacityPair imagePair( source->createImage( key, preCacheOp.get(), progress ), 1.0f ); //If the image is not valid and the progress was not cancelled, blacklist if (!imagePair.first.valid() && (!progress || !progress->isCanceled())) { //Add the tile to the blacklist OE_DEBUG << LC << "Adding tile " << key.str() << " to the blacklist" << std::endl; source->getBlacklist()->add( key.getTileId() ); } if ( imagePair.first.valid() ) { // check for opacity: imagePair.second = i->_imageLayerOptions.isSet() ? i->_imageLayerOptions->opacity().value() : 1.0f; images.push_back( imagePair ); } } else { OE_DEBUG << LC << "Source has no data at " << key.str() << std::endl; } } else { OE_DEBUG << LC << "Tile " << key.str() << " is blacklisted, not checking" << std::endl; } } } if ( progress && progress->isCanceled() ) { return 0L; } else if ( images.size() == 0 ) { return 0L; } else if ( images.size() == 1 ) { return images[0].first.release(); } else { osg::Image* result = new osg::Image( *images[0].first.get() ); for( unsigned int i=1; i<images.size(); ++i ) { ImageOpacityPair& pair = images[i]; if ( pair.first.valid() ) { ImageUtils::mix( result, pair.first.get(), pair.second ); } } return result; } }
void CompositeTileSource::initialize(const osgDB::Options* dbOptions, const Profile* overrideProfile ) { _dbOptions = dbOptions; osg::ref_ptr<const Profile> profile = overrideProfile; for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); i != _options._components.end(); ) { if ( i->_imageLayerOptions.isSet() ) { if ( !i->_tileSourceInstance.valid() ) { i->_tileSourceInstance = TileSourceFactory::create( i->_imageLayerOptions->driver().value() ); if ( !i->_tileSourceInstance.valid() ) { OE_WARN << LC << "Could not find a TileSource for driver [" << i->_imageLayerOptions->driver()->getDriver() << "]" << std::endl; } } } if ( !i->_tileSourceInstance.valid() ) { OE_WARN << LC << "A component has no valid TileSource ... removing." << std::endl; i = _options._components.erase( i ); } else { TileSource* source = i->_tileSourceInstance.get(); if ( source ) { osg::ref_ptr<const Profile> localOverrideProfile = overrideProfile; const TileSourceOptions& opt = source->getOptions(); if ( opt.profile().isSet() ) localOverrideProfile = Profile::create( opt.profile().value() ); source->initialize( dbOptions, localOverrideProfile.get() ); if ( !profile.valid() ) { // assume the profile of the first source to be the overall profile. profile = source->getProfile(); } else if ( !profile->isEquivalentTo( source->getProfile() ) ) { // if sub-sources have different profiles, print a warning because this is // not supported! OE_WARN << LC << "Components with differing profiles are not supported. " << "Visual anomalies may result." << std::endl; } _dynamic = _dynamic || source->isDynamic(); // gather extents const DataExtentList& extents = source->getDataExtents(); for( DataExtentList::const_iterator j = extents.begin(); j != extents.end(); ++j ) { getDataExtents().push_back( *j ); } } } ++i; } setProfile( profile.get() ); _initialized = true; }