QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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();
76  QgsCoordinateTransform t( layerCrs, QgsCoordinateReferenceSystem( 4326 ), project );
77  //transform
78  QgsRectangle BBox;
79  try
80  {
81  BBox = t.transformBoundingBox( layer->extent() );
82  }
83  catch ( QgsCsException &e )
84  {
85  QgsDebugMsg( QStringLiteral( "Transform error caught: %1. Using original layer extent." ).arg( e.what() ) );
86  BBox = layer->extent();
87  }
88  QDomElement lonLatElem = doc.createElement( QStringLiteral( "lonLatEnvelope" ) );
89  lonLatElem.setAttribute( QStringLiteral( "srsName" ), QStringLiteral( "urn:ogc:def:crs:OGC:1.3:CRS84" ) );
90  QDomElement lowerPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
91  QDomText lowerPosText = doc.createTextNode( QString::number( BBox.xMinimum() ) + " " + QString::number( BBox.yMinimum() ) );
92  lowerPosElem.appendChild( lowerPosText );
93  lonLatElem.appendChild( lowerPosElem );
94  QDomElement upperPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
95  QDomText upperPosText = doc.createTextNode( QString::number( BBox.xMaximum() ) + " " + QString::number( BBox.yMaximum() ) );
96  upperPosElem.appendChild( upperPosText );
97  lonLatElem.appendChild( upperPosElem );
98  layerElem.appendChild( lonLatElem );
99 
100  if ( brief )
101  return layerElem;
102 
103  //Defines the spatial-temporal domain set of a coverage offering. The domainSet shall include a SpatialDomain
104  // (describing the spatial locations for which coverages can be requested), a TemporalDomain (describing the
105  // time instants or inter-vals for which coverages can be requested), or both.
106  QDomElement domainSetElem = doc.createElement( QStringLiteral( "domainSet" ) );
107  layerElem.appendChild( domainSetElem );
108 
109  QDomElement spatialDomainElem = doc.createElement( QStringLiteral( "spatialDomain" ) );
110  domainSetElem.appendChild( spatialDomainElem );
111 
112  QgsRectangle layerBBox = layer->extent();
113  QDomElement envelopeElem = doc.createElement( QStringLiteral( "gml:Envelope" ) );
114  envelopeElem.setAttribute( QStringLiteral( "srsName" ), layerCrs.authid() );
115  QDomElement lowerCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
116  QDomText lowerCornerText = doc.createTextNode( QString::number( layerBBox.xMinimum() ) + " " + QString::number( layerBBox.yMinimum() ) );
117  lowerCornerElem.appendChild( lowerCornerText );
118  envelopeElem.appendChild( lowerCornerElem );
119  QDomElement upperCornerElem = doc.createElement( QStringLiteral( "gml:pos" ) );
120  QDomText upperCornerText = doc.createTextNode( QString::number( layerBBox.xMaximum() ) + " " + QString::number( layerBBox.yMaximum() ) );
121  upperCornerElem.appendChild( upperCornerText );
122  envelopeElem.appendChild( upperCornerElem );
123  spatialDomainElem.appendChild( envelopeElem );
124 
125  QDomElement rectGridElem = doc.createElement( QStringLiteral( "gml:RectifiedGrid" ) );
126  rectGridElem.setAttribute( QStringLiteral( "dimension" ), 2 );
127  QDomElement limitsElem = doc.createElement( QStringLiteral( "gml:limits" ) );
128  rectGridElem.appendChild( limitsElem );
129  QDomElement gridEnvElem = doc.createElement( QStringLiteral( "gml:GridEnvelope" ) );
130  limitsElem.appendChild( gridEnvElem );
131  QDomElement lowElem = doc.createElement( QStringLiteral( "gml:low" ) );
132  QDomText lowText = doc.createTextNode( QStringLiteral( "0 0" ) );
133  lowElem.appendChild( lowText );
134  gridEnvElem.appendChild( lowElem );
135  QDomElement highElem = doc.createElement( QStringLiteral( "gml:high" ) );
136  QDomText highText = doc.createTextNode( QString::number( layer->width() ) + " " + QString::number( layer->height() ) );
137  highElem.appendChild( highText );
138  gridEnvElem.appendChild( highElem );
139  spatialDomainElem.appendChild( rectGridElem );
140 
141  QDomElement xAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
142  QDomText xAxisText = doc.createTextNode( QStringLiteral( "x" ) );
143  xAxisElem.appendChild( xAxisText );
144  spatialDomainElem.appendChild( xAxisElem );
145 
146  QDomElement yAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
147  QDomText yAxisText = doc.createTextNode( QStringLiteral( "y" ) );
148  yAxisElem.appendChild( yAxisText );
149  spatialDomainElem.appendChild( yAxisElem );
150 
151  QDomElement originElem = doc.createElement( QStringLiteral( "gml:origin" ) );
152  QDomElement originPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
153  QDomText originPosText = doc.createTextNode( QString::number( layerBBox.xMinimum() ) + " " + QString::number( layerBBox.yMaximum() ) );
154  originPosElem.appendChild( originPosText );
155  spatialDomainElem.appendChild( originElem );
156 
157  QDomElement xOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
158  QDomText xOffsetText = doc.createTextNode( QString::number( layer->rasterUnitsPerPixelX() ) + " 0" );
159  xOffsetElem.appendChild( xOffsetText );
160  spatialDomainElem.appendChild( xOffsetElem );
161 
162  QDomElement yOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
163  QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( layer->rasterUnitsPerPixelY() ) );
164  yOffsetElem.appendChild( yOffsetText );
165  spatialDomainElem.appendChild( yOffsetElem );
166 
167  //GML property containing one RangeSet GML object.
168  QDomElement rangeSetElem = doc.createElement( QStringLiteral( "rangeSet" ) );
169  layerElem.appendChild( rangeSetElem );
170 
171  //Defines the properties (categories, measures, or values) assigned to each location in the domain. Any such
172  // property may be a scalar (numeric or text) value, such as population density, or a compound (vector or tensor)
173  // value, such as incomes by race, or radiances by wavelength. The semantic of the range set is typically an
174  // observable and is referenced by a URI. A rangeSet also has a reference system that is referred by the URI in
175  // the refSys attribute. The refSys is either qualitative (classification) or quantitative (uom). The three attributes
176  // can be included either here and in each axisDescription. If included in both places, the values in the axisDescription
177  // over-ride those included in the RangeSet.
178  QDomElement RangeSetElem = doc.createElement( QStringLiteral( "RangeSet" ) );
179  rangeSetElem.appendChild( RangeSetElem );
180 
181  QDomElement rsNameElem = doc.createElement( QStringLiteral( "name" ) );
182  QDomText rsNameText = doc.createTextNode( QStringLiteral( "Bands" ) );
183  rsNameElem.appendChild( rsNameText );
184  RangeSetElem.appendChild( rsNameElem );
185 
186  QDomElement axisDescElem = doc.createElement( QStringLiteral( "axisDescription" ) );
187  RangeSetElem.appendChild( axisDescElem );
188 
189  QDomElement AxisDescElem = doc.createElement( QStringLiteral( "AxisDescription" ) );
190  axisDescElem.appendChild( AxisDescElem );
191 
192  QDomElement adNameElem = doc.createElement( QStringLiteral( "name" ) );
193  QDomText adNameText = doc.createTextNode( QStringLiteral( "bands" ) );
194  adNameElem.appendChild( adNameText );
195  AxisDescElem.appendChild( adNameElem );
196 
197  QDomElement adValuesElem = doc.createElement( QStringLiteral( "values" ) );
198  for ( int idx = 0; idx < layer->bandCount(); ++idx )
199  {
200  QDomElement adValueElem = doc.createElement( QStringLiteral( "value" ) );
201  QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) );
202  adValueElem.appendChild( adValueText );
203  adValuesElem.appendChild( adValueElem );
204  }
205  AxisDescElem.appendChild( adValuesElem );
206 
207  //The coordinate reference system(s) in which the server can accept requests against
208  // this coverage offering and produce coverages from it.
209  QDomElement sCRSElem = doc.createElement( QStringLiteral( "supportedCRSs" ) );
210  QDomElement rCRSElem = doc.createElement( QStringLiteral( "requestResponseCRSs" ) );
211  QDomText rCRSText = doc.createTextNode( layerCrs.authid() );
212  rCRSElem.appendChild( rCRSText );
213  sCRSElem.appendChild( rCRSElem );
214  QDomElement nCRSElem = doc.createElement( QStringLiteral( "nativeCRSs" ) );
215  QDomText nCRSText = doc.createTextNode( layerCrs.authid() );
216  nCRSElem.appendChild( nCRSText );
217  sCRSElem.appendChild( nCRSElem );
218  layerElem.appendChild( sCRSElem );
219 
220  //The formats (file encodings) in which the server can produce coverages from this
221  // coverage offering.
222  QDomElement sFormatsElem = doc.createElement( QStringLiteral( "supportedFormats" ) );
223  sFormatsElem.setAttribute( QStringLiteral( "nativeFormat" ), QStringLiteral( "raw binary" ) );
224  QDomElement formatsElem = doc.createElement( QStringLiteral( "formats" ) );
225  QDomText formatsText = doc.createTextNode( QStringLiteral( "GeoTIFF" ) );
226  formatsElem.appendChild( formatsText );
227  sFormatsElem.appendChild( formatsElem );
228  layerElem.appendChild( sFormatsElem );
229 
230  return layerElem;
231  }
232 
233 
234  QString serviceUrl( const QgsServerRequest &request, const QgsProject *project )
235  {
236  static QSet< QString > sFilter
237  {
238  QStringLiteral( "REQUEST" ),
239  QStringLiteral( "VERSION" ),
240  QStringLiteral( "SERVICE" ),
241  QStringLiteral( "_DC" )
242  };
243 
244  QString href;
245  if ( project )
246  {
247  href = QgsServerProjectUtils::wcsServiceUrl( *project );
248  }
249 
250  // Build default url
251  if ( href.isEmpty() )
252  {
253  QUrl url = request.originalUrl();
254  QUrlQuery q( url );
255 
256  for ( auto param : q.queryItems() )
257  {
258  if ( sFilter.contains( param.first.toUpper() ) )
259  q.removeAllQueryItems( param.first );
260  }
261 
262  url.setQuery( q );
263  href = url.toString();
264 
265  }
266 
267  return href;
268  }
269 
270  QgsRectangle parseBbox( const QString &bboxStr )
271  {
272  QStringList lst = bboxStr.split( ',' );
273  if ( lst.count() != 4 )
274  return QgsRectangle();
275 
276  double d[4];
277  bool ok;
278  for ( int i = 0; i < 4; i++ )
279  {
280  lst[i].replace( ' ', '+' );
281  d[i] = lst[i].toDouble( &ok );
282  if ( !ok )
283  return QgsRectangle();
284  }
285  return QgsRectangle( d[0], d[1], d[2], d[3] );
286  }
287 
288 } // namespace QgsWfs
289 
290 
int width() const
Returns the width of the (unclipped) raster.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsRectangle parseBbox(const QString &bboxStr)
Parse bounding box.
int bandCount() const
Returns the number of bands in this layer.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:263
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:294
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int height() const
Returns the height of the (unclipped) raster.
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...
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString what() const
Definition: qgsexception.h:48
Reads and writes project states.
Definition: qgsproject.h:89
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:278
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
QString implementationVersion()
Returns the highest version supported by this implementation.
Definition: qgswcsutils.cpp:30
QDomElement getCoverageOffering(QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief)
CoverageOffering or CoverageOfferingBrief element.
Definition: qgswcsutils.cpp:35
SERVER_EXPORT QString wcsServiceUrl(const QgsProject &project)
Returns the WCS service url defined in a QGIS project.
This class represents a coordinate reference system (CRS).
Class for doing transforms between two map coordinate systems.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QString name
Definition: qgsmaplayer.h:82
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
WCS implementation.
Definition: qgswcs.cpp:29
QString authid() const
Returns the authority identifier for the CRS.
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.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:85