QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsrasterinterface.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterface.cpp - Internal raster processing modules interface
3  --------------------------------------
4  Date : Jun 21, 2012
5  Copyright : (C) 2012 by Radim Blazek
6  email : radim dot blazek at gmail 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 <limits>
19 #include <typeinfo>
20 
21 #include <QByteArray>
22 #include <QTime>
23 #include <QStringList>
24 
25 #include "qgslogger.h"
26 #include "qgsrasterbandstats.h"
27 #include "qgsrasterhistogram.h"
28 #include "qgsrasterinterface.h"
29 #include "qgsrectangle.h"
30 
32  : mInput( input )
33 {
34 }
35 
37  int bandNo,
38  int stats,
39  const QgsRectangle &boundingBox,
40  int sampleSize )
41 {
42  QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 sampleSize = %2" ).arg( bandNo ).arg( sampleSize ), 4 );
43 
44  statistics.bandNumber = bandNo;
45  statistics.statsGathered = stats;
46 
47  QgsRectangle finalExtent;
48  if ( boundingBox.isEmpty() )
49  {
50  finalExtent = extent();
51  }
52  else
53  {
54  finalExtent = extent().intersect( boundingBox );
55  }
56  statistics.extent = finalExtent;
57 
58  if ( sampleSize > 0 )
59  {
60  // Calc resolution from theSampleSize
61  double xRes, yRes;
62  xRes = yRes = std::sqrt( ( finalExtent.width() * finalExtent.height() ) / sampleSize );
63 
64  // But limit by physical resolution
65  if ( capabilities() & Size )
66  {
67  const double srcXRes = extent().width() / xSize();
68  const double srcYRes = extent().height() / ySize();
69  if ( xRes < srcXRes ) xRes = srcXRes;
70  if ( yRes < srcYRes ) yRes = srcYRes;
71  }
72  QgsDebugMsgLevel( QStringLiteral( "xRes = %1 yRes = %2" ).arg( xRes ).arg( yRes ), 4 );
73 
74  statistics.width = static_cast <int>( std::ceil( finalExtent.width() / xRes ) );
75  statistics.height = static_cast <int>( std::ceil( finalExtent.height() / yRes ) );
76  }
77  else
78  {
79  if ( capabilities() & Size )
80  {
81  statistics.width = xSize();
82  statistics.height = ySize();
83  }
84  else
85  {
86  statistics.width = 1000;
87  statistics.height = 1000;
88  }
89  }
90  QgsDebugMsgLevel( QStringLiteral( "theStatistics.width = %1 statistics.height = %2" ).arg( statistics.width ).arg( statistics.height ), 4 );
91 }
92 
94  int stats,
95  const QgsRectangle &extent,
96  int sampleSize )
97 {
98  QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 stats = %2 sampleSize = %3" ).arg( bandNo ).arg( stats ).arg( sampleSize ), 4 );
99  if ( mStatistics.isEmpty() ) return false;
100 
101  QgsRasterBandStats myRasterBandStats;
102  initStatistics( myRasterBandStats, bandNo, stats, extent, sampleSize );
103 
104  const auto constMStatistics = mStatistics;
105  for ( const QgsRasterBandStats &stats : constMStatistics )
106  {
107  if ( stats.contains( myRasterBandStats ) )
108  {
109  QgsDebugMsgLevel( QStringLiteral( "Has cached statistics." ), 4 );
110  return true;
111  }
112  }
113  return false;
114 }
115 
117  int stats,
118  const QgsRectangle &extent,
119  int sampleSize, QgsRasterBlockFeedback *feedback )
120 {
121  QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 stats = %2 sampleSize = %3" ).arg( bandNo ).arg( stats ).arg( sampleSize ), 4 );
122 
123  // TODO: null values set on raster layer!!!
124 
125  QgsRasterBandStats myRasterBandStats;
126  initStatistics( myRasterBandStats, bandNo, stats, extent, sampleSize );
127 
128  const auto constMStatistics = mStatistics;
129  for ( const QgsRasterBandStats &stats : constMStatistics )
130  {
131  if ( stats.contains( myRasterBandStats ) )
132  {
133  QgsDebugMsgLevel( QStringLiteral( "Using cached statistics." ), 4 );
134  return stats;
135  }
136  }
137 
138  const QgsRectangle myExtent = myRasterBandStats.extent;
139  const int myWidth = myRasterBandStats.width;
140  const int myHeight = myRasterBandStats.height;
141 
142  //int myDataType = dataType( bandNo );
143 
144  int myXBlockSize = xBlockSize();
145  int myYBlockSize = yBlockSize();
146  if ( myXBlockSize == 0 ) // should not happen, but happens
147  {
148  myXBlockSize = 500;
149  }
150  if ( myYBlockSize == 0 ) // should not happen, but happens
151  {
152  myYBlockSize = 500;
153  }
154 
155  const int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
156  const int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;
157 
158  const double myXRes = myExtent.width() / myWidth;
159  const double myYRes = myExtent.height() / myHeight;
160  // TODO: progress signals
161 
162  // used by single pass stdev
163  double myMean = 0;
164  double mySumOfSquares = 0;
165 
166  bool myFirstIterationFlag = true;
167  bool isNoData = false;
168  for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
169  {
170  for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
171  {
172  if ( feedback && feedback->isCanceled() )
173  return myRasterBandStats;
174 
175  QgsDebugMsgLevel( QStringLiteral( "myYBlock = %1 myXBlock = %2" ).arg( myYBlock ).arg( myXBlock ), 4 );
176  const int myBlockWidth = std::min( myXBlockSize, myWidth - myXBlock * myXBlockSize );
177  const int myBlockHeight = std::min( myYBlockSize, myHeight - myYBlock * myYBlockSize );
178 
179  const double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
180  const double xmax = xmin + myBlockWidth * myXRes;
181  const double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
182  const double ymax = ymin - myBlockHeight * myYRes;
183 
184  const QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );
185 
186  std::unique_ptr< QgsRasterBlock > blk( block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback ) );
187 
188  // Collect the histogram counts.
189  for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
190  {
191  const double myValue = blk->valueAndNoData( i, isNoData );
192  if ( isNoData )
193  continue; // NULL
194 
195  myRasterBandStats.sum += myValue;
196  myRasterBandStats.elementCount++;
197 
198  if ( !std::isfinite( myValue ) ) continue; // inf
199 
200  if ( myFirstIterationFlag )
201  {
202  myFirstIterationFlag = false;
203  myRasterBandStats.minimumValue = myValue;
204  myRasterBandStats.maximumValue = myValue;
205  }
206  else
207  {
208  if ( myValue < myRasterBandStats.minimumValue )
209  {
210  myRasterBandStats.minimumValue = myValue;
211  }
212  if ( myValue > myRasterBandStats.maximumValue )
213  {
214  myRasterBandStats.maximumValue = myValue;
215  }
216  }
217 
218  // Single pass stdev
219  const double myDelta = myValue - myMean;
220  myMean += myDelta / myRasterBandStats.elementCount;
221  mySumOfSquares += myDelta * ( myValue - myMean );
222  }
223  }
224  }
225 
226  myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
227  myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;
228 
229  myRasterBandStats.sumOfSquares = mySumOfSquares; // OK with single pass?
230 
231  // stdDev may differ from GDAL stats, because GDAL is using naive single pass
232  // algorithm which is more error prone (because of rounding errors)
233  // Divide result by sample size - 1 and get square root to get stdev
234  myRasterBandStats.stdDev = std::sqrt( mySumOfSquares / ( myRasterBandStats.elementCount - 1 ) );
235 
236  QgsDebugMsgLevel( QStringLiteral( "************ STATS **************" ), 4 );
237  QgsDebugMsgLevel( QStringLiteral( "MIN %1" ).arg( myRasterBandStats.minimumValue ), 4 );
238  QgsDebugMsgLevel( QStringLiteral( "MAX %1" ).arg( myRasterBandStats.maximumValue ), 4 );
239  QgsDebugMsgLevel( QStringLiteral( "RANGE %1" ).arg( myRasterBandStats.range ), 4 );
240  QgsDebugMsgLevel( QStringLiteral( "MEAN %1" ).arg( myRasterBandStats.mean ), 4 );
241  QgsDebugMsgLevel( QStringLiteral( "STDDEV %1" ).arg( myRasterBandStats.stdDev ), 4 );
242 
243  myRasterBandStats.statsGathered = QgsRasterBandStats::All;
244  mStatistics.append( myRasterBandStats );
245 
246  return myRasterBandStats;
247 }
248 
250  int bandNo,
251  int binCount,
252  double minimum, double maximum,
253  const QgsRectangle &boundingBox,
254  int sampleSize,
255  bool includeOutOfRange )
256 {
257  histogram.bandNumber = bandNo;
258  histogram.minimum = minimum;
259  histogram.maximum = maximum;
260  histogram.includeOutOfRange = includeOutOfRange;
261 
262  const Qgis::DataType mySrcDataType = sourceDataType( bandNo );
263 
264  if ( std::isnan( histogram.minimum ) )
265  {
266  // TODO: this was OK when stats/histogram were calced in provider,
267  // but what TODO in other interfaces? Check for mInput for now.
268  if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
269  {
270  histogram.minimum = 0; // see histogram() for shift for rounding
271  }
272  else
273  {
274  // We need statistics -> avoid histogramDefaults in hasHistogram if possible
275  // TODO: use approximated statistics if approximated histogram is requested
276  // (theSampleSize > 0)
277  const QgsRasterBandStats stats = bandStatistics( bandNo, QgsRasterBandStats::Min, boundingBox, sampleSize );
279  }
280  }
281  if ( std::isnan( histogram.maximum ) )
282  {
283  if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
284  {
285  histogram.maximum = 255;
286  }
287  else
288  {
289  const QgsRasterBandStats stats = bandStatistics( bandNo, QgsRasterBandStats::Max, boundingBox, sampleSize );
291  }
292  }
293 
294  QgsRectangle finalExtent;
295  if ( boundingBox.isEmpty() )
296  {
297  finalExtent = extent();
298  }
299  else
300  {
301  finalExtent = extent().intersect( boundingBox );
302  }
303  histogram.extent = finalExtent;
304 
305  if ( sampleSize > 0 )
306  {
307  // Calc resolution from theSampleSize
308  double xRes, yRes;
309  xRes = yRes = std::sqrt( ( static_cast<double>( finalExtent.width( ) ) * finalExtent.height() ) / sampleSize );
310 
311  // But limit by physical resolution
312  if ( capabilities() & Size )
313  {
314  const double srcXRes = extent().width() / xSize();
315  const double srcYRes = extent().height() / ySize();
316  if ( xRes < srcXRes ) xRes = srcXRes;
317  if ( yRes < srcYRes ) yRes = srcYRes;
318  }
319  QgsDebugMsgLevel( QStringLiteral( "xRes = %1 yRes = %2" ).arg( xRes ).arg( yRes ), 4 );
320 
321  histogram.width = static_cast <int>( finalExtent.width() / xRes );
322  histogram.height = static_cast <int>( finalExtent.height() / yRes );
323  }
324  else
325  {
326  if ( capabilities() & Size )
327  {
328  histogram.width = xSize();
329  histogram.height = ySize();
330  }
331  else
332  {
333  histogram.width = 1000;
334  histogram.height = 1000;
335  }
336  }
337  QgsDebugMsgLevel( QStringLiteral( "theHistogram.width = %1 histogram.height = %2" ).arg( histogram.width ).arg( histogram.height ), 4 );
338 
339  qint64 myBinCount = binCount;
340  if ( myBinCount == 0 )
341  {
342  // TODO: this was OK when stats/histogram were calced in provider,
343  // but what TODO in other interfaces? Check for mInput for now.
344  if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
345  {
346  myBinCount = 256; // Cannot store more values in byte
347  }
348  else
349  {
350  // There is no best default value, to display something reasonable in histogram chart,
351  // binCount should be small, OTOH, to get precise data for cumulative cut, the number should be big.
352  // Because it is easier to define fixed lower value for the chart, we calc optimum binCount
353  // for higher resolution (to avoid calculating that where histogram() is used. In any case,
354  // it does not make sense to use more than width*height;
355 
356  // for Int16/Int32 make sure bin count <= actual range, because there is no sense in having
357  // bins at fractional values
358  if ( !mInput && (
359  mySrcDataType == Qgis::DataType::Int16 || mySrcDataType == Qgis::DataType::Int32 ||
360  mySrcDataType == Qgis::DataType::UInt16 || mySrcDataType == Qgis::DataType::UInt32 ) )
361  {
362  myBinCount = std::min( static_cast<qint64>( histogram.width ) * histogram.height, static_cast<qint64>( std::ceil( histogram.maximum - histogram.minimum + 1 ) ) );
363  }
364  else
365  {
366  // This is for not integer types
367  myBinCount = static_cast<qint64>( histogram.width ) * static_cast<qint64>( histogram.height );
368  }
369  }
370  }
371  // Hard limit 10'000'000
372  histogram.binCount = static_cast<int>( std::min( 10000000LL, myBinCount ) );
373  QgsDebugMsgLevel( QStringLiteral( "theHistogram.binCount = %1" ).arg( histogram.binCount ), 4 );
374 }
375 
376 
378  int binCount,
379  double minimum, double maximum,
380  const QgsRectangle &extent,
381  int sampleSize,
382  bool includeOutOfRange )
383 {
384  QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5" ).arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );
385  // histogramDefaults() needs statistics if minimum or maximum is NaN ->
386  // do other checks which don't need statistics before histogramDefaults()
387  if ( mHistograms.isEmpty() ) return false;
388 
389  QgsRasterHistogram myHistogram;
390  initHistogram( myHistogram, bandNo, binCount, minimum, maximum, extent, sampleSize, includeOutOfRange );
391 
392  const auto constMHistograms = mHistograms;
393  for ( const QgsRasterHistogram &histogram : constMHistograms )
394  {
395  if ( histogram == myHistogram )
396  {
397  QgsDebugMsgLevel( QStringLiteral( "Has cached histogram." ), 4 );
398  return true;
399  }
400  }
401  return false;
402 }
403 
405  int binCount,
406  double minimum, double maximum,
407  const QgsRectangle &extent,
408  int sampleSize,
409  bool includeOutOfRange, QgsRasterBlockFeedback *feedback )
410 {
411  QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5" ).arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );
412 
413  QgsRasterHistogram myHistogram;
414  initHistogram( myHistogram, bandNo, binCount, minimum, maximum, extent, sampleSize, includeOutOfRange );
415 
416  // Find cached
417  const auto constMHistograms = mHistograms;
418  for ( const QgsRasterHistogram &histogram : constMHistograms )
419  {
420  if ( histogram == myHistogram )
421  {
422  QgsDebugMsgLevel( QStringLiteral( "Using cached histogram." ), 4 );
423  return histogram;
424  }
425  }
426 
427  const int myBinCount = myHistogram.binCount;
428  const int myWidth = myHistogram.width;
429  const int myHeight = myHistogram.height;
430  const QgsRectangle myExtent = myHistogram.extent;
431  myHistogram.histogramVector.resize( myBinCount );
432 
433  int myXBlockSize = xBlockSize();
434  int myYBlockSize = yBlockSize();
435  if ( myXBlockSize == 0 ) // should not happen, but happens
436  {
437  myXBlockSize = 500;
438  }
439  if ( myYBlockSize == 0 ) // should not happen, but happens
440  {
441  myYBlockSize = 500;
442  }
443 
444  const int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
445  const int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;
446 
447  const double myXRes = myExtent.width() / myWidth;
448  const double myYRes = myExtent.height() / myHeight;
449 
450  double myMinimum = myHistogram.minimum;
451  double myMaximum = myHistogram.maximum;
452 
453  // To avoid rounding errors
454  // TODO: check this
455  const double myerval = ( myMaximum - myMinimum ) / myHistogram.binCount;
456  myMinimum -= 0.1 * myerval;
457  myMaximum += 0.1 * myerval;
458 
459  QgsDebugMsgLevel( QStringLiteral( "binCount = %1 myMinimum = %2 myMaximum = %3" ).arg( myHistogram.binCount ).arg( myMinimum ).arg( myMaximum ), 4 );
460 
461  const double myBinSize = ( myMaximum - myMinimum ) / myBinCount;
462 
463  // TODO: progress signals
464  bool isNoData = false;
465  for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
466  {
467  for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
468  {
469  if ( feedback && feedback->isCanceled() )
470  return myHistogram;
471 
472  const int myBlockWidth = std::min( myXBlockSize, myWidth - myXBlock * myXBlockSize );
473  const int myBlockHeight = std::min( myYBlockSize, myHeight - myYBlock * myYBlockSize );
474 
475  const double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
476  const double xmax = xmin + myBlockWidth * myXRes;
477  const double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
478  const double ymax = ymin - myBlockHeight * myYRes;
479 
480  const QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );
481 
482  std::unique_ptr< QgsRasterBlock > blk( block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback ) );
483 
484  // Collect the histogram counts.
485  for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
486  {
487  const double myValue = blk->valueAndNoData( i, isNoData );
488  if ( isNoData )
489  {
490  continue; // NULL
491  }
492 
493  int myBinIndex = static_cast <int>( std::floor( ( myValue - myMinimum ) / myBinSize ) );
494 
495  if ( ( myBinIndex < 0 || myBinIndex > ( myBinCount - 1 ) ) && !includeOutOfRange )
496  {
497  continue;
498  }
499  if ( myBinIndex < 0 ) myBinIndex = 0;
500  if ( myBinIndex > ( myBinCount - 1 ) ) myBinIndex = myBinCount - 1;
501 
502  myHistogram.histogramVector[myBinIndex] += 1;
503  myHistogram.nonNullCount++;
504  }
505  }
506  }
507 
508  myHistogram.valid = true;
509  mHistograms.append( myHistogram );
510 
511 #ifdef QGISDEBUG
512  QString hist;
513  for ( std::size_t i = 0; i < std::min< std::size_t >( myHistogram.histogramVector.size(), 500 ); i++ )
514  {
515  hist += QString::number( myHistogram.histogramVector.value( i ) ) + ' ';
516  }
517  QgsDebugMsgLevel( QStringLiteral( "Histogram (max first 500 bins): " ) + hist, 4 );
518 #endif
519 
520  return myHistogram;
521 }
522 
524  double lowerCount, double upperCount,
525  double &lowerValue, double &upperValue,
526  const QgsRectangle &extent,
527  int sampleSize )
528 {
529  QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 lowerCount = %2 upperCount = %3 sampleSize = %4" ).arg( bandNo ).arg( lowerCount ).arg( upperCount ).arg( sampleSize ), 4 );
530 
531  const Qgis::DataType mySrcDataType = sourceDataType( bandNo );
532 
533  // Init to NaN is better than histogram min/max to catch errors
534  lowerValue = std::numeric_limits<double>::quiet_NaN();
535  upperValue = std::numeric_limits<double>::quiet_NaN();
536 
537  //get band stats to specify real histogram min/max (fix #9793 Byte bands)
538  const QgsRasterBandStats stats = bandStatistics( bandNo, QgsRasterBandStats::Min, extent, sampleSize );
539  if ( stats.maximumValue < stats.minimumValue )
540  return;
541 
542  // for byte bands make sure bin count == actual range
543  const int myBinCount = ( mySrcDataType == Qgis::DataType::Byte ) ? int( std::ceil( stats.maximumValue - stats.minimumValue + 1 ) ) : 0;
544  const QgsRasterHistogram myHistogram = histogram( bandNo, myBinCount, stats.minimumValue, stats.maximumValue, extent, sampleSize );
545  //QgsRasterHistogram myHistogram = histogram( bandNo, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), extent, sampleSize );
546 
547  const double myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / myHistogram.binCount;
548  int myCount = 0;
549  const int myMinCount = static_cast< int >( std::round( lowerCount * myHistogram.nonNullCount ) );
550  const int myMaxCount = static_cast< int >( std::round( upperCount * myHistogram.nonNullCount ) );
551  bool myLowerFound = false;
552  QgsDebugMsgLevel( QStringLiteral( "binCount = %1 minimum = %2 maximum = %3 myBinXStep = %4" ).arg( myHistogram.binCount ).arg( myHistogram.minimum ).arg( myHistogram.maximum ).arg( myBinXStep ), 4 );
553  QgsDebugMsgLevel( QStringLiteral( "myMinCount = %1 myMaxCount = %2" ).arg( myMinCount ).arg( myMaxCount ), 4 );
554 
555  for ( int myBin = 0; myBin < myHistogram.histogramVector.size(); myBin++ )
556  {
557  const int myBinValue = myHistogram.histogramVector.value( myBin );
558  myCount += myBinValue;
559  if ( !myLowerFound && myCount > myMinCount )
560  {
561  lowerValue = myHistogram.minimum + myBin * myBinXStep;
562  myLowerFound = true;
563  QgsDebugMsgLevel( QStringLiteral( "found lowerValue %1 at bin %2" ).arg( lowerValue ).arg( myBin ), 4 );
564  }
565  if ( myCount >= myMaxCount )
566  {
567  upperValue = myHistogram.minimum + myBin * myBinXStep;
568  QgsDebugMsgLevel( QStringLiteral( "found upperValue %1 at bin %2" ).arg( upperValue ).arg( myBin ), 4 );
569  break;
570  }
571  }
572 
573  // fix integer data - round down/up
574  if ( mySrcDataType == Qgis::DataType::Byte ||
575  mySrcDataType == Qgis::DataType::Int16 || mySrcDataType == Qgis::DataType::Int32 ||
576  mySrcDataType == Qgis::DataType::UInt16 || mySrcDataType == Qgis::DataType::UInt32 )
577  {
578  if ( !std::isnan( lowerValue ) )
579  lowerValue = std::floor( lowerValue );
580  if ( !std::isnan( upperValue ) )
581  upperValue = std::ceil( upperValue );
582  }
583 }
584 
586 {
587  QStringList abilitiesList;
588 
589  const int abilities = capabilities();
590 
591  // Not all all capabilities are here (Size, IdentifyValue, IdentifyText,
592  // IdentifyHtml, IdentifyFeature) because those are quite technical and probably
593  // would be confusing for users
594 
595  if ( abilities & QgsRasterInterface::Identify )
596  {
597  abilitiesList += tr( "Identify" );
598  }
599 
600  if ( abilities & QgsRasterInterface::Create )
601  {
602  abilitiesList += tr( "Create Datasources" );
603  }
604 
605  if ( abilities & QgsRasterInterface::Remove )
606  {
607  abilitiesList += tr( "Remove Datasources" );
608  }
609 
610  if ( abilities & QgsRasterInterface::BuildPyramids )
611  {
612  abilitiesList += tr( "Build Pyramids" );
613  }
614 
615  QgsDebugMsgLevel( "Capability: " + abilitiesList.join( QLatin1String( ", " ) ), 4 );
616 
617  return abilitiesList.join( QLatin1String( ", " ) );
618 }
619 
620 QString QgsRasterInterface::generateBandName( int bandNumber ) const
621 {
622  if ( mInput )
623  return mInput->generateBandName( bandNumber );
624 
625  return tr( "Band" ) + QStringLiteral( " %1" ) .arg( bandNumber, 1 + static_cast< int >( std::log10( static_cast< double >( bandCount() ) ) ), 10, QChar( '0' ) );
626 }
627 
629 {
630  if ( mInput )
631  return mInput->colorInterpretationName( bandNo );
632 
633  return QString();
634 }
635 
636 QString QgsRasterInterface::displayBandName( int bandNumber ) const
637 {
638  QString name = generateBandName( bandNumber );
639  const QString colorInterp = colorInterpretationName( bandNumber );
640  if ( colorInterp != QLatin1String( "Undefined" ) )
641  {
642  name.append( QStringLiteral( " (%1)" ).arg( colorInterp ) );
643  }
644  return name;
645 }
646 
648 {
649  return mRenderContext;
650 }
651 
653 {
654  mRenderContext = renderContext;
655 }
DataType
Raster data types.
Definition: qgis.h:121
@ Int16
Sixteen bit signed integer (qint16)
@ UInt16
Sixteen bit unsigned integer (quint16)
@ Byte
Eight bit unsigned integer (quint8)
@ Int32
Thirty two bit signed integer (qint32)
@ UInt32
Thirty two bit unsigned integer (quint32)
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
The RasterBandStats struct is a container for statistics about a single raster band.
qgssize elementCount
The number of not no data cells in the band.
int bandNumber
The gdal band number (starts at 1)
double sumOfSquares
The sum of the squares. Used to calculate standard deviation.
int height
Number of rows used to calc statistics.
int statsGathered
Collected statistics.
double mean
The mean cell value for the band. NO_DATA values are excluded.
QgsRectangle extent
Extent used to calc statistics.
double stdDev
The standard deviation of the cell values.
double minimumValue
The minimum cell value in the raster band.
int width
Number of columns used to calc statistics.
double sum
The sum of all cells in the band. NO_DATA values are excluded.
double maximumValue
The maximum cell value in the raster band.
double range
The range is the distance between min & max.
Feedback object tailored for raster block reading.
QgsRenderContext renderContext() const
Returns the render context of the associated block reading.
void setRenderContext(const QgsRenderContext &renderContext)
Sets the render context of the associated block reading.
The QgsRasterHistogram is a container for histogram of a single raster band.
double minimum
The minimum histogram value.
int bandNumber
The gdal band number (starts at 1)
double maximum
The maximum histogram value.
bool includeOutOfRange
Whether histogram includes out of range values (in first and last bin)
QgsRectangle extent
Extent used to calc histogram.
int nonNullCount
The number of non NULL cells used to calculate histogram.
QgsRasterHistogram::HistogramVector histogramVector
Stores the histogram for a given layer.
int height
Number of rows used to calc histogram.
int width
Number of columns used to calc histogram.
bool valid
Histogram is valid.
int binCount
Number of bins (intervals,buckets) in histogram.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual void cumulativeCut(int bandNo, double lowerCount, double upperCount, double &lowerValue, double &upperValue, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Find values for cumulative pixel count cut.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
virtual int yBlockSize() const
QList< QgsRasterBandStats > mStatistics
List of cached statistics, all bands mixed.
QString capabilitiesString() const
Returns the raster interface capabilities in friendly format.
@ BuildPyramids
Supports building of pyramids (overviews)
@ Remove
Delete datasets.
@ Identify
At least one identify format supported.
@ Create
Create new datasets.
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
void initHistogram(QgsRasterHistogram &histogram, int bandNo, int binCount, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &boundingBox=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false)
Fill in histogram defaults if not specified.
virtual int xSize() const
Gets raster size.
virtual QString generateBandName(int bandNumber) const
helper function to create zero padded band names
QgsRasterInterface(QgsRasterInterface *input=nullptr)
virtual Qgis::DataType sourceDataType(int bandNo) const
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual int xBlockSize() const
Gets block size.
void initStatistics(QgsRasterBandStats &statistics, int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &boundingBox=QgsRectangle(), int binCount=0)
Fill in statistics defaults if not specified.
virtual int bandCount() const =0
Gets number of bands.
virtual bool hasHistogram(int bandNo, int binCount, 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)
Returns true if histogram is available (cached, already calculated)
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
virtual bool hasStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Returns true if histogram is available (cached, already calculated).
QgsRasterInterface * mInput
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
virtual int ySize() const
virtual QgsRectangle extent() const
Gets the extent of the interface.
QList< QgsRasterHistogram > mHistograms
List of cached histograms, all bands mixed.
virtual QString colorInterpretationName(int bandNumber) const
Returns the name of the color interpretation for the specified bandNumber.
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.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
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
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:333
Contains information about the context of a rendering operation.
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:2036
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39