QGIS API Documentation  3.13.0-Master (b73bd58cfb)
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  QgsDebugMsg( QStringLiteral( "Error: could not find raster data for \"%1\"" ).arg( mRasterName ) );
64  return false;
65  }
66 
67  int nRows = ( row >= 0 ? 1 : ( *it )->height() );
68  int startRow = ( row >= 0 ? row : 0 );
69  int endRow = startRow + nRows;
70  int nCols = ( *it )->width();
71  int nEntries = nCols * nRows;
72  double *data = new double[nEntries];
73 
74  //convert input raster values to double, also convert input no data to result no data
75 
76  int outRow = 0;
77  bool isNoData = false;
78  for ( int dataRow = startRow; dataRow < endRow ; ++dataRow, ++outRow )
79  {
80  for ( int dataCol = 0; dataCol < nCols; ++dataCol )
81  {
82  const double value = ( *it )->valueAndNoData( dataRow, dataCol, isNoData );
83  data[ dataCol + nCols * outRow] = isNoData ? result.nodataValue() : value;
84  }
85  }
86  result.setData( nCols, nRows, data, result.nodataValue() );
87  return true;
88  }
89  else if ( mType == tOperator )
90  {
91  QgsRasterMatrix leftMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
92  QgsRasterMatrix rightMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
93 
94  if ( !mLeft || !mLeft->calculate( rasterData, leftMatrix, row ) )
95  {
96  return false;
97  }
98  if ( mRight && !mRight->calculate( rasterData, rightMatrix, row ) )
99  {
100  return false;
101  }
102 
103  switch ( mOperator )
104  {
105  case opPLUS:
106  leftMatrix.add( rightMatrix );
107  break;
108  case opMINUS:
109  leftMatrix.subtract( rightMatrix );
110  break;
111  case opMUL:
112  leftMatrix.multiply( rightMatrix );
113  break;
114  case opDIV:
115  leftMatrix.divide( rightMatrix );
116  break;
117  case opPOW:
118  leftMatrix.power( rightMatrix );
119  break;
120  case opEQ:
121  leftMatrix.equal( rightMatrix );
122  break;
123  case opNE:
124  leftMatrix.notEqual( rightMatrix );
125  break;
126  case opGT:
127  leftMatrix.greaterThan( rightMatrix );
128  break;
129  case opLT:
130  leftMatrix.lesserThan( rightMatrix );
131  break;
132  case opGE:
133  leftMatrix.greaterEqual( rightMatrix );
134  break;
135  case opLE:
136  leftMatrix.lesserEqual( rightMatrix );
137  break;
138  case opAND:
139  leftMatrix.logicalAnd( rightMatrix );
140  break;
141  case opOR:
142  leftMatrix.logicalOr( rightMatrix );
143  break;
144  case opMIN:
145  leftMatrix.min( rightMatrix );
146  break;
147  case opMAX:
148  leftMatrix.max( rightMatrix );
149  break;
150  case opSQRT:
151  leftMatrix.squareRoot();
152  break;
153  case opSIN:
154  leftMatrix.sinus();
155  break;
156  case opCOS:
157  leftMatrix.cosinus();
158  break;
159  case opTAN:
160  leftMatrix.tangens();
161  break;
162  case opASIN:
163  leftMatrix.asinus();
164  break;
165  case opACOS:
166  leftMatrix.acosinus();
167  break;
168  case opATAN:
169  leftMatrix.atangens();
170  break;
171  case opSIGN:
172  leftMatrix.changeSign();
173  break;
174  case opLOG:
175  leftMatrix.log();
176  break;
177  case opLOG10:
178  leftMatrix.log10();
179  break;
180  case opABS:
181  leftMatrix.absoluteValue();
182  break;
183  default:
184  return false;
185  }
186  int newNColumns = leftMatrix.nColumns();
187  int newNRows = leftMatrix.nRows();
188  result.setData( newNColumns, newNRows, leftMatrix.takeData(), leftMatrix.nodataValue() );
189  return true;
190  }
191  else if ( mType == tNumber )
192  {
193  size_t nEntries = static_cast<size_t>( result.nColumns() * result.nRows() );
194  double *data = new double[ nEntries ];
195  std::fill( data, data + nEntries, mNumber );
196  result.setData( result.nColumns(), 1, data, result.nodataValue() );
197 
198  return true;
199  }
200  else if ( mType == tMatrix )
201  {
202  int nEntries = mMatrix->nColumns() * mMatrix->nRows();
203  double *data = new double[nEntries];
204  for ( int i = 0; i < nEntries; ++i )
205  {
206  data[i] = mMatrix->data()[i] == mMatrix->nodataValue() ? result.nodataValue() : mMatrix->data()[i];
207  }
208  result.setData( mMatrix->nColumns(), mMatrix->nRows(), data, result.nodataValue() );
209  return true;
210  }
211  return false;
212 }
213 
214 QString QgsRasterCalcNode::toString( bool cStyle ) const
215 {
216  QString result;
217  QString left;
218  QString right;
219  if ( mLeft )
220  left = mLeft->toString( cStyle );
221  if ( mRight )
222  right = mRight->toString( cStyle );
223 
224  switch ( mType )
225  {
226  case tOperator:
227  switch ( mOperator )
228  {
229  case opPLUS:
230  result = QStringLiteral( "( %1 + %2 )" ).arg( left ).arg( right );
231  break;
232  case opMINUS:
233  result = QStringLiteral( "( %1 - %2 )" ).arg( left ).arg( right );
234  break;
235  case opSIGN:
236  result = QStringLiteral( "-%1" ).arg( left );
237  break;
238  case opMUL:
239  result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
240  break;
241  case opDIV:
242  result = QStringLiteral( "%1 / %2" ).arg( left ).arg( right );
243  break;
244  case opPOW:
245  if ( cStyle )
246  result = QStringLiteral( "pow( %1, %2 )" ).arg( left ).arg( right );
247  else
248  result = QStringLiteral( "%1^%2" ).arg( left ).arg( right );
249  break;
250  case opEQ:
251  if ( cStyle )
252  result = QStringLiteral( "( float ) ( %1 == %2 )" ).arg( left ).arg( right );
253  else
254  result = QStringLiteral( "%1 = %2" ).arg( left ).arg( right );
255  break;
256  case opNE:
257  if ( cStyle )
258  result = QStringLiteral( "( float ) ( %1 != %2 )" ).arg( left ).arg( right );
259  else
260  result = QStringLiteral( "%1 != %2" ).arg( left ).arg( right );
261  break;
262  case opGT:
263  if ( cStyle )
264  result = QStringLiteral( "( float ) ( %1 > %2 )" ).arg( left ).arg( right );
265  else
266  result = QStringLiteral( "%1 > %2" ).arg( left ).arg( right );
267  break;
268  case opLT:
269  if ( cStyle )
270  result = QStringLiteral( "( float ) ( %1 < %2 )" ).arg( left ).arg( right );
271  else
272  result = QStringLiteral( "%1 < %2" ).arg( left ).arg( right );
273  break;
274  case opGE:
275  if ( cStyle )
276  result = QStringLiteral( "( float ) ( %1 >= %2 )" ).arg( left ).arg( right );
277  else
278  result = QStringLiteral( "%1 >= %2" ).arg( left ).arg( right );
279  break;
280  case opLE:
281  if ( cStyle )
282  result = QStringLiteral( "( float ) ( %1 <= %2 )" ).arg( left ).arg( right );
283  else
284  result = QStringLiteral( "%1 <= %2" ).arg( left ).arg( right );
285  break;
286  case opAND:
287  if ( cStyle )
288  result = QStringLiteral( "( float ) ( %1 && %2 )" ).arg( left ).arg( right );
289  else
290  result = QStringLiteral( "%1 AND %2" ).arg( left ).arg( right );
291  break;
292  case opOR:
293  if ( cStyle )
294  result = QStringLiteral( "( float ) ( %1 || %2 )" ).arg( left ).arg( right );
295  else
296  result = QStringLiteral( "%1 OR %2" ).arg( left ).arg( right );
297  break;
298  case opSQRT:
299  result = QStringLiteral( "sqrt( %1 )" ).arg( left );
300  break;
301  case opSIN:
302  result = QStringLiteral( "sin( %1 )" ).arg( left );
303  break;
304  case opCOS:
305  result = QStringLiteral( "cos( %1 )" ).arg( left );
306  break;
307  case opTAN:
308  result = QStringLiteral( "tan( %1 )" ).arg( left );
309  break;
310  case opASIN:
311  result = QStringLiteral( "asin( %1 )" ).arg( left );
312  break;
313  case opACOS:
314  result = QStringLiteral( "acos( %1 )" ).arg( left );
315  break;
316  case opATAN:
317  result = QStringLiteral( "atan( %1 )" ).arg( left );
318  break;
319  case opLOG:
320  result = QStringLiteral( "log( %1 )" ).arg( left );
321  break;
322  case opLOG10:
323  result = QStringLiteral( "log10( %1 )" ).arg( left );
324  break;
325  case opABS:
326  if ( cStyle )
327  result = QStringLiteral( "fabs( %1 )" ).arg( left );
328  else
329  // Call the floating point version
330  result = QStringLiteral( "abs( %1 )" ).arg( left );
331  break;
332  case opMIN:
333  if ( cStyle )
334  result = QStringLiteral( "min( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
335  else
336  result = QStringLiteral( "min( %1, %2 )" ).arg( left ).arg( right );
337  break;
338  case opMAX:
339  if ( cStyle )
340  result = QStringLiteral( "max( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
341  else
342  result = QStringLiteral( "max( %1, %2 )" ).arg( left ).arg( right );
343  break;
344  case opNONE:
345  break;
346  }
347  break;
348  case tRasterRef:
349  if ( cStyle )
350  result = QStringLiteral( "( float ) \"%1\"" ).arg( mRasterName );
351  else
352  result = QStringLiteral( "\"%1\"" ).arg( mRasterName );
353  break;
354  case tNumber:
355  result = QString::number( mNumber );
356  if ( cStyle )
357  {
358  result = QStringLiteral( "( float ) %1" ).arg( result );
359  }
360  break;
361  case tMatrix:
362  break;
363  }
364  return result;
365 }
366 
367 QList<const QgsRasterCalcNode *> QgsRasterCalcNode::findNodes( const QgsRasterCalcNode::Type type ) const
368 {
369  QList<const QgsRasterCalcNode *> nodeList;
370  if ( mType == type )
371  nodeList.push_back( this );
372  if ( mLeft )
373  nodeList.append( mLeft->findNodes( type ) );
374  if ( mRight )
375  nodeList.append( mRight->findNodes( type ) );
376  return nodeList;
377 }
378 
379 QgsRasterCalcNode *QgsRasterCalcNode::parseRasterCalcString( const QString &str, QString &parserErrorMsg )
380 {
381  extern QgsRasterCalcNode *localParseRasterCalcString( const QString & str, QString & parserErrorMsg );
382  return localParseRasterCalcString( str, parserErrorMsg );
383 }
384 
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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.