QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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,
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
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
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
244 mStatistics.append( myRasterBandStats );
245
246 return myRasterBandStats;
247}
248
249bool QgsRasterInterface::hasStatistics( int bandNo, int stats, const QgsRectangle &extent, int sampleSize )
250{
251 return hasStatistics( bandNo, static_cast< Qgis::RasterBandStatistics >( stats ), extent, sampleSize );
252}
253
255 int bandNo,
256 int binCount,
257 double minimum, double maximum,
258 const QgsRectangle &boundingBox,
259 int sampleSize,
260 bool includeOutOfRange )
261{
262 histogram.bandNumber = bandNo;
263 histogram.minimum = minimum;
264 histogram.maximum = maximum;
265 histogram.includeOutOfRange = includeOutOfRange;
266
267 const Qgis::DataType mySrcDataType = sourceDataType( bandNo );
268
269 if ( std::isnan( histogram.minimum ) )
270 {
271 // TODO: this was OK when stats/histogram were calced in provider,
272 // but what TODO in other interfaces? Check for mInput for now.
273 if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
274 {
275 histogram.minimum = 0; // see histogram() for shift for rounding
276 }
277 else
278 {
279 // We need statistics -> avoid histogramDefaults in hasHistogram if possible
280 // TODO: use approximated statistics if approximated histogram is requested
281 // (theSampleSize > 0)
282 const QgsRasterBandStats stats = bandStatistics( bandNo, Qgis::RasterBandStatistic::Min, boundingBox, sampleSize );
284 }
285 }
286 if ( std::isnan( histogram.maximum ) )
287 {
288 if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
289 {
290 histogram.maximum = 255;
291 }
292 else
293 {
294 const QgsRasterBandStats stats = bandStatistics( bandNo, Qgis::RasterBandStatistic::Max, boundingBox, sampleSize );
296 }
297 }
298
299 QgsRectangle finalExtent;
300 if ( boundingBox.isEmpty() )
301 {
302 finalExtent = extent();
303 }
304 else
305 {
306 finalExtent = extent().intersect( boundingBox );
307 }
308 histogram.extent = finalExtent;
309
310 if ( sampleSize > 0 )
311 {
312 // Calc resolution from theSampleSize
313 double xRes, yRes;
314 xRes = yRes = std::sqrt( ( static_cast<double>( finalExtent.width( ) ) * finalExtent.height() ) / sampleSize );
315
316 // But limit by physical resolution
317 if ( capabilities() & Size )
318 {
319 const double srcXRes = extent().width() / xSize();
320 const double srcYRes = extent().height() / ySize();
321 if ( xRes < srcXRes ) xRes = srcXRes;
322 if ( yRes < srcYRes ) yRes = srcYRes;
323 }
324 QgsDebugMsgLevel( QStringLiteral( "xRes = %1 yRes = %2" ).arg( xRes ).arg( yRes ), 4 );
325
326 histogram.width = static_cast <int>( finalExtent.width() / xRes );
327 histogram.height = static_cast <int>( finalExtent.height() / yRes );
328 }
329 else
330 {
331 if ( capabilities() & Size )
332 {
335 }
336 else
337 {
338 histogram.width = 1000;
339 histogram.height = 1000;
340 }
341 }
342 QgsDebugMsgLevel( QStringLiteral( "theHistogram.width = %1 histogram.height = %2" ).arg( histogram.width ).arg( histogram.height ), 4 );
343
344 qint64 myBinCount = binCount;
345 if ( myBinCount == 0 )
346 {
347 // TODO: this was OK when stats/histogram were calced in provider,
348 // but what TODO in other interfaces? Check for mInput for now.
349 if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
350 {
351 myBinCount = 256; // Cannot store more values in byte
352 }
353 else
354 {
355 // There is no best default value, to display something reasonable in histogram chart,
356 // binCount should be small, OTOH, to get precise data for cumulative cut, the number should be big.
357 // Because it is easier to define fixed lower value for the chart, we calc optimum binCount
358 // for higher resolution (to avoid calculating that where histogram() is used. In any case,
359 // it does not make sense to use more than width*height;
360
361 // for Int16/Int32 make sure bin count <= actual range, because there is no sense in having
362 // bins at fractional values
363 if ( !mInput && (
364 mySrcDataType == Qgis::DataType::Int16 || mySrcDataType == Qgis::DataType::Int32 ||
365 mySrcDataType == Qgis::DataType::UInt16 || mySrcDataType == Qgis::DataType::UInt32 ) )
366 {
367 myBinCount = std::min( static_cast<qint64>( histogram.width ) * histogram.height, static_cast<qint64>( std::ceil( histogram.maximum - histogram.minimum + 1 ) ) );
368 }
369 else
370 {
371 // This is for not integer types
372 myBinCount = static_cast<qint64>( histogram.width ) * static_cast<qint64>( histogram.height );
373 }
374 }
375 }
376 // Hard limit 10'000'000
377 histogram.binCount = static_cast<int>( std::min( 10000000LL, myBinCount ) );
378 QgsDebugMsgLevel( QStringLiteral( "theHistogram.binCount = %1" ).arg( histogram.binCount ), 4 );
379}
380
381void QgsRasterInterface::initStatistics( QgsRasterBandStats &statistics, int bandNo, int stats, const QgsRectangle &boundingBox, int binCount ) const
382{
383 initStatistics( statistics, bandNo, static_cast< Qgis::RasterBandStatistics>( stats ), boundingBox, binCount );
384}
385
387 int binCount,
388 double minimum, double maximum,
389 const QgsRectangle &extent,
390 int sampleSize,
391 bool includeOutOfRange )
392{
393 QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5" ).arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );
394 // histogramDefaults() needs statistics if minimum or maximum is NaN ->
395 // do other checks which don't need statistics before histogramDefaults()
396 if ( mHistograms.isEmpty() ) return false;
397
398 QgsRasterHistogram myHistogram;
399 initHistogram( myHistogram, bandNo, binCount, minimum, maximum, extent, sampleSize, includeOutOfRange );
400
401 const auto constMHistograms = mHistograms;
402 for ( const QgsRasterHistogram &histogram : constMHistograms )
403 {
404 if ( histogram == myHistogram )
405 {
406 QgsDebugMsgLevel( QStringLiteral( "Has cached histogram." ), 4 );
407 return true;
408 }
409 }
410 return false;
411}
412
414 int binCount,
415 double minimum, double maximum,
416 const QgsRectangle &extent,
417 int sampleSize,
418 bool includeOutOfRange, QgsRasterBlockFeedback *feedback )
419{
420 QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5" ).arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );
421
422 QgsRasterHistogram myHistogram;
423 initHistogram( myHistogram, bandNo, binCount, minimum, maximum, extent, sampleSize, includeOutOfRange );
424
425 // Find cached
426 const auto constMHistograms = mHistograms;
427 for ( const QgsRasterHistogram &histogram : constMHistograms )
428 {
429 if ( histogram == myHistogram )
430 {
431 QgsDebugMsgLevel( QStringLiteral( "Using cached histogram." ), 4 );
432 return histogram;
433 }
434 }
435
436 const int myBinCount = myHistogram.binCount;
437 const int myWidth = myHistogram.width;
438 const int myHeight = myHistogram.height;
439 const QgsRectangle myExtent = myHistogram.extent;
440 myHistogram.histogramVector.resize( myBinCount );
441
442 int myXBlockSize = xBlockSize();
443 int myYBlockSize = yBlockSize();
444 if ( myXBlockSize == 0 ) // should not happen, but happens
445 {
446 myXBlockSize = 500;
447 }
448 if ( myYBlockSize == 0 ) // should not happen, but happens
449 {
450 myYBlockSize = 500;
451 }
452
453 const int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
454 const int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;
455
456 const double myXRes = myExtent.width() / myWidth;
457 const double myYRes = myExtent.height() / myHeight;
458
459 double myMinimum = myHistogram.minimum;
460 double myMaximum = myHistogram.maximum;
461
462 // To avoid rounding errors
463 // TODO: check this
464 const double myerval = ( myMaximum - myMinimum ) / myHistogram.binCount;
465 myMinimum -= 0.1 * myerval;
466 myMaximum += 0.1 * myerval;
467
468 QgsDebugMsgLevel( QStringLiteral( "binCount = %1 myMinimum = %2 myMaximum = %3" ).arg( myHistogram.binCount ).arg( myMinimum ).arg( myMaximum ), 4 );
469
470 const double myBinSize = ( myMaximum - myMinimum ) / myBinCount;
471
472 // TODO: progress signals
473 bool isNoData = false;
474 for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
475 {
476 for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
477 {
478 if ( feedback && feedback->isCanceled() )
479 return myHistogram;
480
481 const int myBlockWidth = std::min( myXBlockSize, myWidth - myXBlock * myXBlockSize );
482 const int myBlockHeight = std::min( myYBlockSize, myHeight - myYBlock * myYBlockSize );
483
484 const double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
485 const double xmax = xmin + myBlockWidth * myXRes;
486 const double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
487 const double ymax = ymin - myBlockHeight * myYRes;
488
489 const QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );
490
491 std::unique_ptr< QgsRasterBlock > blk( block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback ) );
492
493 // Collect the histogram counts.
494 for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
495 {
496 const double myValue = blk->valueAndNoData( i, isNoData );
497 if ( isNoData )
498 {
499 continue; // NULL
500 }
501
502 int myBinIndex = static_cast <int>( std::floor( ( myValue - myMinimum ) / myBinSize ) );
503
504 if ( ( myBinIndex < 0 || myBinIndex > ( myBinCount - 1 ) ) && !includeOutOfRange )
505 {
506 continue;
507 }
508 if ( myBinIndex < 0 ) myBinIndex = 0;
509 if ( myBinIndex > ( myBinCount - 1 ) ) myBinIndex = myBinCount - 1;
510
511 myHistogram.histogramVector[myBinIndex] += 1;
512 myHistogram.nonNullCount++;
513 }
514 }
515 }
516
517 myHistogram.valid = true;
518 mHistograms.append( myHistogram );
519
520#ifdef QGISDEBUG
521 QString hist;
522 for ( std::size_t i = 0; i < std::min< std::size_t >( myHistogram.histogramVector.size(), 500 ); i++ )
523 {
524 hist += QString::number( myHistogram.histogramVector.value( i ) ) + ' ';
525 }
526 QgsDebugMsgLevel( QStringLiteral( "Histogram (max first 500 bins): " ) + hist, 4 );
527#endif
528
529 return myHistogram;
530}
531
533 double lowerCount, double upperCount,
534 double &lowerValue, double &upperValue,
535 const QgsRectangle &extent,
536 int sampleSize )
537{
538 QgsDebugMsgLevel( QStringLiteral( "theBandNo = %1 lowerCount = %2 upperCount = %3 sampleSize = %4" ).arg( bandNo ).arg( lowerCount ).arg( upperCount ).arg( sampleSize ), 4 );
539
540 const Qgis::DataType mySrcDataType = sourceDataType( bandNo );
541
542 // Init to NaN is better than histogram min/max to catch errors
543 lowerValue = std::numeric_limits<double>::quiet_NaN();
544 upperValue = std::numeric_limits<double>::quiet_NaN();
545
546 //get band stats to specify real histogram min/max (fix #9793 Byte bands)
547 const QgsRasterBandStats stats = bandStatistics( bandNo, Qgis::RasterBandStatistic::Min, extent, sampleSize );
548 if ( stats.maximumValue < stats.minimumValue )
549 return;
550
551 // for byte bands make sure bin count == actual range
552 const int myBinCount = ( mySrcDataType == Qgis::DataType::Byte ) ? int( std::ceil( stats.maximumValue - stats.minimumValue + 1 ) ) : 0;
553 const QgsRasterHistogram myHistogram = histogram( bandNo, myBinCount, stats.minimumValue, stats.maximumValue, extent, sampleSize );
554 //QgsRasterHistogram myHistogram = histogram( bandNo, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), extent, sampleSize );
555
556 const double myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / myHistogram.binCount;
557 int myCount = 0;
558 const int myMinCount = static_cast< int >( std::round( lowerCount * myHistogram.nonNullCount ) );
559 const int myMaxCount = static_cast< int >( std::round( upperCount * myHistogram.nonNullCount ) );
560 bool myLowerFound = false;
561 QgsDebugMsgLevel( QStringLiteral( "binCount = %1 minimum = %2 maximum = %3 myBinXStep = %4" ).arg( myHistogram.binCount ).arg( myHistogram.minimum ).arg( myHistogram.maximum ).arg( myBinXStep ), 4 );
562 QgsDebugMsgLevel( QStringLiteral( "myMinCount = %1 myMaxCount = %2" ).arg( myMinCount ).arg( myMaxCount ), 4 );
563
564 for ( int myBin = 0; myBin < myHistogram.histogramVector.size(); myBin++ )
565 {
566 const int myBinValue = myHistogram.histogramVector.value( myBin );
567 myCount += myBinValue;
568 if ( !myLowerFound && myCount > myMinCount )
569 {
570 lowerValue = myHistogram.minimum + myBin * myBinXStep;
571 myLowerFound = true;
572 QgsDebugMsgLevel( QStringLiteral( "found lowerValue %1 at bin %2" ).arg( lowerValue ).arg( myBin ), 4 );
573 }
574 if ( myCount >= myMaxCount )
575 {
576 upperValue = myHistogram.minimum + myBin * myBinXStep;
577 QgsDebugMsgLevel( QStringLiteral( "found upperValue %1 at bin %2" ).arg( upperValue ).arg( myBin ), 4 );
578 break;
579 }
580 }
581
582 // fix integer data - round down/up
583 if ( mySrcDataType == Qgis::DataType::Byte ||
584 mySrcDataType == Qgis::DataType::Int16 || mySrcDataType == Qgis::DataType::Int32 ||
585 mySrcDataType == Qgis::DataType::UInt16 || mySrcDataType == Qgis::DataType::UInt32 )
586 {
587 if ( !std::isnan( lowerValue ) )
588 lowerValue = std::floor( lowerValue );
589 if ( !std::isnan( upperValue ) )
590 upperValue = std::ceil( upperValue );
591 }
592}
593
595{
596 QStringList abilitiesList;
597
598 const int abilities = capabilities();
599
600 // Not all all capabilities are here (Size, IdentifyValue, IdentifyText,
601 // IdentifyHtml, IdentifyFeature) because those are quite technical and probably
602 // would be confusing for users
603
604 if ( abilities & QgsRasterInterface::Identify )
605 {
606 abilitiesList += tr( "Identify" );
607 }
608
609 if ( abilities & QgsRasterInterface::Create )
610 {
611 abilitiesList += tr( "Create Datasources" );
612 }
613
614 if ( abilities & QgsRasterInterface::Remove )
615 {
616 abilitiesList += tr( "Remove Datasources" );
617 }
618
619 if ( abilities & QgsRasterInterface::BuildPyramids )
620 {
621 abilitiesList += tr( "Build Pyramids" );
622 }
623
624 QgsDebugMsgLevel( "Capability: " + abilitiesList.join( QLatin1String( ", " ) ), 4 );
625
626 return abilitiesList.join( QLatin1String( ", " ) );
627}
628
629QString QgsRasterInterface::generateBandName( int bandNumber ) const
630{
631 if ( mInput )
632 return mInput->generateBandName( bandNumber );
633
634 // For bad layers bandCount is 0, no log!
635 return tr( "Band" ) + QStringLiteral( " %1" ) .arg( bandNumber, 1 + ( bandCount() > 0 ? static_cast< int >( std::log10( static_cast< double >( bandCount() ) ) ) : 0 ), 10, QChar( '0' ) );
636}
637
639{
640 if ( mInput )
641 return mInput->colorInterpretationName( bandNo );
642
643 return QString();
644}
645
646QString QgsRasterInterface::displayBandName( int bandNumber ) const
647{
648 QString name = generateBandName( bandNumber );
649 const QString colorInterp = colorInterpretationName( bandNumber );
650 if ( colorInterp != QLatin1String( "Undefined" ) )
651 {
652 name.append( QStringLiteral( " (%1)" ).arg( colorInterp ) );
653 }
654 return name;
655}
656
657QgsRasterBandStats QgsRasterInterface::bandStatistics( int bandNo, int stats, const QgsRectangle &extent, int sampleSize, QgsRasterBlockFeedback *feedback )
658{
659 return bandStatistics( bandNo, static_cast < Qgis::RasterBandStatistics>( stats ), extent, sampleSize, feedback );
660}
661
663{
664 return mRenderContext;
665}
666
668{
669 mRenderContext = renderContext;
670}
QFlags< RasterBandStatistic > RasterBandStatistics
Statistics to be calculated for raster bands.
Definition: qgis.h:4856
@ All
All available statistics.
DataType
Raster data types.
Definition: qgis.h:269
@ 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
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
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.
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.
Qgis::RasterBandStatistics statsGathered
Collected statistics.
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 int yBlockSize() const
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.
Q_DECL_DEPRECATED void initStatistics(QgsRasterBandStats &statistics, int bandNo, int stats, const QgsRectangle &boundingBox=QgsRectangle(), int binCount=0) const
Fill in statistics defaults if not specified.
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)
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
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.
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)
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
Q_DECL_DEPRECATED bool hasStatistics(int bandNo, int stats, 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 xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
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
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:355
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:5747
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39