QGIS API Documentation 3.99.0-Master (d270888f95f)
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( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.xMinimum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.yMinimum(), wgs84precision ), wgs84precision ) );
99 lowerPosElem.appendChild( lowerPosText );
100 lonLatElem.appendChild( lowerPosElem );
101 QDomElement upperPosElem = doc.createElement( u"gml:pos"_s );
102 const QDomText upperPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.xMaximum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.yMaximum(), wgs84precision ), wgs84precision ) );
103 upperPosElem.appendChild( upperPosText );
104 lonLatElem.appendChild( upperPosElem );
105 layerElem.appendChild( lonLatElem );
106
107 if ( brief )
108 return layerElem;
109
110 //Defines the spatial-temporal domain set of a coverage offering. The domainSet shall include a SpatialDomain
111 // (describing the spatial locations for which coverages can be requested), a TemporalDomain (describing the
112 // time instants or inter-vals for which coverages can be requested), or both.
113 QDomElement domainSetElem = doc.createElement( u"domainSet"_s );
114 layerElem.appendChild( domainSetElem );
115
116 QDomElement spatialDomainElem = doc.createElement( u"spatialDomain"_s );
117 domainSetElem.appendChild( spatialDomainElem );
118
119 // Define precision
120 int precision = 3;
121 if ( layer->crs().isGeographic() )
122 {
123 precision = 6;
124 }
125 //create Envelope
126 const QgsRectangle layerBBox = layer->extent();
127 QDomElement envelopeElem = doc.createElement( u"gml:Envelope"_s );
128 envelopeElem.setAttribute( u"srsName"_s, layerCrs.authid() );
129 QDomElement lowerCornerElem = doc.createElement( u"gml:pos"_s );
130 const QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), wgs84precision ), precision ) );
131 lowerCornerElem.appendChild( lowerCornerText );
132 envelopeElem.appendChild( lowerCornerElem );
133 QDomElement upperCornerElem = doc.createElement( u"gml:pos"_s );
134 const QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.xMaximum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.yMaximum(), wgs84precision ), precision ) );
135 upperCornerElem.appendChild( upperCornerText );
136 envelopeElem.appendChild( upperCornerElem );
137 spatialDomainElem.appendChild( envelopeElem );
138
139 QDomElement rectGridElem = doc.createElement( u"gml:RectifiedGrid"_s );
140 rectGridElem.setAttribute( u"dimension"_s, 2 );
141 QDomElement limitsElem = doc.createElement( u"gml:limits"_s );
142 rectGridElem.appendChild( limitsElem );
143 QDomElement gridEnvElem = doc.createElement( u"gml:GridEnvelope"_s );
144 limitsElem.appendChild( gridEnvElem );
145 QDomElement lowElem = doc.createElement( u"gml:low"_s );
146 const QDomText lowText = doc.createTextNode( u"0 0"_s );
147 lowElem.appendChild( lowText );
148 gridEnvElem.appendChild( lowElem );
149 QDomElement highElem = doc.createElement( u"gml:high"_s );
150 const QDomText highText = doc.createTextNode( QString::number( layer->width() ) + " " + QString::number( layer->height() ) );
151 highElem.appendChild( highText );
152 gridEnvElem.appendChild( highElem );
153 spatialDomainElem.appendChild( rectGridElem );
154
155 QDomElement xAxisElem = doc.createElement( u"gml:axisName"_s );
156 const QDomText xAxisText = doc.createTextNode( u"x"_s );
157 xAxisElem.appendChild( xAxisText );
158 rectGridElem.appendChild( xAxisElem );
159
160 QDomElement yAxisElem = doc.createElement( u"gml:axisName"_s );
161 const QDomText yAxisText = doc.createTextNode( u"y"_s );
162 yAxisElem.appendChild( yAxisText );
163 rectGridElem.appendChild( yAxisElem );
164
165 QDomElement originElem = doc.createElement( u"gml:origin"_s );
166 QDomElement originPosElem = doc.createElement( u"gml:pos"_s );
167 originElem.appendChild( originPosElem );
168 const QDomText originPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), precision ), precision ) );
169 originPosElem.appendChild( originPosText );
170 rectGridElem.appendChild( originElem );
171
172 QDomElement xOffsetElem = doc.createElement( u"gml:offsetVector"_s );
173 const QDomText xOffsetText = doc.createTextNode( QString::number( layer->rasterUnitsPerPixelX() ) + " 0" );
174 xOffsetElem.appendChild( xOffsetText );
175 rectGridElem.appendChild( xOffsetElem );
176
177 QDomElement yOffsetElem = doc.createElement( u"gml:offsetVector"_s );
178 const QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( layer->rasterUnitsPerPixelY() ) );
179 yOffsetElem.appendChild( yOffsetText );
180 rectGridElem.appendChild( yOffsetElem );
181
182 //GML property containing one RangeSet GML object.
183 QDomElement rangeSetElem = doc.createElement( u"rangeSet"_s );
184 layerElem.appendChild( rangeSetElem );
185
186 //Defines the properties (categories, measures, or values) assigned to each location in the domain. Any such
187 // property may be a scalar (numeric or text) value, such as population density, or a compound (vector or tensor)
188 // value, such as incomes by race, or radiances by wavelength. The semantic of the range set is typically an
189 // observable and is referenced by a URI. A rangeSet also has a reference system that is referred by the URI in
190 // the refSys attribute. The refSys is either qualitative (classification) or quantitative (uom). The three attributes
191 // can be included either here and in each axisDescription. If included in both places, the values in the axisDescription
192 // over-ride those included in the RangeSet.
193 QDomElement RangeSetElem = doc.createElement( u"RangeSet"_s );
194 rangeSetElem.appendChild( RangeSetElem );
195
196 QDomElement rsNameElem = doc.createElement( u"name"_s );
197 const QDomText rsNameText = doc.createTextNode( u"Bands"_s );
198 rsNameElem.appendChild( rsNameText );
199 RangeSetElem.appendChild( rsNameElem );
200
201 QDomElement rsLabelElem = doc.createElement( u"label"_s );
202 const QDomText rsLabelText = doc.createTextNode( u"Bands"_s );
203 rsLabelElem.appendChild( rsLabelText );
204 RangeSetElem.appendChild( rsLabelElem );
205
206 QDomElement axisDescElem = doc.createElement( u"axisDescription"_s );
207 RangeSetElem.appendChild( axisDescElem );
208
209 QDomElement AxisDescElem = doc.createElement( u"AxisDescription"_s );
210 axisDescElem.appendChild( AxisDescElem );
211
212 QDomElement adNameElem = doc.createElement( u"name"_s );
213 const QDomText adNameText = doc.createTextNode( u"bands"_s );
214 adNameElem.appendChild( adNameText );
215 AxisDescElem.appendChild( adNameElem );
216
217 QDomElement adLabelElem = doc.createElement( u"label"_s );
218 const QDomText adLablelText = doc.createTextNode( u"bands"_s );
219 adLabelElem.appendChild( adLablelText );
220 AxisDescElem.appendChild( adLabelElem );
221
222 QDomElement adValuesElem = doc.createElement( u"values"_s );
223 for ( int idx = 0; idx < layer->bandCount(); ++idx )
224 {
225 QDomElement adValueElem = doc.createElement( u"singleValue"_s );
226 const QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) );
227 adValueElem.appendChild( adValueText );
228 adValuesElem.appendChild( adValueElem );
229 }
230 AxisDescElem.appendChild( adValuesElem );
231
232 //The coordinate reference system(s) in which the server can accept requests against
233 // this coverage offering and produce coverages from it.
234 QDomElement sCRSElem = doc.createElement( u"supportedCRSs"_s );
235 QDomElement rCRSElem = doc.createElement( u"requestResponseCRSs"_s );
236 const QDomText rCRSText = doc.createTextNode( layerCrs.authid() );
237 rCRSElem.appendChild( rCRSText );
238 sCRSElem.appendChild( rCRSElem );
239 QDomElement nCRSElem = doc.createElement( u"nativeCRSs"_s );
240 const QDomText nCRSText = doc.createTextNode( layerCrs.authid() );
241 nCRSElem.appendChild( nCRSText );
242 sCRSElem.appendChild( nCRSElem );
243 layerElem.appendChild( sCRSElem );
244
245 //The formats (file encodings) in which the server can produce coverages from this
246 // coverage offering.
247 QDomElement sFormatsElem = doc.createElement( u"supportedFormats"_s );
248 sFormatsElem.setAttribute( u"nativeFormat"_s, u"raw binary"_s );
249 QDomElement formatsElem = doc.createElement( u"formats"_s );
250 const QDomText formatsText = doc.createTextNode( u"GeoTIFF"_s );
251 formatsElem.appendChild( formatsText );
252 sFormatsElem.appendChild( formatsElem );
253 layerElem.appendChild( sFormatsElem );
254
255 return layerElem;
256 }
257
258
259 QString serviceUrl( const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings )
260 {
261 static const QSet<QString> sFilter {
262 u"REQUEST"_s,
263 u"VERSION"_s,
264 u"SERVICE"_s,
265 u"_DC"_s
266 };
267
268 QString href = QgsServerProjectUtils::wcsServiceUrl( project ? *project : *QgsProject::instance(), request, settings );
269
270 // Build default url
271 if ( href.isEmpty() )
272 {
273 QUrl url = request.originalUrl();
274 QUrlQuery q( url );
275
276 const QList<QPair<QString, QString>> queryItems = q.queryItems();
277 for ( const QPair<QString, QString> &param : queryItems )
278 {
279 if ( sFilter.contains( param.first.toUpper() ) )
280 q.removeAllQueryItems( param.first );
281 }
282
283 url.setQuery( q );
284 href = url.toString();
285 }
286
287 return href;
288 }
289
290 QgsRectangle parseBbox( const QString &bboxStr )
291 {
292 QStringList lst = bboxStr.split( ',' );
293 if ( lst.count() != 4 )
294 return QgsRectangle();
295
296 double d[4];
297 bool ok;
298 for ( int i = 0; i < 4; i++ )
299 {
300 lst[i].replace( ' ', '+' );
301 d[i] = lst[i].toDouble( &ok );
302 if ( !ok )
303 return QgsRectangle();
304 }
305 return QgsRectangle( d[0], d[1], d[2], d[3] );
306 }
307
308} // namespace QgsWcs
static QString geographicCrsAuthId()
Geographic coordinate system auth:id string for a default geographic CRS (EPSG:4326).
Definition qgis.h:6625
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:112
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:34
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:6817
#define QgsDebugError(str)
Definition qgslogger.h:59