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