Esempio n. 1
0
void
Map::clear()
{
    ImageLayerVector     imageLayersRemoved;
    ElevationLayerVector elevLayersRemoved;
    ModelLayerVector     modelLayersRemoved;
    MaskLayerVector      maskLayersRemoved;

    Revision newRevision;
    {
        Threading::ScopedWriteLock lock( _mapDataMutex );

        imageLayersRemoved.swap( _imageLayers );
        elevLayersRemoved.swap ( _elevationLayers );
        modelLayersRemoved.swap( _modelLayers );

        // calculate a new revision.
        newRevision = ++_dataModelRevision;
    }
    
    // a separate block b/c we don't need the mutex   
    for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ )
    {
        for( ImageLayerVector::iterator k = imageLayersRemoved.begin(); k != imageLayersRemoved.end(); ++k )
            i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_IMAGE_LAYER, newRevision, k->get()) );
        for( ElevationLayerVector::iterator k = elevLayersRemoved.begin(); k != elevLayersRemoved.end(); ++k )
            i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_ELEVATION_LAYER, newRevision, k->get()) );
        for( ModelLayerVector::iterator k = modelLayersRemoved.begin(); k != modelLayersRemoved.end(); ++k )
            i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_MODEL_LAYER, newRevision, k->get()) );
    }
}
Esempio n. 2
0
void GlobePlugin::elevationLayersChanged()
{
  if ( mIsGlobeRunning )
  {
    QgsDebugMsg( "elevationLayersChanged: Globe Running, executing" );
    osg::ref_ptr<Map> map = mMapNode->getMap();

    if ( map->getNumElevationLayers() > 1 )
    {
      mOsgViewer->getDatabasePager()->clear();
    }

    // Remove elevation layers
    ElevationLayerVector list;
    map->getElevationLayers( list );
    for ( ElevationLayerVector::iterator i = list.begin(); i != list.end(); ++i )
    {
      map->removeElevationLayer( *i );
    }

    // Add elevation layers
    QSettings settings;
    QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString();
    QTableWidget* table = mSettingsDialog->elevationDatasources();
    for ( int i = 0; i < table->rowCount(); ++i )
    {
      QString type = table->item( i, 0 )->text();
      //bool cache = table->item( i, 1 )->checkState();
      QString uri = table->item( i, 2 )->text();
      ElevationLayer* layer = 0;

      if ( "Raster" == type )
      {
        GDALOptions options;
        options.url() = uri.toStdString();
        layer = new osgEarth::ElevationLayer( uri.toStdString(), options );
      }
      else if ( "TMS" == type )
      {
        TMSOptions options;
        options.url() = uri.toStdString();
        layer = new osgEarth::ElevationLayer( uri.toStdString(), options );
      }
      map->addElevationLayer( layer );

      //if ( !cache || type == "Worldwind" ) layer->setCache( 0 ); //no tms cache for worldwind (use worldwind_cache)
    }
#if OSGEARTH_VERSION_GREATER_OR_EQUAL( 2, 5, 0 )
    double scale = QgsProject::instance()->readDoubleEntry( "Globe-Plugin", "/verticalScale", 1 );
    setVerticalScale( scale );
#endif
  }
  else
  {
    QgsDebugMsg( "layersChanged: Globe NOT running, skipping" );
    return;
  }
}
Esempio n. 3
0
void
MPTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    TerrainEngineNode::postInitialize( map, options );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::MASKED_TERRAIN_LAYERS, "mp-update" );

    // merge in the custom options:
    _terrainOptions.merge( options );

    // a shared registry for tile nodes in the scene graph.
    _liveTiles = new TileNodeRegistry("live");

    // set up a registry for quick release:
    if ( _terrainOptions.quickReleaseGLObjects() == true )
    {
        _deadTiles = new TileNodeRegistry("dead");
    }
    
    // initialize the model factory:
    _tileModelFactory = new TileModelFactory(getMap(), _liveTiles.get(), _terrainOptions );


    // handle an already-established map profile:
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( MapInfo(map) );
    }

    // populate the terrain with whatever data is in the map to begin with:
    if ( _terrain )
    {
        this->getTextureCompositor()->reserveTextureImageUnit( _textureImageUnit );
        updateShaders();
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new MPTerrainEngineNodeMapCallbackProxy(this) );

    // Attach to all of the existing elevation layers
    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
    {
        i->get()->addCallback( _elevationCallback.get() );
    }

    // register this instance to the osgDB plugin can find it.
    registerEngine( this );

    // now that we have a map, set up to recompute the bounds
    dirtyBound();
}
Esempio n. 4
0
Revision
Map::getElevationLayers( ElevationLayerVector& out_list ) const
{
    out_list.reserve( _elevationLayers.size() );

    Threading::ScopedReadLock lock( const_cast<Map*>(this)->_mapDataMutex );
    for( ElevationLayerVector::const_iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); ++i )
        out_list.push_back( i->get() );

    return _dataModelRevision;
}
Esempio n. 5
0
 void onClick(Control*)
 {
     Map* map = s_mapNode->getMap();
     ElevationLayerVector layers;
     map->getLayers(layers);
     map->beginUpdate();
     for (ElevationLayerVector::iterator i = layers.begin(); i != layers.end(); ++i) {
         map->removeLayer(i->get());
     }
     map->endUpdate();
 }
