QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsrastercalcnode.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrastercalcnode.cpp
3  ---------------------
4  begin : October 2010
5  copyright : (C) 2010 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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 #include "qgsrastercalcnode.h"
16 #include "qgsrasterblock.h"
17 #include "qgsrastermatrix.h"
18 
20  : mNumber( number )
21 {
22 }
23 
25  : mType( tMatrix )
26  , mMatrix( matrix )
27 {
28 
29 }
30 
32  : mType( tOperator )
33  , mLeft( left )
34  , mRight( right )
35  , mOperator( op )
36 {
37 }
38 
39 QgsRasterCalcNode::QgsRasterCalcNode( const QString &rasterName )
40  : mType( tRasterRef )
41  , mRasterName( rasterName )
42 {
43  if ( mRasterName.startsWith( '"' ) && mRasterName.endsWith( '"' ) )
44  mRasterName = mRasterName.mid( 1, mRasterName.size() - 2 );
45 }
46 
48 {
49  delete mLeft;
50  delete mRight;
51 }
52 
53 bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData, QgsRasterMatrix &result, int row ) const
54 {
55  //if type is raster ref: return a copy of the corresponding matrix
56 
57  //if type is operator, call the proper matrix operations
58  if ( mType == tRasterRef )
59  {
60  QMap<QString, QgsRasterBlock *>::iterator it = rasterData.find( mRasterName );
61  if ( it == rasterData.end() )
62  {
63  return false;
64  }
65 
66  int nRows = ( row >= 0 ? 1 : ( *it )->height() );
67  int startRow = ( row >= 0 ? row : 0 );
68  int endRow = startRow + nRows;
69  int nCols = ( *it )->width();
70  int nEntries = nCols * nRows;
71  double *data = new double[nEntries];
72 
73  //convert input raster values to double, also convert input no data to result no data
74 
75  int outRow = 0;
76  bool isNoData = false;
77  for ( int dataRow = startRow; dataRow < endRow ; ++dataRow, ++outRow )
78  {
79  for ( int dataCol = 0; dataCol < nCols; ++dataCol )
80  {
81  const double value = ( *it )->valueAndNoData( dataRow, dataCol, isNoData );
82  data[ dataCol + nCols * outRow] = isNoData ? result.nodataValue() : value;
83  }
84  }
85  result.setData( nCols, nRows, data, result.nodataValue() );
86  return true;
87  }
88  else if ( mType == tOperator )
89  {
90  QgsRasterMatrix leftMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
91  QgsRasterMatrix rightMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
92 
93  if ( !mLeft || !mLeft->calculate( rasterData, leftMatrix, row ) )
94  {
95  return false;
96  }
97  if ( mRight && !mRight->calculate( rasterData, rightMatrix, row ) )
98  {
99  return false;
100  }
101 
102  switch ( mOperator )
103  {
104  case opPLUS:
105  leftMatrix.add( rightMatrix );
106  break;
107  case opMINUS:
108  leftMatrix.subtract( rightMatrix );
109  break;
110  case opMUL:
111  leftMatrix.multiply( rightMatrix );
112  break;
113  case opDIV:
114  leftMatrix.divide( rightMatrix );
115  break;
116  case opPOW:
117  leftMatrix.power( rightMatrix );
118  break;
119  case opEQ:
120  leftMatrix.equal( rightMatrix );
121  break;
122  case opNE:
123  leftMatrix.notEqual( rightMatrix );
124  break;
125  case opGT:
126  leftMatrix.greaterThan( rightMatrix );
127  break;
128  case opLT:
129  leftMatrix.lesserThan( rightMatrix );
130  break;
131  case opGE:
132  leftMatrix.greaterEqual( rightMatrix );
133  break;
134  case opLE:
135  leftMatrix.lesserEqual( rightMatrix );
136  break;
137  case opAND:
138  leftMatrix.logicalAnd( rightMatrix );
139  break;
140  case opOR:
141  leftMatrix.logicalOr( rightMatrix );
142  break;
143  case opMIN:
144  leftMatrix.min( rightMatrix );
145  break;
146  case opMAX:
147  leftMatrix.max( rightMatrix );
148  break;
149  case opSQRT:
150  leftMatrix.squareRoot();
151  break;
152  case opSIN:
153  leftMatrix.sinus();
154  break;
155  case opCOS:
156  leftMatrix.cosinus();
157  break;
158  case opTAN:
159  leftMatrix.tangens();
160  break;
161  case opASIN:
162  leftMatrix.asinus();
163  break;
164  case opACOS:
165  leftMatrix.acosinus();
166  break;
167  case opATAN:
168  leftMatrix.atangens();
169  break;
170  case opSIGN:
171  leftMatrix.changeSign();
172  break;
173  case opLOG:
174  leftMatrix.log();
175  break;
176  case opLOG10:
177  leftMatrix.log10();
178  break;
179  case opABS:
180  leftMatrix.absoluteValue();
181  break;
182  default:
183  return false;
184  }
185  int newNColumns = leftMatrix.nColumns();
186  int newNRows = leftMatrix.nRows();
187  result.setData( newNColumns, newNRows, leftMatrix.takeData(), leftMatrix.nodataValue() );
188  return true;
189  }
190  else if ( mType == tNumber )
191  {
192  size_t nEntries = static_cast<size_t>( result.nColumns() * result.nRows() );
193  std::vector<double> *data = new std::vector<double>( nEntries );
194  std::fill( std::begin( *data ), std::end( *data ), mNumber );
195  result.setData( result.nColumns(), 1, data->data(), result.nodataValue() );
196  return true;
197  }
198  else if ( mType == tMatrix )
199  {
200  int nEntries = mMatrix->nColumns() * mMatrix->nRows();
201  double *data = new double[nEntries];
202  for ( int i = 0; i < nEntries; ++i )
203  {
204  data[i] = mMatrix->data()[i] == mMatrix->nodataValue() ? result.nodataValue() : mMatrix->data()[i];
205  }
206  result.setData( mMatrix->nColumns(), mMatrix->nRows(), data, result.nodataValue() );
207  return true;
208  }
209  return false;
210 }
211 
212 QString QgsRasterCalcNode::toString( bool cStyle ) const
213 {
214  QString result;
215  QString left;
216  QString right;
217  if ( mLeft )
218  left = mLeft->toString( cStyle );
219  if ( mRight )
220  right = mRight->toString( cStyle );
221 
222  switch ( mType )
223  {
224  case tOperator:
225  switch ( mOperator )
226  {
227  case opPLUS:
228  result = QStringLiteral( "( %1 + %2 )" ).arg( left ).arg( right );
229  break;
230  case opMINUS:
231  result = QStringLiteral( "( %1 - %2 )" ).arg( left ).arg( right );
232  break;
233  case opSIGN:
234  result = QStringLiteral( "-%1" ).arg( left );
235  break;
236  case opMUL:
237  result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
238  break;
239  case opDIV:
240  result = QStringLiteral( "%1 / %2" ).arg( left ).arg( right );
241  break;
242  case opPOW:
243  if ( cStyle )
244  result = QStringLiteral( "pow( %1, %2 )" ).arg( left ).arg( right );
245  else
246  result = QStringLiteral( "%1^%2" ).arg( left ).arg( right );
247  break;
248  case opEQ:
249  if ( cStyle )
250  result = QStringLiteral( "( float ) ( %1 == %2 )" ).arg( left ).arg( right );
251  else
252  result = QStringLiteral( "%1 = %2" ).arg( left ).arg( right );
253  break;
254  case opNE:
255  if ( cStyle )
256  result = QStringLiteral( "( float ) ( %1 != %2 )" ).arg( left ).arg( right );
257  else
258  result = QStringLiteral( "%1 != %2" ).arg( left ).arg( right );
259  break;
260  case opGT:
261  if ( cStyle )
262  result = QStringLiteral( "( float ) ( %1 > %2 )" ).arg( left ).arg( right );
263  else
264  result = QStringLiteral( "%1 > %2" ).arg( left ).arg( right );
265  break;
266  case opLT:
267  if ( cStyle )
268  result = QStringLiteral( "( float ) ( %1 < %2" ).arg( left ).arg( right );
269  else
270  result = QStringLiteral( "%1 < %2" ).arg( left ).arg( right );
271  break;
272  case opGE:
273  if ( cStyle )
274  result = QStringLiteral( "( float ) ( %1 >= %2 )" ).arg( left ).arg( right );
275  else
276  result = QStringLiteral( "%1 >= %2" ).arg( left ).arg( right );
277  break;
278  case opLE:
279  if ( cStyle )
280  result = QStringLiteral( "( float ) ( %1 <= %2 )" ).arg( left ).arg( right );
281  else
282  result = QStringLiteral( "%1 <= %2" ).arg( left ).arg( right );
283  break;
284  case opAND:
285  if ( cStyle )
286  result = QStringLiteral( "( float ) ( %1 && %2 )" ).arg( left ).arg( right );
287  else
288  result = QStringLiteral( "%1 AND %2" ).arg( left ).arg( right );
289  break;
290  case opOR:
291  if ( cStyle )
292  result = QStringLiteral( "( float ) ( %1 || %2 )" ).arg( left ).arg( right );
293  else
294  result = QStringLiteral( "%1 OR %2" ).arg( left ).arg( right );
295  break;
296  case opSQRT:
297  result = QStringLiteral( "sqrt( %1 )" ).arg( left );
298  break;
299  case opSIN:
300  result = QStringLiteral( "sin( %1 )" ).arg( left );
301  break;
302  case opCOS:
303  result = QStringLiteral( "cos( %1 )" ).arg( left );
304  break;
305  case opTAN:
306  result = QStringLiteral( "tan( %1 )" ).arg( left );
307  break;
308  case opASIN:
309  result = QStringLiteral( "asin( %1 )" ).arg( left );
310  break;
311  case opACOS:
312  result = QStringLiteral( "acos( %1 )" ).arg( left );
313  break;
314  case opATAN:
315  result = QStringLiteral( "atan( %1 )" ).arg( left );
316  break;
317  case opLOG:
318  result = QStringLiteral( "log( %1 )" ).arg( left );
319  break;
320  case opLOG10:
321  result = QStringLiteral( "log10( %1 )" ).arg( left );
322  break;
323  case opABS:
324  if ( cStyle )
325  result = QStringLiteral( "fabs( %1 )" ).arg( left );
326  else
327  // Call the floating point version
328  result = QStringLiteral( "abs( %1 )" ).arg( left );
329  break;
330  case opMIN:
331  if ( cStyle )
332  result = QStringLiteral( "min( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
333  else
334  result = QStringLiteral( "min( %1, %2 )" ).arg( left ).arg( right );
335  break;
336  case opMAX:
337  if ( cStyle )
338  result = QStringLiteral( "max( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
339  else
340  result = QStringLiteral( "max( %1, %2 )" ).arg( left ).arg( right );
341  break;
342  case opNONE:
343  break;
344  }
345  break;
346  case tRasterRef:
347  result = QStringLiteral( "\"%1\"" ).arg( mRasterName );
348  break;
349  case tNumber:
350  result = QString::number( mNumber );
351  if ( cStyle )
352  {
353  result = QStringLiteral( "( float ) ( %1 )" ).arg( result );
354  }
355  break;
356  case tMatrix:
357  break;
358  }
359  return result;
360 }
361 
362 QList<const QgsRasterCalcNode *> QgsRasterCalcNode::findNodes( const QgsRasterCalcNode::Type type ) const
363 {
364  QList<const QgsRasterCalcNode *> nodeList;
365  if ( mType == type )
366  nodeList.push_back( this );
367  if ( mLeft )
368  nodeList.append( mLeft->findNodes( type ) );
369  if ( mRight )
370  nodeList.append( mRight->findNodes( type ) );
371  return nodeList;
372 }
373 
374 QgsRasterCalcNode *QgsRasterCalcNode::parseRasterCalcString( const QString &str, QString &parserErrorMsg )
375 {
376  extern QgsRasterCalcNode *localParseRasterCalcString( const QString & str, QString & parserErrorMsg );
377  return localParseRasterCalcString( str, parserErrorMsg );
378 }
379 
double nodataValue() const
int nRows() const
bool calculate(QMap< QString, QgsRasterBlock * > &rasterData, QgsRasterMatrix &result, int row=-1) const
Calculates result of raster calculation (might be real matrix or single number).
void setData(int cols, int rows, double *data, double nodataValue)
QList< const QgsRasterCalcNode * > findNodes(const QgsRasterCalcNode::Type type) const
Returns a list of nodes of a specific type.
Type
defines possible types of node
Operator
possible operators
QgsRasterCalcNode()=default
Constructor for QgsRasterCalcNode.
int nColumns() const
double * data()
Returns data array (but not ownership)
static QgsRasterCalcNode * parseRasterCalcString(const QString &str, QString &parserErrorMsg)
QString toString(bool cStyle=false) const
Returns a string representation of the expression.