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