QGIS API Documentation  3.6.0-Noosa (5873452)
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, rightMatrix;
91  leftMatrix.setNodataValue( result.nodataValue() );
92  rightMatrix.setNodataValue( 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 opSQRT:
145  leftMatrix.squareRoot();
146  break;
147  case opSIN:
148  leftMatrix.sinus();
149  break;
150  case opCOS:
151  leftMatrix.cosinus();
152  break;
153  case opTAN:
154  leftMatrix.tangens();
155  break;
156  case opASIN:
157  leftMatrix.asinus();
158  break;
159  case opACOS:
160  leftMatrix.acosinus();
161  break;
162  case opATAN:
163  leftMatrix.atangens();
164  break;
165  case opSIGN:
166  leftMatrix.changeSign();
167  break;
168  case opLOG:
169  leftMatrix.log();
170  break;
171  case opLOG10:
172  leftMatrix.log10();
173  break;
174  default:
175  return false;
176  }
177  int newNColumns = leftMatrix.nColumns();
178  int newNRows = leftMatrix.nRows();
179  result.setData( newNColumns, newNRows, leftMatrix.takeData(), leftMatrix.nodataValue() );
180  return true;
181  }
182  else if ( mType == tNumber )
183  {
184  double *data = new double[1];
185  data[0] = mNumber;
186  result.setData( 1, 1, data, result.nodataValue() );
187  return true;
188  }
189  else if ( mType == tMatrix )
190  {
191  int nEntries = mMatrix->nColumns() * mMatrix->nRows();
192  double *data = new double[nEntries];
193  for ( int i = 0; i < nEntries; ++i )
194  {
195  data[i] = mMatrix->data()[i] == mMatrix->nodataValue() ? result.nodataValue() : mMatrix->data()[i];
196  }
197  result.setData( mMatrix->nColumns(), mMatrix->nRows(), data, result.nodataValue() );
198  return true;
199  }
200  return false;
201 }
202 
203 QString QgsRasterCalcNode::toString( bool cStyle ) const
204 {
205  QString result;
206  QString left;
207  QString right;
208  if ( mLeft )
209  left = mLeft->toString( cStyle );
210  if ( mRight )
211  right = mRight->toString( cStyle );
212 
213  auto floatCast = [ ]( const QString s ) -> QString
214  {
215  return QStringLiteral( "(float) ( %1 )" ).arg( s );
216  };
217 
218  switch ( mType )
219  {
220  case tOperator:
221  switch ( mOperator )
222  {
223  case opPLUS:
224  result = QStringLiteral( "%1 + %2" ).arg( left ).arg( right );
225  break;
226  case opMINUS:
227  case opSIGN:
228  result = QStringLiteral( "%1 - %2" ).arg( left ).arg( right );
229  break;
230  case opMUL:
231  result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
232  break;
233  case opDIV:
234  result = QStringLiteral( "%1 / %2" ).arg( left ).arg( right );
235  break;
236  case opPOW:
237  if ( cStyle )
238  result = QStringLiteral( "pow( %1, %2 )" ).arg( floatCast( left ) ).arg( floatCast( right ) );
239  else
240  result = QStringLiteral( "%1^%2" ).arg( left ).arg( right );
241  break;
242  case opEQ:
243  if ( cStyle )
244  result = QStringLiteral( "%1 == %2" ).arg( left ).arg( right );
245  else
246  result = QStringLiteral( "%1 = %2" ).arg( left ).arg( right );
247  break;
248  case opNE:
249  result = QStringLiteral( "%1 != %2" ).arg( left ).arg( right );
250  break;
251  case opGT:
252  result = QStringLiteral( "%1 > %2" ).arg( left ).arg( right );
253  break;
254  case opLT:
255  result = QStringLiteral( "%1 < %2" ).arg( left ).arg( right );
256  break;
257  case opGE:
258  result = QStringLiteral( "%1 >= %2" ).arg( left ).arg( right );
259  break;
260  case opLE:
261  result = QStringLiteral( "%1 <= %2" ).arg( left ).arg( right );
262  break;
263  case opAND:
264  if ( cStyle )
265  result = QStringLiteral( "%1 && %2" ).arg( left ).arg( right );
266  else
267  result = QStringLiteral( "%1 AND %2" ).arg( left ).arg( right );
268  break;
269  case opOR:
270  if ( cStyle )
271  result = QStringLiteral( "%1 || %2" ).arg( left ).arg( right );
272  else
273  result = QStringLiteral( "%1 OR %2" ).arg( left ).arg( right );
274  break;
275  case opSQRT:
276  if ( cStyle )
277  result = QStringLiteral( "sqrt( %1 )" ).arg( floatCast( left ) );
278  else
279  result = QStringLiteral( "sqrt( %1 )" ).arg( left );
280  break;
281  case opSIN:
282  if ( cStyle )
283  result = QStringLiteral( "sin( %1 )" ).arg( floatCast( left ) );
284  else
285  result = QStringLiteral( "sin( %1 )" ).arg( left );
286  break;
287  case opCOS:
288  if ( cStyle )
289  result = QStringLiteral( "cos( %1 )" ).arg( floatCast( left ) );
290  else
291  result = QStringLiteral( "cos( %1 )" ).arg( left );
292  break;
293  case opTAN:
294  if ( cStyle )
295  result = QStringLiteral( "tan( %1 )" ).arg( floatCast( left ) );
296  else
297  result = QStringLiteral( "tan( %1 )" ).arg( left );
298  break;
299  case opASIN:
300  if ( cStyle )
301  result = QStringLiteral( "asin( %1 )" ).arg( floatCast( left ) );
302  else
303  result = QStringLiteral( "asin( %1 )" ).arg( left );
304  break;
305  case opACOS:
306  if ( cStyle )
307  result = QStringLiteral( "acos( %1 )" ).arg( floatCast( left ) );
308  else
309  result = QStringLiteral( "acos( %1 )" ).arg( left );
310  break;
311  case opATAN:
312  if ( cStyle )
313  result = QStringLiteral( "atan( %1 )" ).arg( floatCast( left ) );
314  else
315  result = QStringLiteral( "atan( %1 )" ).arg( left );
316  break;
317  case opLOG:
318  if ( cStyle )
319  result = QStringLiteral( "log( %1 )" ).arg( floatCast( left ) );
320  else
321  result = QStringLiteral( "log( %1 )" ).arg( left );
322  break;
323  case opLOG10:
324  if ( cStyle )
325  result = QStringLiteral( "log10( %1 )" ).arg( floatCast( left ) );
326  else
327  result = QStringLiteral( "log10( %1 )" ).arg( left );
328  break;
329  case opNONE:
330  break;
331  }
332  break;
333  case tRasterRef:
334  result = QStringLiteral( "\"%1\"" ).arg( mRasterName );
335  break;
336  case tNumber:
337  result = QString::number( mNumber );
338  break;
339  case tMatrix:
340  break;
341  }
342  return result;
343 }
344 
345 QList<const QgsRasterCalcNode *> QgsRasterCalcNode::findNodes( const QgsRasterCalcNode::Type type ) const
346 {
347  QList<const QgsRasterCalcNode *> nodeList;
348  if ( mType == type )
349  nodeList.push_back( this );
350  if ( mLeft )
351  nodeList.append( mLeft->findNodes( type ) );
352  if ( mRight )
353  nodeList.append( mRight->findNodes( type ) );
354  return nodeList;
355 }
356 
357 QgsRasterCalcNode *QgsRasterCalcNode::parseRasterCalcString( const QString &str, QString &parserErrorMsg )
358 {
359  extern QgsRasterCalcNode *localParseRasterCalcString( const QString & str, QString & parserErrorMsg );
360  return localParseRasterCalcString( str, parserErrorMsg );
361 }
362 
double * takeData()
Returns data and ownership.
bool add(const QgsRasterMatrix &other)
Adds another matrix to this one.
void setNodataValue(double d)
double nodataValue() const
bool power(const QgsRasterMatrix &other)
bool greaterThan(const QgsRasterMatrix &other)
bool notEqual(const QgsRasterMatrix &other)
bool equal(const QgsRasterMatrix &other)
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).
bool logicalOr(const QgsRasterMatrix &other)
void setData(int cols, int rows, double *data, double nodataValue)
bool subtract(const QgsRasterMatrix &other)
Subtracts another matrix from this one.
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.
bool multiply(const QgsRasterMatrix &other)
int nColumns() const
bool lesserEqual(const QgsRasterMatrix &other)
bool divide(const QgsRasterMatrix &other)
bool greaterEqual(const QgsRasterMatrix &other)
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.
bool lesserThan(const QgsRasterMatrix &other)
bool logicalAnd(const QgsRasterMatrix &other)