osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/TMS.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00020 
00021 #include <osg/Notify>
00022 #include <osgDB/FileUtils>
00023 #include <osgDB/FileNameUtils>
00024 #include <osgEarth/Common>
00025 #include <osgEarth/GeoData>
00026 #include <osgEarth/HTTPClient>
00027 #include <osgEarth/XmlUtils>
00028 #include <osgEarth/TMS>
00029 #include <osgEarth/TileKey>
00030 #include <osgEarth/TileSource>
00031 #include <osgEarth/Registry>
00032 #include <osgEarth/StringUtils>
00033 
00034 #include <limits.h>
00035 #include <iomanip>
00036 
00037 using namespace osgEarth;
00038 
00039 #define LC "[TMS] "
00040 
00041 static std::string toString(double value, int precision = 25)
00042 {
00043     std::stringstream out;
00044     out << std::fixed << std::setprecision(precision) << value;
00045         std::string outStr;
00046         outStr = out.str();
00047     return outStr;
00048 }
00049 
00050 TileFormat::TileFormat():
00051 _width(0),
00052 _height(0)
00053 {
00054 }
00055 
00056 TileSet::TileSet():
00057 _unitsPerPixel(0.0),
00058 _order(0)
00059 {
00060 }
00061 
00062 TileMap::TileMap():
00063 _originX(0),
00064 _originY(0),
00065 _minX(0.0),
00066 _minY(0.0),
00067 _maxX(0.0),
00068 _maxY(0.0),
00069 _minLevel(0),
00070 _maxLevel(0),
00071 _numTilesHigh(-1),
00072 _numTilesWide(-1)
00073 {
00074 }
00075 
00076 void TileMap::setOrigin(double x, double y)
00077 {
00078     _originX = x;
00079     _originY = y;
00080 }
00081 
00082 void TileMap::getExtents( double &minX, double &minY, double &maxX, double &maxY) const
00083 {
00084     minX = _minX;
00085     minY = _minY;
00086     maxX = _maxX;
00087     maxY = _maxY;
00088 }
00089 
00090 void TileMap::setExtents( double minX, double minY, double maxX, double maxY)
00091 {
00092     _minX = minX;
00093     _minY = minY;
00094     _maxX = maxX;
00095     _maxY = maxY;
00096 }
00097 
00098 
00099 
00100 
00101 #define ELEM_TILEMAP "tilemap"
00102 #define ELEM_TITLE "title"
00103 #define ELEM_ABSTRACT "abstract"
00104 #define ELEM_SRS "srs"
00105 #define ELEM_VERTICAL_SRS "vsrs"
00106 #define ELEM_BOUNDINGBOX "boundingbox"
00107 #define ELEM_ORIGIN "origin"
00108 #define ELEM_TILE_FORMAT "tileformat"
00109 #define ELEM_TILESETS "tilesets"
00110 #define ELEM_TILESET "tileset"
00111 #define ELEM_DATA_EXTENTS "dataextents"
00112 #define ELEM_DATA_EXTENT "dataextent"
00113 
00114 #define ATTR_VERSION "version"
00115 #define ATTR_TILEMAPSERVICE "tilemapservice"
00116 
00117 #define ATTR_MINX "minx"
00118 #define ATTR_MINY "miny"
00119 #define ATTR_MAXX "maxx"
00120 #define ATTR_MAXY "maxy"
00121 #define ATTR_X "x"
00122 #define ATTR_Y "y"
00123 #define ATTR_MIN_LEVEL "minlevel"
00124 #define ATTR_MAX_LEVEL "maxlevel"
00125 
00126 #define ATTR_WIDTH "width"
00127 #define ATTR_HEIGHT "height"
00128 #define ATTR_MIME_TYPE "mime-type"
00129 #define ATTR_EXTENSION "extension"
00130 
00131 #define ATTR_PROFILE "profile"
00132 
00133 #define ATTR_HREF "href"
00134 #define ATTR_ORDER "order"
00135 #define ATTR_UNITSPERPIXEL "units-per-pixel"
00136 
00137 bool intersects(const double &minXa, const double &minYa, const double &maxXa, const double &maxYa,
00138                 const double &minXb, const double &minYb, const double &maxXb, const double &maxYb)
00139 {
00140     return  osg::maximum(minXa, minXb) <= osg::minimum(maxXa,maxXb) &&
00141             osg::maximum(minYa, minYb) <= osg::minimum(maxYa, maxYb);
00142 }
00143 
00144 
00145 
00146 void TileMap::computeMinMaxLevel()
00147 {
00148     _minLevel = INT_MAX;
00149     _maxLevel = 0;
00150     for (TileSetList::iterator itr = _tileSets.begin(); itr != _tileSets.end(); ++itr)
00151     { 
00152         if (itr->getOrder() < _minLevel) _minLevel = itr->getOrder();
00153         if (itr->getOrder() > _maxLevel) _maxLevel = itr->getOrder();
00154     }
00155 }
00156 
00157 void TileMap::computeNumTiles()
00158 {
00159     _numTilesWide = -1;
00160     _numTilesHigh = -1;
00161 
00162     if (_tileSets.size() > 0)
00163     {
00164         unsigned int level = _tileSets[0].getOrder();
00165         double res = _tileSets[0].getUnitsPerPixel();
00166 
00167         _numTilesWide = (int)((_maxX - _minX) / (res * _format.getWidth()));
00168         _numTilesHigh = (int)((_maxY - _minY) / (res * _format.getWidth()));
00169 
00170         //In case the first level specified isn't level 0, compute the number of tiles at level 0
00171         for (unsigned int i = 0; i < level; i++)
00172         {
00173             _numTilesWide /= 2;
00174             _numTilesHigh /= 2;
00175         }
00176 
00177         OE_DEBUG << LC << "TMS has " << _numTilesWide << ", " << _numTilesHigh << " tiles at level 0 " <<  std::endl;
00178     }
00179 }
00180 
00181 const Profile*
00182 TileMap::createProfile() const
00183 {
00184     osg::ref_ptr< SpatialReference > spatialReference =  osgEarth::SpatialReference::create(_srs);
00185     
00186     if (spatialReference->isMercator())
00187     {
00188         //HACK:  Some TMS sources, most notably TileCache, use a global mercator extent that is very slightly different than
00189         //       the automatically computed mercator bounds which can cause rendering issues due to the some texture coordinates
00190         //       crossing the dateline.  If the incoming bounds are nearly the same as our definion of global mercator, just use our definition.
00191         double eps = 0.01;
00192         osg::ref_ptr< const Profile > merc = osgEarth::Registry::instance()->getGlobalMercatorProfile();
00193         if (_numTilesWide == 1 && _numTilesHigh == 1 &&
00194             osg::equivalent(merc->getExtent().xMin(), _minX, eps) && 
00195             osg::equivalent(merc->getExtent().yMin(), _minY, eps) &&
00196             osg::equivalent(merc->getExtent().xMax(), _maxX, eps) &&
00197             osg::equivalent(merc->getExtent().yMax(), _maxY, eps))
00198         {            
00199             return osgEarth::Registry::instance()->getGlobalMercatorProfile();
00200         }
00201     }
00202 
00203 
00204     if (_profile_type == Profile::TYPE_GEODETIC) return osgEarth::Registry::instance()->getGlobalGeodeticProfile();
00205     if (_profile_type == Profile::TYPE_MERCATOR) return osgEarth::Registry::instance()->getGlobalMercatorProfile();
00206     
00207 
00208     return Profile::create(
00209         _srs,
00210         _minX, _minY, _maxX, _maxY,
00211         _vsrs,
00212         osg::maximum(_numTilesWide, (unsigned int)1),
00213         osg::maximum(_numTilesHigh, (unsigned int)1) );
00214 }
00215 
00216 
00217 std::string
00218 TileMap::getURL(const osgEarth::TileKey& tilekey, bool invertY)
00219 {
00220     if (!intersectsKey(tilekey))
00221     {
00222         //OE_NOTICE << LC << "No key intersection for tile key " << tilekey.str() << std::endl;
00223         return "";
00224     }
00225 
00226     unsigned int zoom = tilekey.getLevelOfDetail();
00227 
00228     unsigned int x, y;
00229     tilekey.getTileXY(x, y);
00230 
00231     //Some TMS like services swap the Y coordinate so 0,0 is the upper left rather than the lower left.  The normal TMS
00232     //specification has 0,0 at the bottom left, so inverting Y will make 0,0 in the upper left.
00233     //http://code.google.com/apis/maps/documentation/overlays.html#Google_Maps_Coordinates
00234     if (!invertY)
00235     {
00236         unsigned int numRows, numCols;
00237         tilekey.getProfile()->getNumTiles(tilekey.getLevelOfDetail(), numCols, numRows);
00238         y  = numRows - y - 1;
00239     }
00240 
00241     //OE_NOTICE << LC << "KEY: " << tilekey.str() << " level " << zoom << " ( " << x << ", " << y << ")" << std::endl;
00242 
00243     //Select the correct TileSet
00244     if ( _tileSets.size() > 0 )
00245     {
00246         for (TileSetList::iterator itr = _tileSets.begin(); itr != _tileSets.end(); ++itr)
00247         { 
00248             if (itr->getOrder() == zoom)
00249             {
00250                 std::stringstream ss;
00251                 std::string path = osgDB::getFilePath(_filename);
00252                 ss << path << "/" << zoom << "/" << x << "/" << y << "." << _format.getExtension();
00253                 //OE_NOTICE << LC << "Returning URL " << ss.str() << std::endl;
00254                 std::string ssStr;
00255                                 ssStr = ss.str();
00256                                 return ssStr;
00257             }
00258         }
00259     }
00260     else // Just go with it. No way of knowing the max level.
00261     {
00262         std::stringstream ss;
00263         std::string path = osgDB::getFilePath(_filename);
00264         ss << path << "/" << zoom << "/" << x << "/" << y << "." << _format.getExtension();
00265         std::string ssStr;
00266                 ssStr = ss.str();
00267                 return ssStr;        
00268     }
00269 
00270     return "";
00271 }
00272 
00273 bool
00274 TileMap::intersectsKey(const TileKey& tilekey)
00275 {
00276     double keyMinX, keyMinY, keyMaxX, keyMaxY;
00277 
00278     //Check to see if the key overlaps the bounding box using lat/lon.  This is necessary to check even in 
00279     //Mercator situations in case the BoundingBox is described using lat/lon coordinates such as those produced by GDAL2Tiles
00280     //This should be considered a bug on the TMS production side, but we can work around it for now...
00281     tilekey.getExtent().getBounds(keyMinX, keyMinY, keyMaxX, keyMaxY);
00282 
00283     bool inter = intersects(_minX, _minY, _maxX, _maxY, keyMinX, keyMinY, keyMaxX, keyMaxY);
00284 
00285     if (!inter && tilekey.getProfile()->getSRS()->isMercator())
00286     {
00287         tilekey.getProfile()->getSRS()->transform2D(keyMinX, keyMinY, tilekey.getProfile()->getSRS()->getGeographicSRS(), keyMinX, keyMinY);
00288         tilekey.getProfile()->getSRS()->transform2D(keyMaxX, keyMaxY, tilekey.getProfile()->getSRS()->getGeographicSRS(), keyMaxX, keyMaxY);
00289         inter = intersects(_minX, _minY, _maxX, _maxY, keyMinX, keyMinY, keyMaxX, keyMaxY);
00290     }
00291 
00292     return inter;
00293 }
00294 
00295 void
00296 TileMap::generateTileSets(unsigned int numLevels)
00297 {
00298     osg::ref_ptr<const Profile> profile = createProfile();
00299 
00300     _tileSets.clear();
00301 
00302     double width = (_maxX - _minX);
00303 //    double height = (_maxY - _minY);
00304 
00305     for (unsigned int i = 0; i < numLevels; ++i)
00306     {
00307         unsigned int numCols, numRows;
00308         profile->getNumTiles(i, numCols, numRows);
00309         double res = (width / (double)numCols) / (double)_format.getWidth();
00310 
00311         TileSet ts;
00312         ts.setUnitsPerPixel(res);
00313         ts.setOrder(i);
00314         _tileSets.push_back(ts);
00315     }
00316 }
00317 
00318 std::string getSRSString(const osgEarth::SpatialReference* srs)
00319 {
00320     if (srs->isMercator())
00321     {
00322         return "EPSG:900913";
00323     }
00324     else if (srs->isGeographic())
00325     {
00326         return "EPSG:4326";
00327     }
00328     else
00329     {
00330         return srs->getInitString(); //srs();
00331     }   
00332 }
00333 
00334 
00335 TileMap*
00336 TileMap::create(const std::string& url,
00337                 const Profile* profile,
00338                 const std::string& format,
00339                 int tile_width,
00340                 int tile_height)
00341 {
00342     //Profile profile(type);
00343 
00344     const GeoExtent& ex = profile->getExtent();
00345 
00346     TileMap* tileMap = new TileMap();
00347     tileMap->setProfileType(profile->getProfileType()); //type);
00348     tileMap->setExtents(ex.xMin(), ex.yMin(), ex.xMax(), ex.yMax());
00349     tileMap->setOrigin(ex.xMin(), ex.yMin());
00350     tileMap->_filename = url;
00351     tileMap->_srs = getSRSString(profile->getSRS());
00352     tileMap->_vsrs = profile->getVerticalSRS() ? profile->getVerticalSRS()->getInitString() : "";
00353     tileMap->_format.setWidth( tile_width );
00354     tileMap->_format.setHeight( tile_height );
00355     tileMap->_format.setExtension( format );
00356         profile->getNumTiles( 0, tileMap->_numTilesWide, tileMap->_numTilesHigh );
00357 
00358         tileMap->generateTileSets();
00359         tileMap->computeMinMaxLevel();
00360         
00361     return tileMap;
00362 }
00363 
00364 TileMap* TileMap::create(const TileSource* tileSource, const Profile* profile)
00365 {
00366     TileMap* tileMap = new TileMap();
00367 
00368     tileMap->setTitle( tileSource->getName() );
00369     tileMap->setProfileType( profile->getProfileType() );
00370 
00371     const GeoExtent& ex = profile->getExtent();
00372     
00373     tileMap->_srs = getSRSString(profile->getSRS()); //srs();
00374     tileMap->_vsrs = profile->getVerticalSRS() ? profile->getVerticalSRS()->getInitString() : 0L;
00375     tileMap->_originX = ex.xMin();
00376     tileMap->_originY = ex.yMin();
00377     tileMap->_minX = ex.xMin();
00378     tileMap->_minY = ex.yMin();
00379     tileMap->_maxX = ex.xMax();
00380     tileMap->_maxY = ex.yMax();
00381     profile->getNumTiles( 0, tileMap->_numTilesWide, tileMap->_numTilesHigh );
00382 
00383     tileMap->_format.setWidth( tileSource->getPixelsPerTile() );
00384     tileMap->_format.setHeight( tileSource->getPixelsPerTile() );
00385     tileMap->_format.setExtension( tileSource->getExtension() );
00386 
00387     tileMap->generateTileSets();
00388 
00389     return tileMap;
00390 }
00391 
00392 
00393 
00394 //----------------------------------------------------------------------------
00395 
00396 
00397 TileMap* 
00398 TileMapReaderWriter::read( const std::string &location, const osgDB::ReaderWriter::Options* options )
00399 {
00400     TileMap *tileMap = NULL;
00401     if ( osgDB::containsServerAddress( location ) )
00402     {
00403         HTTPResponse response = HTTPClient::get( location, options );
00404         if (response.isOK() && response.getNumParts() > 0 )
00405         {
00406             tileMap = read( response.getPartStream( 0 ) );
00407         }
00408     }
00409     else
00410     {
00411         if ((osgDB::fileExists(location)) && (osgDB::fileType(location) == osgDB::REGULAR_FILE))
00412         {
00413             std::ifstream in( location.c_str() );
00414             tileMap = read( in );
00415         }
00416     }
00417     if (tileMap)
00418     {
00419         tileMap->setFilename( location );
00420     }
00421     return tileMap;
00422 }
00423 
00424 TileMap*
00425 TileMapReaderWriter::read(std::istream &in)
00426 {
00427     osg::ref_ptr<TileMap> tileMap = new TileMap;
00428 
00429     osg::ref_ptr<XmlDocument> doc = XmlDocument::load( in );
00430     if (!doc.valid())
00431     {
00432         OE_DEBUG << LC << "Failed to load TileMap " << std::endl;
00433         return 0;
00434     }
00435    
00436     //Get the root TileMap element
00437     osg::ref_ptr<XmlElement> e_tile_map = doc->getSubElement( ELEM_TILEMAP );
00438     if (!e_tile_map.valid())
00439     {
00440         OE_WARN << LC << "Could not find root TileMap element " << std::endl;
00441         return 0;
00442     }
00443 
00444     tileMap->setVersion( e_tile_map->getAttr( ATTR_VERSION ) );
00445     tileMap->setTileMapService( e_tile_map->getAttr( ATTR_TILEMAPSERVICE ) );
00446 
00447     tileMap->setTitle( e_tile_map->getSubElementText(ELEM_TITLE) );
00448     tileMap->setAbstract( e_tile_map->getSubElementText(ELEM_ABSTRACT) );
00449     tileMap->setSRS( e_tile_map->getSubElementText(ELEM_SRS) );
00450     tileMap->setVerticalSRS( e_tile_map->getSubElementText(ELEM_VERTICAL_SRS) );
00451 
00452     //Read the bounding box
00453     osg::ref_ptr<XmlElement> e_bounding_box = e_tile_map->getSubElement(ELEM_BOUNDINGBOX);
00454     if (e_bounding_box.valid())
00455     {
00456         double minX = as<double>(e_bounding_box->getAttr( ATTR_MINX ), 0.0);
00457         double minY = as<double>(e_bounding_box->getAttr( ATTR_MINY ), 0.0);
00458         double maxX = as<double>(e_bounding_box->getAttr( ATTR_MAXX ), 0.0);
00459         double maxY = as<double>(e_bounding_box->getAttr( ATTR_MAXY ), 0.0);
00460         tileMap->setExtents( minX, minY, maxX, maxY);
00461     }
00462 
00463     //Read the origin
00464     osg::ref_ptr<XmlElement> e_origin = e_tile_map->getSubElement(ELEM_ORIGIN);
00465     if (e_origin.valid())
00466     {
00467         tileMap->setOriginX( as<double>(e_origin->getAttr( ATTR_X ), 0.0) );
00468         tileMap->setOriginY( as<double>(e_origin->getAttr( ATTR_Y ), 0.0) );
00469     }
00470 
00471     //Read the tile format
00472     osg::ref_ptr<XmlElement> e_tile_format = e_tile_map->getSubElement(ELEM_TILE_FORMAT);
00473     if (e_tile_format.valid())
00474     {
00475         tileMap->getFormat().setExtension( e_tile_format->getAttr( ATTR_EXTENSION ) );
00476         tileMap->getFormat().setMimeType( e_tile_format->getAttr( ATTR_MIME_TYPE) );
00477         tileMap->getFormat().setWidth( as<unsigned int>(e_tile_format->getAttr( ATTR_WIDTH ), 0) );
00478         tileMap->getFormat().setHeight( as<unsigned int>(e_tile_format->getAttr( ATTR_HEIGHT ), 0) );
00479     }
00480 
00481     //Read the tilesets
00482     osg::ref_ptr<XmlElement> e_tile_sets = e_tile_map->getSubElement(ELEM_TILESETS);
00483     if (e_tile_sets.valid())
00484     {
00485         //Read the profile
00486         std::string profile = e_tile_sets->getAttr( ATTR_PROFILE );
00487         if (profile == "global-geodetic") tileMap->setProfileType( Profile::TYPE_GEODETIC );
00488         else if (profile == "global-mercator") tileMap->setProfileType( Profile::TYPE_MERCATOR );
00489         else if (profile == "local") tileMap->setProfileType( Profile::TYPE_LOCAL );
00490         else tileMap->setProfileType( Profile::TYPE_UNKNOWN );
00491 
00492         //Read each TileSet
00493         XmlNodeList tile_sets = e_tile_sets->getSubElements( ELEM_TILESET );
00494         for( XmlNodeList::const_iterator i = tile_sets.begin(); i != tile_sets.end(); i++ )
00495         {
00496             osg::ref_ptr<XmlElement> e_tile_set = static_cast<XmlElement*>( i->get() );
00497             TileSet tileset;
00498             tileset.setHref( e_tile_set->getAttr( ATTR_HREF ) );
00499             tileset.setOrder( as<unsigned int>(e_tile_set->getAttr( ATTR_ORDER ), -1) );
00500             tileset.setUnitsPerPixel( as<double>(e_tile_set->getAttr( ATTR_UNITSPERPIXEL ), 0.0 ) );
00501             tileMap->getTileSets().push_back(tileset);
00502         }
00503     }
00504 
00505     //Try to compute the profile based on the SRS if there was no PROFILE tag given
00506     if (tileMap->getProfileType() == Profile::TYPE_UNKNOWN && !tileMap->getSRS().empty())
00507     {
00508         tileMap->setProfileType( Profile::getProfileTypeFromSRS(tileMap->getSRS()) );
00509     }
00510 
00511     tileMap->computeMinMaxLevel();
00512     tileMap->computeNumTiles();
00513 
00514     //Read the data areas
00515     osg::ref_ptr<XmlElement> e_data_extents = e_tile_map->getSubElement(ELEM_DATA_EXTENTS);
00516     if (e_data_extents.valid())
00517     {
00518         osg::ref_ptr< const osgEarth::Profile > profile = tileMap->createProfile();
00519         OE_DEBUG << LC << "Found DataExtents " << std::endl;
00520         XmlNodeList data_extents = e_data_extents->getSubElements( ELEM_DATA_EXTENT );
00521         for( XmlNodeList::const_iterator i = data_extents.begin(); i != data_extents.end(); i++ )
00522         {
00523             osg::ref_ptr<XmlElement> e_data_extent = static_cast<XmlElement*>( i->get() );
00524             double minX = as<double>(e_data_extent->getAttr( ATTR_MINX ), 0.0);
00525             double minY = as<double>(e_data_extent->getAttr( ATTR_MINY ), 0.0);
00526             double maxX = as<double>(e_data_extent->getAttr( ATTR_MAXX ), 0.0);
00527             double maxY = as<double>(e_data_extent->getAttr( ATTR_MAXY ), 0.0);
00528             //unsigned int minLevel = as<unsigned int>(e_data_extent->getAttr( ATTR_MIN_LEVEL ), 0);
00529             unsigned int maxLevel = as<unsigned int>(e_data_extent->getAttr( ATTR_MAX_LEVEL ), 0);            
00530 
00531             //OE_DEBUG << LC << "Read area " << minX << ", " << minY << ", " << maxX << ", " << maxY << ", minlevel=" << minLevel << " maxlevel=" << maxLevel << std::endl;
00532             tileMap->getDataExtents().push_back( DataExtent(GeoExtent(profile->getSRS(), minX, minY, maxX, maxY), 0, maxLevel));
00533         }
00534     }
00535 
00536 
00537     return tileMap.release();
00538 }
00539 
00540 static XmlDocument*
00541 tileMapToXmlDocument(const TileMap* tileMap)
00542 {
00543     //Create the root XML document
00544     osg::ref_ptr<XmlDocument> doc = new XmlDocument();
00545     doc->setName( ELEM_TILEMAP );
00546     
00547     //Create the root node
00548     //osg::ref_ptr<XmlElement> e_tile_map = new XmlElement( ELEM_TILEMAP );
00549     //doc->getChildren().push_back( e_tile_map.get() );
00550 
00551     doc->getAttrs()[ ATTR_VERSION ] = tileMap->getVersion();
00552     doc->getAttrs()[ ATTR_TILEMAPSERVICE ] = tileMap->getTileMapService();
00553   
00554     doc->addSubElement( ELEM_TITLE, tileMap->getTitle() );
00555     doc->addSubElement( ELEM_ABSTRACT, tileMap->getAbstract() );
00556     doc->addSubElement( ELEM_SRS, tileMap->getSRS() );
00557     doc->addSubElement( ELEM_VERTICAL_SRS, tileMap->getVerticalSRS() );
00558 
00559     osg::ref_ptr<XmlElement> e_bounding_box = new XmlElement( ELEM_BOUNDINGBOX );
00560     double minX, minY, maxX, maxY;
00561     tileMap->getExtents( minX, minY, maxX, maxY );
00562     e_bounding_box->getAttrs()[ATTR_MINX] = toString(minX);
00563     e_bounding_box->getAttrs()[ATTR_MINY] = toString(minY);
00564     e_bounding_box->getAttrs()[ATTR_MAXX] = toString(maxX);
00565     e_bounding_box->getAttrs()[ATTR_MAXY] = toString(maxY);
00566     doc->getChildren().push_back(e_bounding_box.get() );
00567 
00568     osg::ref_ptr<XmlElement> e_origin = new XmlElement( ELEM_ORIGIN );
00569     e_origin->getAttrs()[ATTR_X] = toString(tileMap->getOriginX());
00570     e_origin->getAttrs()[ATTR_Y] = toString(tileMap->getOriginY());
00571     doc->getChildren().push_back(e_origin.get());
00572 
00573     osg::ref_ptr<XmlElement> e_tile_format = new XmlElement( ELEM_TILE_FORMAT );
00574     e_tile_format->getAttrs()[ ATTR_EXTENSION ] = tileMap->getFormat().getExtension();
00575     e_tile_format->getAttrs()[ ATTR_MIME_TYPE ] = tileMap->getFormat().getMimeType();
00576     e_tile_format->getAttrs()[ ATTR_WIDTH ] = toString<unsigned int>(tileMap->getFormat().getWidth());
00577     e_tile_format->getAttrs()[ ATTR_HEIGHT ] = toString<unsigned int>(tileMap->getFormat().getHeight());
00578     doc->getChildren().push_back(e_tile_format.get());
00579 
00580     osg::ref_ptr< const osgEarth::Profile > profile = tileMap->createProfile();
00581 
00582     osg::ref_ptr<XmlElement> e_tile_sets = new XmlElement ( ELEM_TILESETS );
00583     std::string profileString = "none";
00584     if (profile->isEquivalentTo(osgEarth::Registry::instance()->getGlobalGeodeticProfile()))
00585     {
00586         profileString = "global-geodetic";
00587     }
00588     else if (profile->isEquivalentTo(osgEarth::Registry::instance()->getGlobalMercatorProfile()))
00589     {
00590         profileString = "global-mercator";
00591     }
00592     else
00593     {
00594         profileString = "local";
00595     }
00596     e_tile_sets->getAttrs()[ ATTR_PROFILE ] = profileString;
00597 
00598 
00599     for (TileMap::TileSetList::const_iterator itr = tileMap->getTileSets().begin(); itr != tileMap->getTileSets().end(); ++itr)
00600     {
00601         osg::ref_ptr<XmlElement> e_tile_set = new XmlElement( ELEM_TILESET );
00602         e_tile_set->getAttrs()[ATTR_HREF] = itr->getHref();
00603         e_tile_set->getAttrs()[ATTR_ORDER] = toString<unsigned int>(itr->getOrder());
00604         e_tile_set->getAttrs()[ATTR_UNITSPERPIXEL] = toString(itr->getUnitsPerPixel());
00605         e_tile_sets->getChildren().push_back( e_tile_set.get() );
00606     }
00607     doc->getChildren().push_back(e_tile_sets.get());
00608 
00609     //Write out the data areas
00610     if (tileMap->getDataExtents().size() > 0)
00611     {
00612         osg::ref_ptr<XmlElement> e_data_extents = new XmlElement( ELEM_DATA_EXTENTS );
00613         for (DataExtentList::const_iterator itr = tileMap->getDataExtents().begin(); itr != tileMap->getDataExtents().end(); ++itr)
00614         {
00615             osg::ref_ptr<XmlElement> e_data_extent = new XmlElement( ELEM_DATA_EXTENT );
00616             e_data_extent->getAttrs()[ATTR_MINX] = toString(itr->xMin());
00617             e_data_extent->getAttrs()[ATTR_MINY] = toString(itr->yMin());
00618             e_data_extent->getAttrs()[ATTR_MAXX] = toString(itr->xMax());
00619             e_data_extent->getAttrs()[ATTR_MAXY] = toString(itr->yMax());
00620             e_data_extent->getAttrs()[ATTR_MIN_LEVEL] = toString<unsigned int>(itr->getMinLevel());
00621             e_data_extent->getAttrs()[ATTR_MAX_LEVEL] = toString<unsigned int>(itr->getMaxLevel());
00622             e_data_extents->getChildren().push_back( e_data_extent );
00623         }
00624         doc->getChildren().push_back( e_data_extents.get() );
00625     }
00626     return doc.release();
00627 }
00628 
00629 void
00630 TileMapReaderWriter::write(const TileMap* tileMap, const std::string &location)
00631 {
00632     std::string path = osgDB::getFilePath(location);
00633     if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path))
00634     {
00635         OE_WARN << LC << "Couldn't create path " << std::endl;
00636     }
00637     std::ofstream out(location.c_str());
00638     write(tileMap, out);
00639 }
00640 
00641 void
00642 TileMapReaderWriter::write(const TileMap* tileMap, std::ostream &output)
00643 {
00644     osg::ref_ptr<XmlDocument> doc = tileMapToXmlDocument(tileMap);    
00645     doc->store(output);
00646 }
00647 
00648 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines