osgEarth 2.1.1
Classes | Public Member Functions | Private Attributes

TileBuilder Class Reference

Inheritance diagram for TileBuilder:
Collaboration diagram for TileBuilder:

List of all members.

Classes

struct  Job
struct  SourceRepo

Public Member Functions

 TileBuilder (const Map *map, const OSGTerrainOptions &terrainOptions, TaskService *service)
void createTile (const TileKey &key, bool parallelize, osg::ref_ptr< Tile > &out_tile, bool &out_hasRealData, bool &out_hasLodBlendedLayers)
JobcreateJob (const TileKey &key, Threading::MultiEvent &semaphore)
void runJob (Job *job)
void finalizeJob (Job *job, osg::ref_ptr< Tile > &out_tile, bool &out_hasRealData, bool &out_hasLodBlending)
TaskServicegetTaskService () const

Private Attributes

const Map_map
TaskService_service
const OSGTerrainOptions_terrainOptions

Detailed Description

Definition at line 30 of file TileBuilder.


Constructor & Destructor Documentation

TileBuilder::TileBuilder ( const Map map,
const OSGTerrainOptions terrainOptions,
TaskService service 
)

Definition at line 182 of file TileBuilder.cpp.

                                                                                                      :
_map( map ),
_terrainOptions( terrainOptions ),
_service( service )
{
    //nop
}

Member Function Documentation

TileBuilder::Job * TileBuilder::createJob ( const TileKey key,
Threading::MultiEvent semaphore 
)

Definition at line 191 of file TileBuilder.cpp.

{
    Job* job = new Job( key, _map );

    // create the image layer tasks:
    for( ImageLayerVector::const_iterator i = job->_mapf.imageLayers().begin(); i != job->_mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();
        if ( layer->isKeyValid(key) )
        {
            ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore );
            j->init( key, layer, job->_mapf.getMapInfo(), _terrainOptions, job->_repo );
            j->setPriority( -(float)key.getLevelOfDetail() );
            job->_tasks.push_back( j );
        }
    }

    // If we have elevation layers, start an elevation job as well. Otherwise just create an
    // empty one while we're waiting for the images to load.
    if ( job->_mapf.elevationLayers().size() > 0 )
    {
        ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore );
        ej->init( key, job->_mapf, _terrainOptions, job->_repo );
        ej->setPriority( -(float)key.getLevelOfDetail() );
        job->_tasks.push_back( ej );
    }

    return job;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void TileBuilder::createTile ( const TileKey key,
bool  parallelize,
osg::ref_ptr< Tile > &  out_tile,
bool &  out_hasRealData,
bool &  out_hasLodBlendedLayers 
)

Definition at line 304 of file TileBuilder.cpp.

