osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/wms/TileService.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 #include "TileService"
00021 
00022 #include <osgEarth/XmlUtils>
00023 #include <osgEarth/HTTPClient>
00024 
00025 #include <osg/io_utils>
00026 #include <osgDB/FileNameUtils>
00027 #include <osgDB/FileUtils>
00028 
00029 using namespace osgEarth;
00030 using namespace std;
00031 
00032 
00033 
00034 std::string extractBetween(const std::string& str, const string &lhs, const string &rhs)
00035 {
00036     std::string result;
00037     string::size_type start = str.find(lhs);
00038     if (start != string::npos)
00039     {
00040         start += lhs.length();
00041         string::size_type count = str.size() - start;
00042         string::size_type end = str.find(rhs, start); 
00043         if (end != string::npos) count = end-start;
00044         result = str.substr(start, count);
00045     }
00046     return result;
00047 }
00048 
00049 TilePattern::TilePattern(const std::string& pattern)
00050 {
00051     _pattern = pattern;
00052     init();
00053 }
00054 
00055 
00056 
00057 void TilePattern::init()
00058 {
00059     _dataMin.x() = -180;
00060     _dataMin.y() = -90;
00061     _dataMax.x() = 180;
00062     _dataMax.y() = 90;
00063 
00064     //request=GetMap&layers=global_mosaic&srs=EPSG:4326&format=image/jpeg&styles=visual&width=512&height=512&bbox=-180,-166,76,90
00065     //Convert the filename to lower case
00066     std::string lower = osgDB::convertToLowerCase( _pattern );
00067 
00068     _layers = extractBetween(lower, "layers=", "&");
00069     _styles = extractBetween(lower, "styles=", "&");
00070     _srs = extractBetween(lower, "srs=", "&");
00071     _format = extractBetween(lower, "format=image/", "&");
00072     _imageWidth = as<int>(extractBetween(lower, "width=", "&"), 0);
00073     _imageHeight = as<int>(extractBetween(lower, "height=", "&"), 0);
00074 
00075     //Read the coordinates of the top left tile
00076     std::string bbox = extractBetween(lower, "bbox=", "&");
00077     sscanf(bbox.c_str(), "%lf,%lf,%lf,%lf", &_topLeftMin.x(), &_topLeftMin.y(), &_topLeftMax.x(), &_topLeftMax.y());
00078 
00079     //Compute the tile dimensions
00080     _tileWidth = _topLeftMax.x() - _topLeftMin.x();
00081     _tileHeight = _topLeftMax.y() - _topLeftMin.y();
00082 
00083     //Create the prototype
00084     string::size_type len = lower.find( bbox );
00085     if (len != string::npos)
00086     {
00087         string beforeBB = _pattern.substr(0, len);
00088 
00089         string::size_type after = len + bbox.length();
00090         string afterBB = "";
00091         if (after < _pattern.length()-1)
00092         {
00093             afterBB = _pattern.substr(after, _pattern.length() - after);
00094         }
00095         _prototype = beforeBB + std::string("%lf,%lf,%lf,%lf") + afterBB;
00096     }
00097 }
00098 
00099 void TilePattern::getTileBounds(const int &x, const int &y, double &minX, double &minY, double &maxX, double &maxY)
00100 {
00101     minX = _topLeftMin.x() + (double)x * _tileWidth;
00102     maxX = minX + _tileWidth;
00103 
00104     maxY = _topLeftMax.y() - (double)y * _tileHeight;
00105     minY = maxY - _tileHeight;
00106 }
00107 
00108 std::string TilePattern::getRequestString(const int &x, const int &y)
00109 {
00110     double minX, minY, maxX, maxY;
00111     getTileBounds(x, y, minX, minY, maxX, maxY);
00112 
00113     char buf[2048];
00114     sprintf(buf, _prototype.c_str(), minX, minY, maxX, maxY);
00115     return buf;
00116 }
00117 
00118 
00119 TileService::TileService():
00120 _dataMin(-180, -90),
00121 _dataMax(180, 90)
00122 {
00123 }
00124 
00125 void TileService::getMatchingPatterns(const std::string &layers, const std::string &format,
00126                                       const std::string &styles, const std::string &srs,
00127                                       unsigned int imageWidth, unsigned int imageHeight,
00128                                       TilePatternList& out_patterns)
00129 {
00130     out_patterns.clear();
00131     for (TilePatternList::iterator i = _patterns.begin(); i < _patterns.end(); ++i)
00132     {
00133         if (osgDB::equalCaseInsensitive(i->getLayers(), layers) &&
00134             osgDB::equalCaseInsensitive(i->getFormat(),format) &&
00135             osgDB::equalCaseInsensitive(i->getStyles(), styles) &&
00136             osgDB::equalCaseInsensitive(i->getSRS(), srs) &&
00137             (i->getImageWidth()  == (int)imageWidth) &&
00138             (i->getImageHeight() == (int)imageHeight))
00139         {
00140             out_patterns.push_back(*i);
00141         }
00142     }
00143 }
00144 
00145 const Profile*
00146 TileService::createProfile(TilePatternList &patterns)
00147 {
00148     //Assume that all the values in the patterns are equal except for the bounding boxes
00149     const Profile* profile = NULL;
00150 
00151     if (patterns.size() > 0)
00152     {
00153       double maxWidth = -1;
00154       double maxHeight = -1;
00155 
00156       osg::Vec2d topLeftMin;
00157       osg::Vec2d topLeftMax;
00158 
00159       //Find the lowest resolution pattern.
00160       for (unsigned int i = 0; i < patterns.size(); ++i)
00161       {
00162           if (maxWidth < patterns[i].getTileWidth() &&
00163               maxHeight < patterns[i].getTileHeight())
00164           {
00165               maxWidth = patterns[i].getTileWidth();
00166               maxHeight = patterns[i].getTileHeight();
00167 
00168               topLeftMin = patterns[i].getTopLeftMin();
00169               topLeftMax = patterns[i].getTopLeftMax();
00170           }
00171       }
00172 
00173       double dataWidth = _dataMax.x() - _dataMin.x();
00174       double dataHeight = _dataMax.y() - _dataMin.y();
00175 
00176       double tileWidth = topLeftMax.x() - topLeftMin.x();
00177       double tileHeight = topLeftMax.y() - topLeftMin.y();
00178 
00179       unsigned int w = (unsigned int) ceil(dataWidth / tileWidth );
00180       unsigned int h = (unsigned int) ceil(dataHeight / tileHeight);
00181 
00182       double xmin = topLeftMin.x();
00183       double xmax = xmin + (double)w * tileWidth;
00184       double ymax = topLeftMax.y();
00185       double ymin = ymax - (double)h * tileHeight;
00186       
00187       profile = Profile::create( patterns[0].getSRS(), xmin, ymin, xmax, ymax, "", w, h);
00188     }
00189 
00190     return profile;
00191 }
00192 
00193 #define ELEM_WMS_TILE_SERVICE "wms_tile_service"
00194 #define ELEM_SERVICE          "service"
00195 #define ATTR_VERSION          "version"
00196 #define ELEM_NAME             "name"
00197 #define ELEM_TITLE            "title"
00198 #define ELEM_ABSTRACT         "abstract"
00199 #define ELEM_ACCESSCONSTRAINTS "accessconstraints"
00200 
00201 #define ELEM_TILEDPATTERNS     "tiledpatterns"
00202 #define ELEM_TILEPATTERN       "tilepattern"
00203 #define ELEM_TILEDGROUP        "tiledgroup"
00204 #define ELEM_LATLONBOUNDINGBOX "latlonboundingbox"
00205 #define ATTR_MINX              "minx"
00206 #define ATTR_MINY              "miny"
00207 #define ATTR_MAXX              "maxx"
00208 #define ATTR_MAXY              "maxy"
00209 
00210 TileService* 
00211 TileServiceReader::read( const std::string &location, const osgDB::ReaderWriter::Options* options )
00212 {
00213     TileService *tileService = NULL;
00214     if ( osgDB::containsServerAddress( location ) )
00215     {
00216         HTTPResponse response = HTTPClient::get( location, options);
00217         if (response.isOK() && response.getNumParts() > 0 )
00218         {
00219             tileService = read( response.getPartStream( 0 ) );
00220         }
00221     }
00222     else
00223     {
00224         if ((osgDB::fileExists(location)) && (osgDB::fileType(location) == osgDB::REGULAR_FILE))
00225         {
00226             std::ifstream in( location.c_str() );
00227             tileService = read( in );
00228         }
00229     }
00230     return tileService;
00231 }
00232 
00233 void readBoundingBox(XmlElement* e_bb, double &minX, double &minY, double &maxX, double &maxY)
00234 {
00235     if (e_bb)
00236     {
00237         minX = as<double>(e_bb->getAttr( ATTR_MINX ), minX);
00238         minY = as<double>(e_bb->getAttr( ATTR_MINY ), minY);
00239         maxX = as<double>(e_bb->getAttr( ATTR_MAXX ), maxX);
00240         maxY = as<double>(e_bb->getAttr( ATTR_MAXY ), maxY);
00241     }
00242 }
00243 
00244 void addTilePatterns(XmlElement* e_root, TileService* tileService)
00245 {
00246     //Read all the TilePatterns
00247     XmlNodeList tile_patterns = e_root->getSubElements( ELEM_TILEPATTERN );
00248     for( XmlNodeList::const_iterator i = tile_patterns.begin(); i != tile_patterns.end(); i++ )
00249     {            
00250         //We only really care about a single access pattern, so extract it
00251         string txt = static_cast<XmlElement*>( i->get() )->getText();
00252         //Access patterns are separated by whitespace 
00253         std::string whitespace (" \t\f\v\n\r");
00254         string::size_type len = txt.find_first_of(whitespace);
00255         if (len != string::npos)
00256         {
00257             txt = trim(txt.substr(0, len));
00258         }
00259         TilePattern pattern(txt);
00260         tileService->getPatterns().push_back(pattern);
00261     }
00262 
00263     //Read all TilePatterns in the TiledGroups
00264     XmlNodeList tiled_groups = e_root->getSubElements(ELEM_TILEDGROUP);
00265     for( XmlNodeList::const_iterator i = tiled_groups.begin(); i != tiled_groups.end(); i++ )
00266     {
00267         addTilePatterns(static_cast<XmlElement*>(i->get()), tileService);
00268     }
00269 }
00270 
00271 TileService*
00272 TileServiceReader::read(std::istream &in)
00273 {
00274     osg::ref_ptr<TileService> tileService = new TileService;
00275 
00276     osg::ref_ptr<XmlDocument> doc = XmlDocument::load( in );
00277     if (!doc.valid())
00278     {
00279         OE_INFO << "Failed to load TileService " << std::endl;
00280         return 0;
00281     }
00282     
00283     //Get the root TileMap element
00284     osg::ref_ptr<XmlElement> e_root = doc->getSubElement( ELEM_WMS_TILE_SERVICE );
00285     if (!e_root.valid())
00286     {
00287         OE_INFO << "Could not find root TileService element " << std::endl;
00288         return 0;
00289     }
00290 
00291     tileService->setVersion( e_root->getAttr( ATTR_VERSION ) );
00292 
00293     //Get properties from the Service element.
00294     osg::ref_ptr<XmlElement> e_service = e_root->getSubElement( ELEM_SERVICE );
00295     if (!e_service.valid())
00296     {
00297         OE_INFO << "Could not find Service element " << std::endl;
00298         return 0;
00299     }
00300 
00301     tileService->setName( e_service->getSubElementText( ELEM_NAME ) );
00302     tileService->setTitle( e_service->getSubElementText( ELEM_TITLE ) );
00303     tileService->setAbstract( e_service->getSubElementText( ELEM_ABSTRACT ) );
00304     tileService->setAccessConstraints( e_service->getSubElementText( ELEM_ACCESSCONSTRAINTS ) );
00305 
00306     //Get the TiledPattern element which contains the TiledGroups
00307     osg::ref_ptr<XmlElement> e_tiledPatterns = e_root->getSubElement( ELEM_TILEDPATTERNS );
00308     if (!e_tiledPatterns.valid())
00309     {
00310         OE_INFO << "Could not find TiledPatterns element" << std::endl;
00311         return 0;
00312     }
00313 
00314     //Get the bounding box from the TiledPatterns
00315     osg::ref_ptr<XmlElement> e_bb = e_tiledPatterns->getSubElement( ELEM_LATLONBOUNDINGBOX );
00316     if (e_bb.valid())
00317     {
00318       double minX, minY, maxX, maxY;
00319       readBoundingBox(e_bb.get(), minX, minY, maxX, maxY);
00320       tileService->setDataMin(osg::Vec2d(minX, minY));
00321       tileService->setDataMax(osg::Vec2d(maxX, maxY));
00322     }
00323 
00324     addTilePatterns(e_tiledPatterns.get(), tileService.get());
00325 
00326     OE_INFO << "Returning TileService with " << tileService->getPatterns().size() << " patterns " << std::endl;
00327     return tileService.release();
00328 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines