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