Esempio n. 6
0
void
OSGTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    TerrainEngineNode::postInitialize( map, options );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::MASKED_TERRAIN_LAYERS, "osgterrain-update" );
    _cull_mapf   = new MapFrame( map, Map::TERRAIN_LAYERS, "osgterrain-cull" );

    // merge in the custom options:
    _terrainOptions.merge( options );

    // handle an already-established map profile:
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( MapInfo(map) );
    }

    // populate the terrain with whatever data is in the map to begin with:
    if ( _terrain )
    {
        // update the terrain revision in threaded mode
        if ( _isStreaming )
        {
            static_cast<StreamingTerrainNode*>(_terrain)->updateTaskServiceThreads( *_update_mapf );
        }

        updateTextureCombining();
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new OSGTerrainEngineNodeMapCallbackProxy(this) );

    //Attach to all of the existing elevation layers
    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
    {
        i->get()->addCallback( _elevationCallback.get() );
    }

    //Attach a callback to all of the 

    // register me.
    registerEngine( this );

    // now that we have a map, set up to recompute the bounds
    dirtyBound();
}
Esempio n. 7
0
bool
OSGTileFactory::hasMoreLevels( Map* map, const TileKey& key )
{
    //Threading::ScopedReadLock lock( map->getMapDataMutex() );

    bool more_levels = false;

    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );

    for ( ImageLayerVector::const_iterator i = imageLayers.begin(); i != imageLayers.end(); i++ )
    {
        const ImageLayerOptions& opt = i->get()->getImageLayerOptions();

        if ( !opt.maxLevel().isSet() || key.getLevelOfDetail() < (unsigned int)*opt.maxLevel() )
        {
            more_levels = true;
            break;
        }
    }
    if ( !more_levels )
    {
        ElevationLayerVector elevLayers;
        map->getElevationLayers( elevLayers );

        for( ElevationLayerVector::const_iterator j = elevLayers.begin(); j != elevLayers.end(); j++ )
        {
            const ElevationLayerOptions& opt = j->get()->getElevationLayerOptions();

            if ( !opt.maxLevel().isSet() || key.getLevelOfDetail() < (unsigned int)*opt.maxLevel() )
            //if ( !j->get()->maxLevel().isSet() || key.getLevelOfDetail() < j->get()->maxLevel().get() )
            {
                more_levels = true;
                break;
            }
        }
    }

    return more_levels;
}
Esempio n. 8
0
void
Map::setLayersFromMap( const Map* map )
{
    this->clear();

    if ( map )
    {
        ImageLayerVector newImages;
        map->getImageLayers( newImages );
        for( ImageLayerVector::iterator i = newImages.begin(); i != newImages.end(); ++i )
            addImageLayer( i->get() );

        ElevationLayerVector newElev;
        map->getElevationLayers( newElev );
        for( ElevationLayerVector::iterator i = newElev.begin(); i != newElev.end(); ++i )
            addElevationLayer( i->get() );

        ModelLayerVector newModels;
        map->getModelLayers( newModels );
        for( ModelLayerVector::iterator i = newModels.begin(); i != newModels.end(); ++i )
            addModelLayer( i->get() );
    }
}
bool
ElevationPool::fetchTileFromMap(const TileKey& key, const ElevationLayerVector& layers, Tile* tile)
{
    tile->_loadTime = osg::Timer::instance()->tick();

    osg::ref_ptr<osg::HeightField> hf = new osg::HeightField();
    hf->allocate( _tileSize, _tileSize );

    // Initialize the heightfield to nodata
    hf->getFloatArray()->assign( hf->getFloatArray()->size(), NO_DATA_VALUE );

    TileKey keyToUse = key;
    while( !tile->_hf.valid() && keyToUse.valid() )
    {
        bool ok;
        if (_layers.empty())
        {
            OE_TEST << LC << "Populating from envelope (" << keyToUse.str() << ")\n";
            ok = layers.populateHeightFieldAndNormalMap(hf.get(), 0L, keyToUse, 0L, INTERP_BILINEAR, 0L);
        }
        else
        {
            OE_TEST << LC << "Populating from layers (" << keyToUse.str() << ")\n";
            ok = _layers.populateHeightFieldAndNormalMap(hf.get(), 0L, keyToUse, 0L, INTERP_BILINEAR, 0L);
        }

        if (ok)
        {
            tile->_hf = GeoHeightField( hf.get(), keyToUse.getExtent() );
            tile->_bounds = keyToUse.getExtent().bounds();
        }
        else
        {
            keyToUse = keyToUse.createParentKey();
        }
    }

    return tile->_hf.valid();
}
Esempio n. 10
0
void
updateControlPanel()
{
    // erase all child controls and just rebuild them b/c we're lazy.

    //Rebuild all the image layers    
    s_imageBox->clearControls();

    int row = 0;

    LabelControl* activeLabel = new LabelControl( "Image Layers", 20, osg::Vec4f(1,1,0,1) );
    s_imageBox->setControl( 1, row++, activeLabel );

    // the active map layers:
    MapFrame mapf( s_activeMap.get() );
    ImageLayerVector imageLayers;
    mapf.getLayers(imageLayers);
    int layerNum = imageLayers.size()-1;
    for( ImageLayerVector::const_reverse_iterator i = imageLayers.rbegin(); i != imageLayers.rend(); ++i )
        createLayerItem( s_imageBox, row++, layerNum--, imageLayers.size(), i->get(), true );

    MapFrame mapf2( s_inactiveMap.get() );
    imageLayers.clear();
    mapf2.getLayers(imageLayers);
    if ( imageLayers.size() > 0 )
    {
        LabelControl* inactiveLabel = new LabelControl( "Removed:", 18, osg::Vec4f(1,1,0,1) );
        s_imageBox->setControl( 1, row++, inactiveLabel );

        for( unsigned int i=0; i<imageLayers.size(); ++i )
        {
            createLayerItem( s_imageBox, row++, -1, -1, imageLayers[i].get(), false );
        }
    }




    //Rebuild the elevation layers
    s_elevationBox->clearControls();

    row = 0;

    activeLabel = new LabelControl( "Elevation Layers", 20, osg::Vec4f(1,1,0,1) );
    s_elevationBox->setControl( 1, row++, activeLabel );

    // the active map layers:
    ElevationLayerVector elevationLayers;
    mapf.getLayers(elevationLayers);

    layerNum = elevationLayers.size()-1;
    for( ElevationLayerVector::const_reverse_iterator i = elevationLayers.rbegin(); i != elevationLayers.rend(); ++i )
        createLayerItem( s_elevationBox, row++, layerNum--, elevationLayers.size(), i->get(), true );

    if ( mapf2.elevationLayers().size() > 0 )
    {
        LabelControl* inactiveLabel = new LabelControl( "Removed:", 18, osg::Vec4f(1,1,0,1) );
        s_elevationBox->setControl( 1, row++, inactiveLabel );

        for( unsigned int i=0; i<mapf2.elevationLayers().size(); ++i )
        {
            createLayerItem( s_elevationBox, row++, -1, -1, mapf2.elevationLayers().at(i), false );
        }
    }



    //Rebuild the model layers
    s_modelBox->clearControls();

    row = 0;

    activeLabel = new LabelControl( "Model Layers", 20, osg::Vec4f(1,1,0,1) );
    s_modelBox->setControl( 1, row++, activeLabel );

    // the active map layers:
    ModelLayerVector modelLayers;
    mapf.getLayers(modelLayers);
    for( ModelLayerVector::const_reverse_iterator i = modelLayers.rbegin(); i != modelLayers.rend(); ++i )
        createModelLayerItem( s_modelBox, row++, i->get(), true );
}
Esempio n. 11
0
void GlobePlugin::layersChanged()
{
  if ( mIsGlobeRunning )
  {
    QgsDebugMsg( "layersChanged: Globe Running, executing" );
    osg::ref_ptr<Map> map = mMapNode->getMap();

    if ( map->getNumImageLayers() > 1 || map->getNumElevationLayers() > 1 )
    {
      viewer.getDatabasePager()->clear();
    }

    // Remove elevation layers
    ElevationLayerVector list;
    map->getElevationLayers( list );
    for ( ElevationLayerVector::iterator i = list.begin(); i != list.end(); i++ )
    {
      map->removeElevationLayer( *i );
    }

    // Add elevation layers
    QSettings settings;
    QString cacheDirectory = settings.value( "cache/directory", QgsApplication::qgisSettingsDirPath() + "cache" ).toString();
    QTableWidget* table = mSettingsDialog.elevationDatasources();
    for ( int i = 0; i < table->rowCount(); ++i )
    {
      QString type = table->item( i, 0 )->text();
      bool cache = table->item( i, 1 )->checkState();
      QString uri = table->item( i, 2 )->text();
      ElevationLayer* layer = 0;

      if ( "Raster" == type )
      {
        GDALOptions options;
        options.url() = uri.toStdString();
        layer = new osgEarth::ElevationLayer( uri.toStdString(), options );
      }
      else if ( "Worldwind" == type )
      {
        WorldWindOptions options;
        options.elevationCachePath() = cacheDirectory.toStdString() + "/globe/worldwind_srtm";
        layer = new osgEarth::ElevationLayer( "WorldWind bil", options );
        TerrainEngineNode* terrainEngineNode = mMapNode->getTerrainEngine();
        terrainEngineNode->setVerticalScale( 2 );
        terrainEngineNode->setElevationSamplingRatio( 0.25 );
      }
      else if ( "TMS" == type )
      {
        TMSOptions options;
        options.url() = uri.toStdString();
        layer = new osgEarth::ElevationLayer( uri.toStdString(), options );
      }
      map->addElevationLayer( layer );

      if ( !cache || type == "Worldwind" ) layer->setCache( 0 ); //no tms cache for worldwind (use worldwind_cache)
    }

    //remove QGIS layer
    if ( mQgisMapLayer )
    {
      QgsDebugMsg( "removeMapLayer" );
      map->removeImageLayer( mQgisMapLayer );
    }

    //add QGIS layer
    QgsDebugMsg( "addMapLayer" );
    mTileSource = new QgsOsgEarthTileSource( mQGisIface );
    mTileSource->initialize( "", 0 );
    ImageLayerOptions options( "QGIS" );
    mQgisMapLayer = new ImageLayer( options, mTileSource );
    map->addImageLayer( mQgisMapLayer );
    mQgisMapLayer->setCache( 0 ); //disable caching
  }
  else
  {
    QgsDebugMsg( "layersChanged: Globe NOT running, skipping" );
    return;
  }
}
Esempio n. 12
0
void
MPTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    TerrainEngineNode::postInitialize( map, options );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::ENTIRE_MODEL, "mp-update" );

    // merge in the custom options:
    _terrainOptions.merge( options );

    // A shared registry for tile nodes in the scene graph. Enable revision tracking
    // if requested in the options. Revision tracking lets the registry notify all
    // live tiles of the current map revision so they can inrementally update
    // themselves if necessary.
    _liveTiles = new TileNodeRegistry("live");
    _liveTiles->setRevisioningEnabled( _terrainOptions.incrementalUpdate() == true );
    _liveTiles->setMapRevision( _update_mapf->getRevision() );

    // set up a registry for quick release:
    if ( _terrainOptions.quickReleaseGLObjects() == true )
    {
        _deadTiles = new TileNodeRegistry("dead");
    }

    // reserve GPU resources. Must do this before initializing the model factory.
    if ( _primaryUnit < 0 )
    {
        getResources()->reserveTextureImageUnit( _primaryUnit, "MP Engine Primary" );
    }

    // "Secondary" unit serves double duty; it's used for parent textures BUT it's also
    // used at the "slot" for the tile coordinates.
    if ( _secondaryUnit < 0 )
    {
        getResources()->reserveTextureImageUnit( _secondaryUnit, "MP Engine Secondary" );
    }
    
    // initialize the model factory:
    _tileModelFactory = new TileModelFactory(_liveTiles.get(), _terrainOptions, this);

    // handle an already-established map profile:
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( MapInfo(map) );
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new MPTerrainEngineNodeMapCallbackProxy(this) );

    // Prime with existing layers:
    _batchUpdateInProgress = true;

    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
        addElevationLayer( i->get() );

    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );
    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
        addImageLayer( i->get() );

    _batchUpdateInProgress = false;

    // register this instance to the osgDB plugin can find it.
    registerEngine( this );

    // set up the initial shaders and reserve the texture image units.
    updateState();

    // now that we have a map, set up to recompute the bounds
    dirtyBound();

    OE_INFO << LC << "Edge normalization is " << (_terrainOptions.normalizeEdges() == true? "ON" : "OFF") << std::endl;
}
Esempio n. 13
0
bool
ElevationLayerVector::populateHeightField(osg::HeightField*      hf,
                                          const TileKey&         key,
                                          const Profile*         haeProfile,
                                          ElevationInterpolation interpolation,
                                          ProgressCallback*      progress ) const
{
    // heightfield must already exist.
    if ( !hf )
        return false;

    // if the caller provided an "HAE map profile", he wants an HAE elevation grid even if
    // the map profile has a vertical datum. This is the usual case when building the 3D
    // terrain, for example. Construct a temporary key that doesn't have the vertical
    // datum info and use that to query the elevation data.
    TileKey keyToUse = key;
    if ( haeProfile )
    {
        keyToUse = TileKey(key.getLOD(), key.getTileX(), key.getTileY(), haeProfile );
    }
    
    // Collect the valid layers for this tile.
    ElevationLayerVector contenders;
    ElevationLayerVector offsets;
    for(ElevationLayerVector::const_reverse_iterator i = this->rbegin(); i != this->rend(); ++i)
    {
        ElevationLayer* layer = i->get();

        if ( layer->getEnabled() && layer->getVisible() )
        {
            // calculate the resolution-mapped key (adjusted for tile resolution differential).            
            TileKey mappedKey = 
                keyToUse.mapResolution(hf->getNumColumns(), layer->getTileSize());

            // Note: isKeyInRange tests the key, but haData tests the mapped key.
            // I think that's right!
            if ((layer->getTileSource() == 0L) || 
                (layer->isKeyInRange(key) && layer->getTileSource()->hasData(mappedKey)))
            {
                if (layer->isOffset())
                    offsets.push_back(layer);
                else
                    contenders.push_back(layer);
            }
        }
    }

    // nothing? bail out.
    if ( contenders.empty() && offsets.empty() )
    {
        return false;
    }

    
    // Sample the layers into our target.
    unsigned numColumns = hf->getNumColumns();
    unsigned numRows    = hf->getNumRows();    
    double   xmin       = key.getExtent().xMin();
    double   ymin       = key.getExtent().yMin();
    double   dx         = key.getExtent().width() / (double)(numColumns-1);
    double   dy         = key.getExtent().height() / (double)(numRows-1);
    
    // We will load the actual heightfields on demand. We might not need them all.
    GeoHeightFieldVector heightFields(contenders.size());
    GeoHeightFieldVector offsetFields(offsets.size());
    std::vector<bool>    heightFailed (contenders.size(), false);
    std::vector<bool>    offsetFailed(offsets.size(), false);

    const SpatialReference* keySRS = keyToUse.getProfile()->getSRS();

    bool realData = false;

    for (unsigned c = 0; c < numColumns; ++c)
    {
        double x = xmin + (dx * (double)c);
        for (unsigned r = 0; r < numRows; ++r)
        {
            double y = ymin + (dy * (double)r);

            // Collect elevations from each layer as necessary.
            bool resolved = false;

            for(int i=0; i<contenders.size() && !resolved; ++i)
            {
                if ( heightFailed[i] )
                    continue;

                GeoHeightField& layerHF = heightFields[i];
                if ( !layerHF.valid() )
                {
                    TileKey mappedKey = 
                        keyToUse.mapResolution(hf->getNumColumns(), contenders[i]->getTileSize());

                    layerHF = contenders[i]->createHeightField(mappedKey, progress);
                    if ( !layerHF.valid() )
                    {
                        heightFailed[i] = true;
                        continue;
                    }
                }

                // If we actually got a layer then we have real data
                realData = true;

                float elevation;
                if (layerHF.getElevation(keySRS, x, y, interpolation, keySRS, elevation) &&
                    elevation != NO_DATA_VALUE)
                {
                    resolved = true;                    
                    hf->setHeight(c, r, elevation);
                }
            }

            for(int i=offsets.size()-1; i>=0; --i)
            {
                if ( offsetFailed[i] )
                    continue;

                GeoHeightField& layerHF = offsetFields[i];
                if ( !layerHF.valid() )
                {
                    TileKey mappedKey = 
                        keyToUse.mapResolution(hf->getNumColumns(), offsets[i]->getTileSize());

                    layerHF = offsets[i]->createHeightField(mappedKey, progress);
                    if ( !layerHF.valid() )
                    {
                        offsetFailed[i] = true;
                        continue;
                    }
                }

                // If we actually got a layer then we have real data
                realData = true;

                float elevation = 0.0f;
                if (layerHF.getElevation(keySRS, x, y, interpolation, keySRS, elevation) &&
                    elevation != NO_DATA_VALUE)
                {                    
                    hf->getHeight(c, r) += elevation;
                }
            }
        }
    }   

    // Return whether or not we actually read any real data
    return realData;
}
Esempio n. 14
0
/** Packages an image layer as a TMS folder. */
int
makeTMS( osg::ArgumentParser& args )
{
    // see if the user wants to override the type extension (imagery only)
    std::string extension = "png";
    args.read( "--ext", extension );

    // verbosity?
    bool verbose = !args.read( "--quiet" );

    // find a .earth file on the command line
    std::string earthFile = findArgumentWithExtension(args, ".earth");
    if ( earthFile.empty() )
        return usage( "Missing required .earth file" );

    // folder to which to write the TMS archive.
    std::string rootFolder;
    if ( !args.read( "--out", rootFolder ) )
        rootFolder = Stringify() << earthFile << ".tms_repo";

    // max level to which to generate
    unsigned maxLevel = ~0;
    args.read( "--max-level", maxLevel );

    // load up the map
    osg::ref_ptr<MapNode> mapNode = MapNode::load( args );
    if ( !mapNode.valid() )
        return usage( "Failed to load a valid .earth file" );

    // create a folder for the output
    osgDB::makeDirectory(rootFolder);
    if ( !osgDB::fileExists(rootFolder) )
        return usage("Failed to create root output folder" );

    Map* map = mapNode->getMap();

    // fire up a packager:
    TMSPackager packager( map->getProfile() );
    packager.setVerbose( verbose );
    if ( maxLevel != ~0 )
        packager.setMaxLevel( maxLevel );
    

    // package any image layers that are enabled:
    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );

    unsigned counter = 0;
    
    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter )
    {
        ImageLayer* layer = i->get();
        if ( layer->getImageLayerOptions().enabled() == true )
        {
            std::string layerFolder = toLegalFileName( layer->getName() );
            if ( layerFolder.empty() )
                layerFolder = Stringify() << "image_layer_" << counter;

            if ( verbose )
            {
                OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl;
            }

            std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder );
            TMSPackager::Result r = packager.package( layer, layerRoot, extension );
            if ( !r.ok )
            {
                OE_WARN << LC << r.message << std::endl;
            }
        }
        else if ( verbose )
        {
            OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl;
        }
    }

    // package any elevation layers that are enabled:
    counter = 0;
    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );

    for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter )
    {
        ElevationLayer* layer = i->get();
        if ( layer->getElevationLayerOptions().enabled() == true )
        {
            std::string layerFolder = toLegalFileName( layer->getName() );
            if ( layerFolder.empty() )
                layerFolder = Stringify() << "elevation_layer_" << counter;

            if ( verbose )
            {
                OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl;
            }

            std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder );
            packager.package( layer, layerRoot );
        }
        else if ( verbose )
        {
            OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl;
        }
    }

    return 0;
}
void
MPTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    TerrainEngineNode::postInitialize( map, options );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::MASKED_TERRAIN_LAYERS, "mp-update" );

    // merge in the custom options:
    _terrainOptions.merge( options );

    // a shared registry for tile nodes in the scene graph.
    _liveTiles = new TileNodeRegistry("live");

    // set up a registry for quick release:
    if ( _terrainOptions.quickReleaseGLObjects() == true )
    {
        _deadTiles = new TileNodeRegistry("dead");
    }
    
    // initialize the model factory:
    _tileModelFactory = new TileModelFactory(getMap(), _liveTiles.get(), _terrainOptions );


    // handle an already-established map profile:
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( MapInfo(map) );
    }

    // populate the terrain with whatever data is in the map to begin with:
    if ( _terrain )
    {
        // reserve a GPU image unit and two attribute indexes.
        this->getTextureCompositor()->reserveTextureImageUnit( _primaryUnit );
        this->getTextureCompositor()->reserveTextureImageUnit( _secondaryUnit );

        //this->getTextureCompositor()->reserveAttribIndex( _attribIndex1 );
        //this->getTextureCompositor()->reserveAttribIndex( _attribIndex2 );
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new MPTerrainEngineNodeMapCallbackProxy(this) );

    // Prime with existing layers:
    _batchUpdateInProgress = true;

    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
        addElevationLayer( i->get() );

    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );
    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
        addImageLayer( i->get() );

    _batchUpdateInProgress = false;
    //{
    //    i->get()->addCallback( _elevationCallback.get() );
    //}

    // install some terrain-wide uniforms
    this->getOrCreateStateSet()->getOrCreateUniform(
        "oe_min_tile_range_factor",
        osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() );

    // set up the initial shaders
    updateShaders();

    // register this instance to the osgDB plugin can find it.
    registerEngine( this );

    // now that we have a map, set up to recompute the bounds
    dirtyBound();
}
Esempio n. 16
0
int
purge( osg::ArgumentParser& args )
{
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles( args );
    if ( !node.valid() )
        return usage( "Failed to read .earth file." );

    MapNode* mapNode = MapNode::findMapNode( node.get() );
    if ( !mapNode )
        return usage( "Input file was not a .earth file" );

    Map* map = mapNode->getMap();

    if ( !map->getCache() )
        return message( "Earth file does not contain a cache." );

    std::vector<Entry> entries;


    ImageLayerVector imageLayers;
    map->getLayers( imageLayers );
    for( ImageLayerVector::const_iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
    {
        ImageLayer* layer = i->get();

        bool useMFP =
            layer->getProfile() &&
            layer->getProfile()->getSRS()->isSphericalMercator() &&
            mapNode->getMapNodeOptions().getTerrainOptions().enableMercatorFastPath() == true;

        const Profile* cacheProfile = useMFP ? layer->getProfile() : map->getProfile();

        CacheSettings* cacheSettings = layer->getCacheSettings();
        if (cacheSettings)
        {
            CacheBin* bin = cacheSettings->getCacheBin();
            if ( bin )
            {
                entries.push_back(Entry());
                entries.back()._isImage = true;
                entries.back()._name = i->get()->getName();
                entries.back()._bin = bin;
            }
        }
    }

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

        bool useMFP =
            layer->getProfile() &&
            layer->getProfile()->getSRS()->isSphericalMercator() &&
            mapNode->getMapNodeOptions().getTerrainOptions().enableMercatorFastPath() == true;

        const Profile* cacheProfile = useMFP ? layer->getProfile() : map->getProfile();
        
        CacheSettings* cacheSettings = layer->getCacheSettings();
        if (cacheSettings)
        {
            CacheBin* bin = cacheSettings->getCacheBin();
            if (bin)
            {
                entries.push_back(Entry());
                entries.back()._isImage = false;
                entries.back()._name = i->get()->getName();
                entries.back()._bin = bin;
            }
        }
    }

    if ( entries.size() > 0 )
    {
        std::cout << std::endl;

        for( unsigned i=0; i<entries.size(); ++i )
        {
            std::cout << (i+1) << ") " << entries[i]._name << " (" << (entries[i]._isImage? "image" : "elevation" ) << ")" << std::endl;
        }

        std::cout 
            << std::endl
            << "Enter number of cache to purge, or <enter> to quit: "
            << std::flush;

        std::string input;
        std::getline( std::cin, input );

        if ( !input.empty() )
        {
            unsigned k = as<unsigned>(input, 0L);
            if ( k > 0 && k <= entries.size() )
            {
                Config meta = entries[k-1]._bin->readMetadata();
                if ( !meta.empty() )
                {
                    std::cout
                        << std::endl
                        << "Cache METADATA:" << std::endl
                        << meta.toJSON() 
                        << std::endl << std::endl;
                }

                std::cout
                    << "Are you sure (y/N)? "
                    << std::flush;

                std::getline( std::cin, input );
                if ( input == "y" || input == "Y" )
                {
                    std::cout << "Purging.." << std::flush;
                    entries[k-1]._bin->clear();
                }
                else
                {
                    std::cout << "No action taken." << std::endl;
                }
            }
            else
            {
                std::cout << "Invalid choice." << std::endl;
            }
        }
        else
        {
            std::cout << "No action taken." << std::endl;
        }
    }

    return 0;
}
Esempio n. 17
0
void
MPTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    TerrainEngineNode::postInitialize( map, options );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::MASKED_TERRAIN_LAYERS, "mp-update" );

    // merge in the custom options:
    _terrainOptions.merge( options );

    // A shared registry for tile nodes in the scene graph. Enable revision tracking
    // if requested in the options. Revision tracking lets the registry notify all
    // live tiles of the current map revision so they can inrementally update
    // themselves if necessary.
    _liveTiles = new TileNodeRegistry("live");
    _liveTiles->setRevisioningEnabled( _terrainOptions.incrementalUpdate() == true );
    _liveTiles->setMapRevision( _update_mapf->getRevision() );

    // set up a registry for quick release:
    if ( _terrainOptions.quickReleaseGLObjects() == true )
    {
        _deadTiles = new TileNodeRegistry("dead");
    }
    
    // initialize the model factory:
    _tileModelFactory = new TileModelFactory(_liveTiles.get(), _terrainOptions );

    // handle an already-established map profile:
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( MapInfo(map) );
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new MPTerrainEngineNodeMapCallbackProxy(this) );

    // Prime with existing layers:
    _batchUpdateInProgress = true;

    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
        addElevationLayer( i->get() );

    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );
    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
        addImageLayer( i->get() );

    _batchUpdateInProgress = false;

    // install some terrain-wide uniforms
    this->getOrCreateStateSet()->getOrCreateUniform(
        "oe_min_tile_range_factor",
        osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() );

    // set up the initial shaders
    updateState();

    // register this instance to the osgDB plugin can find it.
    registerEngine( this );

    // now that we have a map, set up to recompute the bounds
    dirtyBound();

    OE_INFO << LC << "Edge normalization is " << (_terrainOptions.normalizeEdges() == true? "ON" : "OFF") << std::endl;
}
Esempio n. 18
0
void
RexTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    // Force the mercator fast path off, since REX does not support it yet.
    TerrainOptions myOptions = options;
    myOptions.enableMercatorFastPath() = false;

    TerrainEngineNode::postInitialize( map, myOptions );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::ENTIRE_MODEL );

    // A callback for overriding bounding boxes for tiles
    _modifyBBoxCallback = new ModifyBoundingBoxCallback(*_update_mapf);

    // merge in the custom options:
    _terrainOptions.merge( myOptions );

    // morphing imagery LODs requires we bind parent textures to their own unit.
    if ( _terrainOptions.morphImagery() == true )
    {
        _requireParentTextures = true;
    }

    // Terrain morphing doesn't work in projected maps:
    if (map->getSRS()->isProjected())
    {
        _terrainOptions.morphTerrain() = false;
    }

    // if the envvar for tile expiration is set, overide the options setting
    const char* val = ::getenv("OSGEARTH_EXPIRATION_THRESHOLD");
    if ( val )
    {
        _terrainOptions.expirationThreshold() = as<unsigned>(val, _terrainOptions.expirationThreshold().get());
        OE_INFO << LC << "Expiration threshold set by env var = " << _terrainOptions.expirationThreshold().get() << "\n";
    }

    // if the envvar for hires prioritization is set, override the options setting
    const char* hiresFirst = ::getenv("OSGEARTH_HIGH_RES_FIRST");
    if ( hiresFirst )
    {
        _terrainOptions.highResolutionFirst() = true;
    }

    // check for normal map generation (required for lighting).
    if ( _terrainOptions.normalMaps() == true )
    {
        this->_requireNormalTextures = true;
    }

    // A shared registry for tile nodes in the scene graph. Enable revision tracking
    // if requested in the options. Revision tracking lets the registry notify all
    // live tiles of the current map revision so they can inrementally update
    // themselves if necessary.
    _liveTiles = new TileNodeRegistry("live");
    _liveTiles->setMapRevision( _update_mapf->getRevision() );

    // A resource releaser that will call releaseGLObjects() on expired objects.
    _releaser = new ResourceReleaser();
    this->addChild(_releaser.get());

    // A shared geometry pool.
    _geometryPool = new GeometryPool( _terrainOptions );
    _geometryPool->setReleaser( _releaser.get());
    this->addChild( _geometryPool.get() );

    // Make a tile loader
    PagerLoader* loader = new PagerLoader( this );
    loader->setNumLODs(_terrainOptions.maxLOD().getOrUse(DEFAULT_MAX_LOD));
    loader->setMergesPerFrame( _terrainOptions.mergesPerFrame().get() );
    for (std::vector<RexTerrainEngineOptions::LODOptions>::const_iterator i = _terrainOptions.lods().begin(); i != _terrainOptions.lods().end(); ++i) {
        if (i->_lod.isSet()) {
            loader->setLODPriorityScale(i->_lod.get(), i->_priorityScale.getOrUse(1.0f));
            loader->setLODPriorityOffset(i->_lod.get(), i->_priorityOffset.getOrUse(0.0f));
        }
    }

    _loader = loader;
    this->addChild( _loader.get() );

    // Make a tile unloader
    _unloader = new UnloaderGroup( _liveTiles.get() );
    _unloader->setThreshold( _terrainOptions.expirationThreshold().get() );
    _unloader->setReleaser(_releaser.get());
    this->addChild( _unloader.get() );
    
    // handle an already-established map profile:
    MapInfo mapInfo( map );
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( mapInfo );
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new RexTerrainEngineNodeMapCallbackProxy(this) );

    // Prime with existing layers:
    _batchUpdateInProgress = true;

    ElevationLayerVector elevationLayers;
    map->getLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
        addElevationLayer( i->get() );

    ImageLayerVector imageLayers;
    map->getLayers( imageLayers );
    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
        addTileLayer( i->get() );

    _batchUpdateInProgress = false;

    // set up the initial shaders
    updateState();

    // register this instance to the osgDB plugin can find it.
    registerEngine( this );

    // now that we have a map, set up to recompute the bounds
    dirtyBound();
}
Esempio n. 19
0
void
RexTerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
{
    TerrainEngineNode::postInitialize( map, options );

    // Initialize the map frames. We need one for the update thread and one for the
    // cull thread. Someday we can detect whether these are actually the same thread
    // (depends on the viewer's threading mode).
    _update_mapf = new MapFrame( map, Map::ENTIRE_MODEL );

    // merge in the custom options:
    _terrainOptions.merge( options );

    // morphing imagery LODs requires we bind parent textures to their own unit.
    if ( _terrainOptions.morphImagery() == true )
    {
        _requireParentTextures = true;
    }

    // if the envvar for tile expiration is set, overide the options setting
    const char* val = ::getenv("OSGEARTH_EXPIRATION_THRESHOLD");
    if ( val )
    {
        _terrainOptions.expirationThreshold() = as<unsigned>(val, _terrainOptions.expirationThreshold().get());
        OE_INFO << LC << "Expiration threshold set by env var = " << _terrainOptions.expirationThreshold().get() << "\n";
    }

    // if the envvar for hires prioritization is set, override the options setting
    const char* hiresFirst = ::getenv("OSGEARTH_HIGH_RES_FIRST");
    if ( hiresFirst )
    {
        _terrainOptions.highResolutionFirst() = true;
    }

    // check for normal map generation (required for lighting).
    if ( _terrainOptions.normalMaps() == true )
    {
        this->_requireNormalTextures = true;
    }

    // A shared registry for tile nodes in the scene graph. Enable revision tracking
    // if requested in the options. Revision tracking lets the registry notify all
    // live tiles of the current map revision so they can inrementally update
    // themselves if necessary.
    _liveTiles = new TileNodeRegistry("live");
    _liveTiles->setMapRevision( _update_mapf->getRevision() );

    if ( _terrainOptions.quickReleaseGLObjects() == true )
    {
        _deadTiles = new TileNodeRegistry("dead");
        _quickReleaseInstalled = false;
        ADJUST_UPDATE_TRAV_COUNT( this, +1 );
    }

    // A shared geometry pool.
    if ( ::getenv("OSGEARTH_REX_NO_POOL") == 0L )
    {
        _geometryPool = new GeometryPool( _terrainOptions );
    }

    // Make a tile loader
    PagerLoader* loader = new PagerLoader( this );
    loader->setMergesPerFrame( _terrainOptions.mergesPerFrame().get() );

    _loader = loader;
    //_loader = new SimpleLoader();
    this->addChild( _loader.get() );
    
    // handle an already-established map profile:
    MapInfo mapInfo( map );
    if ( _update_mapf->getProfile() )
    {
        // NOTE: this will initialize the map with the startup layers
        onMapInfoEstablished( mapInfo );
    }

    // install a layer callback for processing further map actions:
    map->addMapCallback( new RexTerrainEngineNodeMapCallbackProxy(this) );

    // Prime with existing layers:
    _batchUpdateInProgress = true;

    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
        addElevationLayer( i->get() );

    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );
    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
        addImageLayer( i->get() );

    _batchUpdateInProgress = false;

    // set up the initial shaders
    updateState();

    // register this instance to the osgDB plugin can find it.
    registerEngine( this );

    // now that we have a map, set up to recompute the bounds
    dirtyBound();
}
bool
TerrainTileModelFactory::getOrCreateHeightField(const Map*                      map,
                                                const TileKey&                  key,
                                                ElevationSamplePolicy           samplePolicy,
                                                ElevationInterpolation          interpolation,
                                                unsigned                        border,
                                                osg::ref_ptr<osg::HeightField>& out_hf,
                                                osg::ref_ptr<NormalMap>&        out_normalMap,
                                                ProgressCallback*               progress)
{
    // check the quick cache.
    HFCacheKey cachekey;
    cachekey._key          = key;
    cachekey._revision     = map->getDataModelRevision();
    cachekey._samplePolicy = samplePolicy;

    if (progress)
        progress->stats()["hfcache_try_count"] += 1;

    bool hit = false;
    HFCache::Record rec;
    if ( _heightFieldCacheEnabled && _heightFieldCache.get(cachekey, rec) )
    {
        out_hf = rec.value()._hf.get();
        out_normalMap = rec.value()._normalMap.get();

        if (progress)
        {
            progress->stats()["hfcache_hit_count"] += 1;
            progress->stats()["hfcache_hit_rate"] = progress->stats()["hfcache_hit_count"]/progress->stats()["hfcache_try_count"];
        }

        return true;
    }

    if ( !out_hf.valid() )
    {
        out_hf = HeightFieldUtils::createReferenceHeightField(
            key.getExtent(),
            257, 257,           // base tile size for elevation data
            border,             // 1 sample border around the data makes it 259x259
            true);              // initialize to HAE (0.0) heights
    }

    if (!out_normalMap.valid())
    {
        //OE_INFO << "TODO: check terrain reqs\n";
        out_normalMap = new NormalMap(257, 257); // ImageUtils::createEmptyImage(257, 257);
    }

    ElevationLayerVector layers;
    map->getLayers(layers);

    bool populated = layers.populateHeightFieldAndNormalMap(
        out_hf.get(),
        out_normalMap.get(),
        key,
        map->getProfileNoVDatum(), // convertToHAE,
        INTERP_BILINEAR,
        progress );

#ifdef TREAT_ALL_ZEROS_AS_MISSING_TILE
    // check for a real tile with all zeros and treat it the same as non-existant data.
    if ( populated )
    {
        bool isEmpty = true;
        for(osg::FloatArray::const_iterator f = out_hf->getFloatArray()->begin(); f != out_hf->getFloatArray()->end(); ++f)
        {
            if ( (*f) != 0.0f )
            {
                isEmpty = false;
                break;
            }
        }
        if ( isEmpty )
        {
            populated = false;
        }
    }
#endif

    if ( populated )
    {
        // Treat Plate Carre specially by scaling the height values. (There is no need
        // to do this with an empty heightfield)
        if (map->getSRS()->isPlateCarre())
        {
            HeightFieldUtils::scaleHeightFieldToDegrees( out_hf.get() );
        }

        // cache it.
        if (_heightFieldCacheEnabled )
        {
            HFCacheValue newValue;
            newValue._hf = out_hf.get();
            newValue._normalMap = out_normalMap.get();

            _heightFieldCache.insert( cachekey, newValue );
        }
    }

    return populated;
}
Esempio n. 21
0
/** Packages an image layer as a TMS folder. */
int
makeTMS( osg::ArgumentParser& args )
{
    // see if the user wants to override the type extension (imagery only)
    std::string extension;
    args.read( "--ext", extension );

    // verbosity?
    bool verbose = !args.read( "--quiet" );

    // find a .earth file on the command line
    std::string earthFile = findArgumentWithExtension( args, ".earth" );
    /*   if ( earthFile.empty() )
           return usage( "Missing required .earth file" );
           */
    // folder to which to write the TMS archive.
    std::string rootFolder;
    if( !args.read( "--out", rootFolder ) )
        rootFolder = Stringify() << earthFile << ".tms_repo";

    // whether to overwrite existing tile files
    bool overwrite = false;
    if( args.read( "--overwrite" ) )
        overwrite = true;

    // write out an earth file
    std::string outEarth;
    args.read( "--out-earth", outEarth );

    std::string dbOptions;
    args.read( "--db-options", dbOptions );
    std::string::size_type n = 0;
    while( (n = dbOptions.find( '"', n )) != dbOptions.npos )
    {
        dbOptions.erase( n, 1 );
    }

    osg::ref_ptr<osgDB::Options> options = new osgDB::Options( dbOptions );


    std::vector< Bounds > bounds;
    // restrict packaging to user-specified bounds.    
    double xmin = DBL_MAX, ymin = DBL_MAX, xmax = DBL_MIN, ymax = DBL_MIN;
    while( args.read( "--bounds", xmin, ymin, xmax, ymax ) )
    {
        Bounds b;
        b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax;
        bounds.push_back( b );
    }

    // max level to which to generate
    unsigned maxLevel = ~0;
    args.read( "--max-level", maxLevel );

    // whether to keep 'empty' tiles
    bool keepEmpties = args.read( "--keep-empties" );

    bool continueSingleColor = args.read( "--continue-single-color" );

    // max level to which to generate
    unsigned elevationPixelDepth = 32;
    args.read( "--elevation-pixel-depth", elevationPixelDepth );

    // load up the map
    osg::ref_ptr<MapNode> mapNode = MapNode::load( args );
    if( !mapNode.valid() )
        return usage( "Failed to load a valid .earth file" );

    // create a folder for the output
    osgDB::makeDirectory( rootFolder );
    if( !osgDB::fileExists( rootFolder ) )
        return usage( "Failed to create root output folder" );

    Map* map = mapNode->getMap();

    // fire up a packager:
    TMSPackager packager( map->getProfile(), options );

    packager.setVerbose( verbose );
    packager.setOverwrite( overwrite );
    packager.setKeepEmptyImageTiles( keepEmpties );
    packager.setSubdivideSingleColorImageTiles( continueSingleColor );
    packager.setElevationPixelDepth( elevationPixelDepth );

    if( maxLevel != ~0 )
        packager.setMaxLevel( maxLevel );

    if( bounds.size() > 0 )
    {
        for( unsigned int i = 0; i < bounds.size(); ++i )
        {
            Bounds b = bounds[i];
            if( b.isValid() )
                packager.addExtent( GeoExtent( map->getProfile()->getSRS(), b ) );
        }
    }


    // new map for an output earth file if necessary.
    osg::ref_ptr<Map> outMap = 0L;
    if( !outEarth.empty() )
    {
        // copy the options from the source map first
        outMap = new Map( map->getInitialMapOptions() );
    }

    // establish the output path of the earth file, if applicable:
    std::string outEarthFile = osgDB::concatPaths( rootFolder, osgDB::getSimpleFileName( outEarth ) );

    // package any image layers that are enabled:
    ImageLayerVector imageLayers;
    map->getImageLayers( imageLayers );

    unsigned counter = 0;

    for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter )
    {
        ImageLayer* layer = i->get();
        if( layer->getImageLayerOptions().enabled() == true )
        {
            std::string layerFolder = toLegalFileName( layer->getName() );
            if( layerFolder.empty() )
                layerFolder = Stringify() << "image_layer_" << counter;

            if( verbose )
            {
                OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl;
            }

            osg::ref_ptr< ConsoleProgressCallback > progress = new ConsoleProgressCallback();
            std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder );
            TMSPackager::Result r = packager.package( layer, layerRoot, progress, extension );
            if( r.ok )
            {
                // save to the output map if requested:
                if( outMap.valid() )
                {
                    // new TMS driver info:
                    TMSOptions tms;
                    tms.url() = URI(
                        osgDB::concatPaths( layerFolder, "tms.xml" ),
                        outEarthFile );

                    ImageLayerOptions layerOptions( layer->getName(), tms );
                    layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) );
                    layerOptions.cachePolicy() = CachePolicy::NO_CACHE;

                    outMap->addImageLayer( new ImageLayer( layerOptions ) );
                }
            }
            else
            {
                OE_WARN << LC << r.message << std::endl;
            }
        }
        else if( verbose )
        {
            OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl;
        }
    }

    // package any elevation layers that are enabled:
    counter = 0;
    ElevationLayerVector elevationLayers;
    map->getElevationLayers( elevationLayers );

    for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter )
    {
        ElevationLayer* layer = i->get();
        if( layer->getElevationLayerOptions().enabled() == true )
        {
            std::string layerFolder = toLegalFileName( layer->getName() );
            if( layerFolder.empty() )
                layerFolder = Stringify() << "elevation_layer_" << counter;

            if( verbose )
            {
                OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl;
            }

            std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder );
            TMSPackager::Result r = packager.package( layer, layerRoot );

            if( r.ok )
            {
                // save to the output map if requested:
                if( outMap.valid() )
                {
                    // new TMS driver info:
                    TMSOptions tms;
                    tms.url() = URI(
                        osgDB::concatPaths( layerFolder, "tms.xml" ),
                        outEarthFile );

                    ElevationLayerOptions layerOptions( layer->getName(), tms );
                    layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) );
                    layerOptions.cachePolicy() = CachePolicy::NO_CACHE;

                    outMap->addElevationLayer( new ElevationLayer( layerOptions ) );
                }
            }
            else
            {
                OE_WARN << LC << r.message << std::endl;
            }
        }
        else if( verbose )
        {
            OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl;
        }
    }

    // Finally, write an earth file if requested:
    if( outMap.valid() )
    {
        MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions();
        osg::ref_ptr<MapNode> outMapNode = new MapNode( outMap.get(), outNodeOptions );
        if( !osgDB::writeNodeFile( *outMapNode.get(), outEarthFile ) )
        {
            OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl;
        }
        else if( verbose )
        {
            OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl;
        }
    }

    return 0;
}
Esempio n. 22
0
/** Packages image and elevation layers as a TMS. */
int TMSExporter::exportTMS(MapNode* mapNode, const std::string& path, std::vector< osgEarth::Bounds >& bounds, const std::string& outEarth, bool overwrite, const std::string& extension)
{
  if ( !mapNode )
  {
    _errorMessage = "Invalid MapNode";
    if (_progress.valid()) _progress->onCompleted();
    return 0;
  }

  // folder to which to write the TMS archive.
  std::string rootFolder = path;

  osg::ref_ptr<osgDB::Options> options = new osgDB::Options(_dbOptions);

  // create a folder for the output
  osgDB::makeDirectory(rootFolder);
  if ( !osgDB::fileExists(rootFolder) )
  {
    _errorMessage = "Failed to create root output folder";
    if (_progress.valid()) _progress->onCompleted();
    return 0;
  }

  Map* map = mapNode->getMap();

  // new map for an output earth file if necessary.
  osg::ref_ptr<Map> outMap = 0L;
  if ( !outEarth.empty() )
  {
      // copy the options from the source map first
      outMap = new Map(map->getInitialMapOptions());
  }

  // establish the output path of the earth file, if applicable:
  std::string outEarthName = osgDB::getSimpleFileName(outEarth);
  if (outEarthName.length() > 0 && osgEarth::toLower(osgDB::getFileExtension(outEarthName)) != "earth")
    outEarthName += ".earth";

  std::string outEarthFile = osgDB::concatPaths(rootFolder, outEarthName);
  

  // semaphore and tasks collection for multithreading
  osgEarth::Threading::MultiEvent semaphore;
  osgEarth::TaskRequestVector tasks;
  int taskCount = 0;


  // package any image layers that are enabled and visible
  ImageLayerVector imageLayers;
  map->getImageLayers( imageLayers );

  unsigned imageCount = 0;
  for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++imageCount )
  {
      ImageLayer* layer = i->get();

      if ( layer->getEnabled() && layer->getVisible() )
      {
          std::string layerFolder = toLegalFileName( layer->getName() );
          if ( layerFolder.empty() )
              layerFolder = Stringify() << "image_layer_" << imageCount;

          ParallelTask<PackageLayer>* task = new ParallelTask<PackageLayer>( &semaphore );
          task->init(map, layer, options, rootFolder, layerFolder, true, overwrite, _keepEmpties, _maxLevel, extension, bounds);
          task->setProgressCallback(new PackageLayerProgressCallback(this));
          tasks.push_back(task);
          taskCount++;
      }
  }

  // package any elevation layers that are enabled and visible
  ElevationLayerVector elevationLayers;
  map->getElevationLayers( elevationLayers );

  int elevCount = 0;
  for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++elevCount )
  {
      ElevationLayer* layer = i->get();
      if ( layer->getEnabled() && layer->getVisible() )
      {
          std::string layerFolder = toLegalFileName( layer->getName() );
          if ( layerFolder.empty() )
              layerFolder = Stringify() << "elevation_layer_" << elevCount;

          ParallelTask<PackageLayer>* task = new ParallelTask<PackageLayer>( &semaphore );
          task->init(map, layer, options, rootFolder, layerFolder, true, overwrite, _keepEmpties, _maxLevel, extension, bounds);
          task->setProgressCallback(new PackageLayerProgressCallback(this));
          tasks.push_back(task);
          taskCount++;
      }
  }


  // Run all the tasks in parallel
  _totalTasks = taskCount;
  _completedTasks = 0;

  semaphore.reset( _totalTasks );

  for( TaskRequestVector::iterator i = tasks.begin(); i != tasks.end(); ++i )
        _taskService->add( i->get() );

  // Wait for them to complete
  semaphore.wait();


  // Add successfully packaged layers to the new map object and
  // write out the .earth file (if requested)
  if (outMap.valid())
  {
    for( TaskRequestVector::iterator i = tasks.begin(); i != tasks.end(); ++i )
    {
      PackageLayer* p = dynamic_cast<PackageLayer*>(i->get());
      if (p)
      {
        if (p->_packageResult.ok)
        {
          TMSOptions tms;
          tms.url() = URI(osgDB::concatPaths(p->_layerFolder, "tms.xml"), outEarthFile );

          if (p->_imageLayer.valid())
          {
            ImageLayerOptions layerOptions( p->_imageLayer->getName(), tms );
            layerOptions.mergeConfig( p->_imageLayer->getInitialOptions().getConfig(true) );
            layerOptions.cachePolicy() = CachePolicy::NO_CACHE;

            outMap->addImageLayer( new ImageLayer(layerOptions) );
          }
          else
          {
            ElevationLayerOptions layerOptions( p->_elevationLayer->getName(), tms );
            layerOptions.mergeConfig( p->_elevationLayer->getInitialOptions().getConfig(true) );
            layerOptions.cachePolicy() = CachePolicy::NO_CACHE;

            outMap->addElevationLayer( new ElevationLayer(layerOptions) );
          }
        }
        else
        {
          OE_WARN << LC << p->_packageResult.message << std::endl;
        }
      }
    }
  }

  if ( outMap.valid() )
  {
      MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions();
      osg::ref_ptr<MapNode> outMapNode = new MapNode(outMap.get(), outNodeOptions);
      if ( !osgDB::writeNodeFile(*outMapNode.get(), outEarthFile) )
      {
          OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl;
      }
      else
      {
          OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl;
      }
  }


  // Mark the progress callback as completed
  if (_progress.valid()) _progress->onCompleted();

  return elevCount + imageCount;
}