QGIS API Documentation  3.6.0-Noosa (5873452)
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 
16 #include "qgsrasteranalysisutils.h"
17 
18 #include "qgsfeedback.h"
19 #include "qgsrasterblock.h"
20 #include "qgsrasteriterator.h"
21 #include "qgsgeos.h"
23 #include <map>
25 
26 void QgsRasterAnalysisUtils::cellInfoForBBox( const QgsRectangle &rasterBBox, const QgsRectangle &featureBBox, double cellSizeX, double cellSizeY,
27  int &nCellsX, int &nCellsY, int rasterWidth, int rasterHeight, QgsRectangle &rasterBlockExtent )
28 {
29  //get intersecting bbox
30  QgsRectangle intersectBox = rasterBBox.intersect( featureBBox );
31  if ( intersectBox.isEmpty() )
32  {
33  nCellsX = 0;
34  nCellsY = 0;
35  rasterBlockExtent = QgsRectangle();
36  return;
37  }
38 
39  //get offset in pixels in x- and y- direction
40  int offsetX = static_cast< int >( std::floor( ( intersectBox.xMinimum() - rasterBBox.xMinimum() ) / cellSizeX ) );
41  int offsetY = static_cast< int >( std::floor( ( rasterBBox.yMaximum() - intersectBox.yMaximum() ) / cellSizeY ) );
42 
43  int maxColumn = static_cast< int >( std::floor( ( intersectBox.xMaximum() - rasterBBox.xMinimum() ) / cellSizeX ) ) + 1;
44  int maxRow = static_cast< int >( std::floor( ( rasterBBox.yMaximum() - intersectBox.yMinimum() ) / cellSizeY ) ) + 1;
45 
46  nCellsX = maxColumn - offsetX;
47  nCellsY = maxRow - offsetY;
48 
49  //avoid access to cells outside of the raster (may occur because of rounding)
50  nCellsX = std::min( offsetX + nCellsX, rasterWidth ) - offsetX;
51  nCellsY = std::min( offsetY + nCellsY, rasterHeight ) - offsetY;
52 
53  rasterBlockExtent = QgsRectangle( rasterBBox.xMinimum() + offsetX * cellSizeX,
54  rasterBBox.yMaximum() - offsetY * cellSizeY,
55  rasterBBox.xMinimum() + ( nCellsX + offsetX ) * cellSizeX,
56  rasterBBox.yMaximum() - ( nCellsY + offsetY ) * cellSizeY );
57 }
58 
59 void 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 )> &addValue, bool skipNodata )
60 {
61  std::unique_ptr< QgsGeometryEngine > polyEngine( QgsGeometry::createGeometryEngine( poly.constGet( ) ) );
62  if ( !polyEngine )
63  {
64  return;
65  }
66  polyEngine->prepareGeometry();
67 
68  QgsRasterIterator iter( rasterInterface );
69  iter.startRasterRead( rasterBand, nCellsX, nCellsY, rasterBBox );
70 
71  std::unique_ptr< QgsRasterBlock > block;
72  int iterLeft = 0;
73  int iterTop = 0;
74  int iterCols = 0;
75  int iterRows = 0;
76  QgsRectangle blockExtent;
77  bool isNoData = false;
78  while ( iter.readNextRasterPart( rasterBand, iterCols, iterRows, block, iterLeft, iterTop, &blockExtent ) )
79  {
80  double cellCenterY = blockExtent.yMaximum() - 0.5 * cellSizeY;
81 
82  for ( int row = 0; row < iterRows; ++row )
83  {
84  double cellCenterX = blockExtent.xMinimum() + 0.5 * cellSizeX;
85  for ( int col = 0; col < iterCols; ++col )
86  {
87  const double pixelValue = block->valueAndNoData( row, col, isNoData );
88  if ( validPixel( pixelValue ) && ( !skipNodata || !isNoData ) )
89  {
90  QgsPoint cellCenter( cellCenterX, cellCenterY );
91  if ( polyEngine->contains( &cellCenter ) )
92  {
93  addValue( pixelValue );
94  }
95  }
96  cellCenterX += cellSizeX;
97  }
98  cellCenterY -= cellSizeY;
99  }
100  }
101 }
102 
103 void 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 )> &addValue, bool skipNodata )
104 {
105  QgsGeometry pixelRectGeometry;
106 
107  double hCellSizeX = cellSizeX / 2.0;
108  double hCellSizeY = cellSizeY / 2.0;
109  double pixelArea = cellSizeX * cellSizeY;
110  double weight = 0;
111 
112  std::unique_ptr< QgsGeometryEngine > polyEngine( QgsGeometry::createGeometryEngine( poly.constGet( ) ) );
113  if ( !polyEngine )
114  {
115  return;
116  }
117  polyEngine->prepareGeometry();
118 
119  QgsRasterIterator iter( rasterInterface );
120  iter.startRasterRead( rasterBand, nCellsX, nCellsY, rasterBBox );
121 
122  std::unique_ptr< QgsRasterBlock > block;
123  int iterLeft = 0;
124  int iterTop = 0;
125  int iterCols = 0;
126  int iterRows = 0;
127  QgsRectangle blockExtent;
128  bool isNoData = false;
129  while ( iter.readNextRasterPart( rasterBand, iterCols, iterRows, block, iterLeft, iterTop, &blockExtent ) )
130  {
131  double currentY = blockExtent.yMaximum() - 0.5 * cellSizeY;
132  for ( int row = 0; row < iterRows; ++row )
133  {
134  double currentX = blockExtent.xMinimum() + 0.5 * cellSizeX;
135  for ( int col = 0; col < iterCols; ++col )
136  {
137  const double pixelValue = block->valueAndNoData( row, col, isNoData );
138  if ( validPixel( pixelValue ) && ( !skipNodata || !isNoData ) )
139  {
140  pixelRectGeometry = QgsGeometry::fromRect( QgsRectangle( currentX - hCellSizeX, currentY - hCellSizeY, currentX + hCellSizeX, currentY + hCellSizeY ) );
141  // GEOS intersects tests on prepared geometry is MAGNITUDES faster than calculating the intersection itself,
142  // so we first test to see if there IS an intersection before doing the actual calculation
143  if ( !pixelRectGeometry.isNull() && polyEngine->intersects( pixelRectGeometry.constGet() ) )
144  {
145  //intersection
146  QgsGeometry intersectGeometry = pixelRectGeometry.intersection( poly );
147  if ( !intersectGeometry.isEmpty() )
148  {
149  double intersectionArea = intersectGeometry.area();
150  if ( intersectionArea > 0.0 )
151  {
152  weight = intersectionArea / pixelArea;
153  addValue( pixelValue, weight );
154  }
155  }
156  }
157  }
158  currentX += cellSizeX;
159  }
160  currentY -= cellSizeY;
161  }
162  }
163 }
164 
165 bool QgsRasterAnalysisUtils::validPixel( double value )
166 {
167  return !std::isnan( value );
168 }
169 
170 static QVector< QPair< QString, Qgis::DataType > > sDataTypes;
171 
172 void populateDataTypes()
173 {
174  if ( sDataTypes.empty() )
175  {
176  sDataTypes.append( qMakePair( QStringLiteral( "Byte" ), Qgis::Byte ) );
177  sDataTypes.append( qMakePair( QStringLiteral( "Int16" ), Qgis::Int16 ) );
178  sDataTypes.append( qMakePair( QStringLiteral( "UInt16" ), Qgis::UInt16 ) );
179  sDataTypes.append( qMakePair( QStringLiteral( "Int32" ), Qgis::Int32 ) );
180  sDataTypes.append( qMakePair( QStringLiteral( "UInt32" ), Qgis::UInt32 ) );
181  sDataTypes.append( qMakePair( QStringLiteral( "Float32" ), Qgis::Float32 ) );
182  sDataTypes.append( qMakePair( QStringLiteral( "Float64" ), Qgis::Float64 ) );
183  sDataTypes.append( qMakePair( QStringLiteral( "CInt16" ), Qgis::CInt16 ) );
184  sDataTypes.append( qMakePair( QStringLiteral( "CInt32" ), Qgis::CInt32 ) );
185  sDataTypes.append( qMakePair( QStringLiteral( "CFloat32" ), Qgis::CFloat32 ) );
186  sDataTypes.append( qMakePair( QStringLiteral( "CFloat64" ), Qgis::CFloat64 ) );
187  }
188 }
189 
190 std::unique_ptr<QgsProcessingParameterDefinition> QgsRasterAnalysisUtils::createRasterTypeParameter( const QString &name, const QString &description, Qgis::DataType defaultType )
191 {
192  populateDataTypes();
193 
194  QStringList names;
195  int defaultChoice = 0;
196  int i = 0;
197  for ( auto it = sDataTypes.constBegin(); it != sDataTypes.constEnd(); ++it )
198  {
199  names.append( it->first );
200  if ( it->second == defaultType )
201  defaultChoice = i;
202  i++;
203  }
204 
205  return qgis::make_unique< QgsProcessingParameterEnum >( name, description, names, false, defaultChoice );
206 }
207 
208 Qgis::DataType QgsRasterAnalysisUtils::rasterTypeChoiceToDataType( int choice )
209 {
210  if ( choice < 0 || choice >= sDataTypes.count() )
211  return Qgis::Float32;
212 
213  return sDataTypes.value( choice ).second;
214 }
215 
217 
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Thirty two bit signed integer (qint32)
Definition: qgis.h:86
Iterator for sequentially processing raster cells.
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:85
DataType
Raster data types.
Definition: qgis.h:79
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
Thirty two bit floating point (float)
Definition: qgis.h:87
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
Sixteen bit signed integer (qint16)
Definition: qgis.h:84
Complex Int16.
Definition: qgis.h:89
Sixty four bit floating point (double)
Definition: qgis.h:88
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:426
Complex Float32.
Definition: qgis.h:91
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:312
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Complex Int32.
Definition: qgis.h:90
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:83
Base class for processing filters like renderers, reprojector, resampler etc.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
double area() const
Returns the area of the geometry using GEOS.
Complex Float64.
Definition: qgis.h:92
Eight bit unsigned integer (quint8)
Definition: qgis.h:82