QGIS API Documentation 4.3.0-Master (58212645307)
Loading...
Searching...
No Matches
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 "qgsrasterinterface.h"
19
20#include <limits>
21#include <typeinfo>
22
23#include "qgslogger.h"
24#include "qgsrasterbandstats.h"
25#include "qgsrasterhistogram.h"
26#include "qgsrectangle.h"
27
28#include <QByteArray>
29#include <QString>
30#include <QStringList>
31#include <QTime>
32
33#include "moc_qgsrasterinterface.cpp"
34
35using namespace Qt::StringLiterals;
36
40
45
46void QgsRasterInterface::initStatistics( QgsRasterBandStats &statistics, int bandNo, Qgis::RasterBandStatistics stats, const QgsRectangle &boundingBox, int sampleSize ) const
47{
48 QgsDebugMsgLevel( u"theBandNo = %1 sampleSize = %2"_s.arg( bandNo ).arg( sampleSize ), 4 );
49
50 statistics.bandNumber = bandNo;
51 statistics.statsGathered = stats;
52
53 QgsRectangle finalExtent;
54 if ( boundingBox.isEmpty() )
55 {
56 finalExtent = extent();
57 }
58 else
59 {
60 finalExtent = extent().intersect( boundingBox );
61 }
62 statistics.extent = finalExtent;
63
64 if ( sampleSize > 0 )
65 {
66 // Calc resolution from theSampleSize
67 double xRes, yRes;
68 xRes = yRes = std::sqrt( ( finalExtent.width() * finalExtent.height() ) / sampleSize );
69
70 // But limit by physical resolution
72 {
73 const double srcXRes = extent().width() / xSize();
74 const double srcYRes = extent().height() / ySize();
75 if ( xRes < srcXRes )
76 xRes = srcXRes;
77 if ( yRes < srcYRes )
78 yRes = srcYRes;
79 }
80 QgsDebugMsgLevel( u"xRes = %1 yRes = %2"_s.arg( xRes ).arg( yRes ), 4 );
81
82 statistics.width = static_cast<int>( std::ceil( finalExtent.width() / xRes ) );
83 statistics.height = static_cast<int>( std::ceil( finalExtent.height() / yRes ) );
84 }
85 else
86 {
88 {
89 statistics.width = xSize();
90 statistics.height = ySize();
91 }
92 else
93 {
94 statistics.width = 1000;
95 statistics.height = 1000;
96 }
97 }
98 QgsDebugMsgLevel( u"theStatistics.width = %1 statistics.height = %2"_s.arg( statistics.width ).arg( statistics.height ), 4 );
99}
100
102{
103 QgsDebugMsgLevel( u"theBandNo = %1 stats = %2 sampleSize = %3"_s.arg( bandNo ).arg( static_cast<int>( stats ) ).arg( sampleSize ), 4 );
104 if ( mStatistics.isEmpty() )
105 return false;
106
107 QgsRasterBandStats myRasterBandStats;
108 initStatistics( myRasterBandStats, bandNo, stats, extent, sampleSize );
109
110 const auto constMStatistics = mStatistics;
111 for ( const QgsRasterBandStats &stats : constMStatistics )
112 {
113 if ( stats.contains( myRasterBandStats ) )
114 {
115 QgsDebugMsgLevel( u"Has cached statistics."_s, 4 );
116 return true;
117 }
118 }
119 return false;
120}
121
123{
124 QgsDebugMsgLevel( u"theBandNo = %1 stats = %2 sampleSize = %3"_s.arg( bandNo ).arg( static_cast<int>( stats ) ).arg( sampleSize ), 4 );
125
126 // TODO: null values set on raster layer!!!
127
128 QgsRasterBandStats myRasterBandStats;
129 initStatistics( myRasterBandStats, bandNo, stats, extent, sampleSize );
130
131 const auto constMStatistics = mStatistics;
132 for ( const QgsRasterBandStats &stats : constMStatistics )
133 {
134 if ( stats.contains( myRasterBandStats ) )
135 {
136 QgsDebugMsgLevel( u"Using cached statistics."_s, 4 );
137 return stats;
138 }
139 }
140
141 const QgsRectangle myExtent = myRasterBandStats.extent;
142 const int myWidth = myRasterBandStats.width;
143 const int myHeight = myRasterBandStats.height;
144
145 //int myDataType = dataType( bandNo );
146
147 int myXBlockSize = xBlockSize();
148 int myYBlockSize = yBlockSize();
149 if ( myXBlockSize == 0 ) // should not happen, but happens
150 {
151 myXBlockSize = 500;
152 }
153 if ( myYBlockSize == 0 ) // should not happen, but happens
154 {
155 myYBlockSize = 500;
156 }
157
158 const int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
159 const int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;
160
161 const double myXRes = myExtent.width() / myWidth;
162 const double myYRes = myExtent.height() / myHeight;
163 // TODO: progress signals
164
165 // used by single pass stdev
166 double myMean = 0;
167 double mySumOfSquares = 0;
168
169 bool myFirstIterationFlag = true;
170 bool isNoData = false;
171 for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
172 {
173 for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
174 {
175 if ( feedback && feedback->isCanceled() )
176 return myRasterBandStats;
177
178 QgsDebugMsgLevel( u"myYBlock = %1 myXBlock = %2"_s.arg( myYBlock ).arg( myXBlock ), 4 );
179 const int myBlockWidth = std::min( myXBlockSize, myWidth - myXBlock * myXBlockSize );
180 const int myBlockHeight = std::min( myYBlockSize, myHeight - myYBlock * myYBlockSize );
181
182 const double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
183 const double xmax = xmin + myBlockWidth * myXRes;
184 const double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
185 const double ymax = ymin - myBlockHeight * myYRes;
186
187 const QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );
188
189 std::unique_ptr< QgsRasterBlock > blk( block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback ) );
190
191 // Collect the histogram counts.
192 for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
193 {
194 const double myValue = blk->valueAndNoData( i, isNoData );
195 if ( isNoData )
196 continue; // NULL
197
198 myRasterBandStats.sum += myValue;
199 myRasterBandStats.elementCount++;
200
201 if ( !std::isfinite( myValue ) )
202 continue; // inf
203
204 if ( myFirstIterationFlag )
205 {
206 myFirstIterationFlag = false;
207 myRasterBandStats.minimumValue = myValue;
208 myRasterBandStats.maximumValue = myValue;
209 }
210 else
211 {
212 if ( myValue < myRasterBandStats.minimumValue )
213 {
214 myRasterBandStats.minimumValue = myValue;
215 }
216 if ( myValue > myRasterBandStats.maximumValue )
217 {
218 myRasterBandStats.maximumValue = myValue;
219 }
220 }
221
222 // Single pass stdev
223 const double myDelta = myValue - myMean;
224 myMean += myDelta / myRasterBandStats.elementCount;
225 mySumOfSquares += myDelta * ( myValue - myMean );
226 }
227 }
228 }
229
230 myRasterBandStats.range = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
231 myRasterBandStats.mean = myRasterBandStats.sum / myRasterBandStats.elementCount;
232
233 myRasterBandStats.sumOfSquares = mySumOfSquares; // OK with single pass?
234
235 // stdDev may differ from GDAL stats, because GDAL is using naive single pass
236 // algorithm which is more error prone (because of rounding errors)
237 // Divide result by sample size - 1 and get square root to get stdev
238 myRasterBandStats.stdDev = std::sqrt( mySumOfSquares / ( static_cast< double >( myRasterBandStats.elementCount ) - 1 ) );
239
240 QgsDebugMsgLevel( u"************ STATS **************"_s, 4 );
241 QgsDebugMsgLevel( u"MIN %1"_s.arg( myRasterBandStats.minimumValue ), 4 );
242 QgsDebugMsgLevel( u"MAX %1"_s.arg( myRasterBandStats.maximumValue ), 4 );
243 QgsDebugMsgLevel( u"RANGE %1"_s.arg( myRasterBandStats.range ), 4 );
244 QgsDebugMsgLevel( u"MEAN %1"_s.arg( myRasterBandStats.mean ), 4 );
245 QgsDebugMsgLevel( u"STDDEV %1"_s.arg( myRasterBandStats.stdDev ), 4 );
246
248 mStatistics.append( myRasterBandStats );
249
250 return myRasterBandStats;
251}
252
253bool QgsRasterInterface::hasStatistics( int bandNo, int stats, const QgsRectangle &extent, int sampleSize )
254{
255 return hasStatistics( bandNo, static_cast< Qgis::RasterBandStatistics >( stats ), extent, sampleSize );
256}
257
258void QgsRasterInterface::initHistogram( QgsRasterHistogram &histogram, int bandNo, int binCount, double minimum, double maximum, const QgsRectangle &boundingBox, int sampleSize, bool includeOutOfRange )
259{
260 histogram.bandNumber = bandNo;
261 histogram.minimum = minimum;
262 histogram.maximum = maximum;
263 histogram.includeOutOfRange = includeOutOfRange;
264
265 const Qgis::DataType mySrcDataType = sourceDataType( bandNo );
266
267 if ( std::isnan( histogram.minimum ) )
268 {
269 // TODO: this was OK when stats/histogram were calced in provider,
270 // but what TODO in other interfaces? Check for mInput for now.
271 if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
272 {
273 histogram.minimum = 0; // see histogram() for shift for rounding
274 }
275 else
276 {
277 // We need statistics -> avoid histogramDefaults in hasHistogram if possible
278 // TODO: use approximated statistics if approximated histogram is requested
279 // (theSampleSize > 0)
280 const QgsRasterBandStats stats = bandStatistics( bandNo, Qgis::RasterBandStatistic::Min, boundingBox, sampleSize );
281 histogram.minimum = stats.minimumValue;
282 }
283 }
284 if ( std::isnan( histogram.maximum ) )
285 {
286 if ( !mInput && mySrcDataType == Qgis::DataType::Byte )
287 {
288 histogram.maximum = 255;
289 }
290 else
291 {
292 const QgsRasterBandStats stats = bandStatistics( bandNo, Qgis::RasterBandStatistic::Max, boundingBox, sampleSize );
293 histogram.maximum = stats.maximumValue;
294 }
295 }
296
297 QgsRectangle finalExtent;
298 if ( boundingBox.isEmpty() )
299 {
300 finalExtent = extent();
301 }
302 else
303 {
304 finalExtent = extent().intersect( boundingBox );
305 }
306 histogram.extent = finalExtent;
307
308 if ( sampleSize > 0 )
309 {
310 // Calc resolution from theSampleSize
311 double xRes, yRes;
312 xRes = yRes = std::sqrt( ( static_cast<double>( finalExtent.width() ) * finalExtent.height() ) / sampleSize );
313
314 // But limit by physical resolution
316 {
317 const double srcXRes = extent().width() / xSize();
318 const double srcYRes = extent().height() / ySize();
319 if ( xRes < srcXRes )
320 xRes = srcXRes;
321 if ( yRes < srcYRes )
322 yRes = srcYRes;
323 }
324 QgsDebugMsgLevel( u"xRes = %1 yRes = %2"_s.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 {
332 {
333 histogram.width = xSize();
334 histogram.height = ySize();
335 }
336 else
337 {
338 histogram.width = 1000;
339 histogram.height = 1000;
340 }
341 }
342 QgsDebugMsgLevel( u"theHistogram.width = %1 histogram.height = %2"_s.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.
359
360 // for Int16/Int32 make sure bin count <= actual range, because there is no sense in having
361 // bins at fractional values
362 if ( !mInput && ( mySrcDataType == Qgis::DataType::Int16 || mySrcDataType == Qgis::DataType::Int32 || mySrcDataType == Qgis::DataType::UInt16 || mySrcDataType == Qgis::DataType::UInt32 ) )
363 {
364 myBinCount = std::min( static_cast<qint64>( histogram.width ) * histogram.height, static_cast<qint64>( std::ceil( histogram.maximum - histogram.minimum + 1 ) ) );
365 }
366 else
367 {
368 // This is for not integer types
370 // If stats are not available or stdDev is 0, use width*height as binCount
371 // but this could lead to binCount being too large
373 {
374 // Use Scott's Rule to determine bin count: binCount = 3.49 * stdDev / n^(1/3)
375 // In standard C++ (prior to C++26), std::sqrt is not a constexpr function,
376 // so we precompute the constant value 24 * sqrt( M_PI ) = 42.538892421732385
377 constexpr double SCOTTS_COEFFICIENT = 42.538892421732385;
378 myBinCount = static_cast<qint64>( stats.range / ( stats.stdDev * std::cbrt( SCOTTS_COEFFICIENT / ( sampleSize > 0 ? sampleSize : static_cast<double>( histogram.width ) * histogram.height ) ) ) );
379 }
380 else
381 {
382 // Fallback using the whole histogram size
383 myBinCount = static_cast<qint64>( histogram.width ) * static_cast<qint64>( histogram.height );
384 }
385 }
386 }
387 }
388 // Hard limit 10'000'000
389 histogram.binCount = static_cast<int>( std::min( 10000000LL, myBinCount ) );
390 QgsDebugMsgLevel( u"theHistogram.binCount = %1"_s.arg( histogram.binCount ), 4 );
391}
392
393void QgsRasterInterface::initStatistics( QgsRasterBandStats &statistics, int bandNo, int stats, const QgsRectangle &boundingBox, int binCount ) const
394{
395 initStatistics( statistics, bandNo, static_cast< Qgis::RasterBandStatistics>( stats ), boundingBox, binCount );
396}
397
398bool QgsRasterInterface::hasHistogram( int bandNo, int binCount, double minimum, double maximum, const QgsRectangle &extent, int sampleSize, bool includeOutOfRange )
399{
400 QgsDebugMsgLevel( u"theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5"_s.arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );
401 // histogramDefaults() needs statistics if minimum or maximum is NaN ->
402 // do other checks which don't need statistics before histogramDefaults()
403 if ( mHistograms.isEmpty() )
404 return false;
405
406 QgsRasterHistogram myHistogram;
407 initHistogram( myHistogram, bandNo, binCount, minimum, maximum, extent, sampleSize, includeOutOfRange );
408
409 const auto constMHistograms = mHistograms;
410 for ( const QgsRasterHistogram &histogram : constMHistograms )
411 {
412 if ( histogram == myHistogram )
413 {
414 QgsDebugMsgLevel( u"Has cached histogram."_s, 4 );
415 return true;
416 }
417 }
418 return false;
419}
420
421QgsRasterHistogram QgsRasterInterface::histogram( int bandNo, int binCount, double minimum, double maximum, const QgsRectangle &extent, int sampleSize, bool includeOutOfRange, QgsRasterBlockFeedback *feedback )
422{
423 QgsDebugMsgLevel( u"theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5"_s.arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );
424
425 QgsRasterHistogram myHistogram;
426 initHistogram( myHistogram, bandNo, binCount, minimum, maximum, extent, sampleSize, includeOutOfRange );
427
428 // Find cached
429 const auto constMHistograms = mHistograms;
430 for ( const QgsRasterHistogram &histogram : constMHistograms )
431 {
432 if ( histogram == myHistogram )
433 {
434 QgsDebugMsgLevel( u"Using cached histogram."_s, 4 );
435 return histogram;
436 }
437 }
438
439 const int myBinCount = myHistogram.binCount;
440 const int myWidth = myHistogram.width;
441 const int myHeight = myHistogram.height;
442 const QgsRectangle myExtent = myHistogram.extent;
443 myHistogram.histogramVector.resize( myBinCount );
444
445 int myXBlockSize = xBlockSize();
446 int myYBlockSize = yBlockSize();
447 if ( myXBlockSize == 0 ) // should not happen, but happens
448 {
449 myXBlockSize = 500;
450 }
451 if ( myYBlockSize == 0 ) // should not happen, but happens
452 {
453 myYBlockSize = 500;
454 }
455
456 const int myNXBlocks = ( myWidth + myXBlockSize - 1 ) / myXBlockSize;
457 const int myNYBlocks = ( myHeight + myYBlockSize - 1 ) / myYBlockSize;
458
459 const double myXRes = myExtent.width() / myWidth;
460 const double myYRes = myExtent.height() / myHeight;
461
462 double myMinimum = myHistogram.minimum;
463 double myMaximum = myHistogram.maximum;
464
465 // To avoid rounding errors
466 // TODO: check this
467 const double myerval = ( myMaximum - myMinimum ) / myHistogram.binCount;
468 myMinimum -= 0.1 * myerval;
469 myMaximum += 0.1 * myerval;
470
471 QgsDebugMsgLevel( u"binCount = %1 myMinimum = %2 myMaximum = %3"_s.arg( myHistogram.binCount ).arg( myMinimum ).arg( myMaximum ), 4 );
472
473 const double myBinSize = ( myMaximum - myMinimum ) / myBinCount;
474
475 // TODO: progress signals
476 bool isNoData = false;
477 for ( int myYBlock = 0; myYBlock < myNYBlocks; myYBlock++ )
478 {
479 for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
480 {
481 if ( feedback && feedback->isCanceled() )
482 return myHistogram;
483
484 const int myBlockWidth = std::min( myXBlockSize, myWidth - myXBlock * myXBlockSize );
485 const int myBlockHeight = std::min( myYBlockSize, myHeight - myYBlock * myYBlockSize );
486
487 const double xmin = myExtent.xMinimum() + myXBlock * myXBlockSize * myXRes;
488 const double xmax = xmin + myBlockWidth * myXRes;
489 const double ymin = myExtent.yMaximum() - myYBlock * myYBlockSize * myYRes;
490 const double ymax = ymin - myBlockHeight * myYRes;
491
492 const QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );
493
494 std::unique_ptr< QgsRasterBlock > blk( block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback ) );
495
496 // Collect the histogram counts.
497 for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
498 {
499 const double myValue = blk->valueAndNoData( i, isNoData );
500 if ( isNoData )
501 {
502 continue; // NULL
503 }
504
505 int myBinIndex = static_cast<int>( std::floor( ( myValue - myMinimum ) / myBinSize ) );
506
507 if ( ( myBinIndex < 0 || myBinIndex > ( myBinCount - 1 ) ) && !includeOutOfRange )
508 {
509 continue;
510 }
511 if ( myBinIndex < 0 )
512 myBinIndex = 0;
513 if ( myBinIndex > ( myBinCount - 1 ) )
514 myBinIndex = myBinCount - 1;
515
516 myHistogram.histogramVector[myBinIndex] += 1;
517 myHistogram.nonNullCount++;
518 }
519 }
520 }
521
522 myHistogram.valid = true;
523 mHistograms.append( myHistogram );
524
525#ifdef QGISDEBUG
526 QString hist;
527 for ( std::size_t i = 0; i < std::min< std::size_t >( myHistogram.histogramVector.size(), 500 ); i++ )
528 {
529 hist += QString::number( myHistogram.histogramVector.value( i ) ) + ' ';
530 }
531 QgsDebugMsgLevel( u"Histogram (max first 500 bins): "_s + hist, 4 );
532#endif
533
534 return myHistogram;
535}
536
537void QgsRasterInterface::cumulativeCut( int bandNo, double lowerCount, double upperCount, double &lowerValue, double &upperValue, const QgsRectangle &extent, int sampleSize )
538{
539 QgsDebugMsgLevel( u"theBandNo = %1 lowerCount = %2 upperCount = %3 sampleSize = %4"_s.arg( bandNo ).arg( lowerCount ).arg( upperCount ).arg( sampleSize ), 4 );
540
541 const Qgis::DataType mySrcDataType = sourceDataType( bandNo );
542
543 // Init to NaN is better than histogram min/max to catch errors
544 lowerValue = std::numeric_limits<double>::quiet_NaN();
545 upperValue = std::numeric_limits<double>::quiet_NaN();
546
547 //get band stats to specify real histogram min/max (fix #9793 Byte bands)
548 const QgsRasterBandStats stats = bandStatistics( bandNo, Qgis::RasterBandStatistic::Min, extent, sampleSize );
549 if ( stats.maximumValue < stats.minimumValue )
550 return;
551
552 // for byte bands make sure bin count == actual range
553 const int myBinCount = ( mySrcDataType == Qgis::DataType::Byte ) ? int( std::ceil( stats.maximumValue - stats.minimumValue + 1 ) ) : 0;
554 const QgsRasterHistogram myHistogram = histogram( bandNo, myBinCount, stats.minimumValue, stats.maximumValue, extent, sampleSize );
555 //QgsRasterHistogram myHistogram = histogram( bandNo, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), extent, sampleSize );
556
557 const double myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / myHistogram.binCount;
558 int myCount = 0;
559 const int myMinCount = static_cast< int >( std::round( lowerCount * myHistogram.nonNullCount ) );
560 const int myMaxCount = static_cast< int >( std::round( upperCount * myHistogram.nonNullCount ) );
561 bool myLowerFound = false;
562 QgsDebugMsgLevel( u"binCount = %1 minimum = %2 maximum = %3 myBinXStep = %4"_s.arg( myHistogram.binCount ).arg( myHistogram.minimum ).arg( myHistogram.maximum ).arg( myBinXStep ), 4 );
563 QgsDebugMsgLevel( u"myMinCount = %1 myMaxCount = %2"_s.arg( myMinCount ).arg( myMaxCount ), 4 );
564
565 for ( int myBin = 0; myBin < myHistogram.histogramVector.size(); myBin++ )
566 {
567 const int myBinValue = myHistogram.histogramVector.value( myBin );
568 myCount += myBinValue;
569 if ( !myLowerFound && myCount > myMinCount )
570 {
571 lowerValue = myHistogram.minimum + myBin * myBinXStep;
572 myLowerFound = true;
573 QgsDebugMsgLevel( u"found lowerValue %1 at bin %2"_s.arg( lowerValue ).arg( myBin ), 4 );
574 }
575 if ( myCount >= myMaxCount )
576 {
577 upperValue = myHistogram.minimum + myBin * myBinXStep;
578 QgsDebugMsgLevel( u"found upperValue %1 at bin %2"_s.arg( upperValue ).arg( myBin ), 4 );
579 break;
580 }
581 }
582
583 // fix integer data - round down/up
584 if ( mySrcDataType == Qgis::DataType::Byte
585 || mySrcDataType == Qgis::DataType::Int16
586 || mySrcDataType == Qgis::DataType::Int32
587 || mySrcDataType == Qgis::DataType::UInt16
588 || mySrcDataType == Qgis::DataType::UInt32 )
589 {
590 if ( !std::isnan( lowerValue ) )
591 lowerValue = std::floor( lowerValue );
592 if ( !std::isnan( upperValue ) )
593 upperValue = std::ceil( upperValue );
594 }
595}
596
598{
599 QStringList abilitiesList;
600
602
603 // Not all all capabilities are here (Size, IdentifyValue, IdentifyText,
604 // IdentifyHtml, IdentifyFeature) because those are quite technical and probably
605 // would be confusing for users
606
608 {
609 abilitiesList += tr( "Identify" );
610 }
611
613 {
614 abilitiesList += tr( "Build Pyramids" );
615 }
616
617 QgsDebugMsgLevel( "Capability: " + abilitiesList.join( ", "_L1 ), 4 );
618
619 return abilitiesList.join( ", "_L1 );
620}
621
622QString QgsRasterInterface::generateBandName( int bandNumber ) const
623{
624 if ( mInput )
625 return mInput->generateBandName( bandNumber );
626
627 // For bad layers bandCount is 0, no log!
628 return tr( "Band" ) + u" %1"_s.arg( bandNumber, 1 + ( bandCount() > 0 ? static_cast< int >( std::log10( static_cast< double >( bandCount() ) ) ) : 0 ), 10, QChar( '0' ) );
629}
630
632{
633 if ( mInput )
634 return mInput->colorInterpretationName( bandNo );
635
636 return QString();
637}
638
639QString QgsRasterInterface::displayBandName( int bandNumber ) const
640{
641 QString name = generateBandName( bandNumber );
642 const QString colorInterp = colorInterpretationName( bandNumber );
643 if ( colorInterp != tr( "Undefined" ) )
644 {
645 name.append( u" (%1)"_s.arg( colorInterp ) );
646 }
647 return name;
648}
649
650QgsRasterBandStats QgsRasterInterface::bandStatistics( int bandNo, int stats, const QgsRectangle &extent, int sampleSize, QgsRasterBlockFeedback *feedback )
651{
652 return bandStatistics( bandNo, static_cast< Qgis::RasterBandStatistics>( stats ), extent, sampleSize, feedback );
653}
654
656{
657 return mRenderContext;
658}
659
QFlags< RasterInterfaceCapability > RasterInterfaceCapabilities
Raster interface capabilities.
Definition qgis.h:5311
@ BuildPyramids
Supports building of pyramids (overviews) (Deprecated since QGIS 3.38 – use RasterProviderCapability:...
Definition qgis.h:5296
@ NoCapabilities
No capabilities.
Definition qgis.h:5292
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
Definition qgis.h:5293
@ Identify
At least one identify format supported.
Definition qgis.h:5297
QFlags< RasterBandStatistic > RasterBandStatistics
Statistics to be calculated for raster bands.
Definition qgis.h:6596
@ StdDev
Standard deviation.
Definition qgis.h:6585
@ All
All available statistics.
Definition qgis.h:6587
DataType
Raster data types.
Definition qgis.h:393
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:398
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:397
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:395
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:400
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:399
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
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.
A container for a histogram of a single raster band.
double minimum
The minimum histogram value.
double maximum
The maximum histogram value.
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.
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 Qgis::RasterInterfaceCapabilities capabilities() const
Returns the capabilities supported by the interface.
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.
Q_DECL_DEPRECATED QString capabilitiesString() const
Returns the raster interface capabilities in friendly format.
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 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 QgsRasterInterface * input() const
Current input.
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.
double xMinimum
double yMaximum
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
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:7947
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80