Example #1
0
/**
 * Command-line tool that copies the contents of one TileSource
 * to another. All arguments are Config name/value pairs, so you need
 * to look in the header file for each driver's Options structure for
 * options :)
 *
 * Example: copy a GDAL file to an MBTiles repo:
 *
 *   osgearth_conv
 *      --in driver gdal
 *      --in url world.tif
 *      --out driver mbtiles
 *      --out filename world.db
 *
 * The "in" properties come from the GDALOptions getConfig method. The
 * "out" properties come from the MBTilesOptions getConfig method.
 *
 * Other arguments:
 *
 *      --elevation           : convert as elevation data (instead of image data)
 *      --profile [profile]   : reproject to the target profile, e.g. "wgs84"
 *      --min-level [int]     : min level of detail to copy
 *      --max-level [int]     : max level of detail to copy
 *      --threads [n]         : threads to use (may crash. Careful.)
 *
 *      --extents [minLat] [minLong] [maxLat] [maxLong] : Lat/Long extends to copy (*)
 *
 * Of course, the output driver must support writing (by implementing
 * the ReadWriteTileSource interface).
 */
int
main(int argc, char** argv)
{
    osg::ArgumentParser args(&argc,argv);

    if ( argc == 1 )
        return usage(argv);

    typedef std::map<std::string,std::string> KeyValue;
    std::string key, value;

    // collect input configuration:
    Config inConf;
    while( args.read("--in", key, value) )
        inConf.set(key, value);

    TileSourceOptions inOptions(inConf);
    osg::ref_ptr<TileSource> input = TileSourceFactory::create(inOptions);
    if ( !input.valid() )
    {
        OE_WARN << LC << "Failed to open input" << std::endl;
        return -1;
    }

    TileSource::Status inputStatus = input->open();
    if ( inputStatus.isError() )
    {
        OE_WARN << LC << "Error initializing input" << std::endl;
        return -1;
    }

    // collect output configuration:
    Config outConf;
    while( args.read("--out", key, value) )
        outConf.set(key, value);

    // heightfields?
    bool heightFields = args.read("--heightfield") || args.read("--hf") || args.read("--elevation");
    if ( heightFields )
        OE_INFO << LC << "Converting heightfield tiles" << std::endl;
    else
        OE_INFO << LC << "Converting image tiles" << std::endl;

    // are we changing profiles?
    osg::ref_ptr<const Profile> outputProfile = input->getProfile();
    std::string profileString;
    bool isSameProfile = true;

    if ( args.read("--profile", profileString) )
    {
        outputProfile = Profile::create(profileString);
        if ( !outputProfile.valid() || !outputProfile->isOK() )
        {
            OE_WARN << LC << "Output profile is not recognized" << std::endl;
            return -1;
        }
        isSameProfile = outputProfile->isHorizEquivalentTo(input->getProfile());
    }

    // set the output profile.
    ProfileOptions profileOptions = outputProfile->toProfileOptions();
    outConf.add("profile", profileOptions.getConfig());

    // open the output tile source:
    TileSourceOptions outOptions(outConf);
    osg::ref_ptr<TileSource> output = TileSourceFactory::create(outOptions);
    if ( !output.valid() )
    {
        OE_WARN << LC << "Failed to open output" << std::endl;
        return -1;
    }

    TileSource::Status outputStatus = output->open(TileSource::MODE_WRITE | TileSource::MODE_CREATE);
    if ( outputStatus.isError() )
    {
        OE_WARN << LC << "Error initializing output" << std::endl;
        return -1;
    }

    // Dump out some stuff...
    OE_NOTICE << LC << "FROM:\n"
        << inConf.toJSON(true)
        << std::endl;

    OE_NOTICE << LC << "TO:\n"
        << outConf.toJSON(true)
        << std::endl;

    // create the visitor.
    osg::ref_ptr<TileVisitor> visitor;

    unsigned numThreads = 1;
    if (args.read("--threads", numThreads))
    {
        MultithreadedTileVisitor* mtv = new MultithreadedTileVisitor();
        mtv->setNumThreads( numThreads < 1 ? 1 : numThreads );
        visitor = mtv;
    }
    else
    {
        visitor = new TileVisitor();
    }

    // If the profiles are identical, just use a tile copier.
    if ( isSameProfile )
    {
        OE_NOTICE << LC << "Profiles match - initiating simple tile copy" << std::endl;
        visitor->setTileHandler( new TileSourceToTileSource(input.get(), output.get(), heightFields) );
    }
    else
    {
        OE_NOTICE << LC << "Profiles differ - initiating tile transformation" << std::endl;

        if (heightFields)
        {
            ElevationLayer* layer = new ElevationLayer(ElevationLayerOptions(), input.get());
            if ( !layer->getProfile() || !layer->getProfile()->isOK() )
            {
                OE_WARN << LC << "Input profile is not valid" << std::endl;
                return -1;
            }
            visitor->setTileHandler( new ElevationLayerToTileSource(layer, output.get()) );
        }
        else
        {
            ImageLayer* layer = new ImageLayer(ImageLayerOptions(), input.get());
            if ( !layer->getProfile() || !layer->getProfile()->isOK() )
            {
                OE_WARN << LC << "Input profile is not valid" << std::endl;
                return -1;
            }
            visitor->setTileHandler( new ImageLayerToTileSource(layer, output.get()) );
        }
    }
    
    // Set the level limits:
    unsigned minLevel = ~0;
    bool minLevelSet = args.read("--min-level", minLevel);

    unsigned maxLevel = 0;
    bool maxLevelSet = args.read("--max-level", maxLevel);

    // figure out the max source level:
    if ( !minLevelSet || !maxLevelSet )
    {
        for(DataExtentList::const_iterator i = input->getDataExtents().begin();
            i != input->getDataExtents().end();
            ++i)
        {
            if ( !maxLevelSet && i->maxLevel().isSet() && i->maxLevel().value() > maxLevel )
                maxLevel = i->maxLevel().value();
            if ( !minLevelSet && i->minLevel().isSet() && i->minLevel().value() < minLevel )
                minLevel = i->minLevel().value();
        }
    }
       
    if ( minLevel < ~0 )
    {
        visitor->setMinLevel( minLevel );
    }

    if ( maxLevel > 0 )
    {
        maxLevel = outputProfile->getEquivalentLOD( input->getProfile(), maxLevel );
        visitor->setMaxLevel( maxLevel );
        OE_NOTICE << LC << "Calculated max level = " << maxLevel << std::endl;
    }

    // set the extents:
    double minlat, minlon, maxlat, maxlon;
    while( args.read("--extents", minlat, minlon, maxlat, maxlon) )
    {
        GeoExtent extent(SpatialReference::get("wgs84"), minlon, minlat, maxlon, maxlat);
        visitor->addExtent( extent );
    }

    // Ready!!!
    std::cout << "Working..." << std::endl;

    visitor->setProgressCallback( new ProgressReporter() );

    osg::Timer_t t0 = osg::Timer::instance()->tick();

    visitor->run( outputProfile.get() );

    osg::Timer_t t1 = osg::Timer::instance()->tick();

    std::cout
        << "Time = " 
        << std::fixed
        << std::setprecision(1)
        << osg::Timer::instance()->delta_s(t0, t1)
        << " seconds." << std::endl;

    return 0;
}
int
seed( osg::ArgumentParser& args )
{    
    osgDB::Registry::instance()->getReaderWriterForExtension("png");
    osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
    osgDB::Registry::instance()->getReaderWriterForExtension("tiff");

    //Read the min level
    int minLevel = -1;
    while (args.read("--min-level", minLevel));

    //Read the max level
    int maxLevel = -1;
    while (args.read("--max-level", maxLevel));

    bool estimate = args.read("--estimate");        
    

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

    std::string tileList;
    while (args.read( "--tiles", tileList ) );

    bool verbose = args.read("--verbose");

    unsigned int batchSize = 0;
    args.read("--batchsize", batchSize);

    // Read the concurrency level
    unsigned int concurrency = 0;
    args.read("-c", concurrency);
    args.read("--concurrency", concurrency);

    int imageLayerIndex = -1;
    args.read("--image", imageLayerIndex);

    int elevationLayerIndex = -1;
    args.read("--elevation", elevationLayerIndex);


    //Read in the earth file.
    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" );

    // Read in an index shapefile
    std::string index;
    while (args.read("--index", index))
    {        
        //Open the feature source
        OGRFeatureOptions featureOpt;
        featureOpt.url() = index;        

        osg::ref_ptr< FeatureSource > features = FeatureSourceFactory::create( featureOpt );
        Status status = features->open();

        if (status.isOK())
        {
            osg::ref_ptr< FeatureCursor > cursor = features->createFeatureCursor(0L);
            while (cursor.valid() && cursor->hasMore())
            {
                osg::ref_ptr< Feature > feature = cursor->nextFeature();
                osgEarth::Bounds featureBounds = feature->getGeometry()->getBounds();
                GeoExtent ext( feature->getSRS(), featureBounds );
                ext = ext.transform( mapNode->getMapSRS() );
                bounds.push_back( ext.bounds() );            
            }
        }
        else
        {
            OE_WARN << status.message() << "\n";
        }
    }

    // If they requested to do an estimate then don't do the seed, just print out the estimated values.
    if (estimate)
    {        
        CacheEstimator est;
        if ( minLevel >= 0 )
            est.setMinLevel( minLevel );
        if ( maxLevel >= 0 )
            est.setMaxLevel( maxLevel );
        est.setProfile( mapNode->getMap()->getProfile() );

        for (unsigned int i = 0; i < bounds.size(); i++)
        {
            GeoExtent extent(mapNode->getMapSRS(), bounds[i]);
            OE_DEBUG << "Adding extent " << extent.toString() << std::endl;
            est.addExtent( extent );
        } 

        unsigned int numTiles = est.getNumTiles();
        double size = est.getSizeInMB();
        double time = est.getTotalTimeInSeconds();
        std::cout << "Cache Estimation " << std::endl
            << "---------------- " << std::endl
            << "Total number of tiles: " << numTiles << std::endl
            << "Size on disk:          " << osgEarth::prettyPrintSize( size ) << std::endl
            << "Total time:            " << osgEarth::prettyPrintTime( time ) << std::endl;

        return 0;
    }
    
    osg::ref_ptr< TileVisitor > visitor;


    // If we are given a task file, load it up and create a new TileKeyListVisitor
    if (!tileList.empty())
    {        
        TaskList tasks( mapNode->getMap()->getProfile() );
        tasks.load( tileList );

        TileKeyListVisitor* v = new TileKeyListVisitor();
        v->setKeys( tasks.getKeys() );
        visitor = v;        
        OE_DEBUG << "Read task list with " << tasks.getKeys().size() << " tasks" << std::endl;
    }
  

    // If we dont' have a visitor create one.
    if (!visitor.valid())
    {
        if (args.read("--mt"))
        {
            // Create a multithreaded visitor
            MultithreadedTileVisitor* v = new MultithreadedTileVisitor();
            if (concurrency > 0)
            {
                v->setNumThreads(concurrency);
            }
            visitor = v;            
        }
        else if (args.read("--mp"))
        {
            // Create a multiprocess visitor
            MultiprocessTileVisitor* v = new MultiprocessTileVisitor();
            if (concurrency > 0)
            {
                v->setNumProcesses(concurrency);
            }

            if (batchSize > 0)
            {                
                v->setBatchSize(batchSize);
            }

            // Try to find the earth file
            std::string earthFile;
            for(int pos=1;pos<args.argc();++pos)
            {
                if (!args.isOption(pos))
                {
                    earthFile  = args[ pos ];
                    break;
                }
            }
            v->setEarthFile( earthFile );            
            visitor = v;            
        }
        else
        {
            // Create a single thread visitor
            visitor = new TileVisitor();            
        }        
    }

    osg::ref_ptr< ProgressCallback > progress = new ConsoleProgressCallback();
    
    if (verbose)
    {
        visitor->setProgressCallback( progress.get() );
    }

    if ( minLevel >= 0 )
        visitor->setMinLevel( minLevel );
    if ( maxLevel >= 0 )
        visitor->setMaxLevel( maxLevel );        


    for (unsigned int i = 0; i < bounds.size(); i++)
    {
        GeoExtent extent(mapNode->getMapSRS(), bounds[i]);
        OE_DEBUG << "Adding extent " << extent.toString() << std::endl;                
        visitor->addExtent( extent );
    }    
    

    // Initialize the seeder
    CacheSeed seeder;
    seeder.setVisitor(visitor.get());

    osgEarth::Map* map = mapNode->getMap();

    // They want to seed an image layer
    if (imageLayerIndex >= 0)
    {
        osg::ref_ptr< ImageLayer > layer = map->getLayerAt<ImageLayer>( imageLayerIndex );
        if (layer)
        {
            OE_NOTICE << "Seeding single layer " << layer->getName() << std::endl;
            osg::Timer_t start = osg::Timer::instance()->tick();        
            seeder.run(layer.get(), map);
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }    
        }
        else
        {
            std::cout << "Failed to find an image layer at index " << imageLayerIndex << std::endl;
            return 1;
        }

    }
    // They want to seed an elevation layer
    else if (elevationLayerIndex >= 0)
    {
        osg::ref_ptr< ElevationLayer > layer = map->getLayerAt<ElevationLayer>( elevationLayerIndex );
        if (layer)
        {
            OE_NOTICE << "Seeding single layer " << layer->getName() << std::endl;
            osg::Timer_t start = osg::Timer::instance()->tick();        
            seeder.run(layer.get(), map);
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }    
        }
        else
        {
            std::cout << "Failed to find an elevation layer at index " << elevationLayerIndex << std::endl;
            return 1;
        }
    }
    // They want to seed the entire map
    else
    {
        TerrainLayerVector terrainLayers;
        map->getLayers(terrainLayers);

        // Seed all the map layers
        for (unsigned int i = 0; i < terrainLayers.size(); ++i)
        {            
            osg::ref_ptr< TerrainLayer > layer = terrainLayers[i].get();
            OE_NOTICE << "Seeding layer" << layer->getName() << std::endl;            
            osg::Timer_t start = osg::Timer::instance()->tick();
            seeder.run(layer.get(), map);            
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }                
        }

        //for (unsigned int i = 0; i < map->getNumElevationLayers(); ++i)
        //{
        //    osg::ref_ptr< ElevationLayer > layer = map->getElevationLayerAt(i);
        //    OE_NOTICE << "Seeding layer" << layer->getName() << std::endl;
        //    osg::Timer_t start = osg::Timer::instance()->tick();
        //    seeder.run(layer.get(), map);            
        //    osg::Timer_t end = osg::Timer::instance()->tick();
        //    if (verbose)
        //    {
        //        OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
        //    }                
        //}        
    }    

    return 0;
}
/** Packages an image layer as a TMS folder. */
int
makeTMS( osg::ArgumentParser& args )
{
    osgDB::Registry::instance()->getReaderWriterForExtension("png");
    osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
    osgDB::Registry::instance()->getReaderWriterForExtension("tiff");

    //Read the min level
    unsigned int minLevel = 0;
    while (args.read("--min-level", minLevel));

    //Read the max level
    unsigned int maxLevel = 5;
    while (args.read("--max-level", maxLevel));
    

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

    std::string tileList;
    while (args.read( "--tiles", tileList ) );

    bool verbose = args.read("--verbose");

    unsigned int batchSize = 0;
    args.read("--batchsize", batchSize);

    // Read the concurrency level
    unsigned int concurrency = 0;
    args.read("-c", concurrency);
    args.read("--concurrency", concurrency);

    bool writeXML = true;

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


    // Read in an index shapefile
    std::string index;
    while (args.read("--index", index))
    {        
        //Open the feature source
        OGRFeatureOptions featureOpt;
        featureOpt.url() = index;        

        osg::ref_ptr< FeatureSource > features = FeatureSourceFactory::create( featureOpt );
        features->initialize();
        features->getFeatureProfile();

        osg::ref_ptr< FeatureCursor > cursor = features->createFeatureCursor();
        while (cursor.valid() && cursor->hasMore())
        {
            osg::ref_ptr< Feature > feature = cursor->nextFeature();
            osgEarth::Bounds featureBounds = feature->getGeometry()->getBounds();
            GeoExtent ext( feature->getSRS(), featureBounds );
            ext = ext.transform( mapNode->getMapSRS() );
            bounds.push_back( ext.bounds() );            
        }
    }

    // see if the user wants to override the type extension (imagery only)
    std::string extension;
    args.read( "--ext", extension );

    // find a .earth file on the command line
    std::string earthFile = findArgumentWithExtension( args, ".earth" );
    
    // 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
    //TODO:  Support
    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 );

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

    //TODO:  Single color
    bool continueSingleColor = args.read( "--continue-single-color" );

    // elevation pixel depth
    unsigned elevationPixelDepth = 32;
    args.read( "--elevation-pixel-depth", elevationPixelDepth );
    
    // create a folder for the output
    osgDB::makeDirectory( rootFolder );
    if( !osgDB::fileExists( rootFolder ) )
        return usage( "Failed to create root output folder" );

    int imageLayerIndex = -1;
    args.read("--image", imageLayerIndex);

    int elevationLayerIndex = -1;
    args.read("--elevation", elevationLayerIndex);
    
    Map* map = mapNode->getMap();


    osg::ref_ptr< TileVisitor > visitor;

    // If we are given a task file, load it up and create a new TileKeyListVisitor
    if (!tileList.empty())
    {        
        TaskList tasks( mapNode->getMap()->getProfile() );
        tasks.load( tileList );

        TileKeyListVisitor* v = new TileKeyListVisitor();
        v->setKeys( tasks.getKeys() );
        visitor = v;     
        // This process is a lowly worker, and shouldn't write out the XML file.
        writeXML = false;
    }

    // If we dont' have a visitor create one.
    if (!visitor.valid())
    {
        if (args.read("--mt"))
        {
            // Create a multithreaded visitor
            MultithreadedTileVisitor* v = new MultithreadedTileVisitor();
            if (concurrency > 0)
            {
                v->setNumThreads(concurrency);
            }
            visitor = v;            
        }
        else if (args.read("--mp"))
        {
            // Create a multiprocess visitor
            MultiprocessTileVisitor* v = new MultiprocessTileVisitor();
            if (concurrency > 0)
            {
                v->setNumProcesses(concurrency);
                OE_NOTICE << "Set num processes " << concurrency << std::endl;
            }

            if (batchSize > 0)
            {            
                v->setBatchSize(batchSize);
            }


            // Try to find the earth file
            std::string earthFile;
            for(int pos=1;pos<args.argc();++pos)
            {
                if (!args.isOption(pos))
                {
                    earthFile  = args[ pos ];
                    break;
                }
            }

            v->setEarthFile( earthFile );

            visitor = v;            
        }
        else
        {
            // Create a single thread visitor
            visitor = new TileVisitor();            
        }        
    }

    osg::ref_ptr< ProgressCallback > progress = new ConsoleProgressCallback();

    if (verbose)
    {
        visitor->setProgressCallback( progress );
    }

    visitor->setMinLevel( minLevel );
    visitor->setMaxLevel( maxLevel );        


    for (unsigned int i = 0; i < bounds.size(); i++)
    {
        GeoExtent extent(mapNode->getMapSRS(), bounds[i]);
        OE_DEBUG << "Adding extent " << extent.toString() << std::endl;                
        visitor->addExtent( extent );
    }    


    // Setup a TMSPackager with all the options.
    TMSPackager packager;
    packager.setExtension(extension);
    packager.setVisitor(visitor);
    packager.setDestination(rootFolder);    
    packager.setElevationPixelDepth(elevationPixelDepth);
    packager.setWriteOptions(options);    
    packager.setOverwrite(overwrite);
    packager.setKeepEmpties(keepEmpties);


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

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

    // Package an individual image layer
    if (imageLayerIndex >= 0)
    {        
        ImageLayer* layer = map->getImageLayerAt(imageLayerIndex);
        if (layer)
        {
            packager.run(layer, map);
            if (writeXML)
            {
                packager.writeXML(layer, map);
            }
        }
        else
        {
            std::cout << "Failed to find an image layer at index " << imageLayerIndex << std::endl;
            return 1;
        }
    }
    // Package an individual elevation layer
    else if (elevationLayerIndex >= 0)
    {        
        ElevationLayer* layer = map->getElevationLayerAt(elevationLayerIndex);
        if (layer)
        {
            packager.run(layer, map);
            if (writeXML)
            {
                packager.writeXML(layer, map );
            }
        }
        else
        {
            std::cout << "Failed to find an elevation layer at index " << elevationLayerIndex << std::endl;
            return 1;
        }
    }
    else
    {        
        // Package all the ImageLayer's
        for (unsigned int i = 0; i < map->getNumImageLayers(); i++)
        {            
            ImageLayer* layer = map->getImageLayerAt(i);        
            OE_NOTICE << "Packaging " << layer->getName() << std::endl;
            osg::Timer_t start = osg::Timer::instance()->tick();
            packager.run(layer, map);
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }                

            if (writeXML)
            {
                packager.writeXML(layer, map);
            }

            // save to the output map if requested:
            if( outMap.valid() )
            {
                std::string layerFolder = toLegalFileName( packager.getLayerName() );

                // new TMS driver info:
                TMSOptions tms;
                tms.url() = URI(
                    osgDB::concatPaths( layerFolder, "tms.xml" ),
                    outEarthFile );

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

                outMap->addImageLayer( new ImageLayer( layerOptions ) );
            }
        }    

        // Package all the ElevationLayer's
        for (unsigned int i = 0; i < map->getNumElevationLayers(); i++)
        {            
            ElevationLayer* layer = map->getElevationLayerAt(i);        
            OE_NOTICE << "Packaging " << layer->getName() << std::endl;
            osg::Timer_t start = osg::Timer::instance()->tick();
            packager.run(layer, map);
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }      
            if (writeXML)
            {
                packager.writeXML(layer, map);
            }

            // save to the output map if requested:
            if( outMap.valid() )
            {
                std::string layerFolder = toLegalFileName( packager.getLayerName() );

                // new TMS driver info:
                TMSOptions tms;
                tms.url() = URI(
                    osgDB::concatPaths( layerFolder, "tms.xml" ),
                    outEarthFile );

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

                outMap->addElevationLayer( new ElevationLayer( layerOptions ) );
            }
        }

    }

    // Write out an earth file if it was requested
    // 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;
}
Example #4
0
/** Packages image and elevation layers as a TMS. */
int TMSExporter::exportTMS(MapNode* mapNode, const std::string& earthFilePath, const std::string& path, std::vector< osgEarth::Bounds >& bounds, const std::string& outEarth, bool overwrite, const std::string& extension)
{   
    _totalTimeS = 0.0;
    osg::Timer_t startTime = osg::Timer::instance()->tick();

    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(path, outEarthName);


    // Create the TMS packager.
    TMSPackager packager;

    std::string tmpEarth;

    // Setup the visitor with the concurrency level and processing mode if it's set.
    if (_concurrency > 1)
    {
        if (_mode == MODE_MULTIPROCESS)
        {
            // Write out a temp earth file so the processes can work on it.
            // Determine the output path.  If we loaded from an earth file write out the temp file right next to it so relative paths will work the same.
            // Otherwise use the temp path
            OE_NOTICE << "Earth file path " << earthFilePath << std::endl;
            if (!earthFilePath.empty())
            {
                std::string root = osgDB::getFilePath(earthFilePath);
                root += "/";
                tmpEarth = getTempName(root, ".earth");
            }
            else
            {
                tmpEarth = getTempName(getTempPath(), ".earth");
            }
            OE_INFO << "Writing to " << tmpEarth << std::endl;
            osgDB::writeNodeFile(*mapNode, tmpEarth );         
            MultiprocessTileVisitor* v = new MultiprocessTileVisitor();
            v->setEarthFile(tmpEarth);
            v->setNumProcesses(_concurrency);
            packager.setVisitor(v);
        }
        else if (_mode == MODE_MULTITHREADED)
        {
            MultithreadedTileVisitor* v = new MultithreadedTileVisitor();          
            v->setNumThreads(_concurrency);
            packager.setVisitor(v);          
        }
    }

    // Make the output directory if it doesn't exist  
    osgDB::makeDirectory(path);
    packager.setDestination(path);

    // Setup the osgDB options for the packager.
    osg::ref_ptr<osgDB::Options> options = new osgDB::Options(_dbOptions);
    packager.setWriteOptions( options.get() );

    // Add all the bounds
    for (unsigned int i = 0; i < bounds.size(); i++)
    {
        packager.getTileVisitor()->addExtent( osgEarth::GeoExtent(map->getProfile()->getSRS(), bounds[i]));
    }
    packager.setExtension(extension);  
    packager.setOverwrite(overwrite);
    packager.getTileVisitor()->setProgressCallback( _progress.get() );
    packager.getTileVisitor()->setMaxLevel(_maxLevel);

    // Compute the total number of layers we are going to operate on.
    unsigned int totalLayers = map->getNumImageLayers() + map->getNumElevationLayers();  

    unsigned int layerNum = 1;

    // Package each image layer
    for (unsigned int i = 0; i < map->getNumImageLayers(); i++)
    {            
        // Don't continue if the export has been canceled
        if (_progress->isCanceled())
        {
            break;
        }
        osg::ref_ptr< ImageLayer > layer = map->getImageLayerAt(i);      
        std::stringstream buf;
        buf << "Packaging " << layer->getName() << " (" << layerNum << " of " << totalLayers << ")";
        OE_NOTICE << buf.str() << std::endl;
        _progress->setStatus(buf.str());
        packager.run(layer.get(), map);
        packager.writeXML(layer.get(), map);
        if (outMap)
        {
            std::string layerFolder = toLegalFileName( packager.getLayerName() );

            // new TMS driver info:
            TMSOptions tms;
            tms.url() = URI(
                osgDB::concatPaths( layerFolder, "tms.xml" ),
                outEarthFile );

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

            outMap->addImageLayer( new ImageLayer( layerOptions ) );
        }
        layerNum++;
    }

    // Package each elevation layer
    for (unsigned int i = 0; i < map->getNumElevationLayers(); i++)
    {
        // Don't continue if the export has been canceled
        if (_progress->isCanceled())
        {
            break;
        }

        osg::ref_ptr< ElevationLayer > layer = map->getElevationLayerAt(i);      
        std::stringstream buf;
        buf << "Packaging " << layer->getName() << " (" << layerNum << " of " << totalLayers << ")";
        OE_NOTICE << buf.str() << std::endl;
        _progress->setStatus(buf.str());
        packager.run(layer.get(), map);
        packager.writeXML(layer.get(), map);

        if( outMap.valid() )
        {
            std::string layerFolder = toLegalFileName( packager.getLayerName() );

            // new TMS driver info:
            TMSOptions tms;
            tms.url() = URI(
                osgDB::concatPaths( layerFolder, "tms.xml" ),
                outEarthFile );

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

            outMap->addElevationLayer( new ElevationLayer( layerOptions ) );
        }

        layerNum++;
    }

    // Don't continue if the export has been canceled
    if (!_progress->isCanceled())
    {
        // Write out an earth file if it was requested
        // 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;
            }
        }
    }    

    osg::Timer_t endTime = osg::Timer::instance()->tick();

    _totalTimeS = osg::Timer::instance()->delta_s(startTime, endTime );


    // Tell the progress dialog that we're finished and it can close
    _progress->complete();

    // Remove the temp earth file.
    if (!tmpEarth.empty())
    {
        remove(tmpEarth.c_str());
    }

    return 0;
}