osgEarth 2.1.1
|
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