unsigned TerrainLayer::getTileSize() const { TileSource* ts = getTileSource(); return ts ? ts->getPixelsPerTile() : _tileSize; }
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; } }