Example #1
0
GeoImage
ImageLayer::createImageFromTileSource(const TileKey&    key,
                                      ProgressCallback* progress)
{
    TileSource* source = getTileSource();
    if ( !source )
        return GeoImage::INVALID;

    // If the profiles are different, use a compositing method to assemble the tile.
    if ( !key.getProfile()->isHorizEquivalentTo( getProfile() ) )
    {
        return assembleImage( key, progress );
    }

    // Good to go, ask the tile source for an image:
    osg::ref_ptr<TileSource::ImageOperation> op = getOrCreatePreCacheOp();

    // Fail is the image is blacklisted.
    if ( source->getBlacklist()->contains(key) )
    {
        OE_DEBUG << LC << "createImageFromTileSource: blacklisted(" << key.str() << ")" << std::endl;
        return GeoImage::INVALID;
    }

    if (!mayHaveData(key))
    {
        OE_DEBUG << LC << "createImageFromTileSource: mayHaveData(" << key.str() << ") == false" << std::endl;
        return GeoImage::INVALID;
    }

    //if ( !source->hasData( key ) )
    //{
    //    OE_DEBUG << LC << "createImageFromTileSource: hasData(" << key.str() << ") == false" << std::endl;
    //    return GeoImage::INVALID;
    //}

    // create an image from the tile source.
    osg::ref_ptr<osg::Image> result = source->createImage( key, op.get(), progress );   

    // Process images with full alpha to properly support MP blending.    
    if (result.valid() && 
        options().featherPixels() == true)
    {
        ImageUtils::featherAlphaRegions( result.get() );
    }    
    
    // If image creation failed (but was not intentionally canceled and 
    // didn't time out or end for any other recoverable reason), then
    // blacklist this tile for future requests.
    if (result == 0L)
    {
        if ( progress == 0L ||
             ( !progress->isCanceled() && !progress->needsRetry() ) )
        {
            source->getBlacklist()->add( key );
        }
    }

    return GeoImage(result.get(), key.getExtent());
}
Example #2
0
TileSource*
TileSourceFactory::create( const TileSourceOptions& options )
{
    TileSource* result = 0L;

    std::string driver = options.getDriver();
    if ( driver.empty() )
    {
        OE_WARN << "ILLEGAL- no driver set for tile source" << std::endl;
        return 0L;
    }

    osg::ref_ptr<osgDB::Options> rwopt = Registry::instance()->cloneOrCreateOptions();
    rwopt->setPluginData( TILESOURCEOPTIONS_TAG, (void*)&options );

    std::string driverExt = std::string( ".osgearth_" ) + driver;
    result = dynamic_cast<TileSource*>( osgDB::readObjectFile( driverExt, rwopt.get() ) );
    if ( !result )
    {
        OE_WARN << "WARNING: Failed to load TileSource driver for \"" << driver << "\"" << 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;
}
Example #3
0
bool CacheTileHandler::hasData( const TileKey& key ) const
{
    TileSource* ts = _layer->getTileSource();
    if (ts)
    {
        return ts->hasData(key);
    }
    return true;
}
Example #4
0
GeoImage
ImageLayer::createImageFromTileSource(const TileKey&    key,
                                      ProgressCallback* progress)
{
    TileSource* source = getTileSource();
    if ( !source )
        return GeoImage::INVALID;

    // If the profiles are different, use a compositing method to assemble the tile.
    if ( !key.getProfile()->isHorizEquivalentTo( getProfile() ) )
    {
        return assembleImageFromTileSource( key, progress );
    }

    // Good to go, ask the tile source for an image:
    osg::ref_ptr<TileSource::ImageOperation> op = _preCacheOp;

    // Fail is the image is blacklisted.
    if ( source->getBlacklist()->contains(key) )
    {
        OE_DEBUG << LC << "createImageFromTileSource: blacklisted(" << key.str() << ")" << std::endl;
        return GeoImage::INVALID;
    }
    
    if ( !source->hasData( key ) )
    {
        OE_DEBUG << LC << "createImageFromTileSource: hasData(" << key.str() << ") == false" << std::endl;
        return GeoImage::INVALID;
    }

    // create an image from the tile source.
    osg::ref_ptr<osg::Image> result = source->createImage( key, op.get(), progress );

    // Process images with full alpha to properly support MP blending.    
    if ( result.valid() && *_runtimeOptions.featherPixels())
    {
        ImageUtils::featherAlphaRegions( result.get() );
    }    
    
    // If image creation failed (but was not intentionally canceled),
    // blacklist this tile for future requests.
    if ( result == 0L && (!progress || !progress->isCanceled()) )
    {
        source->getBlacklist()->add( key );
    }

    return GeoImage(result.get(), key.getExtent());
}
Example #5
0
unsigned int
TerrainLayer::getMaxDataLevel() const
{
    //Try the setting first

    if ( _runtimeOptions->maxDataLevel().isSet() )
    {
        return _runtimeOptions->maxDataLevel().get();
    }

    //Try the TileSource
    TileSource* ts = getTileSource();
    if ( ts )
    {
        return ts->getMaxDataLevel();
    }

    //Just default
    return 20;
}
Example #6
0
unsigned int
TerrainLayer::getMaxDataLevel() const
{
    const TerrainLayerOptions& opt = getTerrainLayerOptions();
    //Try the setting first
    if (opt.maxDataLevel().isSet())
    {
        return opt.maxDataLevel().get();
    }

    //Try the TileSource
	TileSource* ts = getTileSource();
	if (ts)
	{
		return ts->getMaxDataLevel();
	}

    //Just default
	return 20;
}
Example #7
0
std::shared_ptr<Tile> TileBuilder::build(TileID _tileID, const TileData& _tileData, const TileSource& _source) {

    m_selectionFeatures.clear();

    auto tile = std::make_shared<Tile>(_tileID, *m_scene->mapProjection(), &_source);

    tile->initGeometry(m_scene->styles().size());

    m_styleContext.setKeywordZoom(_tileID.s);

    for (auto& builder : m_styleBuilder) {
        if (builder.second)
            builder.second->setup(*tile);
    }

    for (const auto& datalayer : m_scene->layers()) {

        if (datalayer.source() != _source.name()) { continue; }

        for (const auto& collection : _tileData.layers) {

            if (!collection.name.empty()) {
                const auto& dlc = datalayer.collections();
                bool layerContainsCollection =
                    std::find(dlc.begin(), dlc.end(), collection.name) != dlc.end();

                if (!layerContainsCollection) { continue; }
            }

            for (const auto& feat : collection.features) {
                applyStyling(feat, datalayer);
            }
        }
    }

    for (auto& builder : m_styleBuilder) {

        builder.second->addLayoutItems(m_labelLayout);
    }

    float tileSize = m_scene->mapProjection()->TileSize() * m_scene->pixelScale();

    m_labelLayout.process(_tileID, tile->getInverseScale(), tileSize);

    for (auto& builder : m_styleBuilder) {
        tile->setMesh(builder.second->style(), builder.second->build());
    }

    tile->setSelectionFeatures(m_selectionFeatures);

    return tile;
}
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;
}
Example #9
0
void CableRenderer::render(const TilePos& pos, Tile* tile, TileTessellator* tess) {
	int x = pos.x, y = pos.y, z = pos.z;
	TileSource* ts = tess->region;
	
	bool front = ts->getTile(x + 1, y, z) == tile->id;
	bool back = ts->getTile(x - 1, y, z) == tile->id;
	bool left = ts->getTile(x, y, z + 1) == tile->id;
	bool right = ts->getTile(x, y, z - 1) == tile->id;
	bool bottom = ts->getTile(x, y - 1, z) == tile->id;
	bool top = ts->getTile(x, y + 1, z) == tile->id;
	
	tess->useForcedUV = true;
	tess->forcedUV = tile->getTexture(0, 0);
	
	tess->setRenderBounds(0.4, 0.4, 0.4, 0.6, 0.6, 0.6);
	tess->tessellateBlockInWorld(tile, {x, y, z});
	
	if(front) {
		tess->setRenderBounds(0.6, 0.4, 0.4, 1, 0.6, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(back) {
		tess->setRenderBounds(0, 0.4, 0.4, 0.4, 0.6, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(left) {
		tess->setRenderBounds(0.4, 0.4, 0.6, 0.6, 0.6, 1);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(right) {
		tess->setRenderBounds(0.4, 0.4, 0, 0.6, 0.6, 0.4);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(bottom) {
		tess->setRenderBounds(0.4, 0, 0.4, 0.6, 0.4, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(top) {
		tess->setRenderBounds(0.4, 0.6, 0.4, 0.6, 1, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	tess->useForcedUV = false;
}
Example #10
0
bool PistonArmTile::addCollisionShapes(TileSource& region, int x, int y, int z, AABB const* posAABB, std::vector<AABB, std::allocator<AABB>>& pool) {
	int data = region.getData(x, y, z);
	float var9 = 0.25F;
	float var10 = 0.375F;
	float var11 = 0.625F;
	float var12 = 0.25F;
	float var13 = 0.75F;

	switch(getRotation(data)) {
    	case 0:
    	    addAABB(AABB(0.0F, 0.0F, 0.0F, 1.0F, 0.25F, 1.0F).move(x, y, z), posAABB, pool);
    	    addAABB(AABB(0.375F, 0.25F, 0.375F, 0.625F, 1.0F, 0.625F).move(x, y, z), posAABB, pool);
    	    break;
    	case 1:
    	    addAABB(AABB(0.0F, 0.75F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), posAABB, pool);
    	    addAABB(AABB(0.375F, 0.0F, 0.375F, 0.625F, 0.75F, 0.625F).move(x, y, z), posAABB, pool);
    	    break;
    	case 2:
    	    addAABB(AABB(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.25F).move(x, y, z), posAABB, pool);
    	    addAABB(AABB(0.25F, 0.375F, 0.25F, 0.75F, 0.625F, 1.0F).move(x, y, z), posAABB, pool);
    	    break;
    	case 3:
    	    addAABB(AABB(0.0F, 0.0F, 0.75F, 1.0F, 1.0F, 1.0F).move(x, y, z), posAABB, pool);
    	    addAABB(AABB(0.25F, 0.375F, 0.0F, 0.75F, 0.625F, 0.75F).move(x, y, z), posAABB, pool);
    	    break;
    	case 4:
    	    addAABB(AABB(0.0F, 0.0F, 0.0F, 0.25F, 1.0F, 1.0F).move(x, y, z), posAABB, pool);
    	    addAABB(AABB(0.375F, 0.25F, 0.25F, 0.625F, 0.75F, 1.0F).move(x, y, z), posAABB, pool);
    	    break;
    	case 5:
    	    addAABB(AABB(0.75F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F).move(x, y, z), posAABB, pool);
    	    addAABB(AABB(0.0F, 0.375F, 0.25F, 0.75F, 0.625F, 0.75F).move(x, y, z), posAABB, pool);
    	    break;
    }
	return true;
}
Example #11
0
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;
    }
}
Example #12
0
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;
}
Example #13
0
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;

        // check that this source is within the level bounds:
        if (i->_imageLayerOptions->minLevel().value() > key.getLevelOfDetail() ||
            i->_imageLayerOptions->maxLevel().value() < key.getLevelOfDetail() )
        {
            continue;
        }

        TileSource* source = i->_tileSourceInstance->get();
        if ( source )
        {
            if ( !source->getBlacklist()->contains( key.getTileId() ) )
            {
                //Only try to get data if the source actually has data
                if ( source->hasData( key ) )
                {
                    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;
    }
}
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;
    }
}
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;
}
Example #16
0
    void execute()
    {
        GeoImage geoImage;
        bool isFallbackData = false;

        bool useMercatorFastPath =
            _opt->enableMercatorFastPath() != false &&
            _mapInfo->isGeocentric()                &&
            _layer->getProfile()                    &&
            _layer->getProfile()->getSRS()->isSphericalMercator();

        // fetch the image from the layer, falling back on parent keys utils we are 
        // able to find one that works.

        bool autoFallback = _key.getLevelOfDetail() <= 1;

        TileKey imageKey( _key );
        TileSource* tileSource = _layer->getTileSource();
        const Profile* layerProfile = _layer->getProfile();

        //Only try to get data from the source if it actually intersects the key extent
        bool hasDataInExtent = true;
        if (tileSource && layerProfile)
        {
            GeoExtent ext = _key.getExtent();
            if (!layerProfile->getSRS()->isEquivalentTo( ext.getSRS()))
            {
                ext = layerProfile->clampAndTransformExtent( ext );
            }
            hasDataInExtent = ext.isValid() && tileSource->hasDataInExtent( ext );
        }        
        
        if (hasDataInExtent)
        {
            while( !geoImage.valid() && imageKey.valid() && _layer->isKeyValid(imageKey) )
            {
                if ( useMercatorFastPath )
                {
                    bool mercFallbackData = false;
                    geoImage = _layer->createImageInNativeProfile( imageKey, 0L, autoFallback, mercFallbackData );
                    if ( geoImage.valid() && mercFallbackData )
                    {
                        isFallbackData = true;
                    }
                }
                else
                {
                    geoImage = _layer->createImage( imageKey, 0L, autoFallback );
                }

                if ( !geoImage.valid() )
                {
                    imageKey = imageKey.createParentKey();
                    isFallbackData = true;
                }
            }
        }

        GeoLocator* locator = 0L;

        if ( !geoImage.valid() )
        {
            // no image found, so make an empty one (one pixel alpha).
            geoImage = GeoImage( ImageUtils::createEmptyImage(), _key.getExtent() );
            locator = GeoLocator::createForKey( _key, *_mapInfo );
            isFallbackData = true;
        }
        else
        {
            if ( useMercatorFastPath )
                locator = new MercatorLocator(geoImage.getExtent());
            else
                locator = GeoLocator::createForExtent(geoImage.getExtent(), *_mapInfo);
        }

        bool isStreaming = _opt->loadingPolicy()->mode() == LoadingPolicy::MODE_PREEMPTIVE || _opt->loadingPolicy()->mode() == LoadingPolicy::MODE_SEQUENTIAL;

        if (geoImage.getImage() && isStreaming)
        {
            // protected against multi threaded access. This is a requirement in sequential/preemptive mode, 
            // for example. This used to be in TextureCompositorTexArray::prepareImage.
            // TODO: review whether this affects performance.    
            geoImage.getImage()->setDataVariance( osg::Object::DYNAMIC );
        }

        // add the color layer to the repo.
        _repo->add( CustomColorLayer(
            _layer,
            geoImage.getImage(),
            locator,
            _key.getLevelOfDetail(),
            _key,
            isFallbackData ) );
    }
void CableRenderer::render(const TilePos& pos, Tile* tile, TileTessellator* tess) {
	int x = pos.x, y = pos.y, z = pos.z;
	TileSource* ts = tess->region;
	
	bool insulated = ts->getTileAndData(x, y, z).data == 1;
	
	FullTile frontt = ts->getTileAndData(x + 1, y, z);
	FullTile backt = ts->getTileAndData(x - 1, y, z);
	FullTile leftt = ts->getTileAndData(x, y, z + 1);
	FullTile rightt = ts->getTileAndData(x, y, z - 1);
	FullTile bottomt = ts->getTileAndData(x, y - 1, z);
	FullTile topt = ts->getTileAndData(x, y + 1, z);
	
	bool front = frontt.id == tile->id;
	bool back = backt.id == tile->id;
	bool left = leftt.id == tile->id;
	bool right = rightt.id == tile->id;
	bool bottom = bottomt.id == tile->id;
	bool top = topt.id == tile->id;
	
	tess->useForcedUV = true;
	tess->forcedUV = tile->getTexture(0, 0);
	
	tess->setRenderBounds(0.4, 0.4, 0.4, 0.6, 0.6, 0.6);
	tess->tessellateBlockInWorld(tile, {x, y, z});
	
	if(insulated) {
		tess->setRenderBounds(0.35, 0.35, 0.35, 0.65, 0.65, 0.65);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(front) {
		tess->setRenderBounds(0.6, 0.4, 0.4, 1, 0.6, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(back) {
		tess->setRenderBounds(0, 0.4, 0.4, 0.4, 0.6, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(left) {
		tess->setRenderBounds(0.4, 0.4, 0.6, 0.6, 0.6, 1);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(right) {
		if(insulated) {
			if(rightt.data == 1) {
				tess->setRenderBounds(0.35, 0.35, 0, 0.65, 0.65, 0.4);
				tess->tessellateBlockInWorld(tile, {x, y, z});
			} else {
				tess->setRenderBounds(0.35, 0.35, 0.1, 0.65, 0.65, 0.4);
				tess->tessellateBlockInWorld(tile, {x, y, z});
			}
		}
		tess->setRenderBounds(0.4, 0.4, 0, 0.6, 0.6, 0.4);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(bottom) {
		if(insulated) {
			if(bottomt.data == 1) {
				tess->setRenderBounds(0.35, 0.1, 0.35, 0.65, 0.4, 0.65);
				tess->tessellateBlockInWorld(tile, {x, y, z});
			}
		}
		tess->setRenderBounds(0.4, 0, 0.4, 0.6, 0.4, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	
	if(top) {
		if(insulated) {
			tess->setRenderBounds(0.35, 0.6, 0.35, 0.65, 0.9, 0.65);
			tess->tessellateBlockInWorld(tile, {x, y, z});
		}
		tess->setRenderBounds(0.4, 0.6, 0.4, 0.6, 1, 0.6);
		tess->tessellateBlockInWorld(tile, {x, y, z});
	}
	tess->useForcedUV = false;
}
Example #18
0
GeoImage
ImageLayer::createImageFromTileSource(const TileKey&    key,
                                      ProgressCallback* progress,
                                      bool              forceFallback,
                                      bool&             out_isFallback)
{
    // Results:
    // 
    // * return an osg::Image matching the key extent is all goes well;
    //
    // * return NULL to indicate that the key exceeds the maximum LOD of the source data,
    //   and that the engine may need to generate a "fallback" tile if necessary;
    //
    // deprecated:
    // * return an "empty image" if the LOD is valid BUT the key does not intersect the
    //   source's data extents.

    out_isFallback = false;

    TileSource* source = getTileSource();
    if ( !source )
        return GeoImage::INVALID;

    // If the profiles are different, use a compositing method to assemble the tile.
    if ( !key.getProfile()->isEquivalentTo( getProfile() ) )
    {
        return assembleImageFromTileSource( key, progress, out_isFallback );
    }

    // Good to go, ask the tile source for an image:
    osg::ref_ptr<TileSource::ImageOperation> op = _preCacheOp;

    osg::ref_ptr<osg::Image> result;

    if ( forceFallback )
    {
        // check if the tile source has any data coverage for the requested key.
        // the LOD is ignore here and checked later
        if ( !source->hasDataInExtent( key.getExtent() ) )
        {
            OE_DEBUG << LC << "createImageFromTileSource: hasDataInExtent(" << key.str() << ") == false" << std::endl;
            return GeoImage::INVALID;
        }

        TileKey finalKey = key;
        while( !result.valid() && finalKey.valid() )
        {
            if ( !source->getBlacklist()->contains( finalKey.getTileId() ) &&
                source->hasDataForFallback(finalKey))
            {
                result = source->createImage( finalKey, op.get(), progress );
                if ( result.valid() )
                {
                    if ( finalKey.getLevelOfDetail() != key.getLevelOfDetail() )
                    {
                        // crop the fallback image to match the input key, and ensure that it remains the
                        // same pixel size; because chances are if we're requesting a fallback that we're
                        // planning to mosaic it later, and the mosaicer requires same-size images.
                        GeoImage raw( result.get(), finalKey.getExtent() );
                        GeoImage cropped = raw.crop( key.getExtent(), true, raw.getImage()->s(), raw.getImage()->t(), *_runtimeOptions.driver()->bilinearReprojection() );
                        result = cropped.takeImage();
                    }
                }
            }
            if ( !result.valid() )
            {
                finalKey = finalKey.createParentKey();
                out_isFallback = true;
            }
        }

        if ( !result.valid() )
        {
            result = 0L;
            //result = _emptyImage.get();
            finalKey = key;
        }
    }
    else
    {
        // Fail is the image is blacklisted.
        if ( source->getBlacklist()->contains( key.getTileId() ) )
        {
            OE_DEBUG << LC << "createImageFromTileSource: blacklisted(" << key.str() << ")" << std::endl;
            return GeoImage::INVALID;
        }
    
        if ( !source->hasData( key ) )
        {
            OE_DEBUG << LC << "createImageFromTileSource: hasData(" << key.str() << ") == false" << std::endl;
            return GeoImage::INVALID;
        }
        result = source->createImage( key, op.get(), progress );
    }

    // Process images with full alpha to properly support MP blending.    
    if ( result != 0L && *_runtimeOptions.featherPixels())
    {
        ImageUtils::featherAlphaRegions( result.get() );
    }    
    
    // If image creation failed (but was not intentionally canceled),
    // blacklist this tile for future requests.
    if ( result == 0L && (!progress || !progress->isCanceled()) )
    {
        source->getBlacklist()->add( key.getTileId() );
    }

    return GeoImage(result.get(), key.getExtent());
}
osg::HeightField*
ElevationLayer::createHeightFieldFromTileSource(const TileKey&    key,
                                                ProgressCallback* progress)
{
    osg::ref_ptr<osg::HeightField> result;

    if (progress && progress->isCanceled())
    {
        return 0L;
    }

    TileSource* source = getTileSource();
    if ( !source )
    {
        if (progress) progress->message() = "no tile source";
        return 0L;
    }

    // If the key is blacklisted, fail.
    if ( source->getBlacklist()->contains( key ))
    {
        OE_DEBUG << LC << "Tile " << key.str() << " is blacklisted " << std::endl;
        if (progress) progress->message() = "blacklisted";
        return 0L;
    }

    // If the profiles are horizontally equivalent (different vdatums is OK), take the
    // quick route:
    if ( key.getProfile()->isHorizEquivalentTo( getProfile() ) )
    {
        // Only try to get data if the source actually has data
        if (!mayHaveData(key))
        {
            OE_DEBUG << LC << "Source for layer has no data at " << key.str() << std::endl;
            //if (progress) progress->message() = "mayHaveData=false";
            return 0L;
        }

        // Make it from the source:
        result = source->createHeightField( key, getOrCreatePreCacheOp(), progress );

        // If the result is good, we how have a heightfield but it's vertical values
        // are still relative to the tile source's vertical datum. Convert them.
        if (result.valid())
        {
            if ( ! key.getExtent().getSRS()->isVertEquivalentTo( getProfile()->getSRS() ) )
            {
                VerticalDatum::transform(
                    getProfile()->getSRS()->getVerticalDatum(),    // from
                    key.getExtent().getSRS()->getVerticalDatum(),  // to
                    key.getExtent(),
                    result.get() );
            }
        }
        
        // Blacklist the tile if it is the same projection as the source and
        // we can't get it and it wasn't cancelled
        if (!result.valid())
        {
            if ( progress == 0L || !progress->isCanceled() )
            {
                source->getBlacklist()->add( key );
            }
        }
    }

    // Otherwise, profiles don't match so we need to composite:
    else
    {
        // note: this method takes care of the vertical datum shift internally.
        osg::ref_ptr<NormalMap> dummyNormalMap;
        assembleHeightField( key, result, dummyNormalMap, progress );
    }

    if (progress && progress->isCanceled())
    {
        return 0L;
    }

    return result.release();
}
Example #20
0
void CacheSeed::seed( Map* map )
{
    Threading::ScopedReadLock lock( map->getMapDataMutex() );

    if (!map->getCache())
    {
        OE_WARN << "Warning:  Map does not have a cache defined, please define a cache." << std::endl;
        return;
    }

    osg::ref_ptr<MapEngine> engine = new MapEngine(); //map->createMapEngine();

    std::vector< osg::ref_ptr<TileKey> > keys;
    map->getProfile()->getRootKeys(keys);

    //Set the default bounds to the entire profile if the user didn't override the bounds
    if (_bounds.xMin() == 0 && _bounds.yMin() == 0 &&
        _bounds.xMax() == 0 && _bounds.yMax() == 0)
    {
        const GeoExtent& mapEx =  map->getProfile()->getExtent();
        _bounds = Bounds( mapEx.xMin(), mapEx.yMin(), mapEx.xMax(), mapEx.yMax() );
    }


    bool hasCaches = false;
    int src_min_level = INT_MAX;
    int src_max_level = 0;

    //Assumes the the TileSource will perform the caching for us when we call createImage
    for( MapLayerList::const_iterator i = map->getImageMapLayers().begin(); i != map->getImageMapLayers().end(); i++ )
    {
		MapLayer* layer = i->get();
        TileSource* src = i->get()->getTileSource();

        if (layer->cacheOnly().get())
        {
            OE_WARN << "Warning:  Cannot seed b/c Layer \"" << layer->getName() << "\" is cache only." << std::endl;
            return;
        }
        else if (!src)
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource." << std::endl;
        }
        else if ( !src->supportsPersistentCaching() )
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" does not support seeding." << std::endl;
        }
        else if ( !layer->getCache() )
        {
            OE_NOTICE << "Notice: Layer \"" << layer->getName() << "\" has no persistent cache defined; skipping." << std::endl;
        }
        else
        {
            hasCaches = true;

			if (layer->minLevel().isSet() && layer->minLevel().get() < src_min_level)
                src_min_level = layer->minLevel().get();
			if (layer->maxLevel().isSet() && layer->maxLevel().get() > src_max_level)
                src_max_level = layer->maxLevel().get();
        }
    }

    for( MapLayerList::const_iterator i = map->getHeightFieldMapLayers().begin(); i != map->getHeightFieldMapLayers().end(); i++ )
    {
		MapLayer* layer = i->get();
        TileSource* src = i->get()->getTileSource();

        if (layer->cacheOnly().get())
        {
            OE_WARN << "Warning:  Cannot seed b/c Layer \"" << layer->getName() << "\" is cache only." << std::endl;
            return;
        }
        else if (!src)
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource." << std::endl;
        }
        else if ( !src->supportsPersistentCaching() )
        {
            OE_WARN << "Warning: Layer \"" << layer->getName() << "\" does not support seeding." << std::endl;
        }
        else if ( !layer->getCache() )
        {
            OE_NOTICE << "Notice: Layer \"" << src->getName() << "\" has no persistent cache defined; skipping." << std::endl;
        }
        else
        {
            hasCaches = true;

			if (layer->minLevel().isSet() && layer->minLevel().get() < src_min_level)
                src_min_level = layer->minLevel().get();
			if (layer->maxLevel().isSet() && layer->maxLevel().get() > src_max_level)
                src_max_level = layer->maxLevel().get();
		}
    }

    if (!hasCaches)
    {
        OE_NOTICE << "There are either no caches defined in the map, or no sources to cache. Exiting." << std::endl;
        return;
    }

    if ( src_max_level > 0 && src_max_level < _maxLevel )
    {
        _maxLevel = src_max_level;
    }

    OE_NOTICE << "Maximum cache level will be " << _maxLevel << std::endl;

    for (unsigned int i = 0; i < keys.size(); ++i)
    {
        processKey( map, engine.get(), keys[i].get() );
    }
}
Example #21
0
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;
}
Example #22
0
bool
TerrainLayer::isDynamic() const
{
    TileSource* ts = getTileSource();
    return ts ? ts->isDynamic() : false;
}
Example #23
0
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() == 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() == 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);

                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 );
                }
            }
        }
    }

    //Adjust the # of tiles again to be bigger than computed to avoid giving false hope
    _total *= 2;
    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");
}
Example #24
0
osg::HeightField*
ElevationLayer::createHeightFieldFromTileSource(const TileKey&    key,
                                                ProgressCallback* progress)
{
    osg::HeightField* result = 0L;

    TileSource* source = getTileSource();
    if ( !source )
        return 0L;

    // If the key is blacklisted, fail.
    if ( source->getBlacklist()->contains( key.getTileId() ) )
    {
        OE_DEBUG << LC << "Tile " << key.str() << " is blacklisted " << std::endl;
        return 0L;
    }

    // If the profiles are horizontally equivalent (different vdatums is OK), take the
    // quick route:
    if ( key.getProfile()->isHorizEquivalentTo( getProfile() ) )
    {
        // Only try to get data if the source actually has data
        if ( !source->hasData(key) )
        {
            OE_DEBUG << LC << "Source for layer has no data at " << key.str() << std::endl;
            return 0L;
        }

        // Make it from the source:
        result = source->createHeightField( key, _preCacheOp.get(), progress );

        // If the result is good, we how have a heightfield but it's vertical values
        // are still relative to the tile source's vertical datum. Convert them.
        if ( result )
        {
            if ( ! key.getExtent().getSRS()->isVertEquivalentTo( getProfile()->getSRS() ) )
            {
                VerticalDatum::transform(
                    getProfile()->getSRS()->getVerticalDatum(),    // from
                    key.getExtent().getSRS()->getVerticalDatum(),  // to
                    key.getExtent(),
                    result );
            }
        }
        
        // Blacklist the tile if it is the same projection as the source and we can't get it and it wasn't cancelled
        if ( !result && (!progress || !progress->isCanceled()))
        {
            source->getBlacklist()->add( key.getTileId() );
        }
    }

    // Otherwise, profiles don't match so we need to composite:
    else
    {
        // note: this method takes care of the vertical datum shift internally.
        result = assembleHeightFieldFromTileSource( key, progress );
    }

#if 0
    // If the profiles don't match, use a more complicated technique to assemble the tile:
    if ( !key.getProfile()->isEquivalentTo( getProfile() ) )
    {
        result = assembleHeightFieldFromTileSource( key, progress );
    }
    else
    {
        // Only try to get data if the source actually has data
        if ( !source->hasData( key ) )
        {
            OE_DEBUG << LC << "Source for layer has no data at " << key.str() << std::endl;
            return 0L;
        }

        // Make it from the source:
        result = source->createHeightField( key, _preCacheOp.get(), progress );
    }
#endif



    return result;
}
Example #25
0
CacheBin*
TerrainLayer::getCacheBin( const Profile* profile, const std::string& binId )
{
    // make sure we've initialized the tile source first.
    TileSource* tileSource = getTileSource();

    // in no-cache mode, there are no cache bins.
    if ( getCachePolicy() == CachePolicy::NO_CACHE )
    {
        return 0L;
    }

    // if cache is not setted, return NULL
    if (_cache == NULL)
    {
        return 0L;
    }

    // see if the cache bin already exists and return it if so
    {
        Threading::ScopedReadLock shared(_cacheBinsMutex);
        CacheBinInfoMap::iterator i = _cacheBins.find( binId );
        if ( i != _cacheBins.end() )
            return i->second._bin.get();
    }

    // create/open the cache bin.
    {
        Threading::ScopedWriteLock exclusive(_cacheBinsMutex);

        // double-check:
        CacheBinInfoMap::iterator i = _cacheBins.find( binId );
        if ( i != _cacheBins.end() )
            return i->second._bin.get();

        // add the new bin:
        osg::ref_ptr<CacheBin> newBin = _cache->addBin( binId );

        // and configure:
        if ( newBin.valid() )
        {
            // attempt to read the cache metadata:
            CacheBinMetadata meta( newBin->readMetadata() );

            if ( meta.isValid() ) // cache exists and is valid.
            {
                // verify that the cache if compatible with the tile source:
                if ( tileSource && getProfile() )
                {
                    //todo: check the profile too
                    if ( *meta._sourceDriver != tileSource->getOptions().getDriver() )
                    {
                        OE_WARN << LC << "Cache has an incompatible driver or profile... disabling"
                            << std::endl;
                        setCachePolicy( CachePolicy::NO_CACHE );
                        return 0L;
                    }
                }   

                else if ( isCacheOnly() && !_profile.valid() )
                {
                    // in cacheonly mode, create a profile from the first cache bin accessed
                    // (they SHOULD all be the same...)
                    _profile = Profile::create( *meta._sourceProfile );
                    _tileSize = *meta._sourceTileSize;
                }
            }

            else
            {
                // cache does not exist, so try to create it. A valid TileSource is necessary
                // for this.
                if ( tileSource && getProfile() )
                {
                    // no existing metadata; create some.
                    meta._cacheBinId      = binId;
                    meta._sourceName      = this->getName();
                    meta._sourceDriver    = tileSource->getOptions().getDriver();
                    meta._sourceTileSize  = getTileSize();
                    meta._sourceProfile   = getProfile()->toProfileOptions();
                    meta._cacheProfile    = profile->toProfileOptions();
                    meta._cacheCreateTime = DateTime().asTimeStamp();

                    // store it in the cache bin.
                    newBin->writeMetadata( meta.getConfig() );
                }
                else if ( isCacheOnly() )
                {
                    OE_WARN << LC <<
                        "Failed to open a cache for layer "
                        "because cache_only policy is in effect and bin [" << binId << "] "
                        "could not be located."
                        << std::endl;
                    return 0L;
                }
                else
                {
                    OE_WARN << LC <<
                        "Failed to create cache bin [" << binId << "] "
                        "because there is no valid tile source."
                        << std::endl;
                    return 0L;
                }
            }

            // store the bin.
            CacheBinInfo& newInfo = _cacheBins[binId];
            newInfo._metadata = meta;
            newInfo._bin      = newBin.get();

            OE_INFO << LC <<
                "Opened cache bin [" << binId << "]" << std::endl;
        }
        else
        {
            // bin creation failed, so disable caching for this layer.
            setCachePolicy( CachePolicy::NO_CACHE );
            OE_WARN << LC << "Failed to create a cache bin; cache disabled." << std::endl;
        }

        return newBin.get(); // not release()
    }
}
Example #26
0
unsigned
TerrainLayer::getTileSize() const
{
    TileSource* ts = getTileSource();
    return ts ? ts->getPixelsPerTile() : _tileSize;
}