QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgswcsutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgswcsutils.cpp
3 -------------------------
4 begin : December 9, 2013
5 copyright : (C) 2013 by René-Luc D'Hont
6 email : rldhont at 3liz dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgswcsutils.h"
19
20#include "qgsconfigcache.h"
23#include "qgsexception.h"
25#include "qgsproject.h"
26#include "qgsrasterlayer.h"
28
29namespace QgsWcs
30{
32 {
33 return QStringLiteral( "1.0.0" );
34 }
35
36 QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief )
37 {
38 QDomElement layerElem;
39 if ( brief )
40 layerElem = doc.createElement( QStringLiteral( "CoverageOfferingBrief" ) );
41 else
42 layerElem = doc.createElement( QStringLiteral( "CoverageOffering" ) );
43
44 // create name
45 QDomElement nameElem = doc.createElement( QStringLiteral( "name" ) );
46 QString name = layer->name();
47 if ( !layer->serverProperties()->shortName().isEmpty() )
48 name = layer->serverProperties()->shortName();
49 name = name.replace( ' ', '_' );
50 const QDomText nameText = doc.createTextNode( name );
51 nameElem.appendChild( nameText );
52 layerElem.appendChild( nameElem );
53
54 // create label
55 QDomElement labelElem = doc.createElement( QStringLiteral( "label" ) );
56 QString title = layer->serverProperties()->title();
57 if ( title.isEmpty() )
58 {
59 title = layer->name();
60 }
61 const QDomText labelText = doc.createTextNode( title );
62 labelElem.appendChild( labelText );
63 layerElem.appendChild( labelElem );
64
65 //create description
66 const QString abstract = layer->serverProperties()->abstract();
67 if ( !abstract.isEmpty() )
68 {
69 QDomElement descriptionElem = doc.createElement( QStringLiteral( "description" ) );
70 const QDomText descriptionText = doc.createTextNode( abstract );
71 descriptionElem.appendChild( descriptionText );
72 layerElem.appendChild( descriptionElem );
73 }
74
75 //lonLatEnvelope
76 const QgsCoordinateReferenceSystem layerCrs = layer->crs();
78 const int wgs84precision = 6;
79 const QgsCoordinateTransform t( layerCrs, wgs84, project );
80 //transform
81 QgsRectangle BBox;
82 try
83 {
84 BBox = t.transformBoundingBox( layer->extent() );
85 }
86 catch ( QgsCsException &e )
87 {
88 QgsDebugError( QStringLiteral( "Transform error caught: %1. Using original layer extent." ).arg( e.what() ) );
89 BBox = layer->extent();
90 }
91 QDomElement lonLatElem = doc.createElement( QStringLiteral( "lonLatEnvelope" ) );
92 lonLatElem.setAttribute( QStringLiteral( "srsName" ), QStringLiteral( "urn:ogc:def:crs:OGC:1.3:CRS84" ) );
93 QDomElement lowerPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
94 const QDomText lowerPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.xMinimum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.yMinimum(), wgs84precision ), wgs84precision ) );
95 lowerPosElem.appendChild( lowerPosText );
96 lonLatElem.appendChild( lowerPosElem );
97 QDomElement upperPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
98 const QDomText upperPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.xMaximum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.yMaximum(), wgs84precision ), wgs84precision ) );
99 upperPosElem.appendChild( upperPosText );
100 lonLatElem.appendChild( upperPosElem );
101 layerElem.appendChild( lonLatElem );
102
103 if ( brief )
104 return layerElem;
105
106 //Defines the spatial-temporal domain set of a coverage offering. The domainSet shall include a SpatialDomain
107 // (describing the spatial locations for which coverages can be requested), a TemporalDomain (describing the
108 // time instants or inter-vals for which coverages can be requested), or both.
109 QDomElement domainSetElem = doc.createElement( QStringLiteral( "domainSet" ) );
110 layerElem.appendChild( domainSetElem );
111
112 QDomElement spatialDomainElem = doc.createElement( QStringLiteral( "spatialDomain" ) );
113 domainSetElem.appendChild( spatialDomainElem );
114
115 // Define precision
116 int precision = 3;
117 if ( layer->crs().isGeographic() )
118 {
119 precision = 6;
120 }
121 //create Envelope
122 const QgsRectangle layerBBox = layer->extent();
123 QDomElement envelopeElem = doc.createElement( QStringLiteral( "gml:Envelope" ) );
124 envelopeElem.setAttribute( QStringLiteral( "srsName" ), layerCrs.authid() );
125 QDomElement lowerCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
126 const QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), wgs84precision ), precision ) );
127 lowerCornerElem.appendChild( lowerCornerText );
128 envelopeElem.appendChild( lowerCornerElem );
129 QDomElement upperCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
130 const QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.xMaximum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.yMaximum(), wgs84precision ), precision ) );
131 upperCornerElem.appendChild( upperCornerText );
132 envelopeElem.appendChild( upperCornerElem );
133 spatialDomainElem.appendChild( envelopeElem );
134
135 QDomElement rectGridElem = doc.createElement( QStringLiteral( "gml:RectifiedGrid" ) );
136 rectGridElem.setAttribute( QStringLiteral( "dimension" ), 2 );
137 QDomElement limitsElem = doc.createElement( QStringLiteral( "gml:limits" ) );
138 rectGridElem.appendChild( limitsElem );
139 QDomElement gridEnvElem = doc.createElement( QStringLiteral( "gml:GridEnvelope" ) );
140 limitsElem.appendChild( gridEnvElem );
141 QDomElement lowElem = doc.createElement( QStringLiteral( "gml:low" ) );
142 const QDomText lowText = doc.createTextNode( QStringLiteral( "0 0" ) );
143 lowElem.appendChild( lowText );
144 gridEnvElem.appendChild( lowElem );
145 QDomElement highElem = doc.createElement( QStringLiteral( "gml:high" ) );
146 const QDomText highText = doc.createTextNode( QString::number( layer->width() ) + " " + QString::number( layer->height() ) );
147 highElem.appendChild( highText );
148 gridEnvElem.appendChild( highElem );
149 spatialDomainElem.appendChild( rectGridElem );
150
151 QDomElement xAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
152 const QDomText xAxisText = doc.createTextNode( QStringLiteral( "x" ) );
153 xAxisElem.appendChild( xAxisText );
154 rectGridElem.appendChild( xAxisElem );
155
156 QDomElement yAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
157 const QDomText yAxisText = doc.createTextNode( QStringLiteral( "y" ) );
158 yAxisElem.appendChild( yAxisText );
159 rectGridElem.appendChild( yAxisElem );
160
161 QDomElement originElem = doc.createElement( QStringLiteral( "gml:origin" ) );
162 QDomElement originPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
163 originElem.appendChild( originPosElem );
164 const QDomText originPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), precision ), precision ) );
165 originPosElem.appendChild( originPosText );
166 rectGridElem.appendChild( originElem );
167
168 QDomElement xOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
169 const QDomText xOffsetText = doc.createTextNode( QString::number( layer->rasterUnitsPerPixelX() ) + " 0" );
170 xOffsetElem.appendChild( xOffsetText );
171 rectGridElem.appendChild( xOffsetElem );
172
173 QDomElement yOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
174 const QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( layer->rasterUnitsPerPixelY() ) );
175 yOffsetElem.appendChild( yOffsetText );
176 rectGridElem.appendChild( yOffsetElem );
177
178 //GML property containing one RangeSet GML object.
179 QDomElement rangeSetElem = doc.createElement( QStringLiteral( "rangeSet" ) );
180 layerElem.appendChild( rangeSetElem );
181
182 //Defines the properties (categories, measures, or values) assigned to each location in the domain. Any such
183 // property may be a scalar (numeric or text) value, such as population density, or a compound (vector or tensor)
184 // value, such as incomes by race, or radiances by wavelength. The semantic of the range set is typically an
185 // observable and is referenced by a URI. A rangeSet also has a reference system that is referred by the URI in
186 // the refSys attribute. The refSys is either qualitative (classification) or quantitative (uom). The three attributes
187 // can be included either here and in each axisDescription. If included in both places, the values in the axisDescription
188 // over-ride those included in the RangeSet.
189 QDomElement RangeSetElem = doc.createElement( QStringLiteral( "RangeSet" ) );
190 rangeSetElem.appendChild( RangeSetElem );
191
192 QDomElement rsNameElem = doc.createElement( QStringLiteral( "name" ) );
193 const QDomText rsNameText = doc.createTextNode( QStringLiteral( "Bands" ) );
194 rsNameElem.appendChild( rsNameText );
195 RangeSetElem.appendChild( rsNameElem );
196
197 QDomElement rsLabelElem = doc.createElement( QStringLiteral( "label" ) );
198 const QDomText rsLabelText = doc.createTextNode( QStringLiteral( "Bands" ) );
199 rsLabelElem.appendChild( rsLabelText );
200 RangeSetElem.appendChild( rsLabelElem );
201
202 QDomElement axisDescElem = doc.createElement( QStringLiteral( "axisDescription" ) );
203 RangeSetElem.appendChild( axisDescElem );
204
205 QDomElement AxisDescElem = doc.createElement( QStringLiteral( "AxisDescription" ) );
206 axisDescElem.appendChild( AxisDescElem );
207
208 QDomElement adNameElem = doc.createElement( QStringLiteral( "name" ) );
209 const QDomText adNameText = doc.createTextNode( QStringLiteral( "bands" ) );
210 adNameElem.appendChild( adNameText );
211 AxisDescElem.appendChild( adNameElem );
212
213 QDomElement adLabelElem = doc.createElement( QStringLiteral( "label" ) );
214 const QDomText adLablelText = doc.createTextNode( QStringLiteral( "bands" ) );
215 adLabelElem.appendChild( adLablelText );
216 AxisDescElem.appendChild( adLabelElem );
217
218 QDomElement adValuesElem = doc.createElement( QStringLiteral( "values" ) );
219 for ( int idx = 0; idx < layer->bandCount(); ++idx )
220 {
221 QDomElement adValueElem = doc.createElement( QStringLiteral( "singleValue" ) );
222 const QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) );
223 adValueElem.appendChild( adValueText );
224 adValuesElem.appendChild( adValueElem );
225 }
226 AxisDescElem.appendChild( adValuesElem );
227
228 //The coordinate reference system(s) in which the server can accept requests against
229 // this coverage offering and produce coverages from it.
230 QDomElement sCRSElem = doc.createElement( QStringLiteral( "supportedCRSs" ) );
231 QDomElement rCRSElem = doc.createElement( QStringLiteral( "requestResponseCRSs" ) );
232 const QDomText rCRSText = doc.createTextNode( layerCrs.authid() );
233 rCRSElem.appendChild( rCRSText );
234 sCRSElem.appendChild( rCRSElem );
235 QDomElement nCRSElem = doc.createElement( QStringLiteral( "nativeCRSs" ) );
236 const QDomText nCRSText = doc.createTextNode( layerCrs.authid() );
237 nCRSElem.appendChild( nCRSText );
238 sCRSElem.appendChild( nCRSElem );
239 layerElem.appendChild( sCRSElem );
240
241 //The formats (file encodings) in which the server can produce coverages from this
242 // coverage offering.
243 QDomElement sFormatsElem = doc.createElement( QStringLiteral( "supportedFormats" ) );
244 sFormatsElem.setAttribute( QStringLiteral( "nativeFormat" ), QStringLiteral( "raw binary" ) );
245 QDomElement formatsElem = doc.createElement( QStringLiteral( "formats" ) );
246 const QDomText formatsText = doc.createTextNode( QStringLiteral( "GeoTIFF" ) );
247 formatsElem.appendChild( formatsText );
248 sFormatsElem.appendChild( formatsElem );
249 layerElem.appendChild( sFormatsElem );
250
251 return layerElem;
252 }
253
254
255 QString serviceUrl( const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings )
256 {
257 static const QSet<QString> sFilter {
258 QStringLiteral( "REQUEST" ),
259 QStringLiteral( "VERSION" ),
260 QStringLiteral( "SERVICE" ),
261 QStringLiteral( "_DC" )
262 };
263
264 QString href = QgsServerProjectUtils::wcsServiceUrl( project ? *project : *QgsProject::instance(), request, settings );
265
266 // Build default url
267 if ( href.isEmpty() )
268 {
269 QUrl url = request.originalUrl();
270 QUrlQuery q( url );
271
272 const QList<QPair<QString, QString>> queryItems = q.queryItems();
273 for ( const QPair<QString, QString> &param : queryItems )
274 {
275 if ( sFilter.contains( param.first.toUpper() ) )
276 q.removeAllQueryItems( param.first );
277 }
278
279 url.setQuery( q );
280 href = url.toString();
281 }
282
283 return href;
284 }
285
286 QgsRectangle parseBbox( const QString &bboxStr )
287 {
288 QStringList lst = bboxStr.split( ',' );
289 if ( lst.count() != 4 )
290 return QgsRectangle();
291
292 double d[4];
293 bool ok;
294 for ( int i = 0; i < 4; i++ )
295 {
296 lst[i].replace( ' ', '+' );
297 d[i] = lst[i].toDouble( &ok );
298 if ( !ok )
299 return QgsRectangle();
300 }
301 return QgsRectangle( d[0], d[1], d[2], d[3] );
302 }
303
304} // namespace QgsWcs
static QString geographicCrsAuthId()
Geographic coordinate system auth:id string for a default geographic CRS (EPSG:4326).
Definition qgis.h:6333
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Handles coordinate transforms between two coordinate systems.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
QString what() const
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
QString abstract() const
Returns the abstract of the layerused by QGIS Server in GetCapabilities request.
QString name
Definition qgsmaplayer.h:84
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:87
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:109
static QgsProject * instance()
Returns the QgsProject singleton instance.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
int bandCount() const
Returns the number of bands in this layer.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
static QString wcsServiceUrl(const QgsProject &project, const QgsServerRequest &request=QgsServerRequest(), const QgsServerSettings &settings=QgsServerSettings())
Returns the WCS service url.
static double ceilWithPrecision(double number, int places)
Returns a double greater than number to the specified number of places.
static double floorWithPrecision(double number, int places)
Returns a double less than number to the specified number of places.
Defines requests passed to QgsService classes.
QUrl originalUrl() const
Returns the request url as seen by the web server, by default this is equal to the url seen by QGIS s...
Provides a way to retrieve settings by prioritizing according to environment variables,...
WCS implementation.
Definition qgswcs.cpp:30
QDomElement getCoverageOffering(QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief)
CoverageOffering or CoverageOfferingBrief element.
QgsRectangle parseBbox(const QString &bboxStr)
Parse bounding box.
QString implementationVersion()
Returns the highest version supported by this implementation.
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings)
Service URL string.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6524
#define QgsDebugError(str)
Definition qgslogger.h:57