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