QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  spatialDomainElem.appendChild( xAxisElem );
154 
155  QDomElement yAxisElem = doc.createElement( QStringLiteral( "gml:axisName" ) );
156  QDomText yAxisText = doc.createTextNode( QStringLiteral( "y" ) );
157  yAxisElem.appendChild( yAxisText );
158  spatialDomainElem.appendChild( yAxisElem );
159 
160  QDomElement originElem = doc.createElement( QStringLiteral( "gml:origin" ) );
161  QDomElement originPosElem = doc.createElement( QStringLiteral( "gml:pos" ) );
162  QDomText originPosText = doc.createTextNode( qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.xMinimum(), precision ), precision ) + " " + qgsDoubleToString( QgsServerProjectUtils::floorWithPrecision( layerBBox.yMinimum(), precision ), precision ) );
163  originPosElem.appendChild( originPosText );
164  spatialDomainElem.appendChild( originElem );
165 
166  QDomElement xOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
167  QDomText xOffsetText = doc.createTextNode( QString::number( layer->rasterUnitsPerPixelX() ) + " 0" );
168  xOffsetElem.appendChild( xOffsetText );
169  spatialDomainElem.appendChild( xOffsetElem );
170 
171  QDomElement yOffsetElem = doc.createElement( QStringLiteral( "gml:offsetVector" ) );
172  QDomText yOffsetText = doc.createTextNode( "0 " + QString::number( layer->rasterUnitsPerPixelY() ) );
173  yOffsetElem.appendChild( yOffsetText );
174  spatialDomainElem.appendChild( yOffsetElem );
175 
176  //GML property containing one RangeSet GML object.
177  QDomElement rangeSetElem = doc.createElement( QStringLiteral( "rangeSet" ) );
178  layerElem.appendChild( rangeSetElem );
179 
180  //Defines the properties (categories, measures, or values) assigned to each location in the domain. Any such
181  // property may be a scalar (numeric or text) value, such as population density, or a compound (vector or tensor)
182  // value, such as incomes by race, or radiances by wavelength. The semantic of the range set is typically an
183  // observable and is referenced by a URI. A rangeSet also has a reference system that is referred by the URI in
184  // the refSys attribute. The refSys is either qualitative (classification) or quantitative (uom). The three attributes
185  // can be included either here and in each axisDescription. If included in both places, the values in the axisDescription
186  // over-ride those included in the RangeSet.
187  QDomElement RangeSetElem = doc.createElement( QStringLiteral( "RangeSet" ) );
188  rangeSetElem.appendChild( RangeSetElem );
189 
190  QDomElement rsNameElem = doc.createElement( QStringLiteral( "name" ) );
191  QDomText rsNameText = doc.createTextNode( QStringLiteral( "Bands" ) );
192  rsNameElem.appendChild( rsNameText );
193  RangeSetElem.appendChild( rsNameElem );
194 
195  QDomElement axisDescElem = doc.createElement( QStringLiteral( "axisDescription" ) );
196  RangeSetElem.appendChild( axisDescElem );
197 
198  QDomElement AxisDescElem = doc.createElement( QStringLiteral( "AxisDescription" ) );
199  axisDescElem.appendChild( AxisDescElem );
200 
201  QDomElement adNameElem = doc.createElement( QStringLiteral( "name" ) );
202  QDomText adNameText = doc.createTextNode( QStringLiteral( "bands" ) );
203  adNameElem.appendChild( adNameText );
204  AxisDescElem.appendChild( adNameElem );
205 
206  QDomElement adValuesElem = doc.createElement( QStringLiteral( "values" ) );
207  for ( int idx = 0; idx < layer->bandCount(); ++idx )
208  {
209  QDomElement adValueElem = doc.createElement( QStringLiteral( "value" ) );
210  QDomText adValueText = doc.createTextNode( QString::number( idx + 1 ) );
211  adValueElem.appendChild( adValueText );
212  adValuesElem.appendChild( adValueElem );
213  }
214  AxisDescElem.appendChild( adValuesElem );
215 
216  //The coordinate reference system(s) in which the server can accept requests against
217  // this coverage offering and produce coverages from it.
218  QDomElement sCRSElem = doc.createElement( QStringLiteral( "supportedCRSs" ) );
219  QDomElement rCRSElem = doc.createElement( QStringLiteral( "requestResponseCRSs" ) );
220  QDomText rCRSText = doc.createTextNode( layerCrs.authid() );
221  rCRSElem.appendChild( rCRSText );
222  sCRSElem.appendChild( rCRSElem );
223  QDomElement nCRSElem = doc.createElement( QStringLiteral( "nativeCRSs" ) );
224  QDomText nCRSText = doc.createTextNode( layerCrs.authid() );
225  nCRSElem.appendChild( nCRSText );
226  sCRSElem.appendChild( nCRSElem );
227  layerElem.appendChild( sCRSElem );
228 
229  //The formats (file encodings) in which the server can produce coverages from this
230  // coverage offering.
231  QDomElement sFormatsElem = doc.createElement( QStringLiteral( "supportedFormats" ) );
232  sFormatsElem.setAttribute( QStringLiteral( "nativeFormat" ), QStringLiteral( "raw binary" ) );
233  QDomElement formatsElem = doc.createElement( QStringLiteral( "formats" ) );
234  QDomText formatsText = doc.createTextNode( QStringLiteral( "GeoTIFF" ) );
235  formatsElem.appendChild( formatsText );
236  sFormatsElem.appendChild( formatsElem );
237  layerElem.appendChild( sFormatsElem );
238 
239  return layerElem;
240  }
241 
242 
243  QString serviceUrl( const QgsServerRequest &request, const QgsProject *project )
244  {
245  static QSet< QString > sFilter
246  {
247  QStringLiteral( "REQUEST" ),
248  QStringLiteral( "VERSION" ),
249  QStringLiteral( "SERVICE" ),
250  QStringLiteral( "_DC" )
251  };
252 
253  QString href;
254  if ( project )
255  {
256  href = QgsServerProjectUtils::wcsServiceUrl( *project );
257  }
258 
259  // Build default url
260  if ( href.isEmpty() )
261  {
262  QUrl url = request.originalUrl();
263  QUrlQuery q( url );
264 
265  for ( auto param : q.queryItems() )
266  {
267  if ( sFilter.contains( param.first.toUpper() ) )
268  q.removeAllQueryItems( param.first );
269  }
270 
271  url.setQuery( q );
272  href = url.toString();
273 
274  }
275 
276  return href;
277  }
278 
279  QgsRectangle parseBbox( const QString &bboxStr )
280  {
281  QStringList lst = bboxStr.split( ',' );
282  if ( lst.count() != 4 )
283  return QgsRectangle();
284 
285  double d[4];
286  bool ok;
287  for ( int i = 0; i < 4; i++ )
288  {
289  lst[i].replace( ' ', '+' );
290  d[i] = lst[i].toDouble( &ok );
291  if ( !ok )
292  return QgsRectangle();
293  }
294  return QgsRectangle( d[0], d[1], d[2], d[3] );
295  }
296 
297 } // namespace QgsWfs
298 
299 
int precision
A rectangle specified with double values.
Definition: qgsrectangle.h:40
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:257
QgsRectangle parseBbox(const QString &bboxStr)
Parse bounding box.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
#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 title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:272
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
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...
int height() const
Returns the height of the (unclipped) raster.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
int bandCount() const
Returns the number of bands in this layer.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:238
SERVER_EXPORT double floorWithPrecision(double number, int places)
Returns a double less than number to the specified number of places.
Reads and writes project states.
Definition: qgsproject.h:89
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
Definition: qgis.cpp:69
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:288
SERVER_EXPORT double ceilWithPrecision(double number, int places)
Returns a double greater than number to the specified number of places.
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
QString what() const
Definition: qgsexception.h:48
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.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
This class represents a coordinate reference system (CRS).
QString authid() const
Returns the authority identifier for the CRS.
Class for doing transforms between two map coordinate systems.
QString name
Definition: qgsmaplayer.h:67
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
WCS implementation.
Definition: qgswcs.cpp:29
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
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:70
int width() const
Returns the width of the (unclipped) raster.