{
    MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS );

    SourceRepo repo;

    // init this to false, then search for real data. "Real data" is data corresponding
    // directly to the key, as opposed to fallback data, which is derived from a lower
    // LOD key.
    out_hasRealData = false;
    out_hasLodBlendedLayers = false;

    const MapInfo& mapInfo = mapf.getMapInfo();

    // If we need more than one layer, fetch them in parallel.
    // TODO: change the test based on isKeyValid total.
    if ( parallelize && (mapf.imageLayers().size() + mapf.elevationLayers().size() > 1) )
    {
        // count the valid layers.
        int jobCount = 0;

        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            if ( i->get()->isKeyValid( key ) )
                ++jobCount;

            if ( i->get()->getImageLayerOptions().lodBlending() == true )
                out_hasLodBlendedLayers = true;
        }

        if ( mapf.elevationLayers().size() > 0 )
            ++jobCount;

        // A thread job monitoring event:
        Threading::MultiEvent semaphore( jobCount );

        // Start the image layer jobs:
        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            if ( layer->isKeyValid(key) )
            {
                ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore );
                j->init( key, layer, mapInfo, _terrainOptions, repo );
                j->setPriority( -(float)key.getLevelOfDetail() );
                _service->add( j );
            }
        }

        // If we have elevation layers, start an elevation job as well. Otherwise just create an
        // empty one while we're waiting for the images to load.
        if ( mapf.elevationLayers().size() > 0 )
        {
            ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore );
            ej->init( key, mapf, _terrainOptions, repo );
            ej->setPriority( -(float)key.getLevelOfDetail() );
            _service->add( ej );
        }
        else
        {
            BuildElevLayer build;
            build.init( key, mapf, _terrainOptions, repo );
            build.execute();
        }

        // Wait for all the jobs to finish.
        semaphore.wait();
    }
    
    // Fetch the image data serially:
    else
    {
        // gather all the image layers serially.
        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            if ( layer->isKeyValid(key) )
            {
                BuildColorLayer build;
                build.init( key, layer, mapInfo, _terrainOptions, repo );
                build.execute();
            }

            if ( layer->getImageLayerOptions().lodBlending() == true )
                out_hasLodBlendedLayers = true;
        }
        
        // make an elevation layer.
        BuildElevLayer build;
        build.init( key, mapf, _terrainOptions, repo );
        build.execute();
    }

    // Bail out now if there's no data to be had.
    if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !repo._elevLayer.getHFLayer() )
    {
        osg::HeightField* hf = key.getProfile()->getVerticalSRS()->createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        repo._elevLayer = CustomElevLayer( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        if ( !i->get()->isKeyValid(key) )
        {
            if ( !emptyImage.valid() )
                emptyImage = ImageUtils::createEmptyImage();

            repo.add( CustomColorLayer(
                i->get(), emptyImage.get(),
                locator,
                key.getLevelOfDetail(),
                key,
                true ) );
        }
    }

    //osg::Vec3dArray* maskBounds = 0L;
    //osgEarth::MaskLayer* mask = mapf.getTerrainMaskLayer();
    //if (mask)
    //  maskBounds = mask->getOrCreateBoundary();

    // Ready to create the actual tile.
    AssembleTile assemble;
    assemble.init( key, mapInfo, _terrainOptions, repo, mapf.terrainMaskLayers() );
    assemble.execute();

    if (!out_hasRealData)
    {
        // Check the results and see if we have any real data.
        for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i )
        {
            if ( !i->second.isFallbackData() ) 
            {
                out_hasRealData = true;
                break;
            }
        }
    }

    if ( !out_hasRealData && !repo._elevLayer.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_tile = assemble._tile;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void TileBuilder::finalizeJob ( TileBuilder::Job job,
osg::ref_ptr< Tile > &  out_tile,
bool &  out_hasRealData,
bool &  out_hasLodBlending 
)

Definition at line 229 of file TileBuilder.cpp.

{
    SourceRepo& repo = job->_repo;

    out_hasRealData = false;
    out_hasLodBlending = false;

    // Bail out now if there's no data to be had.
    if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() )
    {
        return;
    }

    const TileKey& key = job->_key;
    const MapInfo& mapInfo = job->_mapf.getMapInfo();

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !repo._elevLayer.getHFLayer() )
    {
        osg::HeightField* hf = key.getProfile()->getVerticalSRS()->createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        repo._elevLayer = CustomElevLayer( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = job->_mapf.imageLayers().begin(); i != job->_mapf.imageLayers().end(); ++i )
    {
        if ( !i->get()->isKeyValid(key) )
        {
            if ( !emptyImage.valid() )
                emptyImage = ImageUtils::createEmptyImage();

            repo.add( CustomColorLayer(
                i->get(), emptyImage.get(),
                locator,
                key.getLevelOfDetail(),
                key,
                true ) );
        }

        if ( i->get()->getImageLayerOptions().lodBlending() == true )
            out_hasLodBlending = true;
    }

    // Ready to create the actual tile.
    AssembleTile assemble;
    assemble.init( key, mapInfo, _terrainOptions, repo );
    assemble.execute();

    // Check the results and see if we have any real data.
    for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i )
    {
        if ( !i->second.isFallbackData() ) 
        {
            out_hasRealData = true;
            break;
        }
    }
    if ( !out_hasRealData && !repo._elevLayer.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_tile = assemble._tile;
}

Here is the call graph for this function:

Here is the caller graph for this function:

TaskService* TileBuilder::getTaskService ( ) const [inline]

Definition at line 87 of file TileBuilder.

{ return _service; }
void TileBuilder::runJob ( TileBuilder::Job job)

Definition at line 222 of file TileBuilder.cpp.

{
    for( TaskRequestVector::iterator i = job->_tasks.begin(); i != job->_tasks.end(); ++i )
        _service->add( i->get() );
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

const Map* TileBuilder::_map [private]

Definition at line 90 of file TileBuilder.

Definition at line 91 of file TileBuilder.

Definition at line 92 of file TileBuilder.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines