osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/arcgis/MapService.cpp

Go to the documentation of this file.
00001 #include "MapService.h"
00002 #include <osgEarth/HTTPClient>
00003 #include <osgEarth/JsonUtils>
00004 #include <osgEarth/Registry>
00005 #include <osg/Notify>
00006 #include <sstream>
00007 #include <limits.h>
00008 
00009 using namespace osgEarth;
00010 
00011 
00012 MapServiceLayer::MapServiceLayer(int in_id, 
00013                                  const std::string& in_name) :
00014 id( in_id ),
00015 name( in_name )
00016 {
00017     //NOP
00018 }
00019 
00020 int
00021 MapServiceLayer::getId() const {
00022     return id;
00023 }
00024 
00025 const std::string&
00026 MapServiceLayer::getName() const {
00027     return name;
00028 }
00029 
00030 //===========================================================================
00031 
00032 TileInfo::TileInfo()
00033 : is_valid( false )
00034 {
00035     //NOP
00036 }
00037 
00038 TileInfo::TileInfo( int _tile_size, const std::string& _format, int _min_level, int _max_level, int _num_tiles_wide, int _num_tiles_high ) :
00039 format( _format ),
00040 tile_size( _tile_size ),
00041 min_level( _min_level ),
00042 max_level( _max_level ),
00043 is_valid( true ),
00044 num_tiles_wide(_num_tiles_wide),
00045 num_tiles_high(_num_tiles_high)
00046 { 
00047     //NOP
00048 }
00049 
00050 TileInfo::TileInfo( const TileInfo& rhs ) :
00051 format( rhs.format ),
00052 tile_size( rhs.tile_size ),
00053 min_level( rhs.min_level ),
00054 max_level( rhs.max_level ),
00055 is_valid( rhs.is_valid ),
00056 num_tiles_wide( rhs.num_tiles_wide ),
00057 num_tiles_high( rhs.num_tiles_high )
00058 {
00059     //NOP
00060 }
00061 
00062 bool
00063 TileInfo::isValid() const {
00064     return is_valid;
00065 }
00066 
00067 int
00068 TileInfo::getTileSize() const {
00069     return tile_size;
00070 }
00071 
00072 const std::string&
00073 TileInfo::getFormat() const {
00074     return format;
00075 }
00076 
00077 int
00078 TileInfo::getMinLevel() const {
00079     return min_level;
00080 }
00081 
00082 int
00083 TileInfo::getMaxLevel() const {
00084     return max_level;
00085 }
00086 
00087 int
00088 TileInfo::getNumTilesWide() const {
00089     return num_tiles_wide;
00090 }
00091 
00092 int
00093 TileInfo::getNumTilesHigh() const {
00094     return num_tiles_high;
00095 }
00096                                  
00097 
00098 //===========================================================================
00099 
00100 
00101 MapService::MapService() :
00102 is_valid( false ),
00103 tiled( false )
00104 {
00105     //NOP
00106 }
00107 
00108 bool 
00109 MapService::isValid() const {
00110     return is_valid;
00111 }
00112 
00113 bool
00114 MapService::isTiled() const {
00115     return tiled;
00116 }
00117 
00118 const Profile*
00119 MapService::getProfile() const {
00120     return profile.get();
00121 }
00122 
00123 const TileInfo&
00124 MapService::getTileInfo() const {
00125     return tile_info;
00126 }
00127 
00128 bool
00129 MapService::init( const std::string& _url, const osgDB::ReaderWriter::Options* options )
00130 {
00131     url = _url;
00132     std::string sep = url.find( "?" ) == std::string::npos ? "?" : "&";
00133     std::string json_url = url + sep + std::string("f=pjson");  // request the data in JSON format
00134 
00135     HTTPResponse response = HTTPClient::get( json_url, options );
00136     if ( !response.isOK() )
00137         return setError( "Unable to read metadata from ArcGIS service" );
00138 
00139     Json::Value doc;
00140     Json::Reader reader;
00141     if ( !reader.parse( response.getPartStream(0), doc ) )
00142         return setError( "Unable to parse metadata; invalid JSON" );
00143 
00144     // Read the profile. We are using "fullExtent"; perhaps an option to use "initialExtent" instead?
00145     double xmin = doc["fullExtent"].get("xmin", 0).asDouble();
00146     double ymin = doc["fullExtent"].get("ymin", 0).asDouble();
00147     double xmax = doc["fullExtent"].get("xmax", 0).asDouble();
00148     double ymax = doc["fullExtent"].get("ymax", 0).asDouble();
00149     int srs = doc["fullExtent"].get("spatialReference", osgEarth::Json::Value::null).get("wkid", 0).asInt();
00150     
00151     //Assumes the SRS is going to be an EPSG code
00152     std::stringstream ss;
00153     ss << "epsg:" << srs;
00154     
00155     if ( ! (xmax > xmin && ymax > ymin && srs != 0 ) )
00156     {
00157         return setError( "Map service does not define a full extent" );
00158     }
00159 
00160     // Read the layers list
00161     Json::Value j_layers = doc["layers"];
00162     if ( j_layers.empty() )
00163         return setError( "Map service contains no layers" );
00164 
00165     for( unsigned int i=0; i<j_layers.size(); i++ )
00166     {
00167         Json::Value layer = j_layers[i];
00168         int id = i; // layer.get("id", -1).asInt();
00169         std::string name = layer["name"].asString();
00170 
00171         if ( id >= 0 && !name.empty() )
00172         {
00173             layers.push_back( MapServiceLayer( id, name ) );
00174         }
00175     }
00176 
00177     tiled = false;
00178     std::string format = "png";
00179     int tile_rows = 256;
00180     int tile_cols = 256;
00181     int min_level = 25;
00182     int max_level = 0;
00183     int num_tiles_wide = 1;
00184     int num_tiles_high = 1;
00185 
00186     // Read the tiling schema
00187     Json::Value j_tileinfo = doc["tileInfo"];
00188     if ( !j_tileinfo.empty() )
00189     {
00190         tiled = true;
00191 
00192      //   return setError( "Map service does not define a tiling schema" );
00193 
00194         // TODO: what do we do if the width <> height?
00195         tile_rows = j_tileinfo.get( "rows", 0 ).asInt();
00196         tile_cols = j_tileinfo.get( "cols", 0 ).asInt();
00197         if ( tile_rows <= 0 && tile_cols <= 0 )
00198             return setError( "Map service tile size not specified" );
00199 
00200         format = j_tileinfo.get( "format", "" ).asString();
00201         if ( format.empty() )
00202             return setError( "Map service tile schema does not specify an image format" );
00203 
00204         Json::Value j_levels = j_tileinfo["lods"];
00205         if ( j_levels.empty() )
00206             return setError( "Map service tile schema contains no LODs" );
00207         
00208         min_level = INT_MAX;
00209         max_level = 0;
00210         for( unsigned int i=0; i<j_levels.size(); i++ )
00211         {
00212             int level = j_levels[i].get( "level", -1 ).asInt();
00213             if ( level >= 0 && level < min_level )
00214                 min_level = level;
00215             if ( level >= 0 && level > max_level )
00216                 max_level = level;
00217         }
00218 
00219         if (j_levels.size() > 0)
00220         {
00221             int l = j_levels[0u].get("level", -1).asInt();
00222             double res = j_levels[0u].get("resolution", 0.0).asDouble();
00223             num_tiles_wide = (int)osg::round((xmax - xmin) / (res * tile_cols));
00224             num_tiles_high = (int)osg::round((ymax - ymin) / (res * tile_cols));
00225 
00226             //In case the first level specified isn't level 0, compute the number of tiles at level 0
00227             for (int i = 0; i < l; i++)
00228             {
00229                 num_tiles_wide /= 2;
00230                 num_tiles_high /= 2;
00231             }
00232 
00233             //profile.setNumTilesWideAtLod0(num_tiles_wide);
00234             //profile.setNumTilesHighAtLod0(num_tiles_high);
00235         }
00236     }
00237 
00238         std::string ssStr;
00239         ssStr = ss.str();
00240 
00241     osg::ref_ptr< SpatialReference > spatialReference = SpatialReference::create( ssStr );
00242     if (spatialReference->isGeographic())
00243     {
00244         //If we have a geographic SRS, just use the geodetic profile
00245         profile = Registry::instance()->getGlobalGeodeticProfile();
00246     }
00247     else if (spatialReference->isMercator())
00248     {
00249         //If we have a mercator SRS, just use the mercator profile
00250         profile = Registry::instance()->getGlobalMercatorProfile();
00251     }
00252     else
00253     {
00254         //It's not geodetic or mercator, so try to use the full extent
00255         profile = Profile::create(
00256             spatialReference.get(),
00257             xmin, ymin, xmax, ymax,
00258             NULL,
00259             num_tiles_wide,
00260             num_tiles_high);
00261     }    
00262 
00263 
00264 
00265     // now we're good.
00266     tile_info = TileInfo( tile_rows, format, min_level, max_level, num_tiles_wide, num_tiles_high);
00267     is_valid = true;
00268     return is_valid;
00269 }
00270 
00271 bool
00272 MapService::setError( const std::string& msg ) {
00273     error_msg = msg;
00274     return false;
00275 }
00276 
00277 const std::string&
00278 MapService::getError() const {
00279     return error_msg;
00280 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines