1 /* -*-c++-*- */
2 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
3  * Copyright 2008-2010 Pelican Mapping
4  * http://osgearth.org
5  *
6  * osgEarth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19 
20 #include "Capabilities"
21 
22 #include <osgEarth/XmlUtils>
23 #include <osgEarth/HTTPClient>
24 
25 #include <osgDB/FileNameUtils>
26 #include <osgDB/FileUtils>
27 
28 using namespace osgEarth;
29 using namespace std;
30 
31 static
getLayerByName(const string & name,Layer::LayerList & layers)32 Layer* getLayerByName(const string &name, Layer::LayerList& layers)
33 {
34     for (Layer::LayerList::iterator i = layers.begin(); i != layers.end(); ++i)
35     {
36         if (osgDB::equalCaseInsensitive(i->get()->getName(),name)) return i->get();
37         Layer *l = getLayerByName(name, i->get()->getLayers());
38         if (l) return l;
39     }
40     return 0;
41 }
42 
Style()43 Style::Style()
44 {
45 }
46 
Style(const std::string & name,const std::string & title)47 Style::Style(const std::string& name, const std::string &title)
48 {
49     _name = name;
50     _title = title;
51 }
52 
Layer()53 Layer::Layer():
54 _parentLayer(0),
55 _minLon(0),
56 _minLat(0),
57 _maxLon(0),
58 _maxLat(0),
59 _minX(0),
60 _minY(0),
61 _maxX(0),
62 _maxY(0)
63 {
64 }
65 
getLatLonExtents(double & minLon,double & minLat,double & maxLon,double & maxLat)66 void Layer::getLatLonExtents(double &minLon, double &minLat, double &maxLon, double &maxLat)
67 {
68     minLon = _minLon;
69     minLat= _minLat;
70     maxLon = _maxLon;
71     maxLat = _maxLat;
72 }
73 
setLatLonExtents(double minLon,double minLat,double maxLon,double maxLat)74 void Layer::setLatLonExtents(double minLon, double minLat, double maxLon, double maxLat)
75 {
76     _minLon = minLon;
77     _minLat = minLat;
78     _maxLon = maxLon;
79     _maxLat = maxLat;
80 }
81 
getExtents(double & minX,double & minY,double & maxX,double & maxY)82 void Layer::getExtents(double &minX, double &minY, double &maxX, double &maxY)
83 {
84     minX = _minX;
85     minY = _minY;
86     maxX = _maxX;
87     maxY = _maxY;
88 }
89 
setExtents(double minX,double minY,double maxX,double maxY)90 void Layer::setExtents(double minX, double minY, double maxX, double maxY)
91 {
92     _minX = minX;
93     _minY = minY;
94     _maxX = maxX;
95     _maxY = maxY;
96 }
97 
98 
WMSCapabilities()99 WMSCapabilities::WMSCapabilities()
100 {
101 }
102 
suggestExtension()103 std::string WMSCapabilities::suggestExtension()
104 {
105     //Default to png
106     std::string ext = "png";
107 
108     //Find the first format that we have an osg ReaderWriter for
109     for (unsigned int i = 0; i < _formats.size(); ++i)
110     {
111         std::string format = _formats[i];
112         //Strip off the "image/"
113         if ((format.length() > 6) && (format.compare(0,6,"image/") == 0))
114         {
115             format = format.substr(6);
116             //See if we have a ReaderWriter for the extension
117             osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension( format );
118             if (rw)
119             {
120                 ext = format;
121                 OE_DEBUG << "suggestExtension found ReaderWriter for " << ext << std::endl;
122                 break;
123             }
124         }
125     }
126     return ext;
127 }
128 
129 Layer*
getLayerByName(const std::string & name)130 WMSCapabilities::getLayerByName(const std::string &name)
131 {
132     return ::getLayerByName(name, _layers);
133 }
134 
135 WMSCapabilities*
read(const std::string & location,const osgDB::ReaderWriter::Options * options)136 WMSCapabilitiesReader::read( const std::string &location, const osgDB::ReaderWriter::Options* options )
137 {
138     WMSCapabilities *caps = NULL;
139     if ( osgDB::containsServerAddress( location ) )
140     {
141         HTTPResponse response = HTTPClient::get( location, options );
142         if ( response.isOK() && response.getNumParts() > 0 )
143         {
144             caps = read( response.getPartStream( 0 ) );
145         }
146     }
147     else
148     {
149         if ((osgDB::fileExists(location)) && (osgDB::fileType(location) == osgDB::REGULAR_FILE))
150         {
151             std::ifstream in( location.c_str() );
152             caps = read( in );
153         }
154     }
155     return caps;
156 }
157 
158 #define ATTR_VERSION "version"
159 #define ELEM_CAPABILITY "capability"
160 #define ELEM_REQUEST "request"
161 #define ELEM_ABSTRACT "abstract"
162 #define ELEM_GETMAP "getmap"
163 #define ELEM_FORMAT "format"
164 #define ELEM_LAYER "layer"
165 #define ELEM_NAME "name"
166 #define ELEM_TITLE "title"
167 #define ELEM_STYLE "style"
168 #define ELEM_SRS "srs"
169 #define ELEM_CRS "crs"
170 #define ELEM_LATLONBOUNDINGBOX "latlonboundingbox"
171 #define ELEM_BOUNDINGBOX "boundingbox"
172 #define ATTR_MINX              "minx"
173 #define ATTR_MINY              "miny"
174 #define ATTR_MAXX              "maxx"
175 #define ATTR_MAXY              "maxy"
176 
177 
178 
179 static void
readLayers(XmlElement * e,Layer * parentLayer,Layer::LayerList & layers)180 readLayers(XmlElement* e, Layer* parentLayer, Layer::LayerList& layers)
181 {
182     XmlNodeList layerNodes = e->getSubElements( ELEM_LAYER );
183     for( XmlNodeList::const_iterator i = layerNodes.begin(); i != layerNodes.end(); i++ )
184     {
185         XmlElement* e_layer = static_cast<XmlElement*>( i->get() );
186 
187         Layer *layer = new Layer;
188         layer->setName( e_layer->getSubElementText( ELEM_NAME ) );
189         layer->setTitle( e_layer->getSubElementText( ELEM_TITLE ) );
190         layer->setAbstract( e_layer->getSubElementText( ELEM_ABSTRACT ) );
191 
192         //Read all the supported styles
193         XmlNodeList styles = e_layer->getSubElements( ELEM_STYLE );
194         for( XmlNodeList::const_iterator styleitr = styles.begin(); styleitr != styles.end(); styleitr++ )
195         {
196             XmlElement* e_style = static_cast<XmlElement*>( styleitr->get() );
197             string name = e_style->getSubElementText( ELEM_NAME );
198             string title = e_style->getSubElementText( ELEM_TITLE );
199             layer->getStyles().push_back(Style(name,title));
200         }
201 
202         //Read all the supported SRS's
203         XmlNodeList spatialReferences = e_layer->getSubElements( ELEM_SRS );
204         for (XmlNodeList::const_iterator srsitr = spatialReferences.begin(); srsitr != spatialReferences.end(); ++srsitr)
205         {
206             string srs = static_cast<XmlElement*>( srsitr->get() )->getText();
207             layer->getSpatialReferences().push_back(srs);
208         }
209 
210         //Read all the supported CRS's
211         spatialReferences = e_layer->getSubElements( ELEM_CRS );
212         for (XmlNodeList::const_iterator srsitr = spatialReferences.begin(); srsitr != spatialReferences.end(); ++srsitr)
213         {
214             string crs = static_cast<XmlElement*>( srsitr->get() )->getText();
215             layer->getSpatialReferences().push_back(crs);
216         }
217 
218         osg::ref_ptr<XmlElement> e_bb = e_layer->getSubElement( ELEM_LATLONBOUNDINGBOX );
219         if (e_bb.valid())
220         {
221             double minX, minY, maxX, maxY;
222             minX = as<double>(e_bb->getAttr( ATTR_MINX ), 0);
223             minY = as<double>(e_bb->getAttr( ATTR_MINY ), 0);
224             maxX = as<double>(e_bb->getAttr( ATTR_MAXX ), 0);
225             maxY = as<double>(e_bb->getAttr( ATTR_MAXY ), 0);
226             layer->setLatLonExtents(minX, minY, maxX, maxY);
227         }
228 
229         e_bb = e_layer->getSubElement( ELEM_BOUNDINGBOX );
230         if (e_bb.valid())
231         {
232             double minX, minY, maxX, maxY;
233             minX = as<double>(e_bb->getAttr( ATTR_MINX ), 0);
234             minY = as<double>(e_bb->getAttr( ATTR_MINY ), 0);
235             maxX = as<double>(e_bb->getAttr( ATTR_MAXX ), 0);
236             maxY = as<double>(e_bb->getAttr( ATTR_MAXY ), 0);
237             layer->setExtents(minX, minY, maxX, maxY);
238         }
239 
240         //Add the layer to the list and set its parent layer
241         layers.push_back(layer);
242         layer->setParentLayer( parentLayer );
243 
244         //Read any other layers that are in the layer node
245         readLayers( e_layer, layer, layer->getLayers());
246     }
247 }
248 
249 
250 
251 
252 WMSCapabilities*
read(std::istream & in)253 WMSCapabilitiesReader::read(std::istream &in)
254 {
255     osg::ref_ptr<WMSCapabilities> capabilities = new WMSCapabilities;
256 
257     osg::ref_ptr<XmlDocument> doc = XmlDocument::load( in );
258     if (!doc.valid() || doc->getChildren().empty())
259     {
260         OE_NOTICE << "Failed to load Capabilities " << std::endl;
261         return 0;
262     }
263 
264     //Get the Capabilities version
265     osg::ref_ptr<XmlElement> e_root = static_cast<XmlElement*>(doc->getChildren()[0].get());
266     capabilities->setVersion( e_root->getAttr(ATTR_VERSION ) );
267 
268     osg::ref_ptr<XmlElement> e_capability = e_root->getSubElement( ELEM_CAPABILITY );
269     if (!e_capability.valid())
270     {
271         OE_NOTICE << "Could not find Capability element" << std::endl;
272         return 0;
273     }
274 
275     //Get the supported formats
276     osg::ref_ptr<XmlElement> e_request = e_capability->getSubElement( ELEM_REQUEST );
277     if (e_request.valid())
278     {
279         osg::ref_ptr<XmlElement> e_getMap = e_request->getSubElement( ELEM_GETMAP );
280         if ( e_getMap.valid() )
281         {
282             //Read all the formats
283             XmlNodeList formats = e_getMap->getSubElements( ELEM_FORMAT );
284             for( XmlNodeList::const_iterator i = formats.begin(); i != formats.end(); i++ )
285             {
286                 string format = trim(static_cast<XmlElement*>( i->get() )->getText());
287                 capabilities->getFormats().push_back(format);
288             }
289         }
290     }
291 
292     //Try to read the layers
293     readLayers( e_capability.get(), 0, capabilities->getLayers());
294 
295     return capabilities.release();
296 }
297