QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 #include "qgsconfigcache.h"
20 #include "qgsserverprojectutils.h"
21 
22 #include "qgsproject.h"
23 #include "qgsexception.h"
24 #include "qgsrasterlayer.h"
25 #include "qgsmapserviceexception.h"
27 
28 namespace QgsWcs
29 {
31  {
32  return QStringLiteral( "1.0.0" );
33  }
34 
35  QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief )
36  {
37  QDomElement layerElem;
38  if ( brief )
39  layerElem = doc.createElement( QStringLiteral( "CoverageOfferingBrief" ) );
40  else
41  layerElem = doc.createElement( QStringLiteral( "CoverageOffering" ) );
42 
43  // create name
44  QDomElement nameElem = doc.createElement( QStringLiteral( "name" ) );
45  QString name = layer->name();
46  if ( !layer->shortName().isEmpty() )
47  name = layer->shortName();
48  name = name.replace( ' ', '_' );
49  QDomText nameText = doc.createTextNode( name );
50  nameElem.appendChild( nameText );
51  layerElem.appendChild( nameElem );
52 
53  // create label
54  QDomElement labelElem = doc.createElement( QStringLiteral( "label" ) );
55  QString title = layer->title();
56  if ( title.isEmpty() )
57  {
58  title = layer->name();
59  }
60  QDomText labelText = doc.createTextNode( title );
61  labelElem.appendChild( labelText );
62  layerElem.appendChild( labelElem );
63 
64  //create description
65  QString abstract = layer->abstract();
66  if ( !abstract.isEmpty() )
67  {
68  QDomElement descriptionElem = doc.createElement( QStringLiteral( "description" ) );
69  QDomText descriptionText = doc.createTextNode( abstract );
70  descriptionElem.appendChild( descriptionText );
71  layerElem.appendChild( descriptionElem );
72  }
73 
74  //lonLatEnvelope
75  QgsCoordinateReferenceSystem layerCrs = layer->crs();
77  int wgs84precision = 6;
78  QgsCoordinateTransform t( layerCrs, wgs84, project );
79  //transform
80  QgsRectangle BBox;
81  try
82  {
83  BBox = t.transformBoundingBox( layer->extent() );
84  }
85  catch ( QgsCsException &e )
86  {
87  QgsDebugMsg( QStringLiteral( "Transform error caught: %1. Using original layer extent." ).arg( e.what() ) );
88  BBox = layer->extent();
89  }
90  QDomElement lonLatElem = doc.createElement( QStringLiteral( "lonLatEnvelope" ) );
91  lonLatElem.setAttribute( QStringLiteral( "srsName" ), QStringLiteral( "urn:ogc:def:crs:OGC:1.3:CRS84" ) );
92  QDomElement lowerPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
93  QDomText lowerPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.xMinimum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( BBox.yMinimum(), wgs84precision ), wgs84precision ) );
94  lowerPosElem.appendChild( lowerPosText );
95  lonLatElem.appendChild( lowerPosElem );
96  QDomElement upperPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
97  QDomText upperPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.xMaximum(), wgs84precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( BBox.yMaximum(), wgs84precision ), wgs84precision ) );
98  upperPosElem.appendChild( upperPosText );
99  lonLatElem.appendChild( upperPosElem );
100  layerElem.appendChild( lonLatElem );
101 
102  if ( brief )
103  return layerElem;
104 
105  //Defines the spatial-temporal domain set of a coverage offering. The domainSet shall include a SpatialDomain
106  // (describing the spatial locations for which coverages can be requested), a TemporalDomain (describing the
107  // time instants or inter-vals for which coverages can be requested), or both.
108  QDomElement domainSetElem = doc.createElement( QStringLiteral( "domainSet" ) );
109  layerElem.appendChild( domainSetElem );
110 
111  QDomElement spatialDomainElem = doc.createElement( QStringLiteral( "spatialDomain" ) );
112  domainSetElem.appendChild( spatialDomainElem );
113 
114  // Define precision
115  int precision = 3;
116  if ( layer->crs().isGeographic() )
117  {
118  precision = 6;
119  }
120  //create Envelope
121  QgsRectangle layerBBox = layer->extent();
122  QDomElement envelopeElem = doc.createElement( QStringLiteral( "gml:Envelope" ) );
123  envelopeElem.setAttribute( QStringLiteral( "srsName" ), layerCrs.authid() );
124  QDomElement lowerCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
125  QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), wgs84precision ), precision ) );
126  lowerCornerElem.appendChild( lowerCornerText );
127  envelopeElem.appendChild( lowerCornerElem );
128  QDomElement upperCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
129  QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.xMaximum(), precision ), wgs84precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::ceilWithPrecision( layerBBox.yMaximum(), wgs84precision ), precision ) );
130  upperCornerElem.appendChild( upperCornerText );
131  envelopeElem.appendChild( upperCornerElem );
132  spatialDomainElem.appendChild( envelopeElem );
133 
134  QDomElement rectGridElem = doc.createElement( QStringLiteral( "gml:RectifiedGrid" ) );
135  rectGridElem.setAttribute( QStringLiteral( "dimension" ), 2 );
136  QDomElement limitsElem = doc.createElement( QStringLiteral( "gml:limits" ) );
137  rectGridElem.appendChild( limitsElem );
138  QDomElement gridEnvElem = doc.createElement( QStringLiteral( "gml:GridEnvelope" ) );
139  limitsElem.appendChild( gridEnvElem );
140  QDomElement lowElem = doc.createElement( QStringLiteral( "gml:low" ) );
141  QDomText lowText = doc.createTextNode( QStringLiteral( "0 0" ) );
142  lowElem.appendChild( lowText );
143  gridEnvElem.appendChild( lowElem );
144  QDomElement highElem = doc.createElement( QStringLiteral( "gml:high" ) );
145  QDomText highText = doc.createTextNode( QString::number( layer->width() ) + " " + QString::number( layer->height() ) );
146  highElem.appendChild( highText );
147  gridEnvElem.appendChild( highElem );
148  spatialDomainElem.appendChild( rectGridElem );
149 
150  QDomElement xAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
151  QDomText xAxisText = doc.createTextNode( QStringLiteral( "x" ) );
152  xAxisElem.appendChild( xAxisText );
153  rectGridElem.appendChild( xAxisElem );
154 
155  QDomElement yAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
156  QDomText yAxisText = doc.createTextNode( QStringLiteral( "y" ) );
157  yAxisElem.appendChild( yAxisText );
158  rectGridElem.appendChild( yAxisElem );
159 
160  QDomElement originElem = doc.createElement( QStringLiteral( "gml:origin" ) );
161  QDomElement originPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
162  originElem.appendChild( originPosElem );
163  QDomText originPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), precision ), precision ) );
164  originPosElem.appendChild( originPosText );
165  rectGridElem.appendChild( originElem );
166 
167  QDomElement xOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
168  QDomText xOffsetText = doc.createTextNode( QString::number( layer->rasterUnitsPerPixelX() ) + " 0" );
169  xOffsetElem.appendChild( xOffsetText );
170  rectGridElem.appendChild( xOffsetElem );
171 
172  QDomElement yOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
173  QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( layer->rasterUnitsPerPixelY() ) );
174  yOffsetElem.appendChild( yOffsetText );
175  rectGridElem.appendChild( yOffsetElem );
176 
177  //GML property containing one RangeSet GML object.
178  QDomElement rangeSetElem = doc.createElement( QStringLiteral( "rangeSet" ) );
179  layerElem.appendChild( rangeSetElem );
180 
181  //Defines the properties (categories, measures, or values) assigned to each location in the domain. Any such
182  // property may be a scalar (numeric or text) value, such as population density, or a compound (vector or tensor)
183  // value, such as incomes by race, or radiances by wavelength. The semantic of the range set is typically an
184  // observable and is referenced by a URI. A rangeSet also has a reference system that is referred by the URI in
185  // the refSys attribute. The refSys is either qualitative (classification) or quantitative (uom). The three attributes
186  // can be included either here and in each axisDescription. If included in both places, the values in the axisDescription
187  // over-ride those included in the RangeSet.
188  QDomElement RangeSetElem = doc.createElement( QStringLiteral( "RangeSet" ) );
189  rangeSetElem.appendChild( RangeSetElem );
190 
191  QDomElement rsNameElem = doc.createElement( QStringLiteral( "name" ) );
192  QDomText rsNameText = doc.createTextNode( QStringLiteral( "Bands" ) );
193  rsNameElem.appendChild( rsNameText );
194  RangeSetElem.appendChild( rsNameElem );
195 
196  QDomElement rsLabelElem = doc.createElement( QStringLiteral( "label" ) );
197  QDomText rsLabelText = doc.createTextNode( QStringLiteral( "Bands" ) );
198  rsLabelElem.appendChild( rsLabelText );
199  RangeSetElem.appendChild( rsLabelElem );
200 
201  QDomElement axisDescElem = doc.createElement( QStringLiteral( "axisDescription" ) );
202  RangeSetElem.appendChild( axisDescElem );
203 
204  QDomElement AxisDescElem = doc.createElement( QStringLiteral( "AxisDescription" ) );
205  axisDescElem.appendChild( AxisDescElem );
206 
207  QDomElement adNameElem = doc.createElement( QStringLiteral( "name" ) );
208  QDomText adNameText = doc.createTextNode( QStringLiteral( "bands" ) );
209  adNameElem.appendChild( adNameText );
210  AxisDescElem.appendChild( adNameElem );
211 
212  QDomElement adLabelElem = doc.createElement( QStringLiteral( "label" ) );
213  QDomText adLablelText = doc.createTextNode( QStringLiteral( "bands" ) );
214  adLabelElem.appendChild( adLablelText );
215  AxisDescElem.appendChild( adLabelElem );
216 
217  QDomElement adValuesElem = doc.createElement( QStringLiteral( "values" ) );
218  for ( int idx = 0; idx < layer->bandCount(); ++idx )
219  {
220  QDomElement adValueElem = doc.createElement( QStringLiteral( "singleValue" ) );
221  QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) );
222  adValueElem.appendChild( adValueText );
223  adValuesElem.appendChild( adValueElem );
224  }
225  AxisDescElem.appendChild( adValuesElem );
226 
227  //The coordinate reference system(s) in which the server can accept requests against
228  // this coverage offering and produce coverages from it.
229  QDomElement sCRSElem = doc.createElement( QStringLiteral( "supportedCRSs" ) );
230  QDomElement rCRSElem = doc.createElement( QStringLiteral( "requestResponseCRSs" ) );
231  QDomText rCRSText = doc.createTextNode( layerCrs.authid() );
232  rCRSElem.appendChild( rCRSText );
233  sCRSElem.appendChild( rCRSElem );
234  QDomElement nCRSElem = doc.createElement( QStringLiteral( "nativeCRSs" ) );
235  QDomText nCRSText = doc.createTextNode( layerCrs.authid() );
236  nCRSElem.appendChild( nCRSText );
237  sCRSElem.appendChild( nCRSElem );
238  layerElem.appendChild( sCRSElem );
239 
240  //The formats (file encodings) in which the server can produce coverages from this
241  // coverage offering.
242  QDomElement sFormatsElem = doc.createElement( QStringLiteral( "supportedFormats" ) );
243  sFormatsElem.setAttribute( QStringLiteral( "nativeFormat" ), QStringLiteral( "raw binary" ) );
244  QDomElement formatsElem = doc.createElement( QStringLiteral( "formats" ) );
245  QDomText formatsText = doc.createTextNode( QStringLiteral( "GeoTIFF" ) );
246  formatsElem.appendChild( formatsText );
247  sFormatsElem.appendChild( formatsElem );
248  layerElem.appendChild( sFormatsElem );
249 
250  return layerElem;
251  }
252 
253 
254  QString serviceUrl( const QgsServerRequest &request, const QgsProject *project )
255  {
256  static QSet< QString > sFilter
257  {
258  QStringLiteral( "REQUEST" ),
259  QStringLiteral( "VERSION" ),
260  QStringLiteral( "SERVICE" ),
261  QStringLiteral( "_DC" )
262  };
263 
264  QString href;
265  if ( project )
266  {
267  href = QgsServerProjectUtils::wcsServiceUrl( *project );
268  }
269 
270  // Build default url
271  if ( href.isEmpty() )
272  {
273  QUrl url = request.originalUrl();
274  QUrlQuery q( url );
275 
276  for ( auto param : q.queryItems() )
277  {
278  if ( sFilter.contains( param.first.toUpper() ) )
279  q.removeAllQueryItems( param.first );
280  }
281 
282  url.setQuery( q );
283  href = url.toString();
284 
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 QgsWfs
309 
310 
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
QgsRasterLayer::bandCount
int bandCount() const
Returns the number of bands in this layer.
Definition: qgsrasterlayer.cpp:217
qgswcsutils.h
qgsrasterlayer.h
QgsWcs::serviceUrl
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
Definition: qgswcsutils.cpp:254
QgsServerProjectUtils::wcsServiceUrl
SERVER_EXPORT QString wcsServiceUrl(const QgsProject &project)
Returns the WCS service url defined in a QGIS project.
Definition: qgsserverprojectutils.cpp:362
QgsServerProjectUtils::ceilWithPrecision
SERVER_EXPORT double ceilWithPrecision(double number, int places)
Returns a double greater than number to the specified number of places.
Definition: qgsserverprojectutils.cpp:21
QgsCoordinateReferenceSystem::fromOgcWmsCrs
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Definition: qgscoordinatereferencesystem.cpp:200
qgsconfigcache.h
QgsMapLayer::shortName
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.cpp:179
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
qgsserverprojectutils.h
geoEpsgCrsAuthId
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:709
QgsMapLayer::abstract
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:309
qgsmapserviceexception.h
QgsServerRequest
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
Definition: qgsserverrequest.h:39
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:511
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:95
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
precision
int precision
Definition: qgswfsgetfeature.cpp:49
QgsCoordinateReferenceSystem::isGeographic
bool isGeographic
Definition: qgscoordinatereferencesystem.h:210
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
QgsRasterLayer::width
int width() const
Returns the width of the (unclipped) raster.
Definition: qgsrasterlayer.cpp:2448
QgsRasterLayer::height
int height() const
Returns the height of the (unclipped) raster.
Definition: qgsrasterlayer.cpp:2454
QgsMapLayer::extent
virtual QgsRectangle extent() const
Returns the extent of the layer.
Definition: qgsmaplayer.cpp:197
QgsException::what
QString what() const
Definition: qgsexception.h:48
QgsServerProjectUtils::floorWithPrecision
SERVER_EXPORT double floorWithPrecision(double number, int places)
Returns a double less than number to the specified number of places.
Definition: qgsserverprojectutils.cpp:27
QgsCoordinateReferenceSystem::authid
QString authid() const
Returns the authority identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1321
QgsMapLayer::title
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:293
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsRasterLayer
Represents a raster layer.
Definition: qgsrasterlayer.h:71
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsServerRequest::originalUrl
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...
Definition: qgsserverrequest.cpp:70
QgsRasterLayer::rasterUnitsPerPixelY
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
Definition: qgsrasterlayer.cpp:583
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsWcs::implementationVersion
QString implementationVersion()
Returns the highest version supported by this implementation.
Definition: qgswcsutils.cpp:30
QgsWcs::getCoverageOffering
QDomElement getCoverageOffering(QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief)
CoverageOffering or CoverageOfferingBrief element.
Definition: qgswcsutils.cpp:35
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:86
qgsexception.h
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsWcs::parseBbox
QgsRectangle parseBbox(const QString &bboxStr)
Parse bounding box.
Definition: qgswcsutils.cpp:290
qgscoordinatereferencesystem.h
qgsproject.h
QgsWcs
WCS implementation.
Definition: qgswcs.cpp:30
QgsRasterLayer::rasterUnitsPerPixelX
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
Definition: qgsrasterlayer.cpp:567