QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  switch ( mType )
214  {
215  case tOperator:
216  switch ( mOperator )
217  {
218  case opPLUS:
219  result = QStringLiteral( "( %1 + %2 )" ).arg( left ).arg( right );
220  break;
221  case opMINUS:
222  case opSIGN:
223  result = QStringLiteral( "( %1 - %2 )" ).arg( left ).arg( right );
224  break;
225  case opMUL:
226  result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
227  break;
228  case opDIV:
229  result = QStringLiteral( "%1 / %2" ).arg( left ).arg( right );
230  break;
231  case opPOW:
232  if ( cStyle )
233  result = QStringLiteral( "pow( %1, %2 )" ).arg( left ).arg( right );
234  else
235  result = QStringLiteral( "%1^%2" ).arg( left ).arg( right );
236  break;
237  case opEQ:
238  if ( cStyle )
239  result = QStringLiteral( "%1 == %2" ).arg( left ).arg( right );
240  else
241  result = QStringLiteral( "%1 = %2" ).arg( left ).arg( right );
242  break;
243  case opNE:
244  result = QStringLiteral( "%1 != %2" ).arg( left ).arg( right );
245  break;
246  case opGT:
247  result = QStringLiteral( "%1 > %2" ).arg( left ).arg( right );
248  break;
249  case opLT:
250  result = QStringLiteral( "%1 < %2" ).arg( left ).arg( right );
251  break;
252  case opGE:
253  result = QStringLiteral( "%1 >= %2" ).arg( left ).arg( right );
254  break;
255  case opLE:
256  result = QStringLiteral( "%1 <= %2" ).arg( left ).arg( right );
257  break;
258  case opAND:
259  if ( cStyle )
260  result = QStringLiteral( "%1 && %2" ).arg( left ).arg( right );
261  else
262  result = QStringLiteral( "%1 AND %2" ).arg( left ).arg( right );
263  break;
264  case opOR:
265  if ( cStyle )
266  result = QStringLiteral( "%1 || %2" ).arg( left ).arg( right );
267  else
268  result = QStringLiteral( "%1 OR %2" ).arg( left ).arg( right );
269  break;
270  case opSQRT:
271  result = QStringLiteral( "sqrt( %1 )" ).arg( left );
272  break;
273  case opSIN:
274  result = QStringLiteral( "sin( %1 )" ).arg( left );
275  break;
276  case opCOS:
277  result = QStringLiteral( "cos( %1 )" ).arg( left );
278  break;
279  case opTAN:
280  result = QStringLiteral( "tan( %1 )" ).arg( left );
281  break;
282  case opASIN:
283  result = QStringLiteral( "asin( %1 )" ).arg( left );
284  break;
285  case opACOS:
286  result = QStringLiteral( "acos( %1 )" ).arg( left );
287  break;
288  case opATAN:
289  result = QStringLiteral( "atan( %1 )" ).arg( left );
290  break;
291  case opLOG:
292  result = QStringLiteral( "log( %1 )" ).arg( left );
293  break;
294  case opLOG10:
295  result = QStringLiteral( "log10( %1 )" ).arg( left );
296  break;
297  case opNONE:
298  break;
299  }
300  break;
301  case tRasterRef:
302  result = QStringLiteral( "\"%1\"" ).arg( mRasterName );
303  break;
304  case tNumber:
305  result = QString::number( mNumber );
306  if ( cStyle )
307  {
308  result = QStringLiteral( "(float) ( %1 )" ).arg( result );
309  }
310  break;
311  case tMatrix:
312  break;
313  }
314  return result;
315 }
316 
317 QList<const QgsRasterCalcNode *> QgsRasterCalcNode::findNodes( const QgsRasterCalcNode::Type type ) const
318 {
319  QList<const QgsRasterCalcNode *> nodeList;
320  if ( mType == type )
321  nodeList.push_back( this );
322  if ( mLeft )
323  nodeList.append( mLeft->findNodes( type ) );
324  if ( mRight )
325  nodeList.append( mRight->findNodes( type ) );
326  return nodeList;
327 }
328 
329 QgsRasterCalcNode *QgsRasterCalcNode::parseRasterCalcString( const QString &str, QString &parserErrorMsg )
330 {
331  extern QgsRasterCalcNode *localParseRasterCalcString( const QString & str, QString & parserErrorMsg );
332  return localParseRasterCalcString( str, parserErrorMsg );
333 }
334 
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)