QGIS API Documentation  3.23.0-Master (22c16f2067)
qgsrasterdataprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterdataprovider.cpp - DataProvider Interface for raster layers
3  --------------------------------------
4  Date : Mar 11, 2005
5  Copyright : (C) 2005 by Brendan Morley
6  email : morb at ozemail dot com dot au
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 "qgsproviderregistry.h"
19 #include "qgsrasterdataprovider.h"
21 #include "qgsprovidermetadata.h"
22 #include "qgsrasterprojector.h"
23 #include "qgslogger.h"
24 #include "qgsmessagelog.h"
25 #include "qgsapplication.h"
26 #include "qgspoint.h"
27 
28 #include <QTime>
29 #include <QMap>
30 #include <QByteArray>
31 #include <QVariant>
32 
33 #include <QUrl>
34 #include <QUrlQuery>
35 #include <QSet>
36 
37 #define ERR(message) QgsError(message, "Raster provider")
38 
40 {
41  if ( mUseSrcNoDataValue.size() < bandNo )
42  {
43  for ( int i = mUseSrcNoDataValue.size(); i < bandNo; i++ )
44  {
45  mUseSrcNoDataValue.append( false );
46  }
47  }
48  mUseSrcNoDataValue[bandNo - 1] = use;
49 }
50 
51 QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback )
52 {
53  QgsDebugMsgLevel( QStringLiteral( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ), 4 );
54  QgsDebugMsgLevel( QStringLiteral( "boundingBox = %1" ).arg( boundingBox.toString() ), 4 );
55 
56  std::unique_ptr< QgsRasterBlock > block = std::make_unique< QgsRasterBlock >( dataType( bandNo ), width, height );
57  if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
58  {
60  }
61 
62  if ( block->isEmpty() )
63  {
64  QgsDebugMsg( QStringLiteral( "Couldn't create raster block" ) );
65  block->setError( { tr( "Couldn't create raster block." ), QStringLiteral( "Raster" ) } );
66  block->setValid( false );
67  return block.release();
68  }
69 
70  // Read necessary extent only
71  QgsRectangle tmpExtent = boundingBox;
72 
73  if ( tmpExtent.isEmpty() )
74  {
75  QgsDebugMsg( QStringLiteral( "Extent outside provider extent" ) );
76  block->setError( { tr( "Extent outside provider extent." ), QStringLiteral( "Raster" ) } );
77  block->setValid( false );
78  block->setIsNoData();
79  return block.release();
80  }
81 
82  const double xRes = boundingBox.width() / width;
83  const double yRes = boundingBox.height() / height;
84  double tmpXRes, tmpYRes;
85  double providerXRes = 0;
86  double providerYRes = 0;
87  if ( capabilities() & Size )
88  {
89  providerXRes = extent().width() / xSize();
90  providerYRes = extent().height() / ySize();
91  tmpXRes = std::max( providerXRes, xRes );
92  tmpYRes = std::max( providerYRes, yRes );
93  if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes;
94  if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes;
95  }
96  else
97  {
98  tmpXRes = xRes;
99  tmpYRes = yRes;
100  }
101 
102  if ( tmpExtent != boundingBox ||
103  tmpXRes > xRes || tmpYRes > yRes )
104  {
105  // Read smaller extent or lower resolution
106 
107  if ( !extent().contains( boundingBox ) )
108  {
109  const QRect subRect = QgsRasterBlock::subRect( boundingBox, width, height, extent() );
110  block->setIsNoDataExcept( subRect );
111  }
112 
113  // Calculate row/col limits (before tmpExtent is aligned)
114  const int fromRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMaximum() ) / yRes );
115  const int toRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1;
116  const int fromCol = std::round( ( tmpExtent.xMinimum() - boundingBox.xMinimum() ) / xRes );
117  const int toCol = std::round( ( tmpExtent.xMaximum() - boundingBox.xMinimum() ) / xRes ) - 1;
118 
119  QgsDebugMsgLevel( QStringLiteral( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ), 4 );
120 
121  if ( fromRow < 0 || fromRow >= height || toRow < 0 || toRow >= height ||
122  fromCol < 0 || fromCol >= width || toCol < 0 || toCol >= width )
123  {
124  // Should not happen
125  QgsDebugMsg( QStringLiteral( "Row or column limits out of range" ) );
126  block->setError( { tr( "Row or column limits out of range" ), QStringLiteral( "Raster" ) } );
127  block->setValid( false );
128  return block.release();
129  }
130 
131  // If lower source resolution is used, the extent must be aligned to original
132  // resolution to avoid possible shift due to resampling
133  if ( tmpXRes > xRes )
134  {
135  int col = std::floor( ( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes );
136  tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes );
137  col = std::ceil( ( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes );
138  tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes );
139  }
140  if ( tmpYRes > yRes )
141  {
142  int row = std::floor( ( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes );
143  tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes );
144  row = std::ceil( ( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes );
145  tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes );
146  }
147  const int tmpWidth = std::round( tmpExtent.width() / tmpXRes );
148  const int tmpHeight = std::round( tmpExtent.height() / tmpYRes );
149  tmpXRes = tmpExtent.width() / tmpWidth;
150  tmpYRes = tmpExtent.height() / tmpHeight;
151 
152  QgsDebugMsgLevel( QStringLiteral( "Reading smaller block tmpWidth = %1 height = %2" ).arg( tmpWidth ).arg( tmpHeight ), 4 );
153  QgsDebugMsgLevel( QStringLiteral( "tmpExtent = %1" ).arg( tmpExtent.toString() ), 4 );
154 
155  std::unique_ptr< QgsRasterBlock > tmpBlock = std::make_unique< QgsRasterBlock >( dataType( bandNo ), tmpWidth, tmpHeight );
156  if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
157  {
158  tmpBlock->setNoDataValue( sourceNoDataValue( bandNo ) );
159  }
160 
161  if ( !readBlock( bandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits(), feedback ) )
162  {
163  QgsDebugMsg( QStringLiteral( "Error occurred while reading block" ) );
164  block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
165  block->setValid( false );
166  block->setIsNoData();
167  return block.release();
168  }
169 
170  const int pixelSize = dataTypeSize( bandNo );
171 
172  const double xMin = boundingBox.xMinimum();
173  const double yMax = boundingBox.yMaximum();
174  const double tmpXMin = tmpExtent.xMinimum();
175  const double tmpYMax = tmpExtent.yMaximum();
176 
177  for ( int row = fromRow; row <= toRow; row++ )
178  {
179  const double y = yMax - ( row + 0.5 ) * yRes;
180  const int tmpRow = std::floor( ( tmpYMax - y ) / tmpYRes );
181 
182  for ( int col = fromCol; col <= toCol; col++ )
183  {
184  const double x = xMin + ( col + 0.5 ) * xRes;
185  const int tmpCol = std::floor( ( x - tmpXMin ) / tmpXRes );
186 
187  if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth )
188  {
189  QgsDebugMsg( QStringLiteral( "Source row or column limits out of range" ) );
190  block->setIsNoData(); // so that the problem becomes obvious and fixed
191  block->setError( { tr( "Source row or column limits out of range." ), QStringLiteral( "Raster" ) } );
192  block->setValid( false );
193  return block.release();
194  }
195 
196  const qgssize tmpIndex = static_cast< qgssize >( tmpRow ) * static_cast< qgssize >( tmpWidth ) + tmpCol;
197  const qgssize index = row * static_cast< qgssize >( width ) + col;
198 
199  char *tmpBits = tmpBlock->bits( tmpIndex );
200  char *bits = block->bits( index );
201  if ( !tmpBits )
202  {
203  QgsDebugMsg( QStringLiteral( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) );
204  continue;
205  }
206  if ( !bits )
207  {
208  QgsDebugMsg( QStringLiteral( "Cannot set output block data." ) );
209  continue;
210  }
211  memcpy( bits, tmpBits, pixelSize );
212  }
213  }
214  }
215  else
216  {
217  if ( !readBlock( bandNo, boundingBox, width, height, block->bits(), feedback ) )
218  {
219  QgsDebugMsg( QStringLiteral( "Error occurred while reading block" ) );
220  block->setIsNoData();
221  block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
222  block->setValid( false );
223  return block.release();
224  }
225  }
226 
227  // apply scale and offset
228  block->applyScaleOffset( bandScale( bandNo ), bandOffset( bandNo ) );
229  // apply user no data values
231  return block.release();
232 }
233 
235  : QgsDataProvider( QString(), QgsDataProvider::ProviderOptions(), QgsDataProvider::ReadFlags() )
236  , QgsRasterInterface( nullptr )
237  , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
238 {
239 
240 }
241 
243  QgsDataProvider::ReadFlags flags )
244  : QgsDataProvider( uri, options, flags )
245  , QgsRasterInterface( nullptr )
246  , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
247 {
248 }
249 
250 QgsRasterDataProvider::ProviderCapabilities QgsRasterDataProvider::providerCapabilities() const
251 {
253 }
254 
256 {
257  Q_UNUSED( bandNo )
259 }
260 
261 //
262 //Random Static convenience function
263 //
265 
266 // TODO
267 // (WMS) IdentifyFormatFeature is not consistent with QgsRaster::IdentifyFormatValue.
268 // IdentifyFormatHtml: better error reporting
269 QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ )
270 {
271  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
272  QMap<int, QVariant> results;
273 
274  if ( format != QgsRaster::IdentifyFormatValue || !( capabilities() & IdentifyValue ) )
275  {
276  QgsDebugMsg( QStringLiteral( "Format not supported" ) );
277  return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) );
278  }
279 
280  if ( !extent().contains( point ) )
281  {
282  // Outside the raster
283  for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
284  {
285  results.insert( bandNo, QVariant() );
286  }
288  }
289 
290  QgsRectangle finalExtent = boundingBox;
291  if ( finalExtent.isEmpty() )
292  finalExtent = extent();
293 
294  if ( width == 0 )
295  {
296  width = capabilities() & Size ? xSize() : 1000;
297  }
298  if ( height == 0 )
299  {
300  height = capabilities() & Size ? ySize() : 1000;
301  }
302 
303  // Calculate the row / column where the point falls
304  const double xres = ( finalExtent.width() ) / width;
305  const double yres = ( finalExtent.height() ) / height;
306 
307  const int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) );
308  const int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) );
309 
310  const double xMin = finalExtent.xMinimum() + col * xres;
311  const double xMax = xMin + xres;
312  const double yMax = finalExtent.yMaximum() - row * yres;
313  const double yMin = yMax - yres;
314  const QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
315 
316  for ( int i = 1; i <= bandCount(); i++ )
317  {
318  std::unique_ptr< QgsRasterBlock > bandBlock( block( i, pixelExtent, 1, 1 ) );
319 
320  if ( bandBlock )
321  {
322  const double value = bandBlock->value( 0 );
323 
324  results.insert( i, value );
325  }
326  else
327  {
328  results.insert( i, QVariant() );
329  }
330  }
332 }
333 
334 double QgsRasterDataProvider::sample( const QgsPointXY &point, int band,
335  bool *ok, const QgsRectangle &boundingBox, int width, int height, int dpi )
336 {
337  if ( ok )
338  *ok = false;
339 
340  const auto res = identify( point, QgsRaster::IdentifyFormatValue, boundingBox, width, height, dpi );
341  const QVariant value = res.results().value( band );
342 
343  if ( !value.isValid() )
344  return std::numeric_limits<double>::quiet_NaN();
345 
346  if ( ok )
347  *ok = true;
348 
349  return value.toDouble( ok );
350 }
351 
353 {
354  return QStringLiteral( "text/plain" );
355 }
356 
357 bool QgsRasterDataProvider::writeBlock( QgsRasterBlock *block, int band, int xOffset, int yOffset )
358 {
359  if ( !block )
360  return false;
361  if ( !isEditable() )
362  {
363  QgsDebugMsg( QStringLiteral( "writeBlock() called on read-only provider." ) );
364  return false;
365  }
366  return write( block->bits(), band, block->width(), block->height(), xOffset, yOffset );
367 }
368 
369 // typedef QList<QPair<QString, QString> > *pyramidResamplingMethods_t();
370 QList<QPair<QString, QString> > QgsRasterDataProvider::pyramidResamplingMethods( const QString &providerKey )
371 {
372  QList<QPair<QString, QString> > methods = QgsProviderRegistry::instance()->pyramidResamplingMethods( providerKey );
373  if ( methods.isEmpty() )
374  {
375  QgsDebugMsg( QStringLiteral( "provider pyramidResamplingMethods returned no methods" ) );
376  }
377  return methods;
378 }
379 
381 {
382  const QList<QgsRasterPyramid> pyramidList = buildPyramidList();
383  return std::any_of( pyramidList.constBegin(), pyramidList.constEnd(), []( QgsRasterPyramid pyramid ) { return pyramid.getExists(); } );
384 }
385 
387 {
388  if ( bandNo >= mUserNoDataValue.size() )
389  {
390  for ( int i = mUserNoDataValue.size(); i < bandNo; i++ )
391  {
393  }
394  }
395  QgsDebugMsgLevel( QStringLiteral( "set %1 band %1 no data ranges" ).arg( noData.size() ), 4 );
396 
397  if ( mUserNoDataValue[bandNo - 1] != noData )
398  {
399  // Clear statistics
400  mStatistics.erase( std::remove_if( mStatistics.begin(), mStatistics.end(), [bandNo]( const QgsRasterBandStats & stats )
401  {
402  return stats.bandNumber == bandNo;
403  } ), mStatistics.end() );
404  mHistograms.erase( std::remove_if( mHistograms.begin(), mHistograms.end(), [bandNo]( const QgsRasterHistogram & histogram )
405  {
406  return histogram.bandNumber == bandNo;
407  } ), mHistograms.end() );
408  mUserNoDataValue[bandNo - 1] = noData;
409  }
410 }
411 
413 {
414  return mTemporalCapabilities.get();
415 }
416 
418 {
419  return mTemporalCapabilities.get();
420 }
421 
423  const QString &uri,
424  const QString &format, int nBands,
425  Qgis::DataType type,
426  int width, int height, double *geoTransform,
428  const QStringList &createOptions )
429 {
431  providerKey,
432  uri, format,
433  nBands, type, width,
434  height, geoTransform, crs, createOptions );
435  if ( !ret )
436  {
437  QgsDebugMsg( "Cannot resolve 'createRasterDataProviderFunction' function in " + providerKey + " provider" );
438  }
439 
440  // TODO: it would be good to return invalid QgsRasterDataProvider
441  // with QgsError set, but QgsRasterDataProvider has pure virtual methods
442 
443  return ret;
444 }
445 
447 {
448  switch ( format )
449  {
451  return QStringLiteral( "Value" );
453  return QStringLiteral( "Text" );
455  return QStringLiteral( "Html" );
457  return QStringLiteral( "Feature" );
458  default:
459  return QStringLiteral( "Undefined" );
460  }
461 }
462 
464 {
465  switch ( format )
466  {
468  return tr( "Value" );
470  return tr( "Text" );
472  return tr( "Html" );
474  return tr( "Feature" );
475  default:
476  return QStringLiteral( "Undefined" );
477  }
478 }
479 
481 {
482  if ( formatName == QLatin1String( "Value" ) ) return QgsRaster::IdentifyFormatValue;
483  if ( formatName == QLatin1String( "Text" ) ) return QgsRaster::IdentifyFormatText;
484  if ( formatName == QLatin1String( "Html" ) ) return QgsRaster::IdentifyFormatHtml;
485  if ( formatName == QLatin1String( "Feature" ) ) return QgsRaster::IdentifyFormatFeature;
487 }
488 
490 {
491  switch ( format )
492  {
494  return IdentifyValue;
496  return IdentifyText;
498  return IdentifyHtml;
500  return IdentifyFeature;
501  default:
502  return NoCapabilities;
503  }
504 }
505 
507 {
508  return QList< double >();
509 }
510 
512 {
513  return false;
514 }
515 
517 {
518  Q_UNUSED( point )
519  Q_UNUSED( type )
520  return QgsPoint();
521 }
522 
523 bool QgsRasterDataProvider::userNoDataValuesContains( int bandNo, double value ) const
524 {
525  const QgsRasterRangeList rangeList = mUserNoDataValue.value( bandNo - 1 );
526  return QgsRasterRange::contains( value, rangeList );
527 }
528 
530 {
531  mDpi = other.mDpi;
536  mExtent = other.mExtent;
541 
542  // copy temporal properties
543  if ( mTemporalCapabilities && other.mTemporalCapabilities )
544  {
545  *mTemporalCapabilities = *other.mTemporalCapabilities;
546  }
547 }
548 
549 static QgsRasterDataProvider::ResamplingMethod resamplingMethodFromString( const QString &str )
550 {
551  if ( str == QLatin1String( "bilinear" ) )
552  {
554  }
555  else if ( str == QLatin1String( "cubic" ) )
556  {
558  }
559  else if ( str == QLatin1String( "cubicSpline" ) )
560  {
562  }
563  else if ( str == QLatin1String( "lanczos" ) )
564  {
566  }
567  else if ( str == QLatin1String( "average" ) )
568  {
570  }
571  else if ( str == QLatin1String( "mode" ) )
572  {
574  }
575  else if ( str == QLatin1String( "gauss" ) )
576  {
578  }
580 }
581 
582 void QgsRasterDataProvider::readXml( const QDomElement &filterElem )
583 {
584  if ( filterElem.isNull() )
585  {
586  return;
587  }
588 
589  const QDomElement resamplingElement = filterElem.firstChildElement( QStringLiteral( "resampling" ) );
590  if ( !resamplingElement.isNull() )
591  {
592  setMaxOversampling( resamplingElement.attribute( QStringLiteral( "maxOversampling" ), QStringLiteral( "2.0" ) ).toDouble() );
593  setZoomedInResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedInResamplingMethod" ) ) ) );
594  setZoomedOutResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedOutResamplingMethod" ) ) ) );
595  enableProviderResampling( resamplingElement.attribute( QStringLiteral( "enabled" ) ) == QLatin1String( "true" ) );
596  }
597 }
598 
599 static QString resamplingMethodToString( QgsRasterDataProvider::ResamplingMethod method )
600 {
601  switch ( method )
602  {
604  return QStringLiteral( "nearestNeighbour" );
606  return QStringLiteral( "bilinear" );
608  return QStringLiteral( "cubic" );
610  return QStringLiteral( "cubicSpline" );
612  return QStringLiteral( "lanczos" );
614  return QStringLiteral( "average" );
616  return QStringLiteral( "mode" );
618  return QStringLiteral( "gauss" );
619  }
620  // should not happen
621  return QStringLiteral( "nearestNeighbour" );
622 }
623 
624 void QgsRasterDataProvider::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
625 {
626  QDomElement providerElement = doc.createElement( QStringLiteral( "provider" ) );
627  parentElem.appendChild( providerElement );
628 
629  QDomElement resamplingElement = doc.createElement( QStringLiteral( "resampling" ) );
630  providerElement.appendChild( resamplingElement );
631 
632  resamplingElement.setAttribute( QStringLiteral( "enabled" ),
633  mProviderResamplingEnabled ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
634 
635  resamplingElement.setAttribute( QStringLiteral( "zoomedInResamplingMethod" ),
636  resamplingMethodToString( mZoomedInResamplingMethod ) );
637 
638  resamplingElement.setAttribute( QStringLiteral( "zoomedOutResamplingMethod" ),
639  resamplingMethodToString( mZoomedOutResamplingMethod ) );
640 
641  resamplingElement.setAttribute( QStringLiteral( "maxOversampling" ),
642  QString::number( mMaxOversampling ) );
643 }
644 
646 {
647  return colorName( colorInterpretation( bandNo ) );
648 }
649 
651 {
652  QUrl url = QUrl::fromPercentEncoding( uri.toUtf8() );
653  const QUrlQuery query( url.query() );
654  VirtualRasterParameters components;
655 
656  if ( ! query.hasQueryItem( QStringLiteral( "crs" ) ) )
657  {
658  QgsDebugMsg( "crs is missing" );
659  if ( ok ) *ok = false;
660  return components;
661  }
662  if ( ! components.crs.createFromString( query.queryItemValue( QStringLiteral( "crs" ) ) ) )
663  {
664  QgsDebugMsg( "failed to create crs" );
665  if ( ok ) *ok = false;
666  return components;
667  }
668 
669 
670  if ( ! query.hasQueryItem( QStringLiteral( "extent" ) ) )
671  {
672  QgsDebugMsg( "extent is missing" );
673  if ( ok ) *ok = false;
674  return components;
675  }
676  QStringList pointValuesList = query.queryItemValue( QStringLiteral( "extent" ) ).split( ',' );
677  if ( pointValuesList.size() != 4 )
678  {
679  QgsDebugMsg( "the extent is not correct" );
680  if ( ok ) *ok = false;
681  return components;
682  }
683  components.extent = QgsRectangle( pointValuesList.at( 0 ).toDouble(), pointValuesList.at( 1 ).toDouble(),
684  pointValuesList.at( 2 ).toDouble(), pointValuesList.at( 3 ).toDouble() );
685 
686  if ( ! query.hasQueryItem( QStringLiteral( "width" ) ) )
687  {
688  QgsDebugMsg( "width is missing" );
689  if ( ok ) *ok = false;
690  return components;
691  }
692  bool flagW;
693  components.width = query.queryItemValue( QStringLiteral( "width" ) ).toInt( & flagW );
694  if ( !flagW || components.width < 0 )
695  {
696  QgsDebugMsg( "invalid or negative width input" );
697  if ( ok ) *ok = false;
698  return components;
699  }
700 
701  if ( ! query.hasQueryItem( QStringLiteral( "height" ) ) )
702  {
703  QgsDebugMsg( "height is missing" );
704  if ( ok ) *ok = false;
705  return components;
706  }
707  bool flagH;
708  components.height = query.queryItemValue( QStringLiteral( "height" ) ).toInt( & flagH );
709  if ( !flagH || components.height < 0 )
710  {
711  QgsDebugMsg( "invalid or negative width input" );
712  if ( ok ) *ok = false;
713  return components;
714  }
715 
716  if ( ! query.hasQueryItem( QStringLiteral( "formula" ) ) )
717  {
718  QgsDebugMsg( "formula is missing" );
719  if ( ok ) *ok = false;
720  return components;
721  }
722  components.formula = query.queryItemValue( QStringLiteral( "formula" ) );
723 
724  for ( const auto &item : query.queryItems() )
725  {
726  if ( !( item.first.mid( item.first.indexOf( ':' ), -1 ) == QLatin1String( ":uri" ) ) )
727  {
728  continue;
729  }
730 
732  rLayer.name = item.first.mid( 0, item.first.indexOf( ':' ) );
733  rLayer.uri = query.queryItemValue( item.first );
734  rLayer.provider = query.queryItemValue( item.first.mid( 0, item.first.indexOf( ':' ) ) + QStringLiteral( ":provider" ) );
735 
736  if ( rLayer.uri.isNull() || rLayer.provider.isNull() )
737  {
738  QgsDebugMsg( "One or more raster information are missing" );
739  if ( ok ) *ok = false;
740  return components;
741  }
742 
743  components.rInputLayers.append( rLayer ) ;
744 
745  }
746 
747  if ( ok ) *ok = true;
748  return components;
749 }
750 
752 {
753  QUrl uri;
754  QUrlQuery query;
755 
756  if ( parts.crs.isValid() )
757  {
758  query.addQueryItem( QStringLiteral( "crs" ), parts.crs.authid() );
759  }
760 
761  if ( ! parts.extent.isNull() )
762  {
763  QString rect = QString( "%1,%2,%3,%4" ).arg( qgsDoubleToString( parts.extent.xMinimum() ), qgsDoubleToString( parts.extent.yMinimum() ),
765 
766  query.addQueryItem( QStringLiteral( "extent" ), rect );
767  }
768 
769  query.addQueryItem( QStringLiteral( "width" ), QString::number( parts.width ) );
770 
771  query.addQueryItem( QStringLiteral( "height" ), QString::number( parts.height ) );
772 
773  query.addQueryItem( QStringLiteral( "formula" ), parts.formula );
774 
775  if ( ! parts.rInputLayers.isEmpty() )
776  {
777  for ( const auto &it : parts.rInputLayers )
778  {
779  query.addQueryItem( it.name + QStringLiteral( ":uri" ), it.uri );
780  query.addQueryItem( it.name + QStringLiteral( ":provider" ), it.provider );
781  }
782  }
783  uri.setQuery( query );
784  return QString( QUrl::toPercentEncoding( uri.toEncoded() ) );
785 }
DataType
Raster data types.
Definition: qgis.h:121
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
QString authid() const
Returns the authority identifier for the CRS.
Abstract base class for spatial data provider implementations.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
QgsDataSourceUri uri() const
Gets the data source specification.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsRasterDataProvider * createRasterDataProvider(const QString &providerKey, const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates new instance of raster data provider.
QList< QPair< QString, QString > > pyramidResamplingMethods(const QString &providerKey)
Returns list of raster pyramid resampling methods.
The RasterBandStats struct is a container for statistics about a single raster band.
Feedback object tailored for raster block reading.
Raster data container.
bool isEmpty() const
Returns true if block is empty, i.e.
void setNoDataValue(double noDataValue) SIP_HOLDGIL
Sets cell value that will be considered as "no data".
void setValid(bool valid) SIP_HOLDGIL
Mark block as valid or invalid.
int width() const SIP_HOLDGIL
Returns the width (number of columns) of the raster block.
char * bits(int row, int column)
Returns a pointer to block data.
bool setIsNoDataExcept(QRect exceptRect)
Set the whole block to no data except specified rectangle.
void applyNoDataValues(const QgsRasterRangeList &rangeList)
void applyScaleOffset(double scale, double offset)
Apply band scale and offset to raster block values.
static QRect subRect(const QgsRectangle &extent, int width, int height, const QgsRectangle &subExtent)
For extent and width, height find rectangle covered by subextent.
void setError(const QgsError &error)
Sets the last error.
int height() const SIP_HOLDGIL
Returns the height (number of rows) of the raster block.
bool setIsNoData(int row, int column) SIP_HOLDGIL
Set no data on pixel.
Implementation of data provider temporal properties for QgsRasterDataProviders.
Base class for raster data providers.
double mMaxOversampling
Maximum boundary for oversampling (to avoid too much data traffic). Default: 2.0.
QList< bool > mUseSrcNoDataValue
Use source nodata value.
TransformType
Types of transformation in transformCoordinates() function.
static QgsRaster::IdentifyFormat identifyFormatFromName(const QString &formatName)
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
static QString encodeVirtualRasterProviderUri(const VirtualRasterParameters &parts)
Encodes the URI starting from the struct .
virtual double bandOffset(int bandNo) const
Read band offset for raster value.
virtual QString lastErrorFormat()
Returns the format of the error text for the last error in this provider.
bool mProviderResamplingEnabled
Whether provider resampling is enabled.
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
virtual QList< QgsRasterPyramid > buildPyramidList(const QList< int > &overviewList=QList< int >())
Returns the raster layers pyramid list.
static QgsRasterDataProvider::VirtualRasterParameters decodeVirtualRasterProviderUri(const QString &uri, bool *ok=nullptr)
Decodes the URI returning a struct with all the parameters for QgsVirtualRasterProvider class.
virtual void setUseSourceNoDataValue(int bandNo, bool use)
Sets the source nodata value usage.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
QString colorName(int colorInterpretation) const
void readXml(const QDomElement &filterElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
QList< QgsRasterRangeList > mUserNoDataValue
List of lists of user defined additional no data values for each band, indexed from 0.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const
Returns flags containing the supported capabilities of the data provider.
virtual bool isEditable() const
Checks whether the provider is in editing mode, i.e.
void copyBaseSettings(const QgsRasterDataProvider &other)
Copy member variables from other raster data provider. Useful for implementation of clone() method in...
bool userNoDataValuesContains(int bandNo, double value) const
Returns true if user no data contains value.
bool writeBlock(QgsRasterBlock *block, int band, int xOffset=0, int yOffset=0)
Writes pixel data from a raster block into the provider data source.
virtual bool enableProviderResampling(bool enable)
Enable or disable provider-level resampling.
QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual bool ignoreExtents() const
Returns true if the extents reported by the data provider are not reliable and it's possible that the...
virtual bool setMaxOversampling(double factor)
Sets maximum oversampling factor for zoomed-out operations.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
ResamplingMethod mZoomedOutResamplingMethod
Resampling method for zoomed out pixel extraction.
static Capability identifyFormatToCapability(QgsRaster::IdentifyFormat format)
bool hasPyramids()
Returns true if raster has at least one existing pyramid.
virtual double bandScale(int bandNo) const
Read band scale for raster value.
static QString identifyFormatName(QgsRaster::IdentifyFormat format)
@ NoProviderCapabilities
Provider has no capabilities.
int dpi() const
Returns the dpi of the output device.
virtual double sample(const QgsPointXY &point, int band, bool *ok=nullptr, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Samples a raster value from the specified band found at the point position.
static QString identifyFormatLabel(QgsRaster::IdentifyFormat format)
QgsRasterBlock * block(int bandNo, const QgsRectangle &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
virtual int colorInterpretation(int bandNo) const
Returns data type for the band specified by number.
QList< double > mSrcNoDataValue
Source no data value is available and is set to be used or internal no data is available.
virtual bool readBlock(int bandNo, int xBlock, int yBlock, void *data)
Reads a block of raster data into data.
ResamplingMethod mZoomedInResamplingMethod
Resampling method for zoomed in pixel extraction.
QgsRasterDataProvider()
Provider capabilities.
QList< bool > mSrcHasNoDataValue
Source no data value exists.
static QgsRasterDataProvider * create(const QString &providerKey, const QString &uri, const QString &format, int nBands, Qgis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
virtual bool setZoomedInResamplingMethod(ResamplingMethod method)
Set resampling method to apply for zoomed-in operations.
static QList< QPair< QString, QString > > pyramidResamplingMethods(const QString &providerKey)
Returns a list of pyramid resampling method name and label pairs for given provider.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
virtual QList< double > nativeResolutions() const
Returns a list of native resolutions if available, i.e.
virtual QgsPoint transformCoordinates(const QgsPoint &point, TransformType type)
Transforms coordinates between source image coordinate space [0..width]x[0..height] and layer coordin...
QgsRasterDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QString colorInterpretationName(int bandNo) const override
Returns the name of the color interpretation for the specified bandNumber.
ResamplingMethod
Resampling method for provider-level resampling.
@ Lanczos
Lanczos windowed sinc interpolation (6x6 kernel)
@ Nearest
Nearest-neighbour resampling.
@ Mode
Mode (selects the value which appears most often of all the sampled points)
@ Bilinear
Bilinear (2x2 kernel) resampling.
@ CubicSpline
Cubic B-Spline Approximation (4x4 kernel)
@ Cubic
Cubic Convolution Approximation (4x4 kernel) resampling.
virtual bool write(void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
virtual bool setZoomedOutResamplingMethod(ResamplingMethod method)
Set resampling method to apply for zoomed-out operations.
The QgsRasterHistogram is a container for histogram of a single raster band.
Raster identify results container.
Base class for processing filters like renderers, reprojector, resampler etc.
QList< QgsRasterBandStats > mStatistics
List of cached statistics, all bands mixed.
Capability
If you add to this, please also add to capabilitiesString()
@ IdentifyValue
Numerical values.
@ IdentifyFeature
WMS GML -> feature.
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
virtual int xSize() const
Gets raster size.
virtual int bandCount() const =0
Gets number of bands.
int dataTypeSize(int bandNo) const
Returns the size (in bytes) for the data type for the specified band.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual int ySize() const
QList< QgsRasterHistogram > mHistograms
List of cached histograms, all bands mixed.
virtual QgsRasterHistogram histogram(int bandNo, int binCount=0, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false, QgsRasterBlockFeedback *feedback=nullptr)
Returns a band histogram.
This struct is used to store pyramid info for the raster layer.
bool contains(double value) const
Returns true if this range contains the specified value.
IdentifyFormat
Definition: qgsraster.h:58
@ IdentifyFormatFeature
Definition: qgsraster.h:63
@ IdentifyFormatValue
Definition: qgsraster.h:60
@ IdentifyFormatText
Definition: qgsraster.h:61
@ IdentifyFormatUndefined
Definition: qgsraster.h:59
@ IdentifyFormatHtml
Definition: qgsraster.h:62
@ UndefinedColorInterpretation
Definition: qgsraster.h:37
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
Definition: qgsrectangle.h:161
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
Definition: qgsrectangle.h:156
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
Definition: qgsrectangle.h:151
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
Definition: qgsrectangle.h:166
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
#define str(x)
Definition: qgis.cpp:37
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:1443
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:1958
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1491
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define ERR(message)
QList< QgsRasterRange > QgsRasterRangeList
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
Struct that stores information of the raster used in QgsVirtualRasterProvider for the calculations,...
Struct that stores the information about the parameters that should be given to the QgsVirtualRasterP...
QList< QgsRasterDataProvider::VirtualRasterInputLayers > rInputLayers