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