QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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( QString functionName, QVector <QgsRasterCalcNode *> functionArgs )
40  : mType( tFunction )
41  , mFunctionName( functionName )
42  , mFunctionArgs( functionArgs )
43 {
44 }
45 
46 QgsRasterCalcNode::QgsRasterCalcNode( const QString &rasterName )
47  : mType( tRasterRef )
48  , mRasterName( rasterName )
49 {
50  if ( mRasterName.startsWith( '"' ) && mRasterName.endsWith( '"' ) )
51  mRasterName = mRasterName.mid( 1, mRasterName.size() - 2 );
52 }
53 
55 {
56  delete mLeft;
57  delete mRight;
58  for ( int i = 0; i < mFunctionArgs.size(); ++i )
59  {
60  if ( mFunctionArgs.at( i ) )
61  delete mFunctionArgs.at( i );
62  }
63 }
64 
65 bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData, QgsRasterMatrix &result, int row ) const
66 {
67  //if type is raster ref: return a copy of the corresponding matrix
68 
69  //if type is operator, call the proper matrix operations
70  if ( mType == tRasterRef )
71  {
72  const QMap<QString, QgsRasterBlock *>::iterator it = rasterData.find( mRasterName );
73  if ( it == rasterData.end() )
74  {
75  QgsDebugError( QStringLiteral( "Error: could not find raster data for \"%1\"" ).arg( mRasterName ) );
76  return false;
77  }
78 
79  const int nRows = ( row >= 0 ? 1 : ( *it )->height() );
80  const int startRow = ( row >= 0 ? row : 0 );
81  const int endRow = startRow + nRows;
82  const int nCols = ( *it )->width();
83  const int nEntries = nCols * nRows;
84  double *data = new double[nEntries];
85 
86  //convert input raster values to double, also convert input no data to result no data
87 
88  int outRow = 0;
89  bool isNoData = false;
90  for ( int dataRow = startRow; dataRow < endRow ; ++dataRow, ++outRow )
91  {
92  for ( int dataCol = 0; dataCol < nCols; ++dataCol )
93  {
94  const double value = ( *it )->valueAndNoData( dataRow, dataCol, isNoData );
95  data[ dataCol + nCols * outRow] = isNoData ? result.nodataValue() : value;
96  }
97  }
98  result.setData( nCols, nRows, data, result.nodataValue() );
99  return true;
100  }
101  else if ( mType == tOperator )
102  {
103  QgsRasterMatrix leftMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
104  QgsRasterMatrix rightMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
105 
106  if ( !mLeft || !mLeft->calculate( rasterData, leftMatrix, row ) )
107  {
108  return false;
109  }
110  if ( mRight && !mRight->calculate( rasterData, rightMatrix, row ) )
111  {
112  return false;
113  }
114 
115  switch ( mOperator )
116  {
117  case opPLUS:
118  leftMatrix.add( rightMatrix );
119  break;
120  case opMINUS:
121  leftMatrix.subtract( rightMatrix );
122  break;
123  case opMUL:
124  leftMatrix.multiply( rightMatrix );
125  break;
126  case opDIV:
127  leftMatrix.divide( rightMatrix );
128  break;
129  case opPOW:
130  leftMatrix.power( rightMatrix );
131  break;
132  case opEQ:
133  leftMatrix.equal( rightMatrix );
134  break;
135  case opNE:
136  leftMatrix.notEqual( rightMatrix );
137  break;
138  case opGT:
139  leftMatrix.greaterThan( rightMatrix );
140  break;
141  case opLT:
142  leftMatrix.lesserThan( rightMatrix );
143  break;
144  case opGE:
145  leftMatrix.greaterEqual( rightMatrix );
146  break;
147  case opLE:
148  leftMatrix.lesserEqual( rightMatrix );
149  break;
150  case opAND:
151  leftMatrix.logicalAnd( rightMatrix );
152  break;
153  case opOR:
154  leftMatrix.logicalOr( rightMatrix );
155  break;
156  case opMIN:
157  leftMatrix.min( rightMatrix );
158  break;
159  case opMAX:
160  leftMatrix.max( rightMatrix );
161  break;
162  case opSQRT:
163  leftMatrix.squareRoot();
164  break;
165  case opSIN:
166  leftMatrix.sinus();
167  break;
168  case opCOS:
169  leftMatrix.cosinus();
170  break;
171  case opTAN:
172  leftMatrix.tangens();
173  break;
174  case opASIN:
175  leftMatrix.asinus();
176  break;
177  case opACOS:
178  leftMatrix.acosinus();
179  break;
180  case opATAN:
181  leftMatrix.atangens();
182  break;
183  case opSIGN:
184  leftMatrix.changeSign();
185  break;
186  case opLOG:
187  leftMatrix.log();
188  break;
189  case opLOG10:
190  leftMatrix.log10();
191  break;
192  case opABS:
193  leftMatrix.absoluteValue();
194  break;
195  default:
196  return false;
197  }
198  const int newNColumns = leftMatrix.nColumns();
199  const int newNRows = leftMatrix.nRows();
200  result.setData( newNColumns, newNRows, leftMatrix.takeData(), leftMatrix.nodataValue() );
201  return true;
202  }
203  else if ( mType == tNumber )
204  {
205  const size_t nEntries = static_cast<size_t>( result.nColumns() * result.nRows() );
206  double *data = new double[ nEntries ];
207  std::fill( data, data + nEntries, mNumber );
208  result.setData( result.nColumns(), 1, data, result.nodataValue() );
209 
210  return true;
211  }
212  else if ( mType == tMatrix )
213  {
214  const int nEntries = mMatrix->nColumns() * mMatrix->nRows();
215  double *data = new double[nEntries];
216  for ( int i = 0; i < nEntries; ++i )
217  {
218  data[i] = mMatrix->data()[i] == mMatrix->nodataValue() ? result.nodataValue() : mMatrix->data()[i];
219  }
220  result.setData( mMatrix->nColumns(), mMatrix->nRows(), data, result.nodataValue() );
221  return true;
222  }
223  else if ( mType == tFunction )
224  {
225  std::vector< std::unique_ptr< QgsRasterMatrix > > matrixContainer;
226  for ( int i = 0; i < mFunctionArgs.size(); ++i )
227  {
228  std::unique_ptr< QgsRasterMatrix > singleMatrix = std::make_unique< QgsRasterMatrix >( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
229  if ( !mFunctionArgs.at( i ) || !mFunctionArgs.at( i )->calculate( rasterData, *singleMatrix, row ) )
230  {
231  return false;
232  }
233  matrixContainer.emplace_back( std::move( singleMatrix ) );
234  }
235  evaluateFunction( matrixContainer, result );
236  return true;
237  }
238  return false;
239 }
240 
241 QString QgsRasterCalcNode::toString( bool cStyle ) const
242 {
243  QString result;
244  QString left;
245  QString right;
246  if ( mLeft )
247  left = mLeft->toString( cStyle );
248  if ( mRight )
249  right = mRight->toString( cStyle );
250 
251  switch ( mType )
252  {
253  case tOperator:
254  switch ( mOperator )
255  {
256  case opPLUS:
257  result = QStringLiteral( "( %1 + %2 )" ).arg( left ).arg( right );
258  break;
259  case opMINUS:
260  result = QStringLiteral( "( %1 - %2 )" ).arg( left ).arg( right );
261  break;
262  case opSIGN:
263  result = QStringLiteral( "-%1" ).arg( left );
264  break;
265  case opMUL:
266  result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
267  break;
268  case opDIV:
269  result = QStringLiteral( "%1 / %2" ).arg( left ).arg( right );
270  break;
271  case opPOW:
272  if ( cStyle )
273  result = QStringLiteral( "pow( %1, %2 )" ).arg( left ).arg( right );
274  else
275  result = QStringLiteral( "%1^%2" ).arg( left ).arg( right );
276  break;
277  case opEQ:
278  if ( cStyle )
279  result = QStringLiteral( "( float ) ( %1 == %2 )" ).arg( left ).arg( right );
280  else
281  result = QStringLiteral( "%1 = %2" ).arg( left ).arg( right );
282  break;
283  case opNE:
284  if ( cStyle )
285  result = QStringLiteral( "( float ) ( %1 != %2 )" ).arg( left ).arg( right );
286  else
287  result = QStringLiteral( "%1 != %2" ).arg( left ).arg( right );
288  break;
289  case opGT:
290  if ( cStyle )
291  result = QStringLiteral( "( float ) ( %1 > %2 )" ).arg( left ).arg( right );
292  else
293  result = QStringLiteral( "%1 > %2" ).arg( left ).arg( right );
294  break;
295  case opLT:
296  if ( cStyle )
297  result = QStringLiteral( "( float ) ( %1 < %2 )" ).arg( left ).arg( right );
298  else
299  result = QStringLiteral( "%1 < %2" ).arg( left ).arg( right );
300  break;
301  case opGE:
302  if ( cStyle )
303  result = QStringLiteral( "( float ) ( %1 >= %2 )" ).arg( left ).arg( right );
304  else
305  result = QStringLiteral( "%1 >= %2" ).arg( left ).arg( right );
306  break;
307  case opLE:
308  if ( cStyle )
309  result = QStringLiteral( "( float ) ( %1 <= %2 )" ).arg( left ).arg( right );
310  else
311  result = QStringLiteral( "%1 <= %2" ).arg( left ).arg( right );
312  break;
313  case opAND:
314  if ( cStyle )
315  result = QStringLiteral( "( float ) ( %1 && %2 )" ).arg( left ).arg( right );
316  else
317  result = QStringLiteral( "%1 AND %2" ).arg( left ).arg( right );
318  break;
319  case opOR:
320  if ( cStyle )
321  result = QStringLiteral( "( float ) ( %1 || %2 )" ).arg( left ).arg( right );
322  else
323  result = QStringLiteral( "%1 OR %2" ).arg( left ).arg( right );
324  break;
325  case opSQRT:
326  result = QStringLiteral( "sqrt( %1 )" ).arg( left );
327  break;
328  case opSIN:
329  result = QStringLiteral( "sin( %1 )" ).arg( left );
330  break;
331  case opCOS:
332  result = QStringLiteral( "cos( %1 )" ).arg( left );
333  break;
334  case opTAN:
335  result = QStringLiteral( "tan( %1 )" ).arg( left );
336  break;
337  case opASIN:
338  result = QStringLiteral( "asin( %1 )" ).arg( left );
339  break;
340  case opACOS:
341  result = QStringLiteral( "acos( %1 )" ).arg( left );
342  break;
343  case opATAN:
344  result = QStringLiteral( "atan( %1 )" ).arg( left );
345  break;
346  case opLOG:
347  result = QStringLiteral( "log( %1 )" ).arg( left );
348  break;
349  case opLOG10:
350  result = QStringLiteral( "log10( %1 )" ).arg( left );
351  break;
352  case opABS:
353  if ( cStyle )
354  result = QStringLiteral( "fabs( %1 )" ).arg( left );
355  else
356  // Call the floating point version
357  result = QStringLiteral( "abs( %1 )" ).arg( left );
358  break;
359  case opMIN:
360  if ( cStyle )
361  result = QStringLiteral( "min( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
362  else
363  result = QStringLiteral( "min( %1, %2 )" ).arg( left ).arg( right );
364  break;
365  case opMAX:
366  if ( cStyle )
367  result = QStringLiteral( "max( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
368  else
369  result = QStringLiteral( "max( %1, %2 )" ).arg( left ).arg( right );
370  break;
371  case opNONE:
372  break;
373  }
374  break;
375  case tRasterRef:
376  if ( cStyle )
377  result = QStringLiteral( "( float ) \"%1\"" ).arg( mRasterName );
378  else
379  result = QStringLiteral( "\"%1\"" ).arg( mRasterName );
380  break;
381  case tNumber:
382  result = QString::number( mNumber );
383  if ( cStyle )
384  {
385  result = QStringLiteral( "( float ) %1" ).arg( result );
386  }
387  break;
388  case tMatrix:
389  break;
390  case tFunction:
391  if ( mFunctionName == "if" )
392  {
393  const QString argOne = mFunctionArgs.at( 0 )->toString( cStyle );
394  const QString argTwo = mFunctionArgs.at( 1 )->toString( cStyle );
395  const QString argThree = mFunctionArgs.at( 2 )->toString( cStyle );
396  if ( cStyle )
397  result = QStringLiteral( " ( %1 ) ? ( %2 ) : ( %3 ) " ).arg( argOne, argTwo, argThree );
398  else
399  result = QStringLiteral( "if( %1 , %2 , %3 )" ).arg( argOne, argTwo, argThree );
400  }
401  break;
402  }
403  return result;
404 }
405 
406 QList<const QgsRasterCalcNode *> QgsRasterCalcNode::findNodes( const QgsRasterCalcNode::Type type ) const
407 {
408  QList<const QgsRasterCalcNode *> nodeList;
409  if ( mType == type )
410  nodeList.push_back( this );
411  if ( mLeft )
412  nodeList.append( mLeft->findNodes( type ) );
413  if ( mRight )
414  nodeList.append( mRight->findNodes( type ) );
415 
416  for ( QgsRasterCalcNode *node : mFunctionArgs )
417  nodeList.append( node->findNodes( type ) );
418 
419  return nodeList;
420 }
421 
422 QgsRasterCalcNode *QgsRasterCalcNode::parseRasterCalcString( const QString &str, QString &parserErrorMsg )
423 {
424  extern QgsRasterCalcNode *localParseRasterCalcString( const QString & str, QString & parserErrorMsg );
425  return localParseRasterCalcString( str, parserErrorMsg );
426 }
427 
429 {
430  QStringList referencedRasters;
431 
432  QStringList rasterRef = this->cleanRasterReferences();
433  for ( const auto &i : rasterRef )
434  {
435  if ( referencedRasters.contains( i.mid( 0, i.lastIndexOf( "@" ) ) ) ) continue;
436  referencedRasters << i.mid( 0, i.lastIndexOf( "@" ) );
437  }
438 
439  return referencedRasters;
440 }
441 
443 {
444  QStringList rasterReferences;
445  const QList<const QgsRasterCalcNode *> rasterRefNodes = this->findNodes( QgsRasterCalcNode::Type::tRasterRef );
446 
447  for ( const QgsRasterCalcNode *r : rasterRefNodes )
448  {
449 
450  QString layerRef( r->toString() );
451  if ( layerRef.at( 0 ) == QLatin1String( "\"" ) && layerRef.at( layerRef.size() - 1 ) == QLatin1String( "\"" ) )
452  {
453  layerRef.remove( 0, 1 );
454  layerRef.chop( 1 );
455 
456  }
457  layerRef.remove( QChar( '\\' ), Qt::CaseInsensitive );
458  rasterReferences << layerRef;
459  }
460 
461  return rasterReferences;
462 }
463 
464 QgsRasterMatrix QgsRasterCalcNode::evaluateFunction( const std::vector< std::unique_ptr< QgsRasterMatrix > > &matrixVector, QgsRasterMatrix &result ) const
465 {
466 
467  if ( mFunctionName == "if" )
468  {
469  //scalar condition
470  if ( matrixVector.at( 0 )->isNumber() )
471  {
472  result = ( matrixVector.at( 0 )->data() ? * matrixVector.at( 1 ) : * matrixVector.at( 2 ) );
473  return result;
474  }
475  int nCols = matrixVector.at( 0 )->nColumns();
476  int nRows = matrixVector.at( 0 )->nRows();
477  int nEntries = nCols * nRows;
478  std::unique_ptr< double[] > dataResult = std::make_unique< double[] >( nEntries );
479  double *dataResultRawPtr = dataResult.get();
480 
481  double *condition = matrixVector.at( 0 )->data();
482  double *firstOption = matrixVector.at( 1 )->data();
483  double *secondOption = matrixVector.at( 2 )->data();
484 
485  bool isFirstOptionNumber = matrixVector.at( 1 )->isNumber();
486  bool isSecondCOptionNumber = matrixVector.at( 2 )->isNumber();
487  double noDataValueCondition = matrixVector.at( 0 )->nodataValue();
488 
489  for ( int i = 0; i < nEntries; ++i )
490  {
491  if ( condition[i] == noDataValueCondition )
492  {
493  dataResultRawPtr[i] = result.nodataValue();
494  continue;
495  }
496  else if ( condition[i] != 0 )
497  {
498  dataResultRawPtr[i] = isFirstOptionNumber ? firstOption[0] : firstOption[i];
499  continue;
500  }
501  dataResultRawPtr[i] = isSecondCOptionNumber ? secondOption[0] : secondOption[i];
502  }
503 
504  result.setData( nCols, nRows, dataResult.release(), result.nodataValue() );
505  }
506  return result;
507 }
Represents a node in a raster calculator.
QString toString(bool cStyle=false) const
Returns a string representation of the expression.
Operator
possible operators
QgsRasterCalcNode()=default
Constructor for QgsRasterCalcNode.
QList< const QgsRasterCalcNode * > findNodes(const QgsRasterCalcNode::Type type) const
Returns a list of nodes of a specific type.
static QgsRasterCalcNode * parseRasterCalcString(const QString &str, QString &parserErrorMsg)
QStringList referencedLayerNames()
Returns a list of raster layer names that are referenced in the formula without the quotation marks.
bool calculate(QMap< QString, QgsRasterBlock * > &rasterData, QgsRasterMatrix &result, int row=-1) const
Calculates result of raster calculation (might be real matrix or single number).
QStringList cleanRasterReferences()
Returns a list of raster layer references that are addressed in the formula, without quotation marks.
Type
defines possible types of node
Represents a matrix in a raster calculator operation.
bool equal(const QgsRasterMatrix &other)
bool max(const QgsRasterMatrix &other)
Calculates the maximum value between two matrices.
bool greaterEqual(const QgsRasterMatrix &other)
double * data()
Returns data array (but not ownership)
double * takeData()
Returns data and ownership.
bool notEqual(const QgsRasterMatrix &other)
bool greaterThan(const QgsRasterMatrix &other)
bool logicalOr(const QgsRasterMatrix &other)
bool lesserEqual(const QgsRasterMatrix &other)
bool absoluteValue()
Calculates the absolute value.
bool logicalAnd(const QgsRasterMatrix &other)
bool lesserThan(const QgsRasterMatrix &other)
bool add(const QgsRasterMatrix &other)
Adds another matrix to this one.
bool multiply(const QgsRasterMatrix &other)
int nRows() const
bool power(const QgsRasterMatrix &other)
double nodataValue() const
bool min(const QgsRasterMatrix &other)
Calculates the minimum value between two matrices.
bool divide(const QgsRasterMatrix &other)
int nColumns() const
void setData(int cols, int rows, double *data, double nodataValue)
bool subtract(const QgsRasterMatrix &other)
Subtracts another matrix from this one.
#define str(x)
Definition: qgis.cpp:38
#define QgsDebugError(str)
Definition: qgslogger.h:38