QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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
29#include <QString>
30
31using namespace Qt::StringLiterals;
32
33namespace QgsWcs
34{
36 {
37 return u"1.0.0"_s;
38 }
39
40 QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief )
41 {
42 QDomElement layerElem;
43 if ( brief )
44 layerElem = doc.createElement( u"CoverageOfferingBrief"_s );
45 else
46 layerElem = doc.createElement( u"CoverageOffering"_s );
47
48 // create name
49 QDomElement nameElem = doc.createElement( u"name"_s );
50 QString name = layer->name();
51 if ( !layer->serverProperties()->shortName().isEmpty() )
52 name = layer->serverProperties()->shortName();
53 name = name.replace( ' ', '_' );
54 const QDomText nameText = doc.createTextNode( name );
55 nameElem.appendChild( nameText );
56 layerElem.appendChild( nameElem );
57
58 // create label
59 QDomElement labelElem = doc.createElement( u"label"_s );
60 QString title = layer->serverProperties()->title();
61 if ( title.isEmpty() )
62 {
63 title = layer->name();
64 }
65 const QDomText labelText = doc.createTextNode( title );
66 labelElem.appendChild( labelText );
67 layerElem.appendChild( labelElem );
68
69 //create description
70 const QString abstract = layer->serverProperties()->abstract();
71 if ( !abstract.isEmpty() )
72 {
73 QDomElement descriptionElem = doc.createElement( u"description"_s );
74 const QDomText descriptionText = doc.createTextNode( abstract );
75 descriptionElem.appendChild( descriptionText );
76 layerElem.appendChild( descriptionElem );
77 }
78
79 //lonLatEnvelope
80 const QgsCoordinateReferenceSystem layerCrs = layer->crs();
82 const int wgs84precision = 6;
83 const QgsCoordinateTransform t( layerCrs, wgs84, project );
84 //transform
85 QgsRectangle BBox;
86 try
87 {
88 BBox = t.transformBoundingBox( layer->extent() );
89 }
90 catch ( QgsCsException &e )
91 {
92 QgsDebugError( u"Transform error caught: %1. Using original layer extent."_s.arg( e.what() ) );
93 BBox = layer->extent();
94 }
95 QDomElement lonLatElem = doc.createElement( u"lonLatEnvelope"_s );
96 lonLatElem.setAttribute( u"srsName"_s, u"urn:ogc:def:crs:OGC:1.3:CRS84"_s );
97 QDomElement lowerPosElem = doc.createElement( u"gml:pos"_s );
98 const QDomText lowerPosText = doc.createTextNode(
99 qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.xMinimum(), wgs84precision ), wgs84precision )
100 + " "
101 + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.yMinimum(), wgs84precision ), wgs84precision )
102 );
103 lowerPosElem.appendChild( lowerPosText );
104 lonLatElem.appendChild( lowerPosElem );
105 QDomElement upperPosElem = doc.createElement( u"gml:pos"_s );
106 const QDomText upperPosText = doc.createTextNode(
107 qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.xMaximum(), wgs84precision ), wgs84precision )
108 + " "
109 + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.yMaximum(), wgs84precision ), wgs84precision )
110 );
111 upperPosElem.appendChild( upperPosText );
112 lonLatElem.appendChild( upperPosElem );
113 layerElem.appendChild( lonLatElem );
114
115 if ( brief )
116 return layerElem;
117
118 //Defines the spatial-temporal domain set of a coverage offering. The domainSet shall include a SpatialDomain
119 // (describing the spatial locations for which coverages can be requested), a TemporalDomain (describing the
120 // time instants or inter-vals for which coverages can be requested), or both.
121 QDomElement domainSetElem = doc.createElement( u"domainSet"_s );
122 layerElem.appendChild( domainSetElem );
123
124 QDomElement spatialDomainElem = doc.createElement( u"spatialDomain"_s );
125 domainSetElem.appendChild( spatialDomainElem );
126
127 // Define precision
128 int precision = 3;
129 if ( layer->crs().isGeographic() )
130 {
131 precision = 6;
132 }
133 //create Envelope
134 const QgsRectangle layerBBox = layer->extent();
135 QDomElement envelopeElem = doc.createElement( u"gml:Envelope"_s );
136 envelopeElem.setAttribute( u"srsName"_s, layerCrs.authid() );
137 QDomElement lowerCornerElem = doc.createElement( u"gml:pos"_s );
138 const QDomText lowerCornerText = doc.createTextNode(
139 qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), wgs84precision )
140 + " "
141 + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), wgs84precision ), precision )
142 );
143 lowerCornerElem.appendChild( lowerCornerText );
144 envelopeElem.appendChild( lowerCornerElem );
145 QDomElement upperCornerElem = doc.createElement( u"gml:pos"_s );
146 const QDomText upperCornerText = doc.createTextNode(
147 qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.xMaximum(), precision ), wgs84precision )
148 + " "
149 + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.yMaximum(), wgs84precision ), precision )
150 );
151 upperCornerElem.appendChild( upperCornerText );
152 envelopeElem.appendChild( upperCornerElem );
153 spatialDomainElem.appendChild( envelopeElem );
154
155 QDomElement rectGridElem = doc.createElement( u"gml:RectifiedGrid"_s );
156 rectGridElem.setAttribute( u"dimension"_s, 2 );
157 QDomElement limitsElem = doc.createElement( u"gml:limits"_s );
158 rectGridElem.appendChild( limitsElem );
159 QDomElement gridEnvElem = doc.createElement( u"gml:GridEnvelope"_s );
160 limitsElem.appendChild( gridEnvElem );
161 QDomElement lowElem = doc.createElement( u"gml:low"_s );
162 const QDomText lowText = doc.createTextNode( u"0 0"_s );
163 lowElem.appendChild( lowText );
164 gridEnvElem.appendChild( lowElem );
165 QDomElement highElem = doc.createElement( u"gml:high"_s );
166 const QDomText highText = doc.createTextNode( QString::number( layer->width() ) + " " + QString::number( layer->height() ) );
167 highElem.appendChild( highText );
168 gridEnvElem.appendChild( highElem );
169 spatialDomainElem.appendChild( rectGridElem );
170
171 QDomElement xAxisElem = doc.createElement( u"gml:axisName"_s );
172 const QDomText xAxisText = doc.createTextNode( u"x"_s );
173 xAxisElem.appendChild( xAxisText );
174 rectGridElem.appendChild( xAxisElem );
175
176 QDomElement yAxisElem = doc.createElement( u"gml:axisName"_s );
177 const QDomText yAxisText = doc.createTextNode( u"y"_s );
178 yAxisElem.appendChild( yAxisText );
179 rectGridElem.appendChild( yAxisElem );
180
181 QDomElement originElem = doc.createElement( u"gml:origin"_s );
182 QDomElement originPosElem = doc.createElement( u"gml:pos"_s );
183 originElem.appendChild( originPosElem );
184 const QDomText originPosText = doc.createTextNode(
185 qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), precision )
186 + " "
187 + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), precision ), precision )
188 );
189 originPosElem.appendChild( originPosText );
190 rectGridElem.appendChild( originElem );
191
192 QDomElement xOffsetElem = doc.createElement( u"gml:offsetVector"_s );
193 const QDomText xOffsetText = doc.createTextNode( QString::number( layer->rasterUnitsPerPixelX() ) + " 0" );
194 xOffsetElem.appendChild( xOffsetText );
195 rectGridElem.appendChild( xOffsetElem );
196
197 QDomElement yOffsetElem = doc.createElement( u"gml:offsetVector"_s );
198 const QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( layer->rasterUnitsPerPixelY() ) );
199 yOffsetElem.appendChild( yOffsetText );
200 rectGridElem.appendChild( yOffsetElem );
201
202 //GML property containing one RangeSet GML object.
203 QDomElement rangeSetElem = doc.createElement( u"rangeSet"_s );
204 layerElem.appendChild( rangeSetElem );
205
206 //Defines the properties (categories, measures, or values) assigned to each location in the domain. Any such
207 // property may be a scalar (numeric or text) value, such as population density, or a compound (vector or tensor)
208 // value, such as incomes by race, or radiances by wavelength. The semantic of the range set is typically an
209 // observable and is referenced by a URI. A rangeSet also has a reference system that is referred by the URI in
210 // the refSys attribute. The refSys is either qualitative (classification) or quantitative (uom). The three attributes
211 // can be included either here and in each axisDescription. If included in both places, the values in the axisDescription
212 // over-ride those included in the RangeSet.
213 QDomElement RangeSetElem = doc.createElement( u"RangeSet"_s );
214 rangeSetElem.appendChild( RangeSetElem );
215
216 QDomElement rsNameElem = doc.createElement( u"name"_s );
217 const QDomText rsNameText = doc.createTextNode( u"Bands"_s );
218 rsNameElem.appendChild( rsNameText );
219 RangeSetElem.appendChild( rsNameElem );
220
221 QDomElement rsLabelElem = doc.createElement( u"label"_s );
222 const QDomText rsLabelText = doc.createTextNode( u"Bands"_s );
223 rsLabelElem.appendChild( rsLabelText );
224 RangeSetElem.appendChild( rsLabelElem );
225
226 QDomElement axisDescElem = doc.createElement( u"axisDescription"_s );
227 RangeSetElem.appendChild( axisDescElem );
228
229 QDomElement AxisDescElem = doc.createElement( u"AxisDescription"_s );
230 axisDescElem.appendChild( AxisDescElem );
231
232 QDomElement adNameElem = doc.createElement( u"name"_s );
233 const QDomText adNameText = doc.createTextNode( u"bands"_s );
234 adNameElem.appendChild( adNameText );
235 AxisDescElem.appendChild( adNameElem );
236
237 QDomElement adLabelElem = doc.createElement( u"label"_s );
238 const QDomText adLablelText = doc.createTextNode( u"bands"_s );
239 adLabelElem.appendChild( adLablelText );
240 AxisDescElem.appendChild( adLabelElem );
241
242 QDomElement adValuesElem = doc.createElement( u"values"_s );
243 for ( int idx = 0; idx < layer->bandCount(); ++idx )
244 {
245 QDomElement adValueElem = doc.createElement( u"singleValue"_s );
246 const QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) );
247 adValueElem.appendChild( adValueText );
248 adValuesElem.appendChild( adValueElem );
249 }
250 AxisDescElem.appendChild( adValuesElem );
251
252 //The coordinate reference system(s) in which the server can accept requests against
253 // this coverage offering and produce coverages from it.
254 QDomElement sCRSElem = doc.createElement( u"supportedCRSs"_s );
255 QDomElement rCRSElem = doc.createElement( u"requestResponseCRSs"_s );
256 const QDomText rCRSText = doc.createTextNode( layerCrs.authid() );
257 rCRSElem.appendChild( rCRSText );
258 sCRSElem.appendChild( rCRSElem );
259 QDomElement nCRSElem = doc.createElement( u"nativeCRSs"_s );
260 const QDomText nCRSText = doc.createTextNode( layerCrs.authid() );
261 nCRSElem.appendChild( nCRSText );
262 sCRSElem.appendChild( nCRSElem );
263 layerElem.appendChild( sCRSElem );
264
265 //The formats (file encodings) in which the server can produce coverages from this
266 // coverage offering.
267 QDomElement sFormatsElem = doc.createElement( u"supportedFormats"_s );
268 sFormatsElem.setAttribute( u"nativeFormat"_s, u"raw binary"_s );
269 QDomElement formatsElem = doc.createElement( u"formats"_s );
270 const QDomText formatsText = doc.createTextNode( u"GeoTIFF"_s );
271 formatsElem.appendChild( formatsText );
272 sFormatsElem.appendChild( formatsElem );
273 layerElem.appendChild( sFormatsElem );
274
275 return layerElem;
276 }
277
278
279 QString serviceUrl( const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings )
280 {
281 static const QSet<QString> sFilter { u"REQUEST"_s, u"VERSION"_s, u"SERVICE"_s, u"_DC"_s };
282
283 QString href = QgsServerProjectUtils::wcsServiceUrl( project ? *project : *QgsProject::instance(), request, settings );
284
285 // Build default url
286 if ( href.isEmpty() )
287 {
288 QUrl url = request.originalUrl();
289 QUrlQuery q( url );
290
291 const QList<QPair<QString, QString>> queryItems = q.queryItems();
292 for ( const QPair<QString, QString> &param : queryItems )
293 {
294 if ( sFilter.contains( param.first.toUpper() ) )
295 q.removeAllQueryItems( param.first );
296 }
297
298 url.setQuery( q );
299 href = url.toString();
300 }
301
302 return href;
303 }
304
305 QgsRectangle parseBbox( const QString &bboxStr )
306 {
307 QStringList lst = bboxStr.split( ',' );
308 if ( lst.count() != 4 )
309 return QgsRectangle();
310
311 double d[4];
312 bool ok;
313 for ( int i = 0; i < 4; i++ )
314 {
315 lst[i].replace( ' ', '+' );
316 d[i] = lst[i].toDouble( &ok );
317 if ( !ok )
318 return QgsRectangle();
319 }
320 return QgsRectangle( d[0], d[1], d[2], d[3] );
321 }
322
323} // namespace QgsWcs
static QString geographicCrsAuthId()
Geographic coordinate system auth:id string for a default geographic CRS (EPSG:4326).
Definition qgis.h:6714
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:87
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
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:113
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:33
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:6893
#define QgsDebugError(str)
Definition qgslogger.h:59