QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsrasteranalysisutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrasteranalysisutils.cpp
3 ---------------------
4 Date : June 2018
5 Copyright : (C) 2018 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include <cmath>
19#include <map>
20#include <unordered_map>
21#include <unordered_set>
22
23#include "qgsfeedback.h"
24#include "qgsgeos.h"
26#include "qgsrasterblock.h"
27#include "qgsrasteriterator.h"
28
29#include <QString>
30
31using namespace Qt::StringLiterals;
32
34
35void QgsRasterAnalysisUtils::cellInfoForBBox(
36 const QgsRectangle &rasterBBox, const QgsRectangle &featureBBox, double cellSizeX, double cellSizeY, int &nCellsX, int &nCellsY, int rasterWidth, int rasterHeight, QgsRectangle &rasterBlockExtent
37)
38{
39 //get intersecting bbox
40 const QgsRectangle intersectBox = rasterBBox.intersect( featureBBox );
41 if ( intersectBox.isEmpty() )
42 {
43 nCellsX = 0;
44 nCellsY = 0;
45 rasterBlockExtent = QgsRectangle();
46 return;
47 }
48
49 //get offset in pixels in x- and y- direction
50 const int offsetX = static_cast<int>( std::floor( ( intersectBox.xMinimum() - rasterBBox.xMinimum() ) / cellSizeX ) );
51 const int offsetY = static_cast<int>( std::floor( ( rasterBBox.yMaximum() - intersectBox.yMaximum() ) / cellSizeY ) );
52
53 const int maxColumn = static_cast<int>( std::floor( ( intersectBox.xMaximum() - rasterBBox.xMinimum() ) / cellSizeX ) ) + 1;
54 const int maxRow = static_cast<int>( std::floor( ( rasterBBox.yMaximum() - intersectBox.yMinimum() ) / cellSizeY ) ) + 1;
55
56 nCellsX = maxColumn - offsetX;
57 nCellsY = maxRow - offsetY;
58
59 //avoid access to cells outside of the raster (may occur because of rounding)
60 nCellsX = std::min( offsetX + nCellsX, rasterWidth ) - offsetX;
61 nCellsY = std::min( offsetY + nCellsY, rasterHeight ) - offsetY;
62
63 rasterBlockExtent
64 = QgsRectangle( rasterBBox.xMinimum() + offsetX * cellSizeX, rasterBBox.yMaximum() - offsetY * cellSizeY, rasterBBox.xMinimum() + ( nCellsX + offsetX ) * cellSizeX, rasterBBox.yMaximum() - ( nCellsY + offsetY ) * cellSizeY );
65}
66
67void QgsRasterAnalysisUtils::statisticsFromMiddlePointTest(
68 QgsRasterInterface *rasterInterface,
69 int rasterBand,
70 const QgsGeometry &poly,
71 int nCellsX,
72 int nCellsY,
73 double cellSizeX,
74 double cellSizeY,
75 const QgsRectangle &rasterBBox,
76 const std::function<void( double, const QgsPointXY & )> &addValue,
77 bool skipNodata
78)
79{
80 if ( !poly.constGet() )
81 return;
82
83 auto polyEngine = std::make_unique<QgsGeos>( poly.constGet() );
84 polyEngine->prepareGeometry();
85
86 QgsRasterIterator iter( rasterInterface );
87 iter.startRasterRead( rasterBand, nCellsX, nCellsY, rasterBBox );
88
89 std::unique_ptr<QgsRasterBlock> block;
90 int iterLeft = 0;
91 int iterTop = 0;
92 int iterCols = 0;
93 int iterRows = 0;
94 QgsRectangle blockExtent;
95 bool isNoData = false;
96 while ( iter.readNextRasterPart( rasterBand, iterCols, iterRows, block, iterLeft, iterTop, &blockExtent ) )
97 {
98 double cellCenterY = blockExtent.yMaximum() - 0.5 * cellSizeY;
99
100 for ( int row = 0; row < iterRows; ++row )
101 {
102 double cellCenterX = blockExtent.xMinimum() + 0.5 * cellSizeX;
103 for ( int col = 0; col < iterCols; ++col )
104 {
105 const double pixelValue = block->valueAndNoData( row, col, isNoData );
106 if ( validPixel( pixelValue ) && ( !skipNodata || !isNoData ) )
107 {
108 if ( polyEngine->contains( cellCenterX, cellCenterY ) )
109 {
110 addValue( pixelValue, QgsPointXY( cellCenterX, cellCenterY ) );
111 }
112 }
113 cellCenterX += cellSizeX;
114 }
115 cellCenterY -= cellSizeY;
116 }
117 }
118}
119
120void QgsRasterAnalysisUtils::statisticsFromPreciseIntersection(
121 QgsRasterInterface *rasterInterface,
122 int rasterBand,
123 const QgsGeometry &poly,
124 int nCellsX,
125 int nCellsY,
126 double cellSizeX,
127 double cellSizeY,
128 const QgsRectangle &rasterBBox,
129 const std::function<void( double, double, const QgsPointXY & )> &addValue,
130 bool skipNodata
131)
132{
133 QgsGeometry pixelRectGeometry;
134
135 const double hCellSizeX = cellSizeX / 2.0;
136 const double hCellSizeY = cellSizeY / 2.0;
137 const double pixelArea = cellSizeX * cellSizeY;
138 double weight = 0;
139
140 std::unique_ptr<QgsGeometryEngine> polyEngine( QgsGeometry::createGeometryEngine( poly.constGet() ) );
141 if ( !polyEngine )
142 {
143 return;
144 }
145 polyEngine->prepareGeometry();
146
147 QgsRasterIterator iter( rasterInterface );
148 iter.startRasterRead( rasterBand, nCellsX, nCellsY, rasterBBox );
149
150 std::unique_ptr<QgsRasterBlock> block;
151 int iterLeft = 0;
152 int iterTop = 0;
153 int iterCols = 0;
154 int iterRows = 0;
155 QgsRectangle blockExtent;
156 bool isNoData = false;
157 while ( iter.readNextRasterPart( rasterBand, iterCols, iterRows, block, iterLeft, iterTop, &blockExtent ) )
158 {
159 double currentY = blockExtent.yMaximum() - 0.5 * cellSizeY;
160 for ( int row = 0; row < iterRows; ++row )
161 {
162 double currentX = blockExtent.xMinimum() + 0.5 * cellSizeX;
163 for ( int col = 0; col < iterCols; ++col )
164 {
165 const double pixelValue = block->valueAndNoData( row, col, isNoData );
166 if ( validPixel( pixelValue ) && ( !skipNodata || !isNoData ) )
167 {
168 pixelRectGeometry = QgsGeometry::fromRect( QgsRectangle( currentX - hCellSizeX, currentY - hCellSizeY, currentX + hCellSizeX, currentY + hCellSizeY ) );
169 // GEOS intersects tests on prepared geometry is MAGNITUDES faster than calculating the intersection itself,
170 // so we first test to see if there IS an intersection before doing the actual calculation
171 if ( !pixelRectGeometry.isNull() && polyEngine->intersects( pixelRectGeometry.constGet() ) )
172 {
173 //intersection
174 const QgsGeometry intersectGeometry = pixelRectGeometry.intersection( poly );
175 if ( !intersectGeometry.isEmpty() )
176 {
177 const double intersectionArea = intersectGeometry.area();
178 if ( intersectionArea > 0.0 )
179 {
180 weight = intersectionArea / pixelArea;
181 addValue( pixelValue, weight, QgsPointXY( currentX, currentY ) );
182 }
183 }
184 }
185 }
186 currentX += cellSizeX;
187 }
188 currentY -= cellSizeY;
189 }
190 }
191}
192
193bool QgsRasterAnalysisUtils::validPixel( double value )
194{
195 return !std::isnan( value );
196}
197
198void QgsRasterAnalysisUtils::mapToPixel( const double x, const double y, const QgsRectangle bounds, const double unitsPerPixelX, const double unitsPerPixelY, int &px, int &py )
199{
200 px = trunc( ( x - bounds.xMinimum() ) / unitsPerPixelX );
201 py = trunc( ( y - bounds.yMaximum() ) / -unitsPerPixelY );
202}
203
204void QgsRasterAnalysisUtils::pixelToMap( const int px, const int py, const QgsRectangle bounds, const double unitsPerPixelX, const double unitsPerPixelY, double &x, double &y )
205{
206 x = bounds.xMinimum() + ( px + 0.5 ) * unitsPerPixelX;
207 y = bounds.yMaximum() - ( py + 0.5 ) * unitsPerPixelY;
208}
209
210static QVector<QPair<QString, Qgis::DataType>> sDataTypes;
211
212void populateDataTypes()
213{
214 if ( sDataTypes.empty() )
215 {
216 sDataTypes.append( qMakePair( u"Byte"_s, Qgis::DataType::Byte ) );
217 sDataTypes.append( qMakePair( u"Int16"_s, Qgis::DataType::Int16 ) );
218 sDataTypes.append( qMakePair( u"UInt16"_s, Qgis::DataType::UInt16 ) );
219 sDataTypes.append( qMakePair( u"Int32"_s, Qgis::DataType::Int32 ) );
220 sDataTypes.append( qMakePair( u"UInt32"_s, Qgis::DataType::UInt32 ) );
221 sDataTypes.append( qMakePair( u"Float32"_s, Qgis::DataType::Float32 ) );
222 sDataTypes.append( qMakePair( u"Float64"_s, Qgis::DataType::Float64 ) );
223 sDataTypes.append( qMakePair( u"CInt16"_s, Qgis::DataType::CInt16 ) );
224 sDataTypes.append( qMakePair( u"CInt32"_s, Qgis::DataType::CInt32 ) );
225 sDataTypes.append( qMakePair( u"CFloat32"_s, Qgis::DataType::CFloat32 ) );
226 sDataTypes.append( qMakePair( u"CFloat64"_s, Qgis::DataType::CFloat64 ) );
227 sDataTypes.append( qMakePair( u"Int8"_s, Qgis::DataType::Int8 ) );
228 }
229}
230
231std::unique_ptr<QgsProcessingParameterDefinition> QgsRasterAnalysisUtils::createRasterTypeParameter( const QString &name, const QString &description, Qgis::DataType defaultType )
232{
233 populateDataTypes();
234
235 QStringList names;
236 int defaultChoice = 0;
237 int i = 0;
238 for ( auto it = sDataTypes.constBegin(); it != sDataTypes.constEnd(); ++it )
239 {
240 names.append( it->first );
241 if ( it->second == defaultType )
242 defaultChoice = i;
243 i++;
244 }
245
246 return std::make_unique<QgsProcessingParameterEnum>( name, description, names, false, defaultChoice );
247}
248
249Qgis::DataType QgsRasterAnalysisUtils::rasterTypeChoiceToDataType( int choice )
250{
251 if ( choice < 0 || choice >= sDataTypes.count() )
253
254 return sDataTypes.value( choice ).second;
255}
256
257void QgsRasterAnalysisUtils::applyRasterLogicOperator(
258 const std::vector<QgsRasterAnalysisUtils::RasterLogicInput> &inputs,
259 std::unique_ptr<QgsRasterDataProvider> destinationRaster,
260 double outputNoDataValue,
261 const bool treatNoDataAsFalse,
262 int width,
263 int height,
264 const QgsRectangle &extent,
265 QgsFeedback *feedback,
266 std::function<void( const std::vector<std::unique_ptr<QgsRasterBlock>> &, bool &, bool &, int, int, bool )> &applyLogicFunc,
267 qgssize &noDataCount,
268 qgssize &trueCount,
269 qgssize &falseCount
270)
271{
272 destinationRaster->setEditable( true );
273 QgsRasterIterator outputIter( destinationRaster.get() );
274 outputIter.startRasterRead( 1, width, height, extent );
275
276 const bool hasReportsDuringClose = destinationRaster->hasReportsDuringClose();
277 const double maxProgressDuringBlockWriting = hasReportsDuringClose ? 50.0 : 100.0;
278
279 int iterLeft = 0;
280 int iterTop = 0;
281 int iterCols = 0;
282 int iterRows = 0;
283 QgsRectangle blockExtent;
284 std::unique_ptr<QgsRasterBlock> outputBlock;
285 while ( outputIter.readNextRasterPart( 1, iterCols, iterRows, outputBlock, iterLeft, iterTop, &blockExtent ) )
286 {
287 std::vector<std::unique_ptr<QgsRasterBlock>> inputBlocks;
288 for ( const QgsRasterAnalysisUtils::RasterLogicInput &i : inputs )
289 {
290 for ( const int band : i.bands )
291 {
292 std::unique_ptr<QgsRasterBlock> b( i.interface->block( band, blockExtent, iterCols, iterRows ) );
293 inputBlocks.emplace_back( std::move( b ) );
294 }
295 }
296
297 feedback->setProgress( maxProgressDuringBlockWriting * outputIter.progress( 1 ) );
298 for ( int row = 0; row < iterRows; row++ )
299 {
300 if ( feedback->isCanceled() )
301 break;
302
303 for ( int column = 0; column < iterCols; column++ )
304 {
305 bool res = false;
306 bool resIsNoData = false;
307 applyLogicFunc( inputBlocks, res, resIsNoData, row, column, treatNoDataAsFalse );
308 if ( resIsNoData )
309 noDataCount++;
310 else if ( res )
311 trueCount++;
312 else
313 falseCount++;
314
315 outputBlock->setValue( row, column, resIsNoData ? outputNoDataValue : ( res ? 1 : 0 ) );
316 }
317 }
318 if ( !destinationRaster->writeBlock( outputBlock.get(), 1, iterLeft, iterTop ) )
319 {
320 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationRaster->error().summary() ) );
321 }
322 }
323 destinationRaster->setEditable( false );
324
325 if ( hasReportsDuringClose )
326 {
327 std::unique_ptr<QgsFeedback> scaledFeedback( QgsFeedback::createScaledFeedback( feedback, maxProgressDuringBlockWriting, 100.0 ) );
328 if ( !destinationRaster->closeWithProgress( scaledFeedback.get() ) )
329 {
330 if ( feedback->isCanceled() )
331 return;
332 throw QgsProcessingException( QObject::tr( "Could not write raster dataset" ) );
333 }
334 }
335}
336
337std::vector<double> QgsRasterAnalysisUtils::getCellValuesFromBlockStack( const std::vector<std::unique_ptr<QgsRasterBlock>> &inputBlocks, int &row, int &col, bool &noDataInStack )
338{
339 //get all values from inputBlocks
340 std::vector<double> cellValues;
341 bool hasNoData = false;
342 cellValues.reserve( inputBlocks.size() );
343
344 for ( auto &block : inputBlocks )
345 {
346 double value = 0;
347 if ( !block || !block->isValid() )
348 {
349 noDataInStack = true;
350 break;
351 }
352 else
353 {
354 value = block->valueAndNoData( row, col, hasNoData );
355 if ( hasNoData )
356 {
357 noDataInStack = true;
358 continue; //NoData is not included in the cell value vector
359 }
360 else
361 {
362 cellValues.push_back( value );
363 }
364 }
365 }
366 return cellValues;
367}
368
369double QgsRasterAnalysisUtils::meanFromCellValues( std::vector<double> &cellValues, int stackSize )
370{
371 const double sum = std::accumulate( cellValues.begin(), cellValues.end(), 0.0 );
372 const double mean = sum / static_cast<double>( stackSize );
373 return mean;
374}
375
376double QgsRasterAnalysisUtils::medianFromCellValues( std::vector<double> &cellValues, int stackSize )
377{
378 std::sort( cellValues.begin(), cellValues.end() );
379 const bool even = ( stackSize % 2 ) < 1;
380 if ( even )
381 {
382 return ( cellValues[stackSize / 2 - 1] + cellValues[stackSize / 2] ) / 2.0;
383 }
384 else //odd
385 {
386 return cellValues[( stackSize + 1 ) / 2 - 1];
387 }
388}
389
390
391double QgsRasterAnalysisUtils::stddevFromCellValues( std::vector<double> &cellValues, int stackSize )
392{
393 const double variance = varianceFromCellValues( cellValues, stackSize );
394 const double stddev = std::sqrt( variance );
395 return stddev;
396}
397
398double QgsRasterAnalysisUtils::varianceFromCellValues( std::vector<double> &cellValues, int stackSize )
399{
400 const double mean = meanFromCellValues( cellValues, stackSize );
401 double accum = 0.0;
402 for ( int i = 0; i < stackSize; i++ )
403 {
404 accum += std::pow( ( cellValues.at( i ) - mean ), 2.0 );
405 }
406 const double variance = accum / static_cast<double>( stackSize );
407 return variance;
408}
409
410double QgsRasterAnalysisUtils::maximumFromCellValues( std::vector<double> &cellValues )
411{
412 return *std::max_element( cellValues.begin(), cellValues.end() );
413}
414
415double QgsRasterAnalysisUtils::minimumFromCellValues( std::vector<double> &cellValues )
416{
417 return *std::min_element( cellValues.begin(), cellValues.end() );
418}
419
420double QgsRasterAnalysisUtils::majorityFromCellValues( std::vector<double> &cellValues, const double noDataValue, int stackSize )
421{
422 if ( stackSize == 1 )
423 {
424 //output will be same as input if only one layer is entered
425 return cellValues[0];
426 }
427 else if ( stackSize == 2 )
428 {
429 //if only two layers are input, return NoData if values are not the same (eg. no Majority could be found)
430 return ( qgsDoubleNear( cellValues[0], cellValues[1] ) ) ? cellValues[0] : noDataValue;
431 }
432 else if ( std::adjacent_find( cellValues.begin(), cellValues.end(), std::not_equal_to<double>() ) == cellValues.end() )
433 {
434 //check if all values in cellValues are equal
435 //output will be same as input if all cellValues of the stack are the same
436 return cellValues[0];
437 }
438 else
439 {
440 //search for majority using hash map [O(n)]
441 std::unordered_map<double, int> map;
442
443 for ( int i = 0; i < stackSize; i++ )
444 {
445 map[cellValues[i]]++;
446 }
447
448 int maxCount = 0;
449 bool multipleMajorities = false;
450 double result = noDataValue;
451 for ( const auto &pair : std::as_const( map ) )
452 {
453 if ( maxCount < pair.second )
454 {
455 result = pair.first;
456 maxCount = pair.second;
457 multipleMajorities = false;
458 }
459 else if ( maxCount == pair.second )
460 {
461 multipleMajorities = true;
462 }
463 }
464 return multipleMajorities ? noDataValue : result;
465 }
466}
467
468double QgsRasterAnalysisUtils::minorityFromCellValues( std::vector<double> &cellValues, const double noDataValue, int stackSize )
469{
470 if ( stackSize == 1 )
471 {
472 //output will be same as input if only one layer is entered
473 return cellValues[0];
474 }
475 else if ( stackSize == 2 )
476 {
477 //if only two layers are input, return NoData if values are not the same (eg. no minority could be found)
478 return ( qgsDoubleNear( cellValues[0], cellValues[1] ) ) ? cellValues[0] : noDataValue;
479 }
480 else if ( std::adjacent_find( cellValues.begin(), cellValues.end(), std::not_equal_to<double>() ) == cellValues.end() )
481 {
482 //check if all values in cellValues are equal
483 //output will be same as input if all cellValues of the stack are the same
484 return cellValues[0];
485 }
486 else
487 {
488 //search for minority using hash map [O(n)]
489 std::unordered_map<double, int> map;
490
491 for ( int i = 0; i < stackSize; i++ )
492 {
493 map[cellValues[i]]++;
494 }
495
496 int minCount = stackSize;
497 bool multipleMinorities = false;
498 double result = noDataValue; //result will stay NoData if no minority value exists
499 for ( const auto &pair : std::as_const( map ) )
500 {
501 if ( minCount > pair.second )
502 {
503 result = pair.first;
504 minCount = pair.second;
505 multipleMinorities = false;
506 }
507 else if ( minCount == pair.second )
508 {
509 multipleMinorities = true;
510 }
511 }
512 return multipleMinorities ? noDataValue : result;
513 }
514}
515
516double QgsRasterAnalysisUtils::rangeFromCellValues( std::vector<double> &cellValues )
517{
518 const double max = *std::max_element( cellValues.begin(), cellValues.end() );
519 const double min = *std::min_element( cellValues.begin(), cellValues.end() );
520 return max - min;
521}
522
523double QgsRasterAnalysisUtils::varietyFromCellValues( std::vector<double> &cellValues )
524{
525 const std::unordered_set<double> uniqueValues( cellValues.begin(), cellValues.end() );
526 return uniqueValues.size();
527}
528
529double QgsRasterAnalysisUtils::nearestRankPercentile( std::vector<double> &cellValues, int stackSize, double percentile )
530{
531 //if percentile equals 0 -> pick the first element of the ordered list
532 std::sort( cellValues.begin(), cellValues.end() );
533
534 int i = 0;
535 if ( percentile > 0 )
536 {
537 i = std::ceil( percentile * static_cast<double>( stackSize ) ) - 1;
538 }
539
540 return cellValues[i];
541}
542
543double QgsRasterAnalysisUtils::interpolatedPercentileInc( std::vector<double> &cellValues, int stackSize, double percentile )
544{
545 std::sort( cellValues.begin(), cellValues.end() );
546
547 if ( qgsDoubleNear( percentile, 1.0 ) )
548 {
549 return cellValues[stackSize - 1];
550 }
551 else if ( qgsDoubleNear( percentile, 0.0 ) )
552 {
553 return cellValues[0];
554 }
555
556 const double x = ( percentile * ( stackSize - 1 ) );
557
558 const int i = static_cast<int>( std::floor( x ) );
559 const double xFraction = std::fmod( x, 1 );
560
561 if ( stackSize == 1 )
562 {
563 return cellValues[0];
564 }
565 else if ( stackSize == 2 )
566 {
567 return cellValues[0] + ( cellValues[1] - cellValues[0] ) * percentile;
568 }
569 else
570 {
571 return cellValues[i] + ( cellValues[i + 1] - cellValues[i] ) * xFraction;
572 }
573}
574
575double QgsRasterAnalysisUtils::interpolatedPercentileExc( std::vector<double> &cellValues, int stackSize, double percentile, double noDataValue )
576{
577 std::sort( cellValues.begin(), cellValues.end() );
578 const double x = ( percentile * ( stackSize + 1 ) );
579
580 const int i = static_cast<int>( std::floor( x ) ) - 1;
581 const double xFraction = std::fmod( x, 1 );
582 const double lowerExcValue = 1.0 / ( static_cast<double>( stackSize ) + 1.0 );
583 const double upperExcValue = static_cast<double>( stackSize ) / ( static_cast<double>( stackSize ) + 1.0 );
584
585 if ( stackSize < 2 || ( ( percentile < lowerExcValue || percentile > upperExcValue ) ) )
586 {
587 return noDataValue;
588 }
589 else
590 {
591 return cellValues[i] + ( cellValues[i + 1] - cellValues[i] ) * xFraction;
592 }
593}
594
595double QgsRasterAnalysisUtils::interpolatedPercentRankInc( std::vector<double> &cellValues, int stackSize, double value, double noDataValue )
596{
597 std::sort( cellValues.begin(), cellValues.end() );
598
599 if ( value < cellValues[0] || value > cellValues[stackSize - 1] )
600 {
601 return noDataValue;
602 }
603 else
604 {
605 for ( int i = 0; i < stackSize - 1; i++ )
606 {
607 if ( cellValues[i] <= value && cellValues[i + 1] >= value )
608 {
609 double fraction = 0.0;
610
611 //make sure that next number in the distribution is not the same to prevent NaN fractions
612 if ( !qgsDoubleNear( cellValues[i], cellValues[i + 1] ) )
613 fraction = ( value - cellValues[i] ) / ( cellValues[i + 1] - cellValues[i] );
614
615 return ( fraction + i ) / ( stackSize - 1 );
616 }
617 }
618 return noDataValue;
619 }
620}
621
622double QgsRasterAnalysisUtils::interpolatedPercentRankExc( std::vector<double> &cellValues, int stackSize, double value, double noDataValue )
623{
624 std::sort( cellValues.begin(), cellValues.end() );
625
626 if ( value < cellValues[0] || value > cellValues[stackSize - 1] )
627 {
628 return noDataValue;
629 }
630 else
631 {
632 for ( int i = 0; i < stackSize - 1; i++ )
633 {
634 if ( cellValues[i] <= value && cellValues[i + 1] >= value )
635 {
636 double fraction = 0.0;
637
638 //make sure that next number in the distribution is not the same to prevent NaN fractions
639 if ( !qgsDoubleNear( cellValues[i], cellValues[i + 1] ) )
640 fraction = ( value - cellValues[i] ) / ( cellValues[i + 1] - cellValues[i] );
641
642 return ( ( i + 1 ) + fraction ) / ( stackSize + 1 );
643 }
644 }
645 return noDataValue;
646 }
647}
648
649
DataType
Raster data types.
Definition qgis.h:393
@ CInt32
Complex Int32.
Definition qgis.h:404
@ Float32
Thirty two bit floating point (float).
Definition qgis.h:401
@ CFloat64
Complex Float64.
Definition qgis.h:406
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:398
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
Definition qgis.h:396
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:397
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:395
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:400
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:402
@ CFloat32
Complex Float32.
Definition qgis.h:405
@ CInt16
Complex Int16.
Definition qgis.h:403
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:399
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
static std::unique_ptr< QgsFeedback > createScaledFeedback(QgsFeedback *parentFeedback, double startPercentage, double endPercentage)
Returns a feedback object whose [0, 100] progression range will be mapped to parentFeedback [startPer...
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double area() const
Returns the planar, 2-dimensional area of the geometry.
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Represents a 2D point.
Definition qgspointxy.h:62
Custom exception class for processing related exceptions.
Base class for processing filters like renderers, reprojector, resampler etc.
Iterator for sequentially processing raster cells.
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
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:7485
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975