File indexing completed on 2024-04-28 07:38:06
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2023 Torsten Rahn <rahn@kde.org> 0004 // 0005 0006 #include "OwsServiceManager.h" 0007 0008 #include <QUrl> 0009 #include <QUrlQuery> 0010 #include <QNetworkReply> 0011 #include <QAuthenticator> 0012 0013 #include <QBuffer> 0014 #include <QImageReader> 0015 0016 #include <MarbleDebug.h> 0017 #include <cmath> 0018 0019 namespace Marble 0020 { 0021 0022 OwsMappingCapabilities::OwsMappingCapabilities() 0023 { 0024 0025 } 0026 0027 WmsCapabilities::WmsCapabilities() 0028 { 0029 } 0030 0031 WmtsCapabilities::WmtsCapabilities() 0032 { 0033 0034 } 0035 0036 void WmtsCapabilities::setWmtsTileMatrixSets(const QMap<QString, QStringList> &wmtsTileMatrixSets) 0037 { 0038 m_wmtsTileMatrixSets = wmtsTileMatrixSets; 0039 } 0040 0041 QMap<QString, QStringList> WmtsCapabilities::wmtsTileMatrixSets() const 0042 { 0043 return m_wmtsTileMatrixSets; 0044 } 0045 0046 void WmtsCapabilities::setWmtsTileResource(const QMap<QString, QMap<QString, QString> > &wmtsTileRessource) 0047 { 0048 m_wmtsTileResource = wmtsTileRessource; 0049 } 0050 0051 QMap<QString, QMap<QString, QString> > WmtsCapabilities::wmtsTileResource() const 0052 { 0053 return m_wmtsTileResource; 0054 } 0055 0056 ImageRequestResult::ImageRequestResult() 0057 : m_imageStatus(WmsImageNone) 0058 { 0059 0060 } 0061 0062 void ImageRequestResult::setImageStatus(WmsImageStatus imageStatus) 0063 { 0064 m_imageStatus = imageStatus; 0065 } 0066 0067 WmsImageStatus ImageRequestResult::imageStatus() const 0068 { 0069 return m_imageStatus; 0070 } 0071 0072 void ImageRequestResult::setResultImage(const QImage &image) 0073 { 0074 m_resultImage = image; 0075 } 0076 0077 QImage ImageRequestResult::resultImage() const 0078 { 0079 return m_resultImage; 0080 } 0081 0082 void ImageRequestResult::setResultRaw(const QByteArray &resultRaw) 0083 { 0084 m_resultRaw = resultRaw; 0085 } 0086 0087 QByteArray ImageRequestResult::resultRaw() const 0088 { 0089 return m_resultRaw; 0090 } 0091 0092 void ImageRequestResult::setResultFormat(const QString &resultFormat) 0093 { 0094 m_resultFormat = resultFormat; 0095 } 0096 0097 QString ImageRequestResult::resultFormat() const 0098 { 0099 return m_resultFormat; 0100 } 0101 0102 void ImageRequestResult::setResultType(const ImageResultType resultType) 0103 { 0104 m_resultType = resultType; 0105 } 0106 0107 ImageResultType ImageRequestResult::resultType() const 0108 { 0109 return m_resultType; 0110 } 0111 0112 void OwsMappingCapabilities::setVersion(const QString &version) 0113 { 0114 m_version = version; 0115 } 0116 0117 QString OwsMappingCapabilities::version() const 0118 { 0119 return m_version; 0120 } 0121 0122 void OwsMappingCapabilities::setTitle(const QString &title) 0123 { 0124 m_title = title; 0125 } 0126 0127 QString OwsMappingCapabilities::title() const 0128 { 0129 return m_title; 0130 } 0131 0132 void OwsMappingCapabilities::setAbstract(const QString &abstract) 0133 { 0134 m_abstract = abstract; 0135 } 0136 0137 QString OwsMappingCapabilities::abstract() const 0138 { 0139 return m_abstract; 0140 } 0141 0142 void WmsCapabilities::setContactInformation(const QString &info) 0143 { 0144 m_contactInformation = info; 0145 } 0146 0147 QString WmsCapabilities::contactInformation() const 0148 { 0149 return m_contactInformation; 0150 } 0151 0152 void WmsCapabilities::setFees(const QString &fees) 0153 { 0154 m_fees = fees; 0155 } 0156 0157 QString WmsCapabilities::fees() const 0158 { 0159 return m_fees; 0160 } 0161 0162 QStringList OwsMappingCapabilities::layers() const 0163 { 0164 return m_owsLayerMetaInfo.keys(); 0165 } 0166 0167 QStringList WmsCapabilities::projections(const QString &layer) 0168 { 0169 QStringList result = m_wmsLayerCoordinateSystems.value(layer).keys(); 0170 if (!m_wmsLayerCoordinateSystems.isEmpty()) { 0171 result << m_wmsLayerCoordinateSystems.value(m_wmsLayerCoordinateSystems.firstKey()).keys(); 0172 } 0173 result.removeDuplicates(); 0174 0175 return result; 0176 } 0177 0178 QString WmsCapabilities::boundingBox(const QString &layer, const QString &projection) 0179 { 0180 QString result; 0181 result = m_wmsLayerCoordinateSystems.value(layer).value(projection); 0182 if (result.isEmpty()) { 0183 result = m_wmsLayerCoordinateSystems.value(0).value(projection); 0184 } 0185 return result; 0186 } 0187 0188 QString OwsMappingCapabilities::title(const QString &layer) 0189 { 0190 return m_owsLayerMetaInfo.value(layer).at(0); 0191 } 0192 0193 QString OwsMappingCapabilities::abstract(const QString &layer) 0194 { 0195 return m_owsLayerMetaInfo.value(layer).at(1); 0196 } 0197 0198 QString WmsCapabilities::legendUrl(const QString &layer) 0199 { 0200 return m_owsLayerMetaInfo.value(layer).at(2); 0201 } 0202 0203 QString OwsMappingCapabilities::style(const QString &layer) 0204 { 0205 return m_owsLayerMetaInfo.value(layer).at(3); 0206 } 0207 0208 QStringList WmsCapabilities::styles(const QStringList &layers) 0209 { 0210 QStringList retVal; 0211 for (auto layer : layers) { 0212 retVal << style(layer); 0213 } 0214 return retVal; 0215 } 0216 0217 QString WmsCapabilities::boundingBoxNSEWDegrees(const QStringList &layers, const QString& projection) 0218 { 0219 QString retVal; 0220 for (auto layer : layers) { 0221 QString layerBBox = boundingBox(layer, projection); 0222 if (layerBBox.isEmpty()) { 0223 retVal = QString("90,-90,180,-180"); 0224 break; 0225 } 0226 QStringList layerBBoxList = layerBBox.split(","); 0227 qreal west, south, east, north; 0228 if (projection == "epsg:3857") { 0229 west = layerBBoxList.at(0).toDouble() * 180/20037508.34; 0230 south = atan(pow(2.7182818284, (layerBBoxList.at(1).toDouble()/20037508.34 * M_PI))) * (360/M_PI) - 90; 0231 east = layerBBoxList.at(2).toDouble() * 180/20037508.34; 0232 north = atan(pow(2.7182818284, (layerBBoxList.at(3).toDouble()/20037508.34 * M_PI))) * (360/M_PI) - 90; 0233 } 0234 else { 0235 if (projection == "crs:84" || (projection == "4326" && version() != "1.3.0")) { 0236 // order: longitude-latitude 0237 west = layerBBoxList.at(0).toDouble(); 0238 south = layerBBoxList.at(1).toDouble(); 0239 east = layerBBoxList.at(2).toDouble(); 0240 north = layerBBoxList.at(3).toDouble(); 0241 } 0242 else { 0243 // order: latitude-longitude 0244 west = layerBBoxList.at(1).toDouble(); 0245 south = layerBBoxList.at(0).toDouble(); 0246 east = layerBBoxList.at(3).toDouble(); 0247 north = layerBBoxList.at(2).toDouble(); 0248 } 0249 } 0250 retVal = QString("%1,%2,%3,%4").arg(north).arg(south).arg(east).arg(west); 0251 // TODO: merge possibly different layer bboxes 0252 break; 0253 } 0254 return retVal; 0255 } 0256 0257 void WmsCapabilities::setReferenceSystemType(const QString &refSystem) 0258 { 0259 m_referenceSystemType = refSystem; 0260 } 0261 0262 QString WmsCapabilities::referenceSystemType() const 0263 { 0264 return m_referenceSystemType; 0265 } 0266 0267 void OwsMappingCapabilities::setOwsLayerMetaInfo(const QMap<QString, QStringList> &wmsLayerMetaInfo) 0268 { 0269 m_owsLayerMetaInfo = wmsLayerMetaInfo; 0270 } 0271 0272 QMap<QString, QStringList> OwsMappingCapabilities::owsLayerMetaInfo() const 0273 { 0274 return m_owsLayerMetaInfo; 0275 } 0276 0277 void WmsCapabilities::setWmsLayerCoordinateSystems(const QMap<QString, QMap<QString, QString> > &wmsLayerCoordinateSystems) 0278 { 0279 m_wmsLayerCoordinateSystems = wmsLayerCoordinateSystems; 0280 } 0281 0282 QMap<QString, QMap<QString, QString> > WmsCapabilities::wmsLayerCoordinateSystems() const 0283 { 0284 return m_wmsLayerCoordinateSystems; 0285 } 0286 0287 void WmsCapabilities::setFormats(const QStringList &formats) 0288 { 0289 m_formats = formats; 0290 } 0291 0292 QStringList WmsCapabilities::formats() 0293 { 0294 return m_formats; 0295 } 0296 0297 0298 OwsServiceManager::OwsServiceManager(QObject *parent) 0299 : QObject(parent), 0300 m_capabilitiesStatus(OwsCapabilitiesNone) 0301 { 0302 connect( &m_capabilitiesAccessManager, &QNetworkAccessManager::finished, this, &OwsServiceManager::parseOwsCapabilities ); 0303 connect( &m_imageAccessManager, &QNetworkAccessManager::finished, this, &OwsServiceManager::parseImageResult ); 0304 0305 connect( &m_capabilitiesAccessManager, &QNetworkAccessManager::authenticationRequired, this, &OwsServiceManager::handleAuthentication ); 0306 connect( &m_imageAccessManager, &QNetworkAccessManager::authenticationRequired, this, &OwsServiceManager::handleAuthentication ); 0307 } 0308 0309 void OwsServiceManager::queryOwsCapabilities(const QUrl& queryUrl, const QString& serviceString) 0310 { 0311 m_url = queryUrl; 0312 QUrl url(queryUrl); 0313 QUrlQuery urlQuery; 0314 urlQuery.addQueryItem( "service", serviceString ); 0315 urlQuery.addQueryItem( "request", "GetCapabilities" ); 0316 url.setQuery(urlQuery); 0317 0318 QNetworkRequest request; 0319 request.setUrl( url ); 0320 request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); 0321 0322 mDebug() << "for url" << url; 0323 m_capabilitiesAccessManager.get( request ); 0324 } 0325 0326 void OwsServiceManager::queryWmsMap(const QUrl &url, const QString &layers, const QString &projection, 0327 const QString &bbox, const QString &format, const QString &style) 0328 { 0329 m_imageRequestResult.setResultImage(QImage()); 0330 m_imageRequestResult.setImageStatus(WmsImageNone); 0331 m_imageRequestResult.setResultRaw(""); 0332 m_imageRequestResult.setResultFormat(QString()); 0333 0334 QUrlQuery downloadQuery; 0335 downloadQuery.addQueryItem( "request", "GetMap" ); // Requests that the server generates a map. 0336 downloadQuery.addQueryItem( "service", "wms" ); // Service name. Value is WMS. 0337 0338 QString versionkey = wmsCapabilities().version() == "1.0.0" ? "wmtver" : "version"; 0339 downloadQuery.addQueryItem( versionkey , wmsCapabilities().version() ); // Service version. Value is one of 1.0.0, 1.1.0, 1.1.1, 1.3.0. 0340 downloadQuery.addQueryItem( "layers", layers ); // Layers to display on map. Value is a comma-separated list of layer names. 0341 0342 // Spatial Reference System for map output. Value is in the form EPSG:nnn. srs was used before WMS 1.3.0, crs has been used since then. 0343 downloadQuery.addQueryItem( wmsCapabilities().referenceSystemType(), projection ); 0344 // downloadQuery.addQueryItem( "bgcolor", "#ff0000" ); // rarely supported by servers 0345 0346 downloadQuery.addQueryItem( "width", "256" ); // Width of map output, in pixels. 0347 downloadQuery.addQueryItem( "height", "256" ); // Height of map output, in pixels. 0348 0349 QString boundingBox = bbox; 0350 if (boundingBox.isEmpty()) { 0351 if (projection == "epsg:3857") { 0352 boundingBox = "-20037508.34,-20048966.1,20037508.34,20048966.1"; 0353 } 0354 else if (projection == "epsg:4326") { 0355 boundingBox = wmsCapabilities().version() == "1.3.0" ? "-90,-180,90,180" : "-180,-90,180,90"; // flipped axes for 1.3.0 in epsg:4326 according to spec 0356 } 0357 else if (projection == "crs:84") { 0358 boundingBox = "-180,-90,180,90"; // order: WGS84 longitude-latitude 0359 } 0360 } 0361 downloadQuery.addQueryItem( "bbox", boundingBox ); 0362 downloadQuery.addQueryItem( "transparent", "true"); 0363 0364 // Format for the map output. In addition to common bitmap formats WMS servers 0365 // sometimes support "vector" formats (PDF, SVG, KML, etc.) 0366 // Currently Marble only supports JPEG, PNG, TIFF, GIF, BMP and their variants. 0367 downloadQuery.addQueryItem( "format", QString("image/%1").arg(format) ); 0368 0369 // Styles in which layers are to be rendered. Value is a comma-separated list of style names, 0370 // or empty if default styling is required. Style names may be empty in the list, 0371 // to use default layer styling. However some servers do not accept empty style names. 0372 downloadQuery.addQueryItem( "styles", style ); 0373 m_imageRequestResult.setResultFormat((format == QLatin1String("jpeg")) ? "jpg" : format); // Is this needed here? 0374 0375 QUrl finalDownloadUrl( url ); 0376 finalDownloadUrl.setQuery( downloadQuery ); 0377 mDebug() << "requesting WMS image" << finalDownloadUrl; 0378 0379 QNetworkRequest request( finalDownloadUrl ); 0380 0381 m_imageAccessManager.get( request ); 0382 } 0383 0384 void OwsServiceManager::queryWmsLevelZeroTile(const QUrl& url, const QString &layers, const QString &projection, 0385 const QString &format, const QString &style) 0386 { 0387 QString bbox; 0388 if (projection == "epsg:3857") { 0389 bbox = "-20037508.34,-20048966.1,20037508.34,20048966.1"; 0390 0391 } 0392 else if (projection == "epsg:4326") { 0393 bbox = wmsCapabilities().version() == "1.3.0" ? "-90,-180,90,180" : "-180,-90,180,90"; // flipped axes for 1.3.0 in epsg:4326 according to spec 0394 } 0395 else if (projection == "crs:84") { 0396 bbox = "-180,-90,180,90"; // order: WGS84 longitude-latitude 0397 } 0398 0399 m_imageRequestResult.setResultType(LevelZeroTile); 0400 0401 queryWmsMap(url, layers, projection, bbox, format, style); 0402 } 0403 0404 void OwsServiceManager::queryWmsPreviewImage(const QUrl& url, const QString &layers, const QString &projection, 0405 const QString &format, const QString &style) 0406 { 0407 0408 QString firstLayer = layers.contains(',') ? layers.section(',',0,0) : layers; 0409 QString bbox = wmsCapabilities().boundingBox(firstLayer, projection); 0410 0411 m_imageRequestResult.setResultType(PreviewImage); 0412 0413 queryWmsMap(url, layers, projection, bbox, format, style); 0414 } 0415 0416 void OwsServiceManager::queryWmsLegendImage(const QUrl &url) 0417 { 0418 m_imageRequestResult.setResultImage(QImage()); 0419 m_imageRequestResult.setImageStatus(WmsImageNone); 0420 m_imageRequestResult.setResultRaw(""); 0421 m_imageRequestResult.setResultFormat(QString()); 0422 m_imageRequestResult.setResultType(LegendImage); 0423 0424 mDebug() << "requesting legend" << url; 0425 0426 QNetworkRequest request( url ); 0427 0428 m_imageAccessManager.get( request ); 0429 } 0430 0431 void OwsServiceManager::queryWmtsLevelZeroTile(const QString &url, const QString &style, const QString &tileMatrixSet) 0432 { 0433 m_imageRequestResult.setResultType(LevelZeroTile); 0434 queryWmtsTile(url, style, tileMatrixSet, "0", "0", "0"); 0435 } 0436 0437 void OwsServiceManager::queryWmtsPreviewImage(const QString &url, const QString &style, const QString &tileMatrixSet) 0438 { 0439 m_imageRequestResult.setResultType(PreviewImage); 0440 queryWmtsTile(url, style, tileMatrixSet, "0", "0", "0"); 0441 } 0442 0443 void OwsServiceManager::queryWmtsTile(const QString &url, const QString &style, const QString &tileMatrixSet, const QString& tileMatrix, const QString &tileRow, const QString &tileCol) 0444 { 0445 m_imageRequestResult.setResultImage(QImage()); 0446 m_imageRequestResult.setImageStatus(WmsImageNone); 0447 m_imageRequestResult.setResultRaw(""); 0448 m_imageRequestResult.setResultFormat(QString()); 0449 0450 QUrl downloadUrl; 0451 QString baseUrl = url; 0452 baseUrl.replace(baseUrl.indexOf(QLatin1String("{Time}")), 6, "current"); 0453 baseUrl.replace(baseUrl.indexOf(QLatin1String("{style}")), 7, style); 0454 baseUrl.replace(baseUrl.indexOf(QLatin1String("{Style}")), 7, style); 0455 baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileMatrixSet}")), 15, tileMatrixSet); 0456 baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileMatrix}")), 12, tileMatrix); 0457 baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileRow}")), 9, tileRow); 0458 baseUrl.replace(baseUrl.indexOf(QLatin1String("{TileCol}")), 9, tileCol); 0459 downloadUrl.setUrl( baseUrl ); 0460 0461 QNetworkRequest request( downloadUrl ); 0462 mDebug() << "requesting static map" << downloadUrl; 0463 m_imageAccessManager.get( request ); 0464 } 0465 0466 void OwsServiceManager::queryXYZPreviewImage(const QString &urlString) 0467 { 0468 m_imageRequestResult.setResultType(PreviewImage); 0469 queryXYZImage(urlString); 0470 } 0471 0472 void OwsServiceManager::queryXYZLevelZeroTile(const QString &urlString) 0473 { 0474 m_imageRequestResult.setResultType(LevelZeroTile); 0475 queryXYZImage(urlString); 0476 } 0477 0478 void OwsServiceManager::queryXYZImage(const QString urlString) 0479 { 0480 QUrl downloadUrl; 0481 QString baseUrl = urlString; 0482 baseUrl.replace(baseUrl.indexOf(QLatin1String("{x}")), 3, QString::number(0)); 0483 baseUrl.replace(baseUrl.indexOf(QLatin1String("{y}")), 3, QString::number(0)); 0484 baseUrl.replace(baseUrl.indexOf(QLatin1String("{zoomLevel}")), 11, QString::number(0)); 0485 baseUrl.replace(baseUrl.indexOf(QLatin1String("{z}")), 3, QString::number(0)); 0486 downloadUrl.setUrl( baseUrl ); 0487 0488 QNetworkRequest request( downloadUrl ); 0489 mDebug() << "requesting static map" << downloadUrl; 0490 m_imageAccessManager.get( request ); 0491 } 0492 0493 void OwsServiceManager::handleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) 0494 { 0495 if (reply->url().host() == QString("api.tileserver.org")) { 0496 authenticator->setUser(""); 0497 authenticator->setPassword(""); 0498 } 0499 } 0500 0501 void OwsServiceManager::setCapabilitiesStatus(OwsCapabilitiesStatus capabilitiesStatus) 0502 { 0503 m_capabilitiesStatus = capabilitiesStatus; 0504 } 0505 0506 OwsCapabilitiesStatus OwsServiceManager::capabilitiesStatus() const 0507 { 0508 return m_capabilitiesStatus; 0509 } 0510 0511 OwsServiceType OwsServiceManager::owsServiceType() 0512 { 0513 return m_owsServiceType; 0514 } 0515 0516 WmsCapabilities Marble::OwsServiceManager::wmsCapabilities() 0517 { 0518 return m_wmsCapabilities; 0519 } 0520 0521 WmtsCapabilities OwsServiceManager::wmtsCapabilities() 0522 { 0523 return m_wmtsCapabilities; 0524 } 0525 0526 ImageRequestResult OwsServiceManager::imageRequestResult() 0527 { 0528 return m_imageRequestResult; 0529 } 0530 0531 QImage OwsServiceManager::resultImage() 0532 { 0533 return m_imageRequestResult.resultImage(); 0534 } 0535 0536 ImageResultType OwsServiceManager::resultType() 0537 { 0538 return m_imageRequestResult.resultType(); 0539 } 0540 0541 QByteArray OwsServiceManager::resultRaw() 0542 { 0543 return m_imageRequestResult.resultRaw(); 0544 } 0545 0546 QString OwsServiceManager::resultFormat() 0547 { 0548 return m_imageRequestResult.resultFormat(); 0549 } 0550 0551 void OwsServiceManager::parseOwsCapabilities(QNetworkReply *reply) 0552 { 0553 mDebug() << "received reply from" << reply->url(); 0554 QString result( reply->readAll() ); 0555 0556 m_wmsCapabilities = WmsCapabilities(); // clear() 0557 0558 if( !m_xml.setContent( result ) ) 0559 { 0560 setCapabilitiesStatus(OwsCapabilitiesReplyUnreadable); // Wizard cannot parse server's response 0561 emit wmsCapabilitiesReady(); 0562 return; 0563 } 0564 0565 if( m_xml.documentElement().firstChildElement().tagName().isNull() 0566 || !m_xml.documentElement().tagName().contains("Capabilities")) 0567 { 0568 setCapabilitiesStatus(OwsCapabilitiesNoOwsServer); // Server is not a Ows Server. 0569 emit wmsCapabilitiesReady(); 0570 return; 0571 } 0572 0573 if (m_xml.documentElement().tagName() == "WMS_Capabilities" 0574 || m_xml.documentElement().tagName() == "WMT_MS_Capabilities") { // WMTS server used for WMS? 0575 m_owsServiceType = WmsType; 0576 parseWmsCapabilities(reply); 0577 } 0578 else if (m_xml.documentElement().tagName() == "Capabilities") { 0579 m_owsServiceType = WmtsType; 0580 parseWmtsCapabilities(reply); 0581 } 0582 else if (m_xml.documentElement().tagName() == ("wfs:WFS_Capabilities")) { 0583 m_owsServiceType = WfsType; 0584 } 0585 else if (m_xml.documentElement().tagName() == ("wcs:Capabilities")) { 0586 m_owsServiceType = WcsType; 0587 } 0588 else { 0589 m_owsServiceType = NoOwsType; 0590 } 0591 } 0592 0593 void OwsServiceManager::parseWmsCapabilities(QNetworkReply *reply) 0594 { 0595 Q_UNUSED(reply) 0596 0597 m_wmsCapabilities.setVersion( m_xml.documentElement().attribute("version") ); 0598 m_wmsCapabilities.setReferenceSystemType( (m_wmsCapabilities.version() == "1.0.0" 0599 || m_wmsCapabilities.version() == "1.1.0" 0600 || m_wmsCapabilities.version() == "1.1.1") ? "SRS" : "CRS" ); 0601 0602 QDomElement service = m_xml.documentElement().firstChildElement( "Service" ); 0603 QDomNodeList layers = m_xml.documentElement().firstChildElement( "Capability" ).elementsByTagName("Layer"); 0604 0605 m_wmsCapabilities.setTitle(service.firstChildElement( "Title" ).text()); 0606 m_wmsCapabilities.setAbstract(service.firstChildElement( "Abstract" ).text() ); 0607 0608 QDomElement contactElement = service.firstChildElement( "ContactInformation"); 0609 QDomElement contactPersonPrimaryElement = contactElement.firstChildElement("ContactPersonPrimary"); 0610 QString contactPersonPrimary; 0611 if (!contactPersonPrimaryElement.isNull()) { 0612 QString contactPerson = contactPersonPrimaryElement.firstChildElement("ContactPerson").text(); 0613 QString contactOrganisation = contactPersonPrimaryElement.firstChildElement("ContactOrganization").text(); 0614 contactPersonPrimary = contactPerson + "<br>" + contactOrganisation + "<br>"; 0615 } 0616 QString contactPosition = contactElement.firstChildElement("ContactPosition").text(); 0617 contactPersonPrimary += contactPosition; 0618 0619 QDomElement addressElement = contactElement.firstChildElement("ContactAddress"); 0620 QString postalAddress; 0621 if (!addressElement.isNull() && addressElement.firstChildElement("AddressType").text() == "postal") { 0622 QString address = addressElement.firstChildElement("Address").text(); 0623 QString city = addressElement.firstChildElement("City").text(); 0624 QString stateOrProvince = addressElement.firstChildElement("StateOrProvince").text(); 0625 QString postalCode = addressElement.firstChildElement("PostCode").text(); 0626 QString country = addressElement.firstChildElement("Country").text(); 0627 postalAddress = address + "<br>" + city + "<br>" + stateOrProvince + "<br>" + postalCode + "<br>" + country; 0628 } 0629 QString contactVoicePhone = contactElement.firstChildElement("ContactVoiceTelephone").text(); 0630 QString contactFacsimileTelephone = contactElement.firstChildElement("ContactFacsimileTelephone").text(); 0631 QString contactEmail = contactElement.firstChildElement("ContactElectronicMailAddress" ).text(); 0632 QString contactMedium = contactVoicePhone + "<br>" + contactFacsimileTelephone + "<br>" + contactEmail; 0633 0634 QString contactInformation = contactPersonPrimary + "<br><small><font color=\"darkgrey\">" + postalAddress + "<br>" + contactMedium + "</font></small>"; 0635 0636 m_wmsCapabilities.setContactInformation(contactInformation); 0637 QString fees = service.firstChildElement( "Fees" ).text(); 0638 m_wmsCapabilities.setFees(fees); 0639 0640 QMap<QString, QStringList> wmsLayerMetaInfo; 0641 0642 for( int i = 0; i < layers.size(); ++i ) 0643 { 0644 QString name = layers.at(i).firstChildElement( "Name" ).text(); 0645 QString title = layers.at(i).firstChildElement( "Title" ).text(); 0646 QString abstract = layers.at(i ).firstChildElement( "Abstract" ).text(); 0647 QDomElement legendElement = layers.at( i ).firstChildElement( "Style" ).firstChildElement( "LegendURL" ); 0648 QString legendUrl; 0649 if (!legendElement.isNull()) legendUrl = legendElement.firstChildElement( "OnlineResource" ).attribute( "xlink:href" ); 0650 QString style = layers.at(i).firstChildElement("Style").firstChildElement( "Name" ).text(); 0651 if (style.isEmpty()) style = "default"; 0652 /* QDomElement gbboxElement = layers.at(i).firstChildElement("EX_GeographicBoundingBox"); 0653 QStringList bbox; 0654 if (!gbboxElement.isNull()) { 0655 bbox << gbboxElement.firstChildElement("westBoundLongitude").text() << gbboxElement.firstChildElement("southBoundLatitude").text() 0656 << gbboxElement.firstChildElement("eastBoundLongitude").text() << gbboxElement.firstChildElement("northBoundLatitude").text(); 0657 } 0658 wmsLayerMetaInfo[ name ] << title << abstract << legendUrl << style << bbox.join(","); */ 0659 wmsLayerMetaInfo[ name ] << title << abstract << legendUrl << style; 0660 } 0661 0662 m_wmsCapabilities.setOwsLayerMetaInfo(wmsLayerMetaInfo); 0663 0664 QMap<QString, QMap<QString, QString>> wmsLayerCoordinateSystems; 0665 for( int i = 0; i < layers.size(); ++i ) 0666 { 0667 QString layerName = layers.at(i).firstChildElement( "Name" ).text(); 0668 QDomNodeList projectionList = layers.at(i).toElement().elementsByTagName(m_wmsCapabilities.referenceSystemType()); 0669 QDomNodeList layerPreviewBBox = layers.at(i).toElement().elementsByTagName("BoundingBox"); 0670 0671 for ( int s = 0; s < projectionList.size(); ++s ) { 0672 QString projection = projectionList.at(s).toElement().text().toLower(); 0673 // SRS and CRS tags might contain a list of epsgs, so we need to use contains() 0674 if (projection.contains("epsg:3857")) { 0675 /* if (wmsLayerMetaInfo.value(layerName).at(4) != ",,,") { // EX_GeographicBoundingBox 0676 QStringList coords = wmsLayerMetaInfo.value(layerName).at(4).split(","); 0677 double west = (coords.at(0).toDouble() * 20037508.34) / 180; 0678 double south = 20037508.34 / M_PI * log(tan(((90 + coords.at(1).toDouble()) * M_PI) / 360)); 0679 double east = (coords.at(2).toDouble() * 20037508.34) / 180; 0680 double north = 20037508.34 / M_PI * log(tan(((90 + coords.at(3).toDouble()) * M_PI) / 360)); 0681 QString bbox = QString("%1,%2,%3,%4").arg(QString::number( west, 'f', 6 )).arg(QString::number( south, 'f', 6 )) 0682 .arg(QString::number( east, 'f', 6 )).arg(QString::number( north, 'f', 6 )); 0683 wmsLayerCoordinateSystems[layerName]["epsg:3857"] = bbox; 0684 } 0685 else */ 0686 wmsLayerCoordinateSystems[layerName]["epsg:3857"] = QString(); 0687 } 0688 if (projection.contains("epsg:4326")) { 0689 /* if (wmsLayerMetaInfo.value(layerName).at(4) != ",,,") { 0690 wmsLayerCoordinateSystems[layerName]["epsg:4326"] = wmsLayerMetaInfo.value(layerName).at(4); // Ignores flip 0691 } 0692 else */ 0693 wmsLayerCoordinateSystems[layerName]["epsg:4326"] = QString(); 0694 } 0695 if (projection.contains("crs:84")) { 0696 wmsLayerCoordinateSystems[layerName]["crs:84"] = QString(); 0697 } 0698 } 0699 for ( int b = 0; b < layerPreviewBBox.size(); ++b ) { 0700 QDomElement bboxElement = layerPreviewBBox.at(b).toElement(); 0701 QString bboxProjection = bboxElement.attribute(m_wmsCapabilities.referenceSystemType()); 0702 if (bboxProjection != "epsg:3857" && bboxProjection != "epsg:4326" && bboxProjection != "crs:84") continue; 0703 int precision = bboxProjection == "epsg:3857" ? 6 : 12; 0704 double west = bboxElement.attribute("minx").toDouble(); 0705 double south = bboxElement.attribute("miny").toDouble(); 0706 double east = bboxElement.attribute("maxx").toDouble(); 0707 double north = bboxElement.attribute("maxy").toDouble(); 0708 QString bboxString = QString("%1,%2,%3,%4") 0709 .arg(QString::number(west, 'f', precision), 0710 QString::number(south, 'f', precision), 0711 QString::number(east, 'f', precision), 0712 QString::number(north, 'f', precision)); 0713 // TODO: convert bbox coordinates from UTM to 3857 (e.g. from epsg:25832/33) 0714 wmsLayerCoordinateSystems[layerName][bboxProjection] = bboxString; 0715 } 0716 // FIXME: parse EX_GeographicBoundingBox if wmsLayerCoordinateSystems[layerName]["epsg:4326"/"epsg:3857"] == QString() 0717 } 0718 0719 m_wmsCapabilities.setWmsLayerCoordinateSystems(wmsLayerCoordinateSystems); 0720 0721 QDomNodeList formatList = m_xml.documentElement().firstChildElement( "Capability" ).firstChildElement( "Request" ) 0722 .firstChildElement( "GetMap" ).elementsByTagName("Format"); 0723 0724 QStringList formats; 0725 for ( int f = 0; f < formatList.size(); ++f ) { 0726 QString format = formatList.at(f).toElement().text(); 0727 format = format.right(format.length() - format.indexOf(QLatin1Char('/')) - 1).toLower(); 0728 if (format == "jpeg" || format.contains("png") 0729 || format.contains("tif") || format.contains("gif") 0730 || format.contains("bmp") || format.contains("jpg") ) { 0731 formats << format; 0732 } 0733 } 0734 0735 m_wmsCapabilities.setFormats(formats); 0736 0737 setCapabilitiesStatus(OwsCapabilitiesSuccess); 0738 emit wmsCapabilitiesReady(); 0739 } 0740 0741 void OwsServiceManager::parseWmtsCapabilities(QNetworkReply *reply) 0742 { 0743 Q_UNUSED(reply) 0744 0745 m_wmsCapabilities.setVersion( m_xml.documentElement().firstChildElement("ows:ServiceIdentification").firstChildElement("ows:ServiceTypeVersion").text() ); 0746 0747 QDomElement service = m_xml.documentElement().firstChildElement( "ows:ServiceIdentification" ); 0748 QDomNodeList layers = m_xml.documentElement().firstChildElement( "Contents" ).elementsByTagName("Layer"); 0749 0750 m_wmtsCapabilities.setTitle(service.firstChildElement( "ows:Title" ).text()); 0751 m_wmtsCapabilities.setAbstract(service.firstChildElement( "ows:Abstract" ).text() ); 0752 0753 QMap<QString, QStringList> wmtsLayerMetaInfo; 0754 QMap<QString, QStringList> wmtsTileMatrixSets; 0755 QMap<QString, QMap<QString, QString>> wmtsTileResource; 0756 0757 for( int i = 0; i < layers.size(); ++i ) 0758 { 0759 QString name = layers.at(i).firstChildElement( "ows:Identifier" ).text(); 0760 QString title = layers.at(i).firstChildElement( "ows:Title" ).text(); 0761 QString abstract = layers.at(i ).firstChildElement( "ows:Abstract" ).text(); 0762 QDomElement legendElement = layers.at( i ).firstChildElement( "Style" ).firstChildElement( "LegendURL" ); 0763 QString legendUrl; 0764 if (!legendElement.isNull()) legendUrl = legendElement.attribute( "xlink:href" ); 0765 QString style = layers.at(i).firstChildElement("Style").firstChildElement( "ows:Identifier" ).text(); 0766 0767 wmtsLayerMetaInfo[ name ] << title << abstract << legendUrl << style; 0768 0769 QDomNodeList resourceList = layers.at(i).toElement().elementsByTagName("ResourceURL"); 0770 for (int r = 0; r < resourceList.size(); ++r) { 0771 if (resourceList.at(r).toElement().attribute("resourceType") == "tile") { 0772 QString format = resourceList.at(r).toElement().attribute("format"); 0773 QString resultFormat; 0774 format = format.right(format.length() - format.indexOf(QLatin1Char('/')) - 1).toLower(); 0775 if (format == "jpeg" || format.contains("png") 0776 || format.contains("tif") || format.contains("gif") 0777 || format.contains("bmp") || format.contains("jpg") ) { 0778 resultFormat = format; 0779 } 0780 else { 0781 continue; 0782 } 0783 QString templ = resourceList.at(r).toElement().attribute("template"); 0784 wmtsTileResource[name][resultFormat] = templ; 0785 } 0786 } 0787 0788 QStringList tileMatrixSets; 0789 QDomNodeList tileMatrixLinkList = layers.at(i).toElement().elementsByTagName("TileMatrixSetLink"); 0790 for (int t = 0; t < tileMatrixLinkList.size(); ++t) { 0791 tileMatrixSets << tileMatrixLinkList.at(t).toElement().firstChildElement("TileMatrixSet").text(); 0792 } 0793 wmtsTileMatrixSets[name] = tileMatrixSets; 0794 } 0795 0796 m_wmtsCapabilities.setWmtsTileMatrixSets(wmtsTileMatrixSets); 0797 m_wmtsCapabilities.setWmtsTileResource(wmtsTileResource); 0798 0799 m_wmtsCapabilities.setOwsLayerMetaInfo(wmtsLayerMetaInfo); 0800 setCapabilitiesStatus(OwsCapabilitiesSuccess); 0801 emit wmtsCapabilitiesReady(); 0802 } 0803 0804 void OwsServiceManager::parseImageResult(QNetworkReply *reply) 0805 { 0806 // QString request = reply->request().url().toString(); 0807 0808 // m_imageResult is already reset in the queryWmsMap 0809 0810 QImage testImage; 0811 m_imageRequestResult.setResultRaw(reply->readAll()); 0812 testImage = QImage::fromData(m_imageRequestResult.resultRaw()); 0813 0814 if (testImage.isNull()) { 0815 m_imageRequestResult.setImageStatus(WmsImageFailedServerMessage); // Image could not be downloaded 0816 } 0817 else if (m_imageRequestResult.resultRaw().isNull()) { 0818 m_imageRequestResult.setImageStatus(WmsImageFailed); // Image could not be downloaded 0819 } 0820 else { 0821 m_imageRequestResult.setImageStatus(WmsImageSuccess); 0822 } 0823 0824 m_imageRequestResult.setResultImage(testImage); 0825 0826 QByteArray resultRaw = m_imageRequestResult.resultRaw(); 0827 QBuffer testBuffer( &resultRaw ); 0828 m_imageRequestResult.setResultFormat(QImageReader( &testBuffer ).format()); 0829 0830 emit imageRequestResultReady(); 0831 } 0832 0833 } 0834 0835 #include "moc_OwsServiceManager.cpp"