QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 ) const
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 }
QgsRasterInterface::hasStatistics
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).
Definition: qgsrasterinterface.cpp:93
qgsrasterbandstats.h
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
QgsRasterHistogram::histogramVector
QgsRasterHistogram::HistogramVector histogramVector
Stores the histogram for a given layer.
Definition: qgsrasterhistogram.h:84
QgsRasterBandStats::elementCount
qgssize elementCount
The number of not no data cells in the band.
Definition: qgsrasterbandstats.h:95
QgsRasterInterface::mStatistics
QList< QgsRasterBandStats > mStatistics
List of cached statistics, all bands mixed.
Definition: qgsrasterinterface.h:503
QgsRasterInterface::bandStatistics
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
Definition: qgsrasterinterface.cpp:116
QgsRasterInterface::sourceDataType
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...
Definition: qgsrasterinterface.h:242
qgsrectangle.h
Qgis::DataType::UInt32
@ UInt32
Thirty two bit unsigned integer (quint32)
QgsRasterInterface::Size
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
Definition: qgsrasterinterface.h:205
qgsrasterhistogram.h
QgsRasterInterface::mInput
QgsRasterInterface * mInput
Definition: qgsrasterinterface.h:500
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsRasterInterface::cumulativeCut
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.
Definition: qgsrasterinterface.cpp:523
QgsRasterBandStats
The RasterBandStats struct is a container for statistics about a single raster band.
Definition: qgsrasterbandstats.h:34
QgsRasterBandStats::sumOfSquares
double sumOfSquares
The sum of the squares. Used to calculate standard deviation.
Definition: qgsrasterbandstats.h:125
QgsRasterInterface::xBlockSize
virtual int xBlockSize() const
Gets block size.
Definition: qgsrasterinterface.h:259
QgsRasterInterface::displayBandName
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
Definition: qgsrasterinterface.cpp:636
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:128
QgsRasterBandStats::mean
double mean
The mean cell value for the band. NO_DATA values are excluded.
Definition: qgsrasterbandstats.h:110
Qgis::DataType::Byte
@ Byte
Eight bit unsigned integer (quint8)
QgsRasterInterface::BuildPyramids
@ BuildPyramids
Supports building of pyramids (overviews)
Definition: qgsrasterinterface.h:208
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsRasterInterface::yBlockSize
virtual int yBlockSize() const
Definition: qgsrasterinterface.h:260
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsRasterInterface::hasHistogram
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)
Definition: qgsrasterinterface.cpp:377
QgsRasterBandStats::range
double range
The range is the distance between min & max.
Definition: qgsrasterbandstats.h:113
Qgis::DataType::Int32
@ Int32
Thirty two bit signed integer (qint32)
QgsRasterHistogram::valid
bool valid
Histogram is valid.
Definition: qgsrasterhistogram.h:102
QgsRectangle::intersect
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:333
QgsRasterInterface::Identify
@ Identify
At least one identify format supported.
Definition: qgsrasterinterface.h:209
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsRasterBlockFeedback::setRenderContext
void setRenderContext(const QgsRenderContext &renderContext)
Sets the render context of the associated block reading.
Definition: qgsrasterinterface.cpp:652
QgsRasterBandStats::maximumValue
double maximumValue
The maximum cell value in the raster band.
Definition: qgsrasterbandstats.h:101
QgsRasterHistogram::extent
QgsRectangle extent
Extent used to calc histogram.
Definition: qgsrasterhistogram.h:99
qgsrasterinterface.h
QgsRasterHistogram::includeOutOfRange
bool includeOutOfRange
Whether histogram includes out of range values (in first and last bin)
Definition: qgsrasterhistogram.h:79
QgsRasterHistogram::minimum
double minimum
The minimum histogram value.
Definition: qgsrasterhistogram.h:90
QgsRasterBandStats::All
@ All
Definition: qgsrasterbandstats.h:73
QgsRasterInterface::xSize
virtual int xSize() const
Gets raster size.
Definition: qgsrasterinterface.h:263
QgsRasterInterface::generateBandName
virtual QString generateBandName(int bandNumber) const
helper function to create zero padded band names
Definition: qgsrasterinterface.cpp:620
Qgis::DataType::Int16
@ Int16
Sixteen bit signed integer (qint16)
QgsRasterBandStats::Min
@ Min
Definition: qgsrasterbandstats.h:66
QgsRasterInterface::Create
@ Create
Create new datasets.
Definition: qgsrasterinterface.h:206
QgsRasterBlockFeedback::renderContext
QgsRenderContext renderContext() const
Returns the render context of the associated block reading.
Definition: qgsrasterinterface.cpp:647
QgsRasterHistogram::binCount
int binCount
Number of bins (intervals,buckets) in histogram.
Definition: qgsrasterhistogram.h:73
QgsRasterHistogram::nonNullCount
int nonNullCount
The number of non NULL cells used to calculate histogram.
Definition: qgsrasterhistogram.h:76
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
Qgis::DataType::UInt16
@ UInt16
Sixteen bit unsigned integer (quint16)
QgsRasterInterface::initHistogram
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.
Definition: qgsrasterinterface.cpp:249
QgsRasterInterface::ySize
virtual int ySize() const
Definition: qgsrasterinterface.h:264
QgsRasterInterface::Remove
@ Remove
Delete datasets.
Definition: qgsrasterinterface.h:207
QgsRasterBandStats::sum
double sum
The sum of all cells in the band. NO_DATA values are excluded.
Definition: qgsrasterbandstats.h:122
QgsRasterBandStats::minimumValue
double minimumValue
The minimum cell value in the raster band.
Definition: qgsrasterbandstats.h:107
QgsRasterBandStats::Max
@ Max
Definition: qgsrasterbandstats.h:67
QgsRasterInterface::mHistograms
QList< QgsRasterHistogram > mHistograms
List of cached histograms, all bands mixed.
Definition: qgsrasterinterface.h:506
QgsRasterInterface
Base class for processing filters like renderers, reprojector, resampler etc.
Definition: qgsrasterinterface.h:135
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsRasterInterface::histogram
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.
Definition: qgsrasterinterface.cpp:404
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsRasterHistogram
The QgsRasterHistogram is a container for histogram of a single raster band. It is used to cache comp...
Definition: qgsrasterhistogram.h:33
QgsRasterBlockFeedback
Feedback object tailored for raster block reading.
Definition: qgsrasterinterface.h:41
QgsRasterInterface::colorInterpretationName
virtual QString colorInterpretationName(int bandNumber) const
Returns the name of the color interpretation for the specified bandNumber.
Definition: qgsrasterinterface.cpp:628
QgsRasterInterface::initStatistics
void initStatistics(QgsRasterBandStats &statistics, int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &boundingBox=QgsRectangle(), int binCount=0) const
Fill in statistics defaults if not specified.
Definition: qgsrasterinterface.cpp:36
QgsRasterBandStats::extent
QgsRectangle extent
Extent used to calc statistics.
Definition: qgsrasterbandstats.h:134
QgsRasterBandStats::width
int width
Number of columns used to calc statistics.
Definition: qgsrasterbandstats.h:128
QgsRasterHistogram::height
int height
Number of rows used to calc histogram.
Definition: qgsrasterhistogram.h:96
QgsRasterBandStats::stdDev
double stdDev
The standard deviation of the cell values.
Definition: qgsrasterbandstats.h:116
QgsRasterInterface::bandCount
virtual int bandCount() const =0
Gets number of bands.
QgsRasterInterface::block
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.
qgslogger.h
QgsRasterHistogram::width
int width
Number of columns used to calc histogram.
Definition: qgsrasterhistogram.h:93
QgsRasterHistogram::maximum
double maximum
The maximum histogram value.
Definition: qgsrasterhistogram.h:87
QgsRasterInterface::QgsRasterInterface
QgsRasterInterface(QgsRasterInterface *input=nullptr)
Definition: qgsrasterinterface.cpp:31
QgsRectangle::isEmpty
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
QgsRasterInterface::capabilities
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
Definition: qgsrasterinterface.h:225
QgsRasterBandStats::statsGathered
int statsGathered
Collected statistics.
Definition: qgsrasterbandstats.h:119
QgsRasterInterface::capabilitiesString
QString capabilitiesString() const
Returns the raster interface capabilities in friendly format.
Definition: qgsrasterinterface.cpp:585
QgsRasterInterface::extent
virtual QgsRectangle extent() const
Gets the extent of the interface.
Definition: qgsrasterinterface.h:248
QgsRasterHistogram::bandNumber
int bandNumber
The gdal band number (starts at 1)
Definition: qgsrasterhistogram.h:70
QgsRasterBandStats::height
int height
Number of rows used to calc statistics.
Definition: qgsrasterbandstats.h:131
QgsRasterBandStats::bandNumber
int bandNumber
The gdal band number (starts at 1)
Definition: qgsrasterbandstats.h:90
qgssize
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:2791