Esempio n. 1
0
bool
MapFrame::isCached( const TileKey& key ) const
{
    //Check to see if the tile will load fast
    // Check the imagery layers
    for( ImageLayerVector::const_iterator i = imageLayers().begin(); i != imageLayers().end(); i++ )
    {   
        //If we're cache only we should be fast
        if (i->get()->isCacheOnly()) continue;

        osg::ref_ptr< TileSource > source = i->get()->getTileSource();
        if (!source.valid()) continue;

        //If the tile is blacklisted, it should also be fast.
        if ( source->getBlacklist()->contains( key.getTileId() ) ) continue;
        //If no data is available on this tile, we'll be fast
        if ( !source->hasData( key ) ) continue;

        if ( !i->get()->isCached( key ) ) return false;
    }

    for( ElevationLayerVector::const_iterator i = elevationLayers().begin(); i != elevationLayers().end(); ++i )
    {
        //If we're cache only we should be fast
        if (i->get()->isCacheOnly()) continue;

        osg::ref_ptr< TileSource > source = i->get()->getTileSource();
        if (!source.valid()) continue;

        //If the tile is blacklisted, it should also be fast.
        if ( source->getBlacklist()->contains( key.getTileId() ) ) continue;
        if ( !source->hasData( key ) ) continue;
        if ( !i->get()->isCached( key ) )
        {
            return false;
        }
    }

    return true;        
}
Esempio n. 2
0
Tile::Tile( const TileKey& key, GeoLocator* keyLocator, bool quickReleaseGLObjects ) :
_key( key ),
_locator( keyLocator ),
_quickReleaseGLObjects( quickReleaseGLObjects ),
_hasBeenTraversed( false ),
_verticalScale( 1.0f ),
_parentTileSet( false ),
_tileId( key.getTileId() ),
_dirty( true )
{
    this->setThreadSafeRefUnref( true );
    this->setName( key.str() );

    // initially bump the update requirement so that this tile will receive an update
    // traversal the first time through. It is on the first update traversal that we
    // know the tile is in the scene graph and that it can be registered with the terrain.
    ADJUST_UPDATE_TRAV_COUNT( this, 1 );

}
Esempio n. 3
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());
}
bool
ElevationManager::getElevationImpl(double x, double y,
                                   double resolution,
                                   const SpatialReference* srs,
                                   double& out_elevation,
                                   double& out_resolution)
{
    if ( _maxDataLevel == 0 || _tileSize == 0 )
    {
        // this means there are no heightfields.
        out_elevation = 0.0;
        return true;
    }
   
    // this is the ideal LOD for the requested resolution:
    unsigned int idealLevel = resolution > 0.0
        ? _mapf.getProfile()->getLevelOfDetailForHorizResolution( resolution, _tileSize )
        : _maxDataLevel;        

    // based on the heightfields available, this is the best we can theorically do:
    unsigned int bestAvailLevel = osg::minimum( idealLevel, _maxDataLevel );
    if (_maxLevelOverride >= 0)
    {
        bestAvailLevel = osg::minimum(bestAvailLevel, (unsigned int)_maxLevelOverride);
    }
    
    // transform the input coords to map coords:
    double map_x = x, map_y = y;
    if ( srs && !srs->isEquivalentTo( _mapf.getProfile()->getSRS() ) )
    {
        if ( !srs->transform2D( x, y, _mapf.getProfile()->getSRS(), map_x, map_y ) )
        {
            OE_WARN << LC << "Fail: coord transform failed" << std::endl;
            return false;
        }
    }

    osg::ref_ptr<osg::HeightField> hf;
    osg::ref_ptr<osgTerrain::TerrainTile> tile;

    // get the tilekey corresponding to the tile we need:
    TileKey key = _mapf.getProfile()->createTileKey( map_x, map_y, bestAvailLevel );
    if ( !key.valid() )
    {
        OE_WARN << LC << "Fail: coords fall outside map" << std::endl;
        return false;
    }

    // now, see if we already have this tile loaded somewhere:
    osgTerrain::TileID tileId = key.getTileId();

    if ( !tile.valid() )
    {
        // next check the local tile cache:
        TileTable::const_iterator i = _tileCache.find( tileId );
        if ( i != _tileCache.end() )
            tile = i->second.get();
    }

         
    // if we found it, make sure it has a heightfield in it:
    if ( tile.valid() )
    {
        osgTerrain::HeightFieldLayer* layer = dynamic_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer());
        if ( layer )
        {
            hf = layer->getHeightField();
        }
        if ( !hf.valid() )
        {
            tile = NULL;
        }
    }

    // if we didn't find it (or it didn't have heightfield data), build it.
    if ( !tile.valid() )
    {
        //OE_NOTICE << "ElevationManager: cache miss" << std::endl;

        // generate the heightfield corresponding to the tile key, automatically falling back
        // on lower resolution if necessary:
        _mapf.getHeightField( key, true, hf, 0L );

        // bail out if we could not make a heightfield a all.
        if ( !hf.valid() )
        {
            OE_WARN << "ElevationManager: unable to create heightfield" << std::endl;
            return false;
        }

        GeoLocator* locator = GeoLocator::createForKey( key, _mapf.getMapInfo() );

        tile = new osgTerrain::TerrainTile();

        osgTerrain::HeightFieldLayer* layer = new osgTerrain::HeightFieldLayer( hf.get() );
        layer->setLocator( locator );

        tile->setElevationLayer( layer );
        tile->setRequiresNormals( false );
        tile->setTerrainTechnique( new osgTerrain::GeometryTechnique );

        // store it in the local tile cache.
        // TODO: limit the size of the cache with a parallel FIFO list.
        _tileCache[tileId] = tile.get();
        _tileCacheFIFO.push_back( tileId );

        // prune the cache. this is a terrible pruning method.
        if ( _tileCache.size() > _maxCacheSize )
        {
            osgTerrain::TileID id = _tileCacheFIFO.front();
            _tileCacheFIFO.pop_front();
            if ( tileId != id )
                _tileCache.erase( id );
        }
    }


    // see what the actual resolution of the heightfield is.
    out_resolution = (double)hf->getXInterval();


    // finally it's time to get a height value:
    if ( _technique == TECHNIQUE_PARAMETRIC )
    {
        const GeoExtent& extent = key.getExtent();
        double xInterval = extent.width()  / (double)(hf->getNumColumns()-1);
        double yInterval = extent.height() / (double)(hf->getNumRows()-1);
        out_elevation = (double) HeightFieldUtils::getHeightAtLocation( hf.get(), map_x, map_y, extent.xMin(), extent.yMin(), xInterval, yInterval );
        return true;
    }
    else // ( _technique == TECHNIQUE_GEOMETRIC )
    {
        osg::Vec3d start, end, zero;

        if ( _mapf.getMapInfo().isGeocentric() )
        {
            const osg::EllipsoidModel* ellip = _mapf.getProfile()->getSRS()->getEllipsoid();

            ellip->convertLatLongHeightToXYZ(
                osg::DegreesToRadians( map_y ),
                osg::DegreesToRadians( map_x ),
                50000,
                start.x(), start.y(), start.z() );

            ellip->convertLatLongHeightToXYZ(
                osg::DegreesToRadians( map_y ),
                osg::DegreesToRadians( map_x ),
                -50000,
                end.x(), end.y(), end.z() );

            ellip->convertLatLongHeightToXYZ(
                osg::DegreesToRadians( map_y ),
                osg::DegreesToRadians( map_x ),
                0.0,
                zero.x(), zero.y(), zero.z() );
        }
        else // PROJECTED
        {
            start.x() = map_x; start.y() = map_y; start.z() = 50000;
            end.x() = map_x; end.y() = map_y; end.z() = -50000;
            zero.x() = map_x; zero.y() = map_y; zero.z() = 0;
        }

        osgUtil::LineSegmentIntersector* i = new osgUtil::LineSegmentIntersector( start, end );
        osgUtil::IntersectionVisitor iv;
        iv.setIntersector( i );

        tile->accept( iv );

        osgUtil::LineSegmentIntersector::Intersections& results = i->getIntersections();
        if ( !results.empty() )
        {
            const osgUtil::LineSegmentIntersector::Intersection& result = *results.begin();
            osg::Vec3d isectPoint = result.getWorldIntersectPoint();
            out_elevation = (isectPoint-end).length2() > (zero-end).length2()
                ? (isectPoint-zero).length()
                : -(isectPoint-zero).length();
            return true;            
        }

        OE_WARN << "ElevationManager: no intersections" << std::endl;
        return false;
    }
}
Esempio n. 5
0
osg::Node*
OSGTileFactory::createPlaceholderTile(const MapFrame&   mapf,
                                      StreamingTerrain* terrain,
                                      const TileKey&    key )
{
    // Start out by finding the nearest registered ancestor tile, since the placeholder is
    // going to be based on inherited data. Note- the ancestor may not be the immediate
    // parent, b/c the parent may or may not be in the scene graph.
    TileKey ancestorKey = key.createParentKey();
    osg::ref_ptr<StreamingTile> ancestorTile;
    while( !ancestorTile.valid() && ancestorKey.valid() )
    {
        terrain->getTile( ancestorKey.getTileId(), ancestorTile );
        if ( !ancestorTile.valid() )
            ancestorKey = ancestorKey.createParentKey();
    }
    if ( !ancestorTile.valid() )
    {
        OE_WARN << LC << "cannot find ancestor tile for (" << key.str() << ")" <<std::endl;
        return 0L;
    }

    OE_DEBUG << LC << "Creating placeholder for " << key.str() << std::endl;

    const MapInfo& mapInfo = mapf.getMapInfo();

    bool hasElevation = mapf.elevationLayers().size() > 0;

    // Build a "placeholder" tile.
    double xmin, ymin, xmax, ymax;
    key.getExtent().getBounds( xmin, ymin, xmax, ymax );

    // A locator will place the tile on the globe:
    osg::ref_ptr<GeoLocator> locator = GeoLocator::createForKey( key, mapInfo );

    // The empty tile:
    StreamingTile* tile = new StreamingTile( key, locator.get(), terrain->getQuickReleaseGLObjects() );
    tile->setTerrainTechnique( terrain->cloneTechnique() );
    tile->setVerticalScale( _terrainOptions.verticalScale().value() );
    tile->setDataVariance( osg::Object::DYNAMIC );
    //tile->setLocator( locator.get() );

    // Attach an updatecallback to normalize the edges of TerrainTiles.
#if 0
    if ( hasElevation && _terrainOptions.normalizeEdges().get() )
    {
        tile->setUpdateCallback(new TerrainTileEdgeNormalizerUpdateCallback());
        tile->setDataVariance(osg::Object::DYNAMIC);
    }
#endif

    // Generate placeholder imagery and elevation layers. These "inherit" data from an
    // ancestor tile.
    {
        //Threading::ScopedReadLock parentLock( ancestorTile->getTileLayersMutex() );
        addPlaceholderImageLayers     ( tile, ancestorTile.get() );
        addPlaceholderHeightfieldLayer( tile, ancestorTile.get(), locator.get(), key, ancestorKey );
    }

    // calculate the switching distances:
    osg::BoundingSphere bs = tile->getBound();
    double max_range = 1e10;
    double radius = bs.radius();
    double min_range = radius * _terrainOptions.minTileRangeFactor().get();

    // Set the skirt height of the heightfield
    osgTerrain::HeightFieldLayer* hfLayer = static_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer());
    if (!hfLayer)
    {
        OE_WARN << LC << "Warning: Couldn't get hfLayer for " << key.str() << std::endl;
    }
    hfLayer->getHeightField()->setSkirtHeight(radius * _terrainOptions.heightFieldSkirtRatio().get() );

    // In a Plate Carre tesselation, scale the heightfield elevations from meters to degrees
    if ( mapInfo.isPlateCarre() && hfLayer->getHeightField() )
        HeightFieldUtils::scaleHeightFieldToDegrees( hfLayer->getHeightField() );

    bool markTileLoaded = false;

    if ( _terrainOptions.loadingPolicy()->mode().get() != LoadingPolicy::MODE_STANDARD )
    {
        markTileLoaded = true;
        tile->setHasElevationHint( hasElevation );
    }

    // install a tile switcher:
    tile->attachToTerrain( terrain );
    //tile->setTerrain( terrain );
    //terrain->registerTile( tile );

    osg::Node* result = 0L;

    // create a PLOD so we can keep subdividing:
    osg::PagedLOD* plod = new osg::PagedLOD();
    plod->setCenter( bs.center() );
    plod->addChild( tile, min_range, max_range );

    if ( key.getLevelOfDetail() < (unsigned int)getTerrainOptions().maxLOD().get() )
    {
        plod->setFileName( 1, createURI( _engineId, key ) ); //map->getId(), key ) );
        plod->setRange( 1, 0.0, min_range );
    }
    else
    {
        plod->setRange( 0, 0, FLT_MAX );
    }

#if 0 //USE_FILELOCATIONCALLBACK
    osgDB::Options* options = new osgDB::Options;
    options->setFileLocationCallback( new FileLocationCallback);
    plod->setDatabaseOptions( options );
#endif

    result = plod;

    // Install a callback that will load the actual tile data via the pager.
    result->addCullCallback( new PopulateStreamingTileDataCallback( _cull_thread_mapf ) );

    // Install a cluster culler (FIXME for cube mode)
    //bool isCube = map->getMapOptions().coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE;
    if ( mapInfo.isGeocentric() && !mapInfo.isCube() )
    {
        osg::ClusterCullingCallback* ccc = createClusterCullingCallback( tile, locator->getEllipsoidModel() );
        result->addCullCallback( ccc );
    }     

    return result;
}
// This method is called by StreamingTerrainNode::traverse() in the UPDATE TRAVERSAL.
void
StreamingTerrainNode::refreshFamily(const MapInfo&           mapInfo,
                                    const TileKey&           key,
                                    StreamingTile::Relative* family,
                                    bool                     tileTableLocked )
{
    osgTerrain::TileID tileId = key.getTileId();

    // geocentric maps wrap around in the X dimension.
    bool wrapX = mapInfo.isGeocentric();
    unsigned int tileCountX, tileCountY;
    mapInfo.getProfile()->getNumTiles( tileId.level, tileCountX, tileCountY );

    // Relative::PARENT
    {
        family[StreamingTile::Relative::PARENT].expected = true; // TODO: is this always correct?
        family[StreamingTile::Relative::PARENT].elevLOD = -1;
        family[StreamingTile::Relative::PARENT].imageLODs.clear();
        family[StreamingTile::Relative::PARENT].tileID = osgTerrain::TileID( tileId.level-1, tileId.x/2, tileId.y/2 );

        osg::ref_ptr<StreamingTile> parent;
        getTile( family[StreamingTile::Relative::PARENT].tileID, parent, !tileTableLocked );
        if ( parent.valid() )
        {
            family[StreamingTile::Relative::PARENT].elevLOD = parent->getElevationLOD();

            ColorLayersByUID relLayers;
            parent->getCustomColorLayers( relLayers );

            for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
            {
                family[StreamingTile::Relative::PARENT].imageLODs[i->first] = i->second.getLevelOfDetail();
            }
        }
    }

    // Relative::WEST
    {
        family[StreamingTile::Relative::WEST].expected = tileId.x > 0 || wrapX;
        family[StreamingTile::Relative::WEST].elevLOD = -1;
        family[StreamingTile::Relative::WEST].imageLODs.clear();
        family[StreamingTile::Relative::WEST].tileID = osgTerrain::TileID( tileId.level, tileId.x > 0? tileId.x-1 : tileCountX-1, tileId.y );
        osg::ref_ptr<StreamingTile> west;
        getTile( family[StreamingTile::Relative::WEST].tileID, west, !tileTableLocked );
        if ( west.valid() )
        {
            family[StreamingTile::Relative::WEST].elevLOD = west->getElevationLOD();

            ColorLayersByUID relLayers;
            west->getCustomColorLayers( relLayers );

            for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
            {
                family[StreamingTile::Relative::WEST].imageLODs[i->first] = i->second.getLevelOfDetail();
            }
        }
    }

    // Relative::NORTH
    {
        family[StreamingTile::Relative::NORTH].expected = tileId.y < (int)tileCountY-1;
        family[StreamingTile::Relative::NORTH].elevLOD = -1;
        family[StreamingTile::Relative::NORTH].imageLODs.clear();
        family[StreamingTile::Relative::NORTH].tileID = osgTerrain::TileID( tileId.level, tileId.x, tileId.y < (int)tileCountY-1 ? tileId.y+1 : 0 );
        osg::ref_ptr<StreamingTile> north;
        getTile( family[StreamingTile::Relative::NORTH].tileID, north, !tileTableLocked );
        if ( north.valid() )
        {
            family[StreamingTile::Relative::NORTH].elevLOD = north->getElevationLOD();

            ColorLayersByUID relLayers;
            north->getCustomColorLayers( relLayers );

            for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
            {
                family[StreamingTile::Relative::NORTH].imageLODs[i->first] = i->second.getLevelOfDetail();
            }
        }
    }

    // Relative::EAST
    {
        family[StreamingTile::Relative::EAST].expected = tileId.x < (int)tileCountX-1 || wrapX;
        family[StreamingTile::Relative::EAST].elevLOD = -1;
        family[StreamingTile::Relative::EAST].imageLODs.clear();
        family[StreamingTile::Relative::EAST].tileID = osgTerrain::TileID( tileId.level, tileId.x < (int)tileCountX-1 ? tileId.x+1 : 0, tileId.y );
        osg::ref_ptr<StreamingTile> east;
        getTile( family[StreamingTile::Relative::EAST].tileID, east, !tileTableLocked );
        if ( east.valid() )
        {
            family[StreamingTile::Relative::EAST].elevLOD = east->getElevationLOD();

            ColorLayersByUID relLayers;
            east->getCustomColorLayers( relLayers );

            for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
            {
                family[StreamingTile::Relative::EAST].imageLODs[i->first] = i->second.getLevelOfDetail();
            }
        }
    }

    // Relative::SOUTH
    {
        family[StreamingTile::Relative::SOUTH].expected = tileId.y > 0;
        family[StreamingTile::Relative::SOUTH].elevLOD = -1;
        family[StreamingTile::Relative::SOUTH].imageLODs.clear();
        family[StreamingTile::Relative::SOUTH].tileID = osgTerrain::TileID( tileId.level, tileId.x, tileId.y > 0 ? tileId.y-1 : tileCountY-1 );
        osg::ref_ptr<StreamingTile> south;
        getTile( family[StreamingTile::Relative::SOUTH].tileID, south, !tileTableLocked );
        if ( south.valid() )
        {
            family[StreamingTile::Relative::SOUTH].elevLOD = south->getElevationLOD();

            ColorLayersByUID relLayers;
            south->getCustomColorLayers( relLayers );

            for( ColorLayersByUID::const_iterator i = relLayers.begin(); i != relLayers.end(); ++i )
            {
                family[StreamingTile::Relative::SOUTH].imageLODs[i->first] = i->second.getLevelOfDetail();
            }
        }
    }
}
Esempio n. 7
0
osg::HeightField*
ElevationLayer::assembleHeightFieldFromTileSource(const TileKey&    key,
                                                  ProgressCallback* progress)
{			
    osg::HeightField* result = 0L;

    // Collect the heightfields for each of the intersecting tiles.
    GeoHeightFieldVector heightFields;

    //Determine the intersecting keys
    std::vector< TileKey > intersectingTiles;
    getProfile()->getIntersectingTiles( key, intersectingTiles );


    //Maintain a list of heightfield tiles that have been added to the list already.
    std::set< osgTerrain::TileID > existingTiles; 

    // collect heightfield for each intersecting key. Note, we're hitting the
    // underlying tile source here, so there's no vetical datum shifts happening yet.
    // we will do that later.
    if ( intersectingTiles.size() > 0 )
    {
        for (unsigned int i = 0; i < intersectingTiles.size(); ++i)
        {
            const TileKey& layerKey = intersectingTiles[i];

            if ( isKeyValid(layerKey) )
            {
                osg::HeightField* hf = createHeightFieldFromTileSource( layerKey, progress );
                if ( hf )
                {
                    heightFields.push_back( GeoHeightField(hf, layerKey.getExtent()) );
                }
                else
                { 
                    // We couldn't get a heightfield at the given key so fall back on parent tiles
                    TileKey parentKey = layerKey.createParentKey();
                    while (!hf && parentKey.valid())
                    {
                        // Make sure we haven't already added this heightfield to the list.
                        // This could happen if you have multiple high resolution tiles that dont' have data.
                        // So if you have four level 5 tiles with no data, they will fall back on the same level 4 tile.
                        // This existingTiles check makes sure we don't process and add the same tile multiple times
                        if (existingTiles.find(parentKey.getTileId()) == existingTiles.end()) 
                        {
                            hf = createHeightFieldFromTileSource( parentKey, progress );
                            if (hf)
                            {
                                heightFields.push_back( GeoHeightField(hf, parentKey.getExtent()) );                                
                                existingTiles.insert(parentKey.getTileId());
                                break;
                            }                        
                            parentKey = parentKey.createParentKey();
                        }                        
                        else
                        {                            
                            break;
                        }                        
                    }                    
                }
            }
        }
    }

    // If we actually got a HeightField, resample/reproject it to match the incoming TileKey's extents.
    if (heightFields.size() > 0)
    {		
        unsigned int width = 0;
        unsigned int height = 0;

        for (GeoHeightFieldVector::iterator itr = heightFields.begin(); itr != heightFields.end(); ++itr)
        {
            if (itr->getHeightField()->getNumColumns() > width)
                width = itr->getHeightField()->getNumColumns();
            if (itr->getHeightField()->getNumRows() > height) 
                height = itr->getHeightField()->getNumRows();                        
        }

        //Now sort the heightfields by resolution to make sure we're sampling the highest resolution one first.
        std::sort( heightFields.begin(), heightFields.end(), GeoHeightField::SortByResolutionFunctor());        

        result = new osg::HeightField();
        result->allocate(width, height);

        //Go ahead and set up the heightfield so we don't have to worry about it later
        double minx, miny, maxx, maxy;
        key.getExtent().getBounds(minx, miny, maxx, maxy);
        double dx = (maxx - minx)/(double)(width-1);
        double dy = (maxy - miny)/(double)(height-1);

        //Create the new heightfield by sampling all of them.
        for (unsigned int c = 0; c < width; ++c)
        {
            double x = minx + (dx * (double)c);
            for (unsigned r = 0; r < height; ++r)
            {
                double y = miny + (dy * (double)r);

                //For each sample point, try each heightfield.  The first one with a valid elevation wins.
                float elevation = NO_DATA_VALUE;
                for (GeoHeightFieldVector::iterator itr = heightFields.begin(); itr != heightFields.end(); ++itr)
                {
                    // get the elevation value, at the same time transforming it vertically into the 
                    // requesting key's vertical datum.
                    float e = 0.0;
                    if (itr->getElevation(key.getExtent().getSRS(), x, y, INTERP_BILINEAR, key.getExtent().getSRS(), e))
                    {
                        elevation = e;
                        break;
                    }
                }
                result->setHeight( c, r, elevation );                
            }
        }
    }

    return result;
}
Esempio n. 8
0
bool
MapFrame::isCached( const TileKey& key ) const
{
    // is there a map cache at all?
    if ( _map->getCache() == 0L )
        return false;

    //Check to see if the tile will load fast
    // Check the imagery layers
    for( ImageLayerVector::const_iterator i = imageLayers().begin(); i != imageLayers().end(); i++ )
    {   
        const ImageLayer* layer = i->get();

        if (!layer->getEnabled())
            continue;

        // If we're cache only we should be fast
        if (layer->isCacheOnly())
            continue;

        // no-cache mode? always slow
        if (layer->isNoCache())
            return false;

        // No tile source? skip it
        osg::ref_ptr< TileSource > source = layer->getTileSource();
        if (!source.valid())
            continue;

        //If the tile is blacklisted, it should also be fast.
        if ( source->getBlacklist()->contains( key.getTileId() ) )
            continue;

        //If no data is available on this tile, we'll be fast
        if ( !source->hasData( key ) )
            continue;

        if ( !layer->isCached(key) )
            return false;
    }

    for( ElevationLayerVector::const_iterator i = elevationLayers().begin(); i != elevationLayers().end(); ++i )
    {
        const ElevationLayer* layer = i->get();

        if (!layer->getEnabled())
            continue;

        //If we're cache only we should be fast
        if (layer->isCacheOnly())
            continue;

        // no-cache mode? always high-latency.
        if (layer->isNoCache())
            return false;

        osg::ref_ptr< TileSource > source = layer->getTileSource();
        if (!source.valid())
            continue;

        //If the tile is blacklisted, it should also be fast.
        if ( source->getBlacklist()->contains( key.getTileId() ) )
            continue;

        if ( !source->hasData( key ) )
            continue;

        if ( !i->get()->isCached( key ) )
            return false;
    }

    return true;
}