QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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 "qgslogger.h"
22 #include "qgspoint.h"
23 #include "qgsthreadingutils.h"
24 
25 #include <QTime>
26 #include <QMap>
27 #include <QByteArray>
28 #include <QVariant>
29 
30 #include <QUrl>
31 #include <QUrlQuery>
32 #include <QSet>
33 
34 #define ERR(message) QgsError(message, "Raster provider")
35 
37 {
39 
40  if ( mUseSrcNoDataValue.size() < bandNo )
41  {
42  for ( int i = mUseSrcNoDataValue.size(); i < bandNo; i++ )
43  {
44  mUseSrcNoDataValue.append( false );
45  }
46  }
47  mUseSrcNoDataValue[bandNo - 1] = use;
48 }
49 
50 QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback )
51 {
53 
54  QgsDebugMsgLevel( QStringLiteral( "bandNo = %1 width = %2 height = %3" ).arg( bandNo ).arg( width ).arg( height ), 4 );
55  QgsDebugMsgLevel( QStringLiteral( "boundingBox = %1" ).arg( boundingBox.toString() ), 4 );
56 
57  std::unique_ptr< QgsRasterBlock > block = std::make_unique< QgsRasterBlock >( dataType( bandNo ), width, height );
58  if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
59  {
61  }
62 
63  if ( block->isEmpty() )
64  {
65  QgsDebugError( QStringLiteral( "Couldn't create raster block" ) );
66  block->setError( { tr( "Couldn't create raster block." ), QStringLiteral( "Raster" ) } );
67  block->setValid( false );
68  return block.release();
69  }
70 
71  // Read necessary extent only
72  QgsRectangle tmpExtent = boundingBox;
73 
74  if ( tmpExtent.isEmpty() )
75  {
76  QgsDebugError( QStringLiteral( "Extent outside provider extent" ) );
77  block->setError( { tr( "Extent outside provider extent." ), QStringLiteral( "Raster" ) } );
78  block->setValid( false );
79  block->setIsNoData();
80  return block.release();
81  }
82 
83  const double xRes = boundingBox.width() / width;
84  const double yRes = boundingBox.height() / height;
85  double tmpXRes, tmpYRes;
86  double providerXRes = 0;
87  double providerYRes = 0;
88  if ( capabilities() & Size )
89  {
90  providerXRes = extent().width() / xSize();
91  providerYRes = extent().height() / ySize();
92  tmpXRes = std::max( providerXRes, xRes );
93  tmpYRes = std::max( providerYRes, yRes );
94  if ( qgsDoubleNear( tmpXRes, xRes ) ) tmpXRes = xRes;
95  if ( qgsDoubleNear( tmpYRes, yRes ) ) tmpYRes = yRes;
96  }
97  else
98  {
99  tmpXRes = xRes;
100  tmpYRes = yRes;
101  }
102 
103  if ( tmpExtent != boundingBox ||
104  tmpXRes > xRes || tmpYRes > yRes )
105  {
106  // Read smaller extent or lower resolution
107 
108  if ( !extent().contains( boundingBox ) )
109  {
110  const QRect subRect = QgsRasterBlock::subRect( boundingBox, width, height, extent() );
111  block->setIsNoDataExcept( subRect );
112  }
113 
114  // Calculate row/col limits (before tmpExtent is aligned)
115  const int fromRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMaximum() ) / yRes );
116  const int toRow = std::round( ( boundingBox.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1;
117  const int fromCol = std::round( ( tmpExtent.xMinimum() - boundingBox.xMinimum() ) / xRes );
118  const int toCol = std::round( ( tmpExtent.xMaximum() - boundingBox.xMinimum() ) / xRes ) - 1;
119 
120  QgsDebugMsgLevel( QStringLiteral( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ), 4 );
121 
122  if ( fromRow < 0 || fromRow >= height || toRow < 0 || toRow >= height ||
123  fromCol < 0 || fromCol >= width || toCol < 0 || toCol >= width )
124  {
125  // Should not happen
126  QgsDebugError( QStringLiteral( "Row or column limits out of range" ) );
127  block->setError( { tr( "Row or column limits out of range" ), QStringLiteral( "Raster" ) } );
128  block->setValid( false );
129  return block.release();
130  }
131 
132  // If lower source resolution is used, the extent must be aligned to original
133  // resolution to avoid possible shift due to resampling
134  if ( tmpXRes > xRes )
135  {
136  int col = std::floor( ( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes );
137  tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes );
138  col = std::ceil( ( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes );
139  tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes );
140  }
141  if ( tmpYRes > yRes )
142  {
143  int row = std::floor( ( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes );
144  tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes );
145  row = std::ceil( ( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes );
146  tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes );
147  }
148  const int tmpWidth = std::round( tmpExtent.width() / tmpXRes );
149  const int tmpHeight = std::round( tmpExtent.height() / tmpYRes );
150  tmpXRes = tmpExtent.width() / tmpWidth;
151  tmpYRes = tmpExtent.height() / tmpHeight;
152 
153  QgsDebugMsgLevel( QStringLiteral( "Reading smaller block tmpWidth = %1 height = %2" ).arg( tmpWidth ).arg( tmpHeight ), 4 );
154  QgsDebugMsgLevel( QStringLiteral( "tmpExtent = %1" ).arg( tmpExtent.toString() ), 4 );
155 
156  std::unique_ptr< QgsRasterBlock > tmpBlock = std::make_unique< QgsRasterBlock >( dataType( bandNo ), tmpWidth, tmpHeight );
157  if ( sourceHasNoDataValue( bandNo ) && useSourceNoDataValue( bandNo ) )
158  {
159  tmpBlock->setNoDataValue( sourceNoDataValue( bandNo ) );
160  }
161 
162  if ( !readBlock( bandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->bits(), feedback ) )
163  {
164  QgsDebugError( QStringLiteral( "Error occurred while reading block" ) );
165  block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
166  block->setValid( false );
167  block->setIsNoData();
168  return block.release();
169  }
170 
171  const int pixelSize = dataTypeSize( bandNo );
172 
173  const double xMin = boundingBox.xMinimum();
174  const double yMax = boundingBox.yMaximum();
175  const double tmpXMin = tmpExtent.xMinimum();
176  const double tmpYMax = tmpExtent.yMaximum();
177 
178  for ( int row = fromRow; row <= toRow; row++ )
179  {
180  const double y = yMax - ( row + 0.5 ) * yRes;
181  const int tmpRow = std::floor( ( tmpYMax - y ) / tmpYRes );
182 
183  for ( int col = fromCol; col <= toCol; col++ )
184  {
185  const double x = xMin + ( col + 0.5 ) * xRes;
186  const int tmpCol = std::floor( ( x - tmpXMin ) / tmpXRes );
187 
188  if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth )
189  {
190  QgsDebugError( QStringLiteral( "Source row or column limits out of range" ) );
191  block->setIsNoData(); // so that the problem becomes obvious and fixed
192  block->setError( { tr( "Source row or column limits out of range." ), QStringLiteral( "Raster" ) } );
193  block->setValid( false );
194  return block.release();
195  }
196 
197  const qgssize tmpIndex = static_cast< qgssize >( tmpRow ) * static_cast< qgssize >( tmpWidth ) + tmpCol;
198  const qgssize index = row * static_cast< qgssize >( width ) + col;
199 
200  char *tmpBits = tmpBlock->bits( tmpIndex );
201  char *bits = block->bits( index );
202  if ( !tmpBits )
203  {
204  QgsDebugError( QStringLiteral( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) );
205  continue;
206  }
207  if ( !bits )
208  {
209  QgsDebugError( QStringLiteral( "Cannot set output block data." ) );
210  continue;
211  }
212  memcpy( bits, tmpBits, pixelSize );
213  }
214  }
215  }
216  else
217  {
218  if ( !readBlock( bandNo, boundingBox, width, height, block->bits(), feedback ) )
219  {
220  QgsDebugError( QStringLiteral( "Error occurred while reading block" ) );
221  block->setIsNoData();
222  block->setError( { tr( "Error occurred while reading block." ), QStringLiteral( "Raster" ) } );
223  block->setValid( false );
224  return block.release();
225  }
226  }
227 
228  // apply scale and offset
229  block->applyScaleOffset( bandScale( bandNo ), bandOffset( bandNo ) );
230  // apply user no data values
232  return block.release();
233 }
234 
237  , QgsRasterInterface( nullptr )
238  , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
239  , mElevationProperties( std::make_unique< QgsRasterDataProviderElevationProperties >() )
240 {
241 
242 }
243 
246  : QgsDataProvider( uri, options, flags )
247  , QgsRasterInterface( nullptr )
248  , mTemporalCapabilities( std::make_unique< QgsRasterDataProviderTemporalCapabilities >() )
249  , mElevationProperties( std::make_unique< QgsRasterDataProviderElevationProperties >() )
250 {
251 }
252 
254 {
256 
258 }
259 
261 {
263 
264  Q_UNUSED( bandNo )
266 }
267 
268 // TODO
269 // (WMS) IdentifyFormatFeature is not consistent with QgsRaster::IdentifyFormatValue.
270 // IdentifyFormatHtml: better error reporting
271 QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, Qgis::RasterIdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ )
272 {
274 
275  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
276  QMap<int, QVariant> results;
277 
279  {
280  QgsDebugError( QStringLiteral( "Format not supported" ) );
281  return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) );
282  }
283 
284  if ( !extent().contains( point ) )
285  {
286  // Outside the raster
287  for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ )
288  {
289  results.insert( bandNo, QVariant() );
290  }
292  }
293 
294  QgsRectangle finalExtent = boundingBox;
295  if ( finalExtent.isEmpty() )
296  finalExtent = extent();
297 
298  if ( width == 0 )
299  {
300  width = capabilities() & Size ? xSize() : 1000;
301  }
302  if ( height == 0 )
303  {
304  height = capabilities() & Size ? ySize() : 1000;
305  }
306 
307  // Calculate the row / column where the point falls
308  const double xres = ( finalExtent.width() ) / width;
309  const double yres = ( finalExtent.height() ) / height;
310 
311  const int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) );
312  const int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) );
313 
314  const double xMin = finalExtent.xMinimum() + col * xres;
315  const double xMax = xMin + xres;
316  const double yMax = finalExtent.yMaximum() - row * yres;
317  const double yMin = yMax - yres;
318  const QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
319 
320  for ( int bandNumber = 1; bandNumber <= bandCount(); bandNumber++ )
321  {
322  std::unique_ptr< QgsRasterBlock > bandBlock( block( bandNumber, pixelExtent, 1, 1 ) );
323 
324  if ( bandBlock )
325  {
326  const double value = bandBlock->value( 0 );
327  results.insert( bandNumber, value );
328  }
329  else
330  {
331  results.insert( bandNumber, QVariant() );
332  }
333  }
335 }
336 
337 double QgsRasterDataProvider::sample( const QgsPointXY &point, int band,
338  bool *ok, const QgsRectangle &boundingBox, int width, int height, int dpi )
339 {
341 
342  if ( ok )
343  *ok = false;
344 
345  const auto res = identify( point, Qgis::RasterIdentifyFormat::Value, boundingBox, width, height, dpi );
346  const QVariant value = res.results().value( band );
347 
348  if ( !value.isValid() )
349  return std::numeric_limits<double>::quiet_NaN();
350 
351  if ( ok )
352  *ok = true;
353 
354  return value.toDouble( ok );
355 }
356 
358 {
360 
361  return QStringLiteral( "text/plain" );
362 }
363 
364 bool QgsRasterDataProvider::writeBlock( QgsRasterBlock *block, int band, int xOffset, int yOffset )
365 {
367 
368  if ( !block )
369  return false;
370  if ( !isEditable() )
371  {
372  QgsDebugError( QStringLiteral( "writeBlock() called on read-only provider." ) );
373  return false;
374  }
375  return write( block->bits(), band, block->width(), block->height(), xOffset, yOffset );
376 }
377 
378 // typedef QList<QPair<QString, QString> > *pyramidResamplingMethods_t();
379 QList<QPair<QString, QString> > QgsRasterDataProvider::pyramidResamplingMethods( const QString &providerKey )
380 {
381  QList<QPair<QString, QString> > methods = QgsProviderRegistry::instance()->pyramidResamplingMethods( providerKey );
382  if ( methods.isEmpty() )
383  {
384  QgsDebugMsgLevel( QStringLiteral( "provider pyramidResamplingMethods returned no methods" ), 2 );
385  }
386  return methods;
387 }
388 
390 {
392 
393  const QList<QgsRasterPyramid> pyramidList = buildPyramidList();
394  return std::any_of( pyramidList.constBegin(), pyramidList.constEnd(), []( QgsRasterPyramid pyramid ) { return pyramid.getExists(); } );
395 }
396 
398 {
400 
401  if ( bandNo >= mUserNoDataValue.size() )
402  {
403  for ( int i = mUserNoDataValue.size(); i < bandNo; i++ )
404  {
406  }
407  }
408  QgsDebugMsgLevel( QStringLiteral( "set %1 band %1 no data ranges" ).arg( noData.size() ), 4 );
409 
410  if ( mUserNoDataValue[bandNo - 1] != noData )
411  {
412  // Clear statistics
413  mStatistics.erase( std::remove_if( mStatistics.begin(), mStatistics.end(), [bandNo]( const QgsRasterBandStats & stats )
414  {
415  return stats.bandNumber == bandNo;
416  } ), mStatistics.end() );
417  mHistograms.erase( std::remove_if( mHistograms.begin(), mHistograms.end(), [bandNo]( const QgsRasterHistogram & histogram )
418  {
419  return histogram.bandNumber == bandNo;
420  } ), mHistograms.end() );
421  mUserNoDataValue[bandNo - 1] = noData;
422  }
423 }
424 
426 {
428 
429  return mTemporalCapabilities.get();
430 }
431 
433 {
435 
436  return mTemporalCapabilities.get();
437 }
438 
440 {
442 
443  return mElevationProperties.get();
444 }
445 
447 {
449 
450  return mElevationProperties.get();
451 }
452 
454  const QString &uri,
455  const QString &format, int nBands,
456  Qgis::DataType type,
457  int width, int height, double *geoTransform,
459  const QStringList &createOptions )
460 {
462  providerKey,
463  uri, format,
464  nBands, type, width,
465  height, geoTransform, crs, createOptions );
466  if ( !ret )
467  {
468  QgsDebugError( "Cannot resolve 'createRasterDataProviderFunction' function in " + providerKey + " provider" );
469  }
470 
471  // TODO: it would be good to return invalid QgsRasterDataProvider
472  // with QgsError set, but QgsRasterDataProvider has pure virtual methods
473 
474  return ret;
475 }
476 
478 {
479  switch ( format )
480  {
482  return QStringLiteral( "Value" );
484  return QStringLiteral( "Text" );
486  return QStringLiteral( "Html" );
488  return QStringLiteral( "Feature" );
490  break;
491  }
492  return QStringLiteral( "Undefined" );
493 }
494 
496 {
497  switch ( format )
498  {
500  return tr( "Value" );
502  return tr( "Text" );
504  return tr( "HTML" );
506  return tr( "Feature" );
508  break;
509  }
510  return QStringLiteral( "Undefined" );
511 }
512 
514 {
515  if ( formatName == QLatin1String( "Value" ) )
517  if ( formatName == QLatin1String( "Text" ) )
519  if ( formatName == QLatin1String( "Html" ) )
521  if ( formatName == QLatin1String( "Feature" ) )
524 }
525 
527 {
528  switch ( format )
529  {
531  return IdentifyValue;
533  return IdentifyText;
535  return IdentifyHtml;
537  return IdentifyFeature;
539  break;
540  }
541  return NoCapabilities;
542 }
543 
545 {
547 
548  return QList< double >();
549 }
550 
552 {
554 
555  return false;
556 }
557 
559 {
561 
562  Q_UNUSED( point )
563  Q_UNUSED( type )
564  return QgsPoint();
565 }
566 
567 bool QgsRasterDataProvider::userNoDataValuesContains( int bandNo, double value ) const
568 {
570 
571  const QgsRasterRangeList rangeList = mUserNoDataValue.value( bandNo - 1 );
572  return QgsRasterRange::contains( value, rangeList );
573 }
574 
576 {
578 
579  mDpi = other.mDpi;
584  mExtent = other.mExtent;
589 
590  if ( mTemporalCapabilities && other.mTemporalCapabilities )
591  {
592  *mTemporalCapabilities = *other.mTemporalCapabilities;
593  }
594  if ( mElevationProperties && other.mElevationProperties )
595  {
596  *mElevationProperties = *other.mElevationProperties;
597  }
598 }
599 
600 static QgsRasterDataProvider::ResamplingMethod resamplingMethodFromString( const QString &str )
601 {
602  if ( str == QLatin1String( "bilinear" ) )
603  {
605  }
606  else if ( str == QLatin1String( "cubic" ) )
607  {
609  }
610  else if ( str == QLatin1String( "cubicSpline" ) )
611  {
613  }
614  else if ( str == QLatin1String( "lanczos" ) )
615  {
617  }
618  else if ( str == QLatin1String( "average" ) )
619  {
621  }
622  else if ( str == QLatin1String( "mode" ) )
623  {
625  }
626  else if ( str == QLatin1String( "gauss" ) )
627  {
629  }
631 }
632 
633 void QgsRasterDataProvider::readXml( const QDomElement &filterElem )
634 {
636 
637  if ( filterElem.isNull() )
638  {
639  return;
640  }
641 
642  const QDomElement resamplingElement = filterElem.firstChildElement( QStringLiteral( "resampling" ) );
643  if ( !resamplingElement.isNull() )
644  {
645  setMaxOversampling( resamplingElement.attribute( QStringLiteral( "maxOversampling" ), QStringLiteral( "2.0" ) ).toDouble() );
646  setZoomedInResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedInResamplingMethod" ) ) ) );
647  setZoomedOutResamplingMethod( resamplingMethodFromString( resamplingElement.attribute( QStringLiteral( "zoomedOutResamplingMethod" ) ) ) );
648  enableProviderResampling( resamplingElement.attribute( QStringLiteral( "enabled" ) ) == QLatin1String( "true" ) );
649  }
650 }
651 
652 static QString resamplingMethodToString( QgsRasterDataProvider::ResamplingMethod method )
653 {
654  switch ( method )
655  {
657  return QStringLiteral( "nearestNeighbour" );
659  return QStringLiteral( "bilinear" );
661  return QStringLiteral( "cubic" );
663  return QStringLiteral( "cubicSpline" );
665  return QStringLiteral( "lanczos" );
667  return QStringLiteral( "average" );
669  return QStringLiteral( "mode" );
671  return QStringLiteral( "gauss" );
672  }
673  // should not happen
674  return QStringLiteral( "nearestNeighbour" );
675 }
676 
677 void QgsRasterDataProvider::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
678 {
680 
681  QDomElement providerElement = doc.createElement( QStringLiteral( "provider" ) );
682  parentElem.appendChild( providerElement );
683 
684  QDomElement resamplingElement = doc.createElement( QStringLiteral( "resampling" ) );
685  providerElement.appendChild( resamplingElement );
686 
687  resamplingElement.setAttribute( QStringLiteral( "enabled" ),
688  mProviderResamplingEnabled ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
689 
690  resamplingElement.setAttribute( QStringLiteral( "zoomedInResamplingMethod" ),
691  resamplingMethodToString( mZoomedInResamplingMethod ) );
692 
693  resamplingElement.setAttribute( QStringLiteral( "zoomedOutResamplingMethod" ),
694  resamplingMethodToString( mZoomedOutResamplingMethod ) );
695 
696  resamplingElement.setAttribute( QStringLiteral( "maxOversampling" ),
697  QString::number( mMaxOversampling ) );
698 }
699 
701 {
703 
704  try
705  {
706  return mAttributeTables.at( bandNumber ).get();
707  }
708  catch ( std::out_of_range const & )
709  {
710  return nullptr;
711  }
712 }
713 
715 {
717 
718  if ( attributeTable )
719  {
720  mAttributeTables[ bandNumber ] = std::unique_ptr<QgsRasterAttributeTable>( attributeTable );
721  }
722  else
723  {
724  removeAttributeTable( bandNumber );
725  }
726 }
727 
729 {
731 
732  if ( mAttributeTables.find( bandNumber ) != std::end( mAttributeTables ) )
733  {
734  mAttributeTables.erase( bandNumber );
735  }
736 }
737 
738 bool QgsRasterDataProvider::writeFileBasedAttributeTable( int bandNumber, const QString &path, QString *errorMessage ) const
739 {
741 
742  QgsRasterAttributeTable *rat { attributeTable( bandNumber ) };
743  if ( ! rat )
744  {
745  if ( errorMessage )
746  {
747  *errorMessage = QObject::tr( "Raster has no Raster Attribute Table for band %1" ).arg( bandNumber );
748  }
749  return false;
750  }
751 
752  return rat->writeToFile( path, errorMessage );
753 }
754 
756 {
758 
759  if ( errorMessage )
760  {
761  *errorMessage = QObject::tr( "Raster data provider has no native Raster Attribute Table support." );
762  }
763  return false;
764 }
765 
766 QString QgsRasterDataProvider::bandDescription( int bandNumber )
767 {
768  Q_UNUSED( bandNumber )
769  return QString();
770 }
771 
772 bool QgsRasterDataProvider::readFileBasedAttributeTable( int bandNumber, const QString &path, QString *errorMessage )
773 {
775 
776  std::unique_ptr<QgsRasterAttributeTable> rat = std::make_unique<QgsRasterAttributeTable>();
777  if ( rat->readFromFile( path, errorMessage ) )
778  {
779  setAttributeTable( bandNumber, rat.release() );
780  return true;
781  }
782  else
783  {
784  return false;
785  }
786 }
787 
788 bool QgsRasterDataProvider::writeNativeAttributeTable( QString *errorMessage ) //#spellok
789 {
791 
792  Q_UNUSED( errorMessage );
793  return false;
794 }
795 
797 {
799 
800  return colorName( colorInterpretation( bandNo ) );
801 }
802 
804 {
805  QUrl url = QUrl::fromPercentEncoding( uri.toUtf8() );
806  const QUrlQuery query( url.query() );
807  VirtualRasterParameters components;
808 
809  if ( ! query.hasQueryItem( QStringLiteral( "crs" ) ) )
810  {
811  QgsDebugError( "crs is missing" );
812  if ( ok ) *ok = false;
813  return components;
814  }
815  if ( ! components.crs.createFromString( query.queryItemValue( QStringLiteral( "crs" ) ) ) )
816  {
817  QgsDebugError( "failed to create crs" );
818  if ( ok ) *ok = false;
819  return components;
820  }
821 
822 
823  if ( ! query.hasQueryItem( QStringLiteral( "extent" ) ) )
824  {
825  QgsDebugError( "extent is missing" );
826  if ( ok ) *ok = false;
827  return components;
828  }
829  QStringList pointValuesList = query.queryItemValue( QStringLiteral( "extent" ) ).split( ',' );
830  if ( pointValuesList.size() != 4 )
831  {
832  QgsDebugError( "the extent is not correct" );
833  if ( ok ) *ok = false;
834  return components;
835  }
836  components.extent = QgsRectangle( pointValuesList.at( 0 ).toDouble(), pointValuesList.at( 1 ).toDouble(),
837  pointValuesList.at( 2 ).toDouble(), pointValuesList.at( 3 ).toDouble() );
838 
839  if ( ! query.hasQueryItem( QStringLiteral( "width" ) ) )
840  {
841  QgsDebugError( "width is missing" );
842  if ( ok ) *ok = false;
843  return components;
844  }
845  bool flagW;
846  components.width = query.queryItemValue( QStringLiteral( "width" ) ).toInt( & flagW );
847  if ( !flagW || components.width < 0 )
848  {
849  QgsDebugError( "invalid or negative width input" );
850  if ( ok ) *ok = false;
851  return components;
852  }
853 
854  if ( ! query.hasQueryItem( QStringLiteral( "height" ) ) )
855  {
856  QgsDebugError( "height is missing" );
857  if ( ok ) *ok = false;
858  return components;
859  }
860  bool flagH;
861  components.height = query.queryItemValue( QStringLiteral( "height" ) ).toInt( & flagH );
862  if ( !flagH || components.height < 0 )
863  {
864  QgsDebugError( "invalid or negative width input" );
865  if ( ok ) *ok = false;
866  return components;
867  }
868 
869  if ( ! query.hasQueryItem( QStringLiteral( "formula" ) ) )
870  {
871  QgsDebugError( "formula is missing" );
872  if ( ok ) *ok = false;
873  return components;
874  }
875  components.formula = query.queryItemValue( QStringLiteral( "formula" ) );
876 
877  for ( const auto &item : query.queryItems() )
878  {
879  if ( !( item.first.mid( item.first.indexOf( ':' ), -1 ) == QLatin1String( ":uri" ) ) )
880  {
881  continue;
882  }
883 
885  rLayer.name = item.first.mid( 0, item.first.indexOf( ':' ) );
886  rLayer.uri = query.queryItemValue( item.first );
887  rLayer.provider = query.queryItemValue( item.first.mid( 0, item.first.indexOf( ':' ) ) + QStringLiteral( ":provider" ) );
888 
889  if ( rLayer.uri.isNull() || rLayer.provider.isNull() )
890  {
891  QgsDebugError( "One or more raster information are missing" );
892  if ( ok ) *ok = false;
893  return components;
894  }
895 
896  components.rInputLayers.append( rLayer ) ;
897 
898  }
899 
900  if ( ok ) *ok = true;
901  return components;
902 }
903 
905 {
906  QUrl uri;
907  QUrlQuery query;
908 
909  if ( parts.crs.isValid() )
910  {
911  query.addQueryItem( QStringLiteral( "crs" ), parts.crs.authid() );
912  }
913 
914  if ( ! parts.extent.isNull() )
915  {
916  QString rect = QString( "%1,%2,%3,%4" ).arg( qgsDoubleToString( parts.extent.xMinimum() ), qgsDoubleToString( parts.extent.yMinimum() ),
918 
919  query.addQueryItem( QStringLiteral( "extent" ), rect );
920  }
921 
922  query.addQueryItem( QStringLiteral( "width" ), QString::number( parts.width ) );
923 
924  query.addQueryItem( QStringLiteral( "height" ), QString::number( parts.height ) );
925 
926  query.addQueryItem( QStringLiteral( "formula" ), parts.formula );
927 
928  if ( ! parts.rInputLayers.isEmpty() )
929  {
930  for ( const auto &it : parts.rInputLayers )
931  {
932  query.addQueryItem( it.name + QStringLiteral( ":uri" ), it.uri );
933  query.addQueryItem( it.name + QStringLiteral( ":provider" ), it.provider );
934  }
935  }
936  uri.setQuery( query );
937  return QString( QUrl::toPercentEncoding( uri.toEncoded() ) );
938 }
DataType
Raster data types.
Definition: qgis.h:269
RasterColorInterpretation
Raster color interpretation.
Definition: qgis.h:3878
RasterIdentifyFormat
Raster identify formats.
Definition: qgis.h:3977
@ Feature
WMS GML/JSON -> feature.
@ Value
Numerical pixel value.
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.
Abstract base class for spatial data provider implementations.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
QFlags< ReadFlag > ReadFlags
QgsDataSourceUri uri() const
Gets the data source specification.
A class to represent a 2D point.
Definition: qgspointxy.h:60
double y
Definition: qgspointxy.h:64
Q_GADGET double x
Definition: qgspointxy.h:63
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 QgsRasterAttributeTable class represents a Raster Attribute Table (RAT).
bool writeToFile(const QString &path, QString *errorMessage=nullptr)
Writes the Raster Attribute Table to a DBF file specified by path, optionally reporting any error in ...
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 setValid(bool valid)
Mark block as valid or invalid.
int height() const
Returns the height (number of rows) 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 setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
int width() const
Returns the width (number of columns) of the raster block.
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.
bool setIsNoData(int row, int column)
Set no data on pixel.
Handles elevation related properties for a raster data provider.
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.
static Capability identifyFormatToCapability(Qgis::RasterIdentifyFormat format)
Converts a raster identify format to a capability.
QList< bool > mUseSrcNoDataValue
Use source nodata value.
TransformType
Types of transformation in transformCoordinates() function.
bool writeFileBasedAttributeTable(int bandNumber, const QString &path, QString *errorMessage=nullptr) const
Writes the filesystem-based attribute table for the specified bandNumber to path, optionally reportin...
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 writeNativeAttributeTable(QString *errorMessage=nullptr)
Writes the native attribute table, optionally reporting any error in errorMessage,...
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.
bool readFileBasedAttributeTable(int bandNumber, const QString &path, QString *errorMessage=nullptr)
Loads the filesystem-based attribute table for the specified bandNumber from path,...
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.
QgsRasterAttributeTable * attributeTable(int bandNumber) const
Returns the (possibly NULL) attribute table for the specified bandNumber.
void setAttributeTable(int bandNumber, QgsRasterAttributeTable *attributeTable)
Set the attribute table to attributeTable for the specified bandNumber, if the attributeTable is NULL...
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
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 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.
QString colorName(Qgis::RasterColorInterpretation colorInterpretation) const
Returns a string color name representation of a color interpretation.
virtual bool readNativeAttributeTable(QString *errorMessage=nullptr)
Reads the native attribute table, optionally reporting any error in errorMessage, returns true on suc...
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.
QgsRasterDataProviderElevationProperties * elevationProperties() override
Returns the provider's elevation properties.
bool hasPyramids()
Returns true if raster has at least one existing pyramid.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, Qgis::RasterIdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
virtual double bandScale(int bandNo) const
Read band scale for raster value.
@ NoProviderCapabilities
Provider has no capabilities.
int dpi() const
Returns the dpi of the output device.
virtual Qgis::RasterColorInterpretation colorInterpretation(int bandNo) const
Returns data type for the band specified by number.
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.
QFlags< ProviderCapability > ProviderCapabilities
Provider capabilities.
QgsRasterBlock * block(int bandNo, const QgsRectangle &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
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.
QList< bool > mSrcHasNoDataValue
Source no data value exists.
void removeAttributeTable(int bandNumber)
Remove the attribute table for the specified bandNumber.
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...
static QString identifyFormatName(Qgis::RasterIdentifyFormat format)
Converts a raster identify format to a string name.
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 QString bandDescription(int bandNumber)
Returns the description for band bandNumber, or an empty string if the band is not valid or has not d...
virtual bool write(void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
static Qgis::RasterIdentifyFormat identifyFormatFromName(const QString &formatName)
Converts a string formatName to a raster identify format.
static QString identifyFormatLabel(Qgis::RasterIdentifyFormat format)
Converts a raster identify format to a translated string label.
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.
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 xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:159
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:149
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
bool isNull() const
Test if the rectangle is null (holding no spatial information).
Definition: qgsrectangle.h:505
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:164
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:154
bool isEmpty() const
Returns true if the rectangle has no area.
Definition: qgsrectangle.h:492
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:243
#define str(x)
Definition: qgis.cpp:38
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:5089
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:5712
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5172
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
#define ERR(message)
QList< QgsRasterRange > QgsRasterRangeList
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
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