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