20#include <unordered_map>
21#include <unordered_set>
31void QgsRasterAnalysisUtils::cellInfoForBBox(
const QgsRectangle &rasterBBox,
const QgsRectangle &featureBBox,
double cellSizeX,
double cellSizeY,
int &nCellsX,
int &nCellsY,
int rasterWidth,
int rasterHeight,
QgsRectangle &rasterBlockExtent )
44 const int offsetX =
static_cast<int>( std::floor( ( intersectBox.
xMinimum() - rasterBBox.
xMinimum() ) / cellSizeX ) );
45 const int offsetY =
static_cast<int>( std::floor( ( rasterBBox.
yMaximum() - intersectBox.
yMaximum() ) / cellSizeY ) );
47 const int maxColumn =
static_cast<int>( std::floor( ( intersectBox.
xMaximum() - rasterBBox.
xMinimum() ) / cellSizeX ) ) + 1;
48 const int maxRow =
static_cast<int>( std::floor( ( rasterBBox.
yMaximum() - intersectBox.
yMinimum() ) / cellSizeY ) ) + 1;
50 nCellsX = maxColumn - offsetX;
51 nCellsY = maxRow - offsetY;
54 nCellsX = std::min( offsetX + nCellsX, rasterWidth ) - offsetX;
55 nCellsY = std::min( offsetY + nCellsY, rasterHeight ) - offsetY;
57 rasterBlockExtent =
QgsRectangle( rasterBBox.
xMinimum() + offsetX * cellSizeX, rasterBBox.
yMaximum() - offsetY * cellSizeY, rasterBBox.
xMinimum() + ( nCellsX + offsetX ) * cellSizeX, rasterBBox.
yMaximum() - ( nCellsY + offsetY ) * cellSizeY );
60void QgsRasterAnalysisUtils::statisticsFromMiddlePointTest(
QgsRasterInterface *rasterInterface,
int rasterBand,
const QgsGeometry &poly,
int nCellsX,
int nCellsY,
double cellSizeX,
double cellSizeY,
const QgsRectangle &rasterBBox,
const std::function<
void(
double,
const QgsPointXY & )> &addValue,
bool skipNodata )
65 auto polyEngine = std::make_unique<QgsGeos>( poly.
constGet() );
66 polyEngine->prepareGeometry();
69 iter.startRasterRead( rasterBand, nCellsX, nCellsY, rasterBBox );
71 std::unique_ptr<QgsRasterBlock> block;
77 bool isNoData =
false;
78 while ( iter.readNextRasterPart( rasterBand, iterCols, iterRows, block, iterLeft, iterTop, &blockExtent ) )
80 double cellCenterY = blockExtent.
yMaximum() - 0.5 * cellSizeY;
82 for (
int row = 0; row < iterRows; ++row )
84 double cellCenterX = blockExtent.
xMinimum() + 0.5 * cellSizeX;
85 for (
int col = 0; col < iterCols; ++col )
87 const double pixelValue = block->valueAndNoData( row, col, isNoData );
88 if ( validPixel( pixelValue ) && ( !skipNodata || !isNoData ) )
90 if ( polyEngine->contains( cellCenterX, cellCenterY ) )
92 addValue( pixelValue,
QgsPointXY( cellCenterX, cellCenterY ) );
95 cellCenterX += cellSizeX;
97 cellCenterY -= cellSizeY;
102void QgsRasterAnalysisUtils::statisticsFromPreciseIntersection(
QgsRasterInterface *rasterInterface,
int rasterBand,
const QgsGeometry &poly,
int nCellsX,
int nCellsY,
double cellSizeX,
double cellSizeY,
const QgsRectangle &rasterBBox,
const std::function<
void(
double,
double,
const QgsPointXY & )> &addValue,
bool skipNodata )
106 const double hCellSizeX = cellSizeX / 2.0;
107 const double hCellSizeY = cellSizeY / 2.0;
108 const double pixelArea = cellSizeX * cellSizeY;
116 polyEngine->prepareGeometry();
119 iter.startRasterRead( rasterBand, nCellsX, nCellsY, rasterBBox );
121 std::unique_ptr<QgsRasterBlock> block;
127 bool isNoData =
false;
128 while ( iter.readNextRasterPart( rasterBand, iterCols, iterRows, block, iterLeft, iterTop, &blockExtent ) )
130 double currentY = blockExtent.
yMaximum() - 0.5 * cellSizeY;
131 for (
int row = 0; row < iterRows; ++row )
133 double currentX = blockExtent.
xMinimum() + 0.5 * cellSizeX;
134 for (
int col = 0; col < iterCols; ++col )
136 const double pixelValue = block->valueAndNoData( row, col, isNoData );
137 if ( validPixel( pixelValue ) && ( !skipNodata || !isNoData ) )
142 if ( !pixelRectGeometry.
isNull() && polyEngine->intersects( pixelRectGeometry.
constGet() ) )
146 if ( !intersectGeometry.
isEmpty() )
148 const double intersectionArea = intersectGeometry.
area();
149 if ( intersectionArea > 0.0 )
151 weight = intersectionArea / pixelArea;
152 addValue( pixelValue, weight,
QgsPointXY( currentX, currentY ) );
157 currentX += cellSizeX;
159 currentY -= cellSizeY;
164bool QgsRasterAnalysisUtils::validPixel(
double value )
166 return !std::isnan( value );
169void QgsRasterAnalysisUtils::mapToPixel(
const double x,
const double y,
const QgsRectangle bounds,
const double unitsPerPixelX,
const double unitsPerPixelY,
int &px,
int &py )
171 px = trunc( ( x - bounds.
xMinimum() ) / unitsPerPixelX );
172 py = trunc( ( y - bounds.
yMaximum() ) / -unitsPerPixelY );
175void QgsRasterAnalysisUtils::pixelToMap(
const int px,
const int py,
const QgsRectangle bounds,
const double unitsPerPixelX,
const double unitsPerPixelY,
double &x,
double &y )
177 x = bounds.
xMinimum() + ( px + 0.5 ) * unitsPerPixelX;
178 y = bounds.
yMaximum() - ( py + 0.5 ) * unitsPerPixelY;
181static QVector<QPair<QString, Qgis::DataType>> sDataTypes;
183void populateDataTypes()
185 if ( sDataTypes.empty() )
202std::unique_ptr<QgsProcessingParameterDefinition> QgsRasterAnalysisUtils::createRasterTypeParameter(
const QString &name,
const QString &description,
Qgis::DataType defaultType )
207 int defaultChoice = 0;
209 for (
auto it = sDataTypes.constBegin(); it != sDataTypes.constEnd(); ++it )
211 names.append( it->first );
212 if ( it->second == defaultType )
217 return std::make_unique<QgsProcessingParameterEnum>( name, description, names,
false, defaultChoice );
220Qgis::DataType QgsRasterAnalysisUtils::rasterTypeChoiceToDataType(
int choice )
222 if ( choice < 0 || choice >= sDataTypes.count() )
225 return sDataTypes.value( choice ).second;
228void QgsRasterAnalysisUtils::applyRasterLogicOperator(
const std::vector<QgsRasterAnalysisUtils::RasterLogicInput> &inputs,
QgsRasterDataProvider *destinationRaster,
double outputNoDataValue,
const bool treatNoDataAsFalse,
int width,
int height,
const QgsRectangle &extent,
QgsFeedback *feedback, std::function<
void(
const std::vector<std::unique_ptr<QgsRasterBlock>> &,
bool &,
bool &,
int,
int,
bool )> &applyLogicFunc,
qgssize &noDataCount,
qgssize &trueCount,
qgssize &falseCount )
232 const int nbBlocksWidth =
static_cast<int>( std::ceil( 1.0 * width / maxWidth ) );
233 const int nbBlocksHeight =
static_cast<int>( std::ceil( 1.0 * height / maxHeight ) );
234 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
238 outputIter.startRasterRead( 1, width, height, extent );
245 std::unique_ptr<QgsRasterBlock> outputBlock;
246 while ( outputIter.readNextRasterPart( 1, iterCols, iterRows, outputBlock, iterLeft, iterTop, &blockExtent ) )
248 std::vector<std::unique_ptr<QgsRasterBlock>> inputBlocks;
249 for (
const QgsRasterAnalysisUtils::RasterLogicInput &i : inputs )
251 for (
const int band : i.bands )
253 std::unique_ptr<QgsRasterBlock> b( i.interface->block( band, blockExtent, iterCols, iterRows ) );
254 inputBlocks.emplace_back( std::move( b ) );
258 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
259 for (
int row = 0; row < iterRows; row++ )
264 for (
int column = 0; column < iterCols; column++ )
267 bool resIsNoData =
false;
268 applyLogicFunc( inputBlocks, res, resIsNoData, row, column, treatNoDataAsFalse );
276 outputBlock->setValue( row, column, resIsNoData ? outputNoDataValue : ( res ? 1 : 0 ) );
279 if ( !destinationRaster->
writeBlock( outputBlock.get(), 1, iterLeft, iterTop ) )
287std::vector<double> QgsRasterAnalysisUtils::getCellValuesFromBlockStack(
const std::vector<std::unique_ptr<QgsRasterBlock>> &inputBlocks,
int &row,
int &col,
bool &noDataInStack )
290 std::vector<double> cellValues;
291 bool hasNoData =
false;
292 cellValues.reserve( inputBlocks.size() );
294 for (
auto &block : inputBlocks )
297 if ( !block || !block->isValid() )
299 noDataInStack =
true;
304 value = block->valueAndNoData( row, col, hasNoData );
307 noDataInStack =
true;
312 cellValues.push_back( value );
319double QgsRasterAnalysisUtils::meanFromCellValues( std::vector<double> &cellValues,
int stackSize )
321 const double sum = std::accumulate( cellValues.begin(), cellValues.end(), 0.0 );
322 const double mean = sum /
static_cast<double>( stackSize );
326double QgsRasterAnalysisUtils::medianFromCellValues( std::vector<double> &cellValues,
int stackSize )
328 std::sort( cellValues.begin(), cellValues.end() );
329 const bool even = ( stackSize % 2 ) < 1;
332 return ( cellValues[stackSize / 2 - 1] + cellValues[stackSize / 2] ) / 2.0;
336 return cellValues[( stackSize + 1 ) / 2 - 1];
341double QgsRasterAnalysisUtils::stddevFromCellValues( std::vector<double> &cellValues,
int stackSize )
343 const double variance = varianceFromCellValues( cellValues, stackSize );
344 const double stddev = std::sqrt( variance );
348double QgsRasterAnalysisUtils::varianceFromCellValues( std::vector<double> &cellValues,
int stackSize )
350 const double mean = meanFromCellValues( cellValues, stackSize );
352 for (
int i = 0; i < stackSize; i++ )
354 accum += std::pow( ( cellValues.at( i ) - mean ), 2.0 );
356 const double variance = accum /
static_cast<double>( stackSize );
360double QgsRasterAnalysisUtils::maximumFromCellValues( std::vector<double> &cellValues )
362 return *std::max_element( cellValues.begin(), cellValues.end() );
365double QgsRasterAnalysisUtils::minimumFromCellValues( std::vector<double> &cellValues )
367 return *std::min_element( cellValues.begin(), cellValues.end() );
370double QgsRasterAnalysisUtils::majorityFromCellValues( std::vector<double> &cellValues,
const double noDataValue,
int stackSize )
372 if ( stackSize == 1 )
375 return cellValues[0];
377 else if ( stackSize == 2 )
380 return (
qgsDoubleNear( cellValues[0], cellValues[1] ) ) ? cellValues[0] : noDataValue;
382 else if ( std::adjacent_find( cellValues.begin(), cellValues.end(), std::not_equal_to<double>() ) == cellValues.end() )
386 return cellValues[0];
391 std::unordered_map<double, int> map;
393 for (
int i = 0; i < stackSize; i++ )
395 map[cellValues[i]]++;
399 bool multipleMajorities =
false;
400 double result = noDataValue;
401 for (
const auto &pair : std::as_const( map ) )
403 if ( maxCount < pair.second )
406 maxCount = pair.second;
407 multipleMajorities =
false;
409 else if ( maxCount == pair.second )
411 multipleMajorities =
true;
414 return multipleMajorities ? noDataValue : result;
418double QgsRasterAnalysisUtils::minorityFromCellValues( std::vector<double> &cellValues,
const double noDataValue,
int stackSize )
420 if ( stackSize == 1 )
423 return cellValues[0];
425 else if ( stackSize == 2 )
428 return (
qgsDoubleNear( cellValues[0], cellValues[1] ) ) ? cellValues[0] : noDataValue;
430 else if ( std::adjacent_find( cellValues.begin(), cellValues.end(), std::not_equal_to<double>() ) == cellValues.end() )
434 return cellValues[0];
439 std::unordered_map<double, int> map;
441 for (
int i = 0; i < stackSize; i++ )
443 map[cellValues[i]]++;
446 int minCount = stackSize;
447 bool multipleMinorities =
false;
448 double result = noDataValue;
449 for (
const auto &pair : std::as_const( map ) )
451 if ( minCount > pair.second )
454 minCount = pair.second;
455 multipleMinorities =
false;
457 else if ( minCount == pair.second )
459 multipleMinorities =
true;
462 return multipleMinorities ? noDataValue : result;
466double QgsRasterAnalysisUtils::rangeFromCellValues( std::vector<double> &cellValues )
468 const double max = *std::max_element( cellValues.begin(), cellValues.end() );
469 const double min = *std::min_element( cellValues.begin(), cellValues.end() );
473double QgsRasterAnalysisUtils::varietyFromCellValues( std::vector<double> &cellValues )
475 const std::unordered_set<double> uniqueValues( cellValues.begin(), cellValues.end() );
476 return uniqueValues.size();
479double QgsRasterAnalysisUtils::nearestRankPercentile( std::vector<double> &cellValues,
int stackSize,
double percentile )
482 std::sort( cellValues.begin(), cellValues.end() );
485 if ( percentile > 0 )
487 i = std::ceil( percentile *
static_cast<double>( stackSize ) ) - 1;
490 return cellValues[i];
493double QgsRasterAnalysisUtils::interpolatedPercentileInc( std::vector<double> &cellValues,
int stackSize,
double percentile )
495 std::sort( cellValues.begin(), cellValues.end() );
499 return cellValues[stackSize - 1];
503 return cellValues[0];
506 const double x = ( percentile * ( stackSize - 1 ) );
508 const int i =
static_cast<int>( std::floor( x ) );
509 const double xFraction = std::fmod( x, 1 );
511 if ( stackSize == 1 )
513 return cellValues[0];
515 else if ( stackSize == 2 )
517 return cellValues[0] + ( cellValues[1] - cellValues[0] ) * percentile;
521 return cellValues[i] + ( cellValues[i + 1] - cellValues[i] ) * xFraction;
525double QgsRasterAnalysisUtils::interpolatedPercentileExc( std::vector<double> &cellValues,
int stackSize,
double percentile,
double noDataValue )
527 std::sort( cellValues.begin(), cellValues.end() );
528 const double x = ( percentile * ( stackSize + 1 ) );
530 const int i =
static_cast<int>( std::floor( x ) ) - 1;
531 const double xFraction = std::fmod( x, 1 );
532 const double lowerExcValue = 1.0 / (
static_cast<double>( stackSize ) + 1.0 );
533 const double upperExcValue =
static_cast<double>( stackSize ) / (
static_cast<double>( stackSize ) + 1.0 );
535 if ( stackSize < 2 || ( ( percentile < lowerExcValue || percentile > upperExcValue ) ) )
541 return cellValues[i] + ( cellValues[i + 1] - cellValues[i] ) * xFraction;
545double QgsRasterAnalysisUtils::interpolatedPercentRankInc( std::vector<double> &cellValues,
int stackSize,
double value,
double noDataValue )
547 std::sort( cellValues.begin(), cellValues.end() );
549 if ( value < cellValues[0] || value > cellValues[stackSize - 1] )
555 for (
int i = 0; i < stackSize - 1; i++ )
557 if ( cellValues[i] <= value && cellValues[i + 1] >= value )
559 double fraction = 0.0;
563 fraction = ( value - cellValues[i] ) / ( cellValues[i + 1] - cellValues[i] );
565 return ( fraction + i ) / ( stackSize - 1 );
572double QgsRasterAnalysisUtils::interpolatedPercentRankExc( std::vector<double> &cellValues,
int stackSize,
double value,
double noDataValue )
574 std::sort( cellValues.begin(), cellValues.end() );
576 if ( value < cellValues[0] || value > cellValues[stackSize - 1] )
582 for (
int i = 0; i < stackSize - 1; i++ )
584 if ( cellValues[i] <= value && cellValues[i + 1] >= value )
586 double fraction = 0.0;
590 fraction = ( value - cellValues[i] ) / ( cellValues[i + 1] - cellValues[i] );
592 return ( ( i + 1 ) + fraction ) / ( stackSize + 1 );
DataType
Raster data types.
@ Float32
Thirty two bit floating point (float).
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16).
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
@ UInt16
Sixteen bit unsigned integer (quint16).
@ Byte
Eight bit unsigned integer (quint8).
@ Int32
Thirty two bit signed integer (qint32).
@ Float64
Sixty four bit floating point (double).
@ CFloat32
Complex Float32.
@ UInt32
Thirty two bit unsigned integer (quint32).
virtual QgsError error() const
Gets current status error.
QString summary() const
Short error description, usually the first error in chain, the real error.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
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 ¶meters=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...
Custom exception class for processing related exceptions.
Base class for raster data providers.
bool writeBlock(QgsRasterBlock *block, int band, int xOffset=0, int yOffset=0)
Writes pixel data from a raster block into the provider data source.
virtual bool setEditable(bool enabled)
Turns on/off editing mode of the provider.
Base class for processing filters like renderers, reprojector, resampler etc.
Iterator for sequentially processing raster cells.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
A rectangle specified with double values.
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...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).