From 3bd2537587eef4653e12bf34e046edbd580cf0ba Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 4 Apr 2014 20:04:55 +0200 Subject: [PATCH] Re-enabled WCS server --- src/mapserver/qgswcsprojectparser.cpp | 452 ++++++++++++++++++++++++++ src/mapserver/qgswcsprojectparser.h | 8 + src/mapserver/qgswcsserver.cpp | 12 - 3 files changed, 460 insertions(+), 12 deletions(-) diff --git a/src/mapserver/qgswcsprojectparser.cpp b/src/mapserver/qgswcsprojectparser.cpp index d96feb79d27..86636a60ba4 100644 --- a/src/mapserver/qgswcsprojectparser.cpp +++ b/src/mapserver/qgswcsprojectparser.cpp @@ -16,6 +16,8 @@ ***************************************************************************/ #include "qgswcsprojectparser.h" +#include "qgsconfigparserutils.h" +#include "qgsrasterlayer.h" QgsWCSProjectParser::QgsWCSProjectParser( QDomDocument* xmlDoc, const QString& filePath ): mProjectParser( xmlDoc, filePath ) { @@ -24,3 +26,453 @@ QgsWCSProjectParser::QgsWCSProjectParser( QDomDocument* xmlDoc, const QString& f QgsWCSProjectParser::~QgsWCSProjectParser() { } + +void QgsWCSProjectParser::serviceCapabilities( QDomElement& parentElement, QDomDocument& doc ) const +{ + QDomElement serviceElem = doc.createElement( "Service" ); + + QDomElement propertiesElem = mProjectParser.propertiesElem(); + if ( propertiesElem.isNull() ) + { + QgsConfigParserUtils::fallbackServiceCapabilities( parentElement, doc ); + return; + } + + QDomElement serviceCapabilityElem = propertiesElem.firstChildElement( "WMSServiceCapabilities" ); + if ( serviceCapabilityElem.isNull() || serviceCapabilityElem.text().compare( "true", Qt::CaseInsensitive ) != 0 ) + { + QgsConfigParserUtils::fallbackServiceCapabilities( parentElement, doc ); + return; + } + + //Service name is always WCS + QDomElement wcsNameElem = doc.createElement( "name" ); + QDomText wcsNameText = doc.createTextNode( "WCS" ); + wcsNameElem.appendChild( wcsNameText ); + serviceElem.appendChild( wcsNameElem ); + + //WMS title + QDomElement titleElem = propertiesElem.firstChildElement( "WMSServiceTitle" ); + if ( !titleElem.isNull() ) + { + QDomElement wcsLabelElem = doc.createElement( "label" ); + QDomText wcsLabelText = doc.createTextNode( titleElem.text() ); + wcsLabelElem.appendChild( wcsLabelText ); + serviceElem.appendChild( wcsLabelElem ); + } + + //WMS abstract + QDomElement abstractElem = propertiesElem.firstChildElement( "WMSServiceAbstract" ); + if ( !abstractElem.isNull() ) + { + QDomElement wcsDescriptionElem = doc.createElement( "description" ); + QDomText wcsDescriptionText = doc.createTextNode( abstractElem.text() ); + wcsDescriptionElem.appendChild( wcsDescriptionText ); + serviceElem.appendChild( wcsDescriptionElem ); + } + + //keyword list + QDomElement keywordListElem = propertiesElem.firstChildElement( "WMSKeywordList" ); + if ( !keywordListElem.isNull() && !keywordListElem.text().isEmpty() ) + { + QDomNodeList keywordList = keywordListElem.elementsByTagName( "value" ); + if ( keywordList.size() > 0 ) + { + QDomElement wcsKeywordsElem = doc.createElement( "keywords" ); + for ( int i = 0; i < keywordList.size(); ++i ) + { + QDomElement wcsKeywordElem = doc.createElement( "keyword" ); + QDomText keywordText = doc.createTextNode( keywordList.at( i ).toElement().text() ); + wcsKeywordElem.appendChild( keywordText ); + wcsKeywordsElem.appendChild( wcsKeywordElem ); + } + serviceElem.appendChild( wcsKeywordsElem ); + } + } + + //Fees + QDomElement feesElem = propertiesElem.firstChildElement( "WMSFees" ); + if ( !feesElem.isNull() ) + { + QDomElement wcsFeesElem = doc.createElement( "fees" ); + QDomText wcsFeesText = doc.createTextNode( feesElem.text() ); + wcsFeesElem.appendChild( wcsFeesText ); + serviceElem.appendChild( wcsFeesElem ); + } + + //AccessConstraints + QDomElement accessConstraintsElem = propertiesElem.firstChildElement( "WMSAccessConstraints" ); + if ( !accessConstraintsElem.isNull() ) + { + QDomElement wcsAccessConstraintsElem = doc.createElement( "accessConstraints" ); + QDomText wcsAccessConstraintsText = doc.createTextNode( accessConstraintsElem.text() ); + wcsAccessConstraintsElem.appendChild( wcsAccessConstraintsText ); + serviceElem.appendChild( wcsAccessConstraintsElem ); + } + + parentElement.appendChild( serviceElem ); +} + +QString QgsWCSProjectParser::wcsServiceUrl() const +{ + QString url; + + if ( !mProjectParser.xmlDocument() ) + { + return url; + } + + QDomElement propertiesElem = mProjectParser.propertiesElem(); + if ( !propertiesElem.isNull() ) + { + QDomElement wcsUrlElem = propertiesElem.firstChildElement( "WCSUrl" ); + if ( !wcsUrlElem.isNull() ) + { + url = wcsUrlElem.text(); + } + } + return url; +} + +QString QgsWCSProjectParser::serviceUrl() const +{ + return mProjectParser.serviceUrl(); +} + +void QgsWCSProjectParser::wcsContentMetadata( QDomElement& parentElement, QDomDocument& doc ) const +{ + const QList& projectLayerElements = mProjectParser.projectLayerElements(); + if ( projectLayerElements.size() < 1 ) + { + return; + } + + QStringList wcsLayersId = wcsLayers(); + + QMap layerMap; + + foreach ( const QDomElement &elem, projectLayerElements ) + { + QString type = elem.attribute( "type" ); + if ( type == "raster" ) + { + QgsMapLayer *layer = mProjectParser.createLayerFromElement( elem ); + if ( layer && wcsLayersId.contains( layer->id() ) ) + { + QgsDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) ); + layerMap.insert( layer->id(), layer ); + + QDomElement layerElem = doc.createElement( "CoverageOfferingBrief" ); + QDomElement nameElem = doc.createElement( "name" ); + //We use the layer name even though it might not be unique. + //Because the id sometimes contains user/pw information and the name is more descriptive + QString typeName = layer->name(); + typeName = typeName.replace( " ", "_" ); + QDomText nameText = doc.createTextNode( typeName ); + nameElem.appendChild( nameText ); + layerElem.appendChild( nameElem ); + + QDomElement labelElem = doc.createElement( "label" ); + QString titleName = layer->title(); + if ( titleName.isEmpty() ) + { + titleName = layer->name(); + } + QDomText labelText = doc.createTextNode( titleName ); + labelElem.appendChild( labelText ); + layerElem.appendChild( labelElem ); + + QDomElement descriptionElem = doc.createElement( "description" ); + QString abstractName = layer->abstract(); + if ( abstractName.isEmpty() ) + { + abstractName = ""; + } + QDomText descriptionText = doc.createTextNode( abstractName ); + descriptionElem.appendChild( descriptionText ); + layerElem.appendChild( descriptionElem ); + + //lonLatEnvelope + const QgsCoordinateReferenceSystem& layerCrs = layer->crs(); + QgsCoordinateTransform t( layerCrs, QgsCoordinateReferenceSystem( 4326 ) ); + //transform + QgsRectangle BBox = t.transformBoundingBox( layer->extent() ); + QDomElement lonLatElem = doc.createElement( "lonLatEnvelope" ); + lonLatElem.setAttribute( "srsName", "urn:ogc:def:crs:OGC:1.3:CRS84" ); + QDomElement lowerPosElem = doc.createElement( "gml:pos" ); + QDomText lowerPosText = doc.createTextNode( QString::number( BBox.xMinimum() ) + " " + QString::number( BBox.yMinimum() ) ); + lowerPosElem.appendChild( lowerPosText ); + lonLatElem.appendChild( lowerPosElem ); + QDomElement upperPosElem = doc.createElement( "gml:pos" ); + QDomText upperPosText = doc.createTextNode( QString::number( BBox.xMaximum() ) + " " + QString::number( BBox.yMaximum() ) ); + upperPosElem.appendChild( upperPosText ); + lonLatElem.appendChild( upperPosElem ); + layerElem.appendChild( lonLatElem ); + + parentElement.appendChild( layerElem ); + } + } + } +} + +QStringList QgsWCSProjectParser::wcsLayers() const +{ + QStringList wcsList; + if ( !mProjectParser.xmlDocument() ) + { + return wcsList; + } + + QDomElement propertiesElem = mProjectParser.propertiesElem(); + if ( propertiesElem.isNull() ) + { + return wcsList; + } + QDomElement wcsLayersElem = propertiesElem.firstChildElement( "WCSLayers" ); + if ( wcsLayersElem.isNull() ) + { + return wcsList; + } + QDomNodeList valueList = wcsLayersElem.elementsByTagName( "value" ); + for ( int i = 0; i < valueList.size(); ++i ) + { + wcsList << valueList.at( i ).toElement().text(); + } + return wcsList; +} + +void QgsWCSProjectParser::describeCoverage( const QString& aCoveName, QDomElement& parentElement, QDomDocument& doc ) const +{ + const QList& projectLayerElements = mProjectParser.projectLayerElements(); + if ( projectLayerElements.size() < 1 ) + { + return; + } + + QStringList wcsLayersId = wcsLayers(); + QStringList coveNameList; + if ( aCoveName != "" ) + { + QStringList coveNameSplit = aCoveName.split( "," ); + foreach ( const QString &str, coveNameSplit ) + { + coveNameList << str; + } + } + + QMap layerMap; + + foreach ( const QDomElement &elem, projectLayerElements ) + { + QString type = elem.attribute( "type" ); + if ( type == "raster" ) + { + QgsMapLayer *layer = mProjectParser.createLayerFromElement( elem ); + if ( !layer ) + continue; + QString coveName = layer->name(); + coveName = coveName.replace( " ", "_" ); + if ( wcsLayersId.contains( layer->id() ) && ( aCoveName == "" || coveNameList.contains( coveName ) ) ) + { + QgsDebugMsg( QString( "add layer %1 to map" ).arg( layer->id() ) ); + layerMap.insert( layer->id(), layer ); + + QDomElement layerElem = doc.createElement( "CoverageOffering" ); + QDomElement nameElem = doc.createElement( "name" ); + //We use the layer name even though it might not be unique. + //Because the id sometimes contains user/pw information and the name is more descriptive + QString typeName = layer->name(); + typeName = typeName.replace( " ", "_" ); + QDomText nameText = doc.createTextNode( typeName ); + nameElem.appendChild( nameText ); + layerElem.appendChild( nameElem ); + + QDomElement labelElem = doc.createElement( "label" ); + QString titleName = layer->title(); + if ( titleName.isEmpty() ) + { + titleName = layer->name(); + } + QDomText labelText = doc.createTextNode( titleName ); + labelElem.appendChild( labelText ); + layerElem.appendChild( labelElem ); + + QDomElement descriptionElem = doc.createElement( "description" ); + QString abstractName = layer->abstract(); + if ( abstractName.isEmpty() ) + { + abstractName = ""; + } + QDomText descriptionText = doc.createTextNode( abstractName ); + descriptionElem.appendChild( descriptionText ); + layerElem.appendChild( descriptionElem ); + + //lonLatEnvelope + const QgsCoordinateReferenceSystem& layerCrs = layer->crs(); + QgsCoordinateTransform t( layerCrs, QgsCoordinateReferenceSystem( 4326 ) ); + //transform + QgsRectangle BBox = t.transformBoundingBox( layer->extent() ); + QDomElement lonLatElem = doc.createElement( "lonLatEnvelope" ); + lonLatElem.setAttribute( "srsName", "urn:ogc:def:crs:OGC:1.3:CRS84" ); + QDomElement lowerPosElem = doc.createElement( "gml:pos" ); + QDomText lowerPosText = doc.createTextNode( QString::number( BBox.xMinimum() ) + " " + QString::number( BBox.yMinimum() ) ); + lowerPosElem.appendChild( lowerPosText ); + lonLatElem.appendChild( lowerPosElem ); + QDomElement upperPosElem = doc.createElement( "gml:pos" ); + QDomText upperPosText = doc.createTextNode( QString::number( BBox.xMaximum() ) + " " + QString::number( BBox.yMaximum() ) ); + upperPosElem.appendChild( upperPosText ); + lonLatElem.appendChild( upperPosElem ); + layerElem.appendChild( lonLatElem ); + + QgsRasterLayer* rLayer = dynamic_cast( layer ); + QDomElement domainSetElem = doc.createElement( "domainSet" ); + layerElem.appendChild( domainSetElem ); + + QDomElement spatialDomainElem = doc.createElement( "spatialDomain" ); + domainSetElem.appendChild( spatialDomainElem ); + + QgsRectangle layerBBox = layer->extent(); + QDomElement envelopeElem = doc.createElement( "gml:Envelope" ); + envelopeElem.setAttribute( "srsName", layerCrs.authid() ); + QDomElement lowerCornerElem = doc.createElement( "gml:pos" ); + QDomText lowerCornerText = doc.createTextNode( QString::number( layerBBox.xMinimum() ) + " " + QString::number( layerBBox.yMinimum() ) ); + lowerCornerElem.appendChild( lowerCornerText ); + envelopeElem.appendChild( lowerCornerElem ); + QDomElement upperCornerElem = doc.createElement( "gml:pos" ); + QDomText upperCornerText = doc.createTextNode( QString::number( layerBBox.xMaximum() ) + " " + QString::number( layerBBox.yMaximum() ) ); + upperCornerElem.appendChild( upperCornerText ); + envelopeElem.appendChild( upperCornerElem ); + spatialDomainElem.appendChild( envelopeElem ); + + QDomElement rectGridElem = doc.createElement( "gml:RectifiedGrid" ); + rectGridElem.setAttribute( "dimension", 2 ); + QDomElement limitsElem = doc.createElement( "gml:limits" ); + rectGridElem.appendChild( limitsElem ); + QDomElement gridEnvElem = doc.createElement( "gml:GridEnvelope" ); + limitsElem.appendChild( gridEnvElem ); + QDomElement lowElem = doc.createElement( "gml:low" ); + QDomText lowText = doc.createTextNode( "0 0" ); + lowElem.appendChild( lowText ); + gridEnvElem.appendChild( lowElem ); + QDomElement highElem = doc.createElement( "gml:high" ); + QDomText highText = doc.createTextNode( QString::number( rLayer->width() ) + " " + QString::number( rLayer->height() ) ); + highElem.appendChild( highText ); + gridEnvElem.appendChild( highElem ); + spatialDomainElem.appendChild( rectGridElem ); + + QDomElement xAxisElem = doc.createElement( "gml:axisName" ); + QDomText xAxisText = doc.createTextNode( "x" ); + xAxisElem.appendChild( xAxisText ); + spatialDomainElem.appendChild( xAxisElem ); + + QDomElement yAxisElem = doc.createElement( "gml:axisName" ); + QDomText yAxisText = doc.createTextNode( "y" ); + yAxisElem.appendChild( yAxisText ); + spatialDomainElem.appendChild( yAxisElem ); + + QDomElement originElem = doc.createElement( "gml:origin" ); + QDomElement originPosElem = doc.createElement( "gml:pos" ); + QDomText originPosText = doc.createTextNode( QString::number( layerBBox.xMinimum() ) + " " + QString::number( layerBBox.yMaximum() ) ); + originPosElem.appendChild( originPosText ); + spatialDomainElem.appendChild( originElem ); + + QDomElement xOffsetElem = doc.createElement( "gml:offsetVector" ); + QDomText xOffsetText = doc.createTextNode( QString::number( rLayer->rasterUnitsPerPixelX() ) + " 0" ); + xOffsetElem.appendChild( xOffsetText ); + spatialDomainElem.appendChild( xOffsetElem ); + + QDomElement yOffsetElem = doc.createElement( "gml:offsetVector" ); + QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( rLayer->rasterUnitsPerPixelY() ) ); + yOffsetElem.appendChild( yOffsetText ); + spatialDomainElem.appendChild( yOffsetElem ); + + QDomElement rangeSetElem = doc.createElement( "rangeSet" ); + layerElem.appendChild( rangeSetElem ); + + QDomElement RangeSetElem = doc.createElement( "RangeSet" ); + rangeSetElem.appendChild( RangeSetElem ); + + QDomElement rsNameElem = doc.createElement( "name" ); + QDomText rsNameText = doc.createTextNode( "Bands" ); + rsNameElem.appendChild( rsNameText ); + RangeSetElem.appendChild( rsNameElem ); + + QDomElement axisDescElem = doc.createElement( "axisDescription" ); + RangeSetElem.appendChild( axisDescElem ); + + QDomElement AxisDescElem = doc.createElement( "AxisDescription" ); + axisDescElem.appendChild( AxisDescElem ); + + QDomElement adNameElem = doc.createElement( "name" ); + QDomText adNameText = doc.createTextNode( "bands" ); + adNameElem.appendChild( adNameText ); + AxisDescElem.appendChild( adNameElem ); + + QDomElement adValuesElem = doc.createElement( "values" ); + for ( int idx = 0; idx < rLayer->bandCount(); ++idx ) + { + QDomElement adValueElem = doc.createElement( "value" ); + QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) ); + adValueElem.appendChild( adValueText ); + adValuesElem.appendChild( adValueElem ); + } + AxisDescElem.appendChild( adValuesElem ); + + QDomElement sCRSElem = doc.createElement( "supportedCRSs" ); + QDomElement rCRSElem = doc.createElement( "requestResponseCRSs" ); + QDomText rCRSText = doc.createTextNode( layerCrs.authid() ); + rCRSElem.appendChild( rCRSText ); + sCRSElem.appendChild( rCRSElem ); + QDomElement nCRSElem = doc.createElement( "nativeCRSs" ); + QDomText nCRSText = doc.createTextNode( layerCrs.authid() ); + nCRSElem.appendChild( nCRSText ); + sCRSElem.appendChild( nCRSElem ); + layerElem.appendChild( sCRSElem ); + + QDomElement sFormatsElem = doc.createElement( "supportedFormats" ); + sFormatsElem.setAttribute( "nativeFormat", "raw binary" ); + QDomElement formatsElem = doc.createElement( "formats" ); + QDomText formatsText = doc.createTextNode( "GeoTIFF" ); + formatsElem.appendChild( formatsText ); + sFormatsElem.appendChild( formatsElem ); + layerElem.appendChild( sFormatsElem ); + + parentElement.appendChild( layerElem ); + } + } + } +} + +QList QgsWCSProjectParser::mapLayerFromCoverage( const QString& cName, bool useCache ) const +{ + QList layerList; + + const QList& projectLayerElements = mProjectParser.projectLayerElements(); + if ( projectLayerElements.size() < 1 ) + { + return layerList; + } + + QStringList wcsLayersId = wcsLayers(); + + foreach ( const QDomElement &elem, projectLayerElements ) + { + QString type = elem.attribute( "type" ); + if ( type == "raster" ) + { + QgsMapLayer *mLayer = mProjectParser.createLayerFromElement( elem, useCache ); + QgsRasterLayer* layer = dynamic_cast( mLayer ); + if ( !layer || !wcsLayersId.contains( layer->id() ) ) + return layerList; + + QString coveName = layer->name(); + coveName = coveName.replace( " ", "_" ); + if ( cName == coveName ) + { + layerList.push_back( mLayer ); + return layerList; + } + } + } + return layerList; +} diff --git a/src/mapserver/qgswcsprojectparser.h b/src/mapserver/qgswcsprojectparser.h index 06ce7e47d3a..24b8ed510a3 100644 --- a/src/mapserver/qgswcsprojectparser.h +++ b/src/mapserver/qgswcsprojectparser.h @@ -26,6 +26,14 @@ class QgsWCSProjectParser QgsWCSProjectParser( QDomDocument* xmlDoc, const QString& filePath ); ~QgsWCSProjectParser(); + void serviceCapabilities( QDomElement& parentElement, QDomDocument& doc ) const; + QString wcsServiceUrl() const; + QString serviceUrl() const; + void wcsContentMetadata( QDomElement& parentElement, QDomDocument& doc ) const; + QStringList wcsLayers() const; + void describeCoverage( const QString& aCoveName, QDomElement& parentElement, QDomDocument& doc ) const; + QList mapLayerFromCoverage( const QString& cName, bool useCache = true ) const; + private: QgsServerProjectParser mProjectParser; }; diff --git a/src/mapserver/qgswcsserver.cpp b/src/mapserver/qgswcsserver.cpp index 7338ce5ac01..05311e48be6 100644 --- a/src/mapserver/qgswcsserver.cpp +++ b/src/mapserver/qgswcsserver.cpp @@ -118,8 +118,6 @@ QDomDocument QgsWCSServer::getCapabilities() QgsDebugMsg( "Entering." ); QDomDocument doc; -#if 0 //todo: fixme - //wcs:WCS_Capabilities element QDomElement wcsCapabilitiesElement = doc.createElement( "WCS_Capabilities"/*wcs:WCS_Capabilities*/ ); wcsCapabilitiesElement.setAttribute( "xmlns", WCS_NAMESPACE ); @@ -198,8 +196,6 @@ QDomDocument QgsWCSServer::getCapabilities() mConfigParser->wcsContentMetadata( contentMetadataElement, doc ); } -#endif //0 //todo: fixme - return doc; } @@ -208,8 +204,6 @@ QDomDocument QgsWCSServer::describeCoverage() QgsDebugMsg( "Entering." ); QDomDocument doc; -#if 0 //todo: fixme - //wcs:WCS_Capabilities element QDomElement coveDescElement = doc.createElement( "CoverageDescription"/*wcs:CoverageDescription*/ ); coveDescElement.setAttribute( "xmlns", WCS_NAMESPACE ); @@ -238,16 +232,11 @@ QDomDocument QgsWCSServer::describeCoverage() } } mConfigParser->describeCoverage( coveName, coveDescElement, doc ); - -#endif //0 //todo: fixme - return doc; } QByteArray* QgsWCSServer::getCoverage() { -#if 0 //todo: fixme - QStringList wcsLayersId = mConfigParser->wcsLayers(); QList layerList; @@ -411,7 +400,6 @@ QByteArray* QgsWCSServer::getCoverage() return ba; } -#endif //0 //todo: fixme return 0; }