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