Virtual Earth driver

classic Classic list List threaded Threaded
6 messages Options
Raphael Raphael
Reply | Threaded
Open this post in threaded view
|

Virtual Earth driver

Hello,
I tried to write a driver for virtual earth tiles. But I have got a message "Error:No readerWriter for file http://r0.ortho.tiles.virtualearth.net/tiles/r0.png?g15"
I don't understand what happens. Have you think of such a plugin (WorldWind has a virtual earth plugin => they don't bann IP adresses like google does).  
Sorry for all these questions...

#include <osgEarth/MapConfig>
#include <osgEarth/Mercator>
#include <osg/Notify>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <sstream>

using namespace osgEarth;

#define PROPERTY_DATASET    "dataset"
#define PROPERTY_VERSION    "version"
#define PROPERTY_LANGUAGE   "language"
#define PROPERTY_MAP_CONFIG "map_config"

class VirtualEarthSource : public TileSource
{
public:
    VirtualEarthSource( const osgDB::ReaderWriter::Options* _options ) :
      options( _options ),
      map_config(0),
      profile( TileGridProfile::GLOBAL_MERCATOR )
    {
        if ( options.valid() )
        {
            if ( options->getPluginData( PROPERTY_DATASET ) )
                dataset = std::string( (const char*)options->getPluginData( PROPERTY_DATASET ) );

            if ( options->getPluginData( PROPERTY_VERSION ) )
                version = std::string( (const char*)options->getPluginData( PROPERTY_VERSION ) );

            if ( options->getPluginData( PROPERTY_LANGUAGE ) )
                language = std::string( (const char*)options->getPluginData( PROPERTY_LANGUAGE ) );
            else
                language = "en";

            if (options->getPluginData( PROPERTY_MAP_CONFIG ))
                map_config = (const MapConfig*)options->getPluginData(PROPERTY_MAP_CONFIG);
        }

        // validate dataset
        if ( dataset.empty() ) dataset = "aerial"; // default to the aerial view
    }

    const TileGridProfile& getProfile() const
    {
        return profile;
    }

        std::string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
        {
                std::string quad;
                quad = "";
                for (int i = levelOfDetail; i > 0; i--)
                {
                  int mask = 1 << (i - 1);
                  int cell = 0;
                  if ((tileX  & mask) != 0)
                  {
                        cell++;
                  }
                  if ((tileY & mask) != 0)
                  {
                        cell += 2;
                  }
                  quad += cell;
                }
                return quad;
        }

    osg::Image* createImage( const TileKey* key )
    {
        // If we are given a geodetic key, resample the mercator imagery. Some quality
        // loss will result.
        if ( key->isGeodetic() )
        {
            MercatorToGeodeticAdapter converter( this );
            return converter.createImage( key );
        }

        //Return NULL if we are given a non-mercator key
        if ( !key->isMercator() ) return 0;

        std::stringstream buf;
       
        if ( dataset == "aerial" )
        {            
            unsigned int tile_x, tile_y;
            key->getTileXY( tile_x, tile_y );
            int zoom = key->getLevelOfDetail();
                        std::string quadKey = TileXYToQuadKey(tile_x, tile_y, zoom);
            std::string _serverUri = ".ortho.tiles.virtualearth.net/tiles/";

            buf << "http://" << "a"
                                << quadKey[quadKey.length()-1]
                << _serverUri
                << "a"
                << quadKey
                << "."
                << "jpeg"
                << "?g=" << 15;
        }
        else if ( dataset == "road" )
        {
            unsigned int tile_x, tile_y;
            key->getTileXY( tile_x, tile_y );
            int zoom = key->getLevelOfDetail();
                        std::string quadKey = TileXYToQuadKey(tile_x, tile_y, zoom);
            std::string _serverUri = ".ortho.tiles.virtualearth.net/tiles/";

            buf << "http://" << "r"
                                << quadKey[quadKey.length()-1]
                << _serverUri
                << "r"
                << quadKey
                << "."
                << "png"
                << "?g=" << 15;
        }
        else if ( dataset == "hybrid" )
        {
            unsigned int tile_x, tile_y;
            key->getTileXY( tile_x, tile_y );
            int zoom = key->getLevelOfDetail();
                        std::string quadKey = TileXYToQuadKey(tile_x, tile_y, zoom);
            std::string _serverUri = ".ortho.tiles.virtualearth.net/tiles/";

            buf << "http://" << "h"
                                << quadKey[quadKey.length()-1]
                << _serverUri
                << "h"
                << quadKey
                << "."
                << "jpeg"
                << "?g=" << 15;
        }

        osg::notify(osg::INFO)
            << "[osgEarth] Virtual Earth: option string = "
            << (options.valid()? options->getOptionString() : "<empty>")
            << std::endl;

        return osgDB::readImageFile ( buf.str(), options.get());
    }

    osg::HeightField* createHeightField( const TileKey* key )
    {
        //TODO
        return NULL;
    }

    virtual std::string getExtension()  const
    {
        if ( dataset == "aerial" ) return "jpeg";
        else if ( dataset == "road" ) return "png";
        else if ( dataset == "hybrid" ) return "jpeg";
        else return "";
    }

private:
    osg::ref_ptr<const osgDB::ReaderWriter::Options> options;
    std::string dataset;
    std::string version;
    std::string language;
    TileGridProfile profile;
    const MapConfig* map_config;
};


class ReaderWriterVirtualEarth : public osgDB::ReaderWriter
{
    public:
        ReaderWriterVirtualEarth()
        {
            supportsExtension( "osgearth_virtual_earth", "Virtual Earth maps imagery" );
        }

        virtual const char* className()
        {
            return "Virtual Earth Imagery ReaderWriter";
        }

        virtual ReadResult readObject(const std::string& file_name, const Options* options) const
        {
            if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name )))
                        {
                                std::cout<<"ReaderWriterVirtualEarth !acceptsExtension"<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
                        }
            return new VirtualEarthSource(options);
        }
};

REGISTER_OSGPLUGIN(osgearth_virtual_earth, ReaderWriterVirtualEarth)
jasonbeverage jasonbeverage
Reply | Threaded
Open this post in threaded view
|

Re: Virtual Earth driver

Hi Raphael,

Looks like you put the extension too early in the filename.

Jason

On Tue, Feb 10, 2009 at 7:45 AM, Raphael (via Nabble) - No Reply <[hidden email]> wrote:
Hello,
I tried to write a driver for virtual earth tiles. But I have got a message "Error:No readerWriter for file http://r0.ortho.tiles.virtualearth.net/tiles/r0.png?g15"
I don't understand what happens. Have you think of such a plugin (WorldWind has a virtual earth plugin => they don't bann IP adresses like google does).  
Sorry for all these questions...

#include <osgEarth/MapConfig>
#include <osgEarth/Mercator>
#include <osg/Notify>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <sstream>

using namespace osgEarth;

#define PROPERTY_DATASET    "dataset"
#define PROPERTY_VERSION    "version"
#define PROPERTY_LANGUAGE   "language"
#define PROPERTY_MAP_CONFIG "map_config"

class VirtualEarthSource : public TileSource
{
public:
    VirtualEarthSource( const osgDB::ReaderWriter::Options* _options ) :
      options( _options ),
      map_config(0),
      profile( TileGridProfile::GLOBAL_MERCATOR )
    {
        if ( options.valid() )
        {
            if ( options->getPluginData( PROPERTY_DATASET ) )
                dataset = std::string( (const char*)options->getPluginData( PROPERTY_DATASET ) );

            if ( options->getPluginData( PROPERTY_VERSION ) )
                version = std::string( (const char*)options->getPluginData( PROPERTY_VERSION ) );

            if ( options->getPluginData( PROPERTY_LANGUAGE ) )
                language = std::string( (const char*)options->getPluginData( PROPERTY_LANGUAGE ) );
            else
                language = "en";

            if (options->getPluginData( PROPERTY_MAP_CONFIG ))
                map_config = (const MapConfig*)options->getPluginData(PROPERTY_MAP_CONFIG);
        }

        // validate dataset
        if ( dataset.empty() ) dataset = "aerial"; // default to the aerial view
    }

    const TileGridProfile& getProfile() const
    {
        return profile;
    }

        std::string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
        {
                std::string quad;
                quad = "";
                for (int i = levelOfDetail; i > 0; i--)
                {
                  int mask = 1 << (i - 1);
                  int cell = 0;
                  if ((tileX  & mask) != 0)
                  {
                        cell++;
                  }
                  if ((tileY & mask) != 0)
                  {
                        cell += 2;
                  }
                  quad += cell;
                }
                return quad;
        }

    osg::Image* createImage( const TileKey* key )
    {
        // If we are given a geodetic key, resample the mercator imagery. Some quality
        // loss will result.
        if ( key->isGeodetic() )
        {
            MercatorToGeodeticAdapter converter( this );
            return converter.createImage( key );
        }

        //Return NULL if we are given a non-mercator key
        if ( !key->isMercator() ) return 0;

        std::stringstream buf;
       
        if ( dataset == "aerial" )
        {            
            unsigned int tile_x, tile_y;
            key->getTileXY( tile_x, tile_y );
            int zoom = key->getLevelOfDetail();
                        std::string quadKey = TileXYToQuadKey(tile_x, tile_y, zoom);
            std::string _serverUri = ".ortho.tiles.virtualearth.net/tiles/";

            buf << "http://" << "a"
                                << quadKey[quadKey.length()-1]
                << _serverUri
                << "a"
                << quadKey
                << "."
                << "jpeg"
                << "?g=" << 15;
        }
        else if ( dataset == "road" )
        {
            unsigned int tile_x, tile_y;
            key->getTileXY( tile_x, tile_y );
            int zoom = key->getLevelOfDetail();
                        std::string quadKey = TileXYToQuadKey(tile_x, tile_y, zoom);
            std::string _serverUri = ".ortho.tiles.virtualearth.net/tiles/";

            buf << "http://" << "r"
                                << quadKey[quadKey.length()-1]
                << _serverUri
                << "r"
                << quadKey
                << "."
                << "png"
                << "?g=" << 15;
        }
        else if ( dataset == "hybrid" )
        {
            unsigned int tile_x, tile_y;
            key->getTileXY( tile_x, tile_y );
            int zoom = key->getLevelOfDetail();
                        std::string quadKey = TileXYToQuadKey(tile_x, tile_y, zoom);
            std::string _serverUri = ".ortho.tiles.virtualearth.net/tiles/";

            buf << "http://" << "h"
                                << quadKey[quadKey.length()-1]
                << _serverUri
                << "h"
                << quadKey
                << "."
                << "jpeg"
                << "?g=" << 15;
        }

        osg::notify(osg::INFO)
            << "[osgEarth] Virtual Earth: option string = "
            << (options.valid()? options->getOptionString() : "<empty>")
            << std::endl;

        return osgDB::readImageFile ( buf.str(), options.get());
    }

    osg::HeightField* createHeightField( const TileKey* key )
    {
        //TODO
        return NULL;
    }

    virtual std::string getExtension()  const
    {
        if ( dataset == "aerial" ) return "jpeg";
        else if ( dataset == "road" ) return "png";
        else if ( dataset == "hybrid" ) return "jpeg";
        else return "";
    }

private:
    osg::ref_ptr<const osgDB::ReaderWriter::Options> options;
    std::string dataset;
    std::string version;
    std::string language;
    TileGridProfile profile;
    const MapConfig* map_config;
};


class ReaderWriterVirtualEarth : public osgDB::ReaderWriter
{
    public:
        ReaderWriterVirtualEarth()
        {
            supportsExtension( "osgearth_virtual_earth", "Virtual Earth maps imagery" );
        }

        virtual const char* className()
        {
            return "Virtual Earth Imagery ReaderWriter";
        }

        virtual ReadResult readObject(const std::string& file_name, const Options* options) const
        {
            if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name )))
                        {
                                std::cout<<"ReaderWriterVirtualEarth !acceptsExtension"<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
                        }
            return new VirtualEarthSource(options);
        }
};

REGISTER_OSGPLUGIN(osgearth_virtual_earth, ReaderWriterVirtualEarth)



View message @ http://n2.nabble.com/Virtual-Earth-driver-tp2302326p2302326.html
To start a new topic under osgEarth, email [hidden email]
To unsubscribe from osgEarth, click here.


Raphael Raphael
Reply | Threaded
Open this post in threaded view
|

Re: Virtual Earth driver

Sorry, I don't see what you mean. I end up with an url that I can display in FireFox :  
http://r0.ortho.tiles.virtualearth.net/tiles/r0.png?g15
Raphael Raphael
Reply | Threaded
Open this post in threaded view
|

Re: Virtual Earth driver

jasonbeverage jasonbeverage
Reply | Threaded
Open this post in threaded view
|

Re: Virtual Earth driver

Hi Raphael,

The issue is that OSG doesn't understand what type of file you are trying to download from that URL since it doesn't have an extension, so it doesn't know which plugin to use.  Try adding a &.png to the end of the URL so OSG uses the correct plugin.

Jason

On Tue, Feb 10, 2009 at 10:10 AM, Raphael (via Nabble) - No Reply <[hidden email]> wrote:
http://r0.ortho.tiles.virtualearth.net/tiles/r0.png?g=15



View message @ http://n2.nabble.com/Virtual-Earth-driver-tp2302326p2303015.html
To start a new topic under osgEarth, email [hidden email]
To unsubscribe from osgEarth, click here.


Raphael Raphael
Reply | Threaded
Open this post in threaded view
|

Re: Virtual Earth driver

Thank you for the advice. It works fine.
For those interested, I finally build the url like this : (for aerial dataset) :
buf << "http://tiles.virtualearth.net/tiles/a"
     << key->str()
     << "."
     << "jpg"
     << "?g=" << 15
     << "&.jpg";
I say it again but you performed a really nice job !
The result is impressive and the code looks clean and "simple" (I used ossimPlanet in the past and the code was much more complicated for the same kind of behaviour).