Fix multiple raster calc issues

Fixes #32023 Raster calculator change sign does not work when OpenCL is on
Fixes #32025 QGIS Raster Calculator outputs nodata only rasters

Bonus: three new operators with full test coverage
- ABS
- MIN
- MAX
This commit is contained in:
Alessandro Pasotti 2019-09-26 18:00:09 +02:00
parent f32d6fdcf2
commit d730c97f46
13 changed files with 273 additions and 118 deletions

View File

@ -50,6 +50,9 @@ class QgsRasterCalcNode
opSIGN,
opLOG,
opLOG10,
opABS,
opMAX,
opMIN,
opNONE,
};

View File

@ -31,7 +31,9 @@ class QgsRasterMatrix
opGE,
opLE,
opAND,
opOR
opOR,
opMIN,
opMAX
};
enum OneArgOperator
@ -46,6 +48,7 @@ class QgsRasterMatrix
opSIGN,
opLOG,
opLOG10,
opABS,
};
QgsRasterMatrix();
@ -91,6 +94,8 @@ Subtracts another matrix from this one
bool lesserEqual( const QgsRasterMatrix &other );
bool logicalAnd( const QgsRasterMatrix &other );
bool logicalOr( const QgsRasterMatrix &other );
bool max( const QgsRasterMatrix &other );
bool min( const QgsRasterMatrix &other );
bool squareRoot();
bool sinus();
@ -102,6 +107,7 @@ Subtracts another matrix from this one
bool changeSign();
bool log();
bool log10();
bool absoluteValue();
};

View File

@ -62,6 +62,9 @@ raster_band_ref_quoted \"(\\.|[^"])*\"
"atan" { rasterlval.op = QgsRasterCalcNode::opATAN; return FUNCTION;}
"ln" { rasterlval.op = QgsRasterCalcNode::opLOG; return FUNCTION;}
"log10" { rasterlval.op = QgsRasterCalcNode::opLOG10; return FUNCTION;}
"abs" { rasterlval.op = QgsRasterCalcNode::opABS; return FUNCTION;}
"min" { rasterlval.op = QgsRasterCalcNode::opMIN; return FUNCTION;}
"max" { rasterlval.op = QgsRasterCalcNode::opMAX; return FUNCTION;}
"AND" { return AND; }
"OR" { return OR; }

View File

@ -87,9 +87,8 @@ bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData,
}
else if ( mType == tOperator )
{
QgsRasterMatrix leftMatrix, rightMatrix;
leftMatrix.setNodataValue( result.nodataValue() );
rightMatrix.setNodataValue( result.nodataValue() );
QgsRasterMatrix leftMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
QgsRasterMatrix rightMatrix( result.nColumns(), result.nRows(), nullptr, result.nodataValue() );
if ( !mLeft || !mLeft->calculate( rasterData, leftMatrix, row ) )
{
@ -141,6 +140,12 @@ bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData,
case opOR:
leftMatrix.logicalOr( rightMatrix );
break;
case opMIN:
leftMatrix.min( rightMatrix );
break;
case opMAX:
leftMatrix.max( rightMatrix );
break;
case opSQRT:
leftMatrix.squareRoot();
break;
@ -171,6 +176,9 @@ bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData,
case opLOG10:
leftMatrix.log10();
break;
case opABS:
leftMatrix.absoluteValue();
break;
default:
return false;
}
@ -181,9 +189,10 @@ bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData,
}
else if ( mType == tNumber )
{
double *data = new double[1];
data[0] = mNumber;
result.setData( 1, 1, data, result.nodataValue() );
size_t nEntries = static_cast<size_t>( result.nColumns() * result.nRows() );
std::vector<double> *data = new std::vector<double>( nEntries );
std::fill( std::begin( *data ), std::end( *data ), mNumber );
result.setData( result.nColumns(), 1, data->data(), result.nodataValue() );
return true;
}
else if ( mType == tMatrix )
@ -219,9 +228,11 @@ QString QgsRasterCalcNode::toString( bool cStyle ) const
result = QStringLiteral( "( %1 + %2 )" ).arg( left ).arg( right );
break;
case opMINUS:
case opSIGN:
result = QStringLiteral( "( %1 - %2 )" ).arg( left ).arg( right );
break;
case opSIGN:
result = QStringLiteral( "-%1" ).arg( left );
break;
case opMUL:
result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
break;
@ -309,6 +320,25 @@ QString QgsRasterCalcNode::toString( bool cStyle ) const
case opLOG10:
result = QStringLiteral( "log10( %1 )" ).arg( left );
break;
case opABS:
if ( cStyle )
result = QStringLiteral( "fabs( %1 )" ).arg( left );
else
// Call the floating point version
result = QStringLiteral( "abs( %1 )" ).arg( left );
break;
case opMIN:
if ( cStyle )
result = QStringLiteral( "min( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
else
result = QStringLiteral( "min( %1, %2 )" ).arg( left ).arg( right );
break;
case opMAX:
if ( cStyle )
result = QStringLiteral( "max( ( float ) ( %1 ), ( float ) ( %2 ) )" ).arg( left ).arg( right );
else
result = QStringLiteral( "max( %1, %2 )" ).arg( left ).arg( right );
break;
case opNONE:
break;
}

View File

@ -70,6 +70,9 @@ class ANALYSIS_EXPORT QgsRasterCalcNode
opSIGN, // change sign
opLOG,
opLOG10,
opABS,
opMAX,
opMIN,
opNONE,
};

View File

@ -79,6 +79,7 @@ root: raster_exp{}
raster_exp:
FUNCTION '(' raster_exp ')' { $$ = new QgsRasterCalcNode($1, $3, 0); joinTmpNodes($$, $3, 0);}
| FUNCTION '(' raster_exp ',' raster_exp ')' { $$ = new QgsRasterCalcNode($1, $3, $5); joinTmpNodes($$, $3, $5);}
| raster_exp AND raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opAND, $1, $3 ); joinTmpNodes($$,$1,$3); }
| raster_exp OR raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opOR, $1, $3 ); joinTmpNodes($$,$1,$3); }
| raster_exp '=' raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opEQ, $1, $3 ); joinTmpNodes($$,$1,$3); }

View File

@ -220,8 +220,8 @@ QgsRasterCalculator::Result QgsRasterCalculator::processCalculation( QgsFeedback
}
}
QgsRasterMatrix resultMatrix;
resultMatrix.setNodataValue( outputNodataValue );
// 1 row X mNumOutputColumns matrix
QgsRasterMatrix resultMatrix( mNumOutputColumns, 1, nullptr, outputNodataValue );
_rasterData.clear();
for ( const auto &layerRef : inputBlocks )

View File

@ -18,6 +18,7 @@
#include "qgsrastermatrix.h"
#include <cstring>
#include <cmath>
#include<algorithm>
QgsRasterMatrix::QgsRasterMatrix( int nCols, int nRows, double *data, double nodataValue )
: mColumns( nCols )
@ -132,6 +133,16 @@ bool QgsRasterMatrix::logicalOr( const QgsRasterMatrix &other )
return twoArgumentOperation( opOR, other );
}
bool QgsRasterMatrix::max( const QgsRasterMatrix &other )
{
return twoArgumentOperation( opMAX, other );
}
bool QgsRasterMatrix::min( const QgsRasterMatrix &other )
{
return twoArgumentOperation( opMIN, other );
}
bool QgsRasterMatrix::squareRoot()
{
return oneArgumentOperation( opSQRT );
@ -182,6 +193,11 @@ bool QgsRasterMatrix::log10()
return oneArgumentOperation( opLOG10 );
}
bool QgsRasterMatrix::absoluteValue()
{
return oneArgumentOperation( opABS );
}
bool QgsRasterMatrix::oneArgumentOperation( OneArgOperator op )
{
if ( !mData )
@ -249,6 +265,9 @@ bool QgsRasterMatrix::oneArgumentOperation( OneArgOperator op )
mData[i] = ::log10( value );
}
break;
case opABS:
mData[i] = ::fabs( value );
break;
}
}
}
@ -299,6 +318,10 @@ double QgsRasterMatrix::calculateTwoArgumentOp( TwoArgOperator op, double arg1,
return ( arg1 && arg2 ? 1.0 : 0.0 );
case opOR:
return ( arg1 || arg2 ? 1.0 : 0.0 );
case opMAX:
return std::max( arg1, arg2 );
case opMIN:
return std::min( arg1, arg2 );
}
return mNodataValue;
}

View File

@ -43,7 +43,9 @@ class ANALYSIS_EXPORT QgsRasterMatrix
opGE, // >=
opLE, // <=
opAND,
opOR
opOR,
opMIN,
opMAX
};
enum OneArgOperator
@ -58,6 +60,7 @@ class ANALYSIS_EXPORT QgsRasterMatrix
opSIGN,
opLOG,
opLOG10,
opABS,
};
//! Takes ownership of data array
@ -108,6 +111,8 @@ class ANALYSIS_EXPORT QgsRasterMatrix
bool lesserEqual( const QgsRasterMatrix &other );
bool logicalAnd( const QgsRasterMatrix &other );
bool logicalOr( const QgsRasterMatrix &other );
bool max( const QgsRasterMatrix &other );
bool min( const QgsRasterMatrix &other );
bool squareRoot();
bool sinus();
@ -119,6 +124,7 @@ class ANALYSIS_EXPORT QgsRasterMatrix
bool changeSign();
bool log();
bool log10();
bool absoluteValue();
private:
int mColumns = 0;

View File

@ -69,6 +69,9 @@ QgsRasterCalcDialog::QgsRasterCalcDialog( QgsRasterLayer *rasterLayer, QWidget *
connect( mLesserEqualButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mLesserEqualButton_clicked );
connect( mGreaterEqualButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mGreaterEqualButton_clicked );
connect( mAndButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mAndButton_clicked );
connect( mAbsButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mAbsButton_clicked );
connect( mMinButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mMinButton_clicked );
connect( mMaxButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mMaxButton_clicked );
connect( mOrButton, &QPushButton::clicked, this, &QgsRasterCalcDialog::mOrButton_clicked );
connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsRasterCalcDialog::showHelp );
@ -474,6 +477,21 @@ void QgsRasterCalcDialog::mOrButton_clicked()
mExpressionTextEdit->insertPlainText( QStringLiteral( " OR " ) );
}
void QgsRasterCalcDialog::mAbsButton_clicked()
{
mExpressionTextEdit->insertPlainText( QStringLiteral( " ABS ( " ) );
}
void QgsRasterCalcDialog::mMinButton_clicked()
{
mExpressionTextEdit->insertPlainText( QStringLiteral( " MIN ( " ) );
}
void QgsRasterCalcDialog::mMaxButton_clicked()
{
mExpressionTextEdit->insertPlainText( QStringLiteral( " MAX ( " ) );
}
QString QgsRasterCalcDialog::quoteBandEntry( const QString &layerName )
{
// '"' -> '\\"'

View File

@ -91,6 +91,9 @@ class APP_EXPORT QgsRasterCalcDialog: public QDialog, private Ui::QgsRasterCalcD
void mGreaterEqualButton_clicked();
void mAndButton_clicked();
void mOrButton_clicked();
void mAbsButton_clicked();
void mMinButton_clicked();
void mMaxButton_clicked();
private:
//! Sets the extent and size of the output

View File

@ -260,24 +260,17 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="6">
<widget class="QPushButton" name="mASinButton">
<item row="2" column="11">
<widget class="QPushButton" name="mOrButton">
<property name="text">
<string>asin</string>
<string>OR</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="mCosButton">
<item row="1" column="10">
<widget class="QPushButton" name="mLnButton">
<property name="text">
<string>cos</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="mNotEqualButton">
<property name="text">
<string>!=</string>
<string>ln</string>
</property>
</widget>
</item>
@ -288,24 +281,31 @@
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QPushButton" name="mSinButton">
<item row="2" column="10">
<widget class="QPushButton" name="mAndButton">
<property name="text">
<string>sin</string>
<string>AND</string>
</property>
</widget>
</item>
<item row="1" column="8">
<widget class="QPushButton" name="mATanButton">
<item row="0" column="10">
<widget class="QPushButton" name="mLogButton">
<property name="text">
<string>atan</string>
<string>log10</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="mEqualButton">
<item row="2" column="0">
<widget class="QPushButton" name="mLessButton">
<property name="text">
<string>=</string>
<string>&lt;</string>
</property>
</widget>
</item>
<item row="2" column="8">
<widget class="QPushButton" name="mGreaterEqualButton">
<property name="text">
<string>&gt;=</string>
</property>
</widget>
</item>
@ -316,17 +316,31 @@
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="mACosButton">
<item row="0" column="0">
<widget class="QPushButton" name="mPlusPushButton">
<property name="text">
<string>acos</string>
<string>+</string>
</property>
</widget>
</item>
<item row="2" column="10">
<widget class="QPushButton" name="mAndButton">
<item row="0" column="1">
<widget class="QPushButton" name="mMultiplyPushButton">
<property name="text">
<string>AND</string>
<string>*</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="mCosButton">
<property name="text">
<string>cos</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="mGreaterButton">
<property name="text">
<string>&gt;</string>
</property>
</widget>
</item>
@ -343,80 +357,31 @@
</property>
</spacer>
</item>
<item row="2" column="8">
<widget class="QPushButton" name="mGreaterEqualButton">
<item row="1" column="8">
<widget class="QPushButton" name="mATanButton">
<property name="text">
<string>&gt;=</string>
<string>atan</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="mMinusPushButton">
<item row="1" column="4">
<widget class="QPushButton" name="mACosButton">
<property name="text">
<string>-</string>
<string>acos</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="mDividePushButton">
<item row="1" column="6">
<widget class="QPushButton" name="mASinButton">
<property name="text">
<string>/</string>
<string>asin</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="mGreaterButton">
<item row="2" column="4">
<widget class="QPushButton" name="mNotEqualButton">
<property name="text">
<string>&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="mLessButton">
<property name="text">
<string>&lt;</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="mMultiplyPushButton">
<property name="text">
<string>*</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="mPlusPushButton">
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item row="2" column="11">
<widget class="QPushButton" name="mOrButton">
<property name="text">
<string>OR</string>
</property>
</widget>
</item>
<item row="0" column="10">
<widget class="QPushButton" name="mLogButton">
<property name="text">
<string>log10</string>
</property>
</widget>
</item>
<item row="1" column="10">
<widget class="QPushButton" name="mLnButton">
<property name="text">
<string>ln</string>
</property>
</widget>
</item>
<item row="0" column="11">
<widget class="QPushButton" name="mOpenBracketPushButton">
<property name="text">
<string>(</string>
<string>!=</string>
</property>
</widget>
</item>
@ -427,10 +392,31 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="mSqrtButton">
<item row="2" column="2">
<widget class="QPushButton" name="mEqualButton">
<property name="text">
<string>sqrt</string>
<string>=</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="mMinusPushButton">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item row="0" column="11">
<widget class="QPushButton" name="mOpenBracketPushButton">
<property name="text">
<string>(</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="mDividePushButton">
<property name="text">
<string>/</string>
</property>
</widget>
</item>
@ -441,6 +427,41 @@
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QPushButton" name="mSinButton">
<property name="text">
<string>sin</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="mSqrtButton">
<property name="text">
<string>sqrt</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="mAbsButton">
<property name="text">
<string>abs</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="mMinButton">
<property name="text">
<string>min</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="mMaxButton">
<property name="text">
<string>max</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -173,7 +173,7 @@ void TestQgsRasterCalculator::dualOp()
QgsRasterCalcNode node( op, new QgsRasterCalcNode( left ), new QgsRasterCalcNode( right ) );
QgsRasterMatrix result;
QgsRasterMatrix result( 1, 1, nullptr, -999 );
result.setNodataValue( -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
@ -223,8 +223,7 @@ void TestQgsRasterCalculator::singleOp()
QgsRasterCalcNode node( op, new QgsRasterCalcNode( value ), nullptr );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
QVERIFY( node.calculate( rasterData, result ) );
@ -249,8 +248,7 @@ void TestQgsRasterCalculator::singleOpMatrices()
QgsRasterCalcNode node( QgsRasterCalcNode::opSIGN, new QgsRasterCalcNode( &m ), nullptr );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
QVERIFY( node.calculate( rasterData, result ) );
@ -278,8 +276,7 @@ void TestQgsRasterCalculator::dualOpNumberMatrix()
QgsRasterCalcNode node( QgsRasterCalcNode::opPLUS, new QgsRasterCalcNode( 5.0 ), new QgsRasterCalcNode( &m ) );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
QVERIFY( node.calculate( rasterData, result ) );
@ -312,8 +309,7 @@ void TestQgsRasterCalculator::dualOpMatrixNumber()
QgsRasterCalcNode node( QgsRasterCalcNode::opPLUS, new QgsRasterCalcNode( &m ), new QgsRasterCalcNode( 5.0 ) );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
QVERIFY( node.calculate( rasterData, result ) );
@ -354,8 +350,7 @@ void TestQgsRasterCalculator::dualOpMatrixMatrix()
QgsRasterCalcNode node( QgsRasterCalcNode::opPLUS, new QgsRasterCalcNode( &m1 ), new QgsRasterCalcNode( &m2 ) );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
QVERIFY( node.calculate( rasterData, result ) );
@ -373,8 +368,7 @@ void TestQgsRasterCalculator::rasterRefOp()
// test single op run on raster ref
QgsRasterCalcNode node( QgsRasterCalcNode::opSIGN, new QgsRasterCalcNode( QStringLiteral( "raster" ) ), nullptr );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QMap<QString, QgsRasterBlock *> rasterData;
//first test invalid raster ref
@ -427,8 +421,7 @@ void TestQgsRasterCalculator::dualOpRasterRaster()
QgsRasterCalcNode node( QgsRasterCalcNode::opPLUS, new QgsRasterCalcNode( QStringLiteral( "raster1" ) ), new QgsRasterCalcNode( QStringLiteral( "raster2" ) ) );
QgsRasterMatrix result;
result.setNodataValue( -9999 );
QgsRasterMatrix result( 1, 1, nullptr, -9999 );
QVERIFY( node.calculate( rasterData, result ) );
QCOMPARE( result.data()[0], 0.0 );
@ -587,6 +580,18 @@ void TestQgsRasterCalculator::findNodes()
QVERIFY( ! node );
QVERIFY( ! errorString.isEmpty() );
// Test new abs, min, max
errorString = QString();
node = QgsRasterCalcNode::parseRasterCalcString( QStringLiteral( "abs(2)" ), errorString );
QVERIFY( node );
QVERIFY( errorString.isEmpty() );
node = QgsRasterCalcNode::parseRasterCalcString( QStringLiteral( "min(-1,1)" ), errorString );
QVERIFY( node );
QVERIFY( errorString.isEmpty() );
node = QgsRasterCalcNode::parseRasterCalcString( QStringLiteral( "max(-1,1)" ), errorString );
QVERIFY( node );
QVERIFY( errorString.isEmpty() );
}
void TestQgsRasterCalculator::testRasterEntries()
@ -728,6 +733,16 @@ void TestQgsRasterCalculator::toString()
QCOMPARE( _test( QStringLiteral( "0.5 * ( 1.4 * (\"raster@1\" + 2) )" ), true ), QString( "( float ) ( 0.5 ) * ( float ) ( 1.4 ) * ( \"raster@1\" + ( float ) ( 2 ) )" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * ( 1 > 0 )" ), false ), QString( "0.5 * 1 > 0" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * ( 1 > 0 )" ), true ), QString( "( float ) ( 0.5 ) * ( float ) ( ( float ) ( 1 ) > ( float ) ( 0 ) )" ) );
// Test negative numbers
QCOMPARE( _test( QStringLiteral( "0.5 * ( -1 > 0 )" ), false ), QString( "0.5 * -1 > 0" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * ( -1 > 0 )" ), true ), QString( "( float ) ( 0.5 ) * ( float ) ( -( float ) ( 1 ) > ( float ) ( 0 ) )" ) );
// Test new functions
QCOMPARE( _test( QStringLiteral( "0.5 * abs( -1 )" ), false ), QString( "0.5 * abs( -1 )" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * abs( -1 )" ), true ), QString( "( float ) ( 0.5 ) * fabs( -( float ) ( 1 ) )" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * min( -1, 1 )" ), false ), QString( "0.5 * min( -1, 1 )" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * min( -1, 1 )" ), true ), QString( "( float ) ( 0.5 ) * min( ( float ) ( -( float ) ( 1 ) ), ( float ) ( ( float ) ( 1 ) ) )" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * max( -1, 1 )" ), false ), QString( "0.5 * max( -1, 1 )" ) );
QCOMPARE( _test( QStringLiteral( "0.5 * max( -1, 1 )" ), true ), QString( "( float ) ( 0.5 ) * max( ( float ) ( -( float ) ( 1 ) ), ( float ) ( ( float ) ( 1 ) ) )" ) );
}
void TestQgsRasterCalculator::calcFormulasWithReprojectedLayers()
@ -753,6 +768,8 @@ void TestQgsRasterCalculator::calcFormulasWithReprojectedLayers()
auto _chk = [ = ]( const QString & formula, const std::vector<float> &values, bool useOpenCL )
{
qDebug() << formula;
#ifdef HAVE_OPENCL
if ( ! QgsOpenClUtils::available() )
return ;
@ -798,6 +815,27 @@ void TestQgsRasterCalculator::calcFormulasWithReprojectedLayers()
_chk( QStringLiteral( "\"landsat@1\" * ( \"landsat@1\" > 124 )" ), {125.0, 125.0, 0.0, 125.0, 125.0, 0.0}, false );
_chk( QStringLiteral( "\"landsat@1\" * ( \"landsat@1\" > 124 )" ), {125.0, 125.0, 0.0, 125.0, 125.0, 0.0}, true );
// Test negative numbers
_chk( QStringLiteral( "-2.5" ), { -2.5, -2.5, -2.5, -2.5, -2.5, -2.5 }, false );
_chk( QStringLiteral( "- 2.5" ), { -2.5, -2.5, -2.5, -2.5, -2.5, -2.5 }, false );
_chk( QStringLiteral( "-2.5" ), { -2.5, -2.5, -2.5, -2.5, -2.5, -2.5 }, true );
_chk( QStringLiteral( "- 2.5" ), { -2.5, -2.5, -2.5, -2.5, -2.5, -2.5 }, true );
_chk( QStringLiteral( "-\"landsat@1\"" ), {-125, -125, -124, -125, -125, -124}, false );
_chk( QStringLiteral( "-\"landsat@1\"" ), {-125, -125, -124, -125, -125, -124}, true );
// Test abs, min and max
// landsat values: 125 125 124 125 125 124
// landsat_4326 values: 139 138 140 139 141 137
_chk( QStringLiteral( "abs(-123)" ), {123, 123, 123, 123, 123, 123}, false );
_chk( QStringLiteral( "abs(-\"landsat@1\")" ), {125, 125, 124, 125, 125, 124}, true );
_chk( QStringLiteral( "abs(-123)" ), {123, 123, 123, 123, 123, 123}, false );
_chk( QStringLiteral( "abs(-\"landsat@1\")" ), {125, 125, 124, 125, 125, 124}, true );
_chk( QStringLiteral( "-\"landsat_4326@2\" + 15" ), {-124, -123, -125, -124, -126, -122}, false );
_chk( QStringLiteral( "min(-\"landsat@1\", -\"landsat_4326@2\" + 15 )" ), {-125, -125, -125, -125, -126, -124}, false );
_chk( QStringLiteral( "min(-\"landsat@1\", -\"landsat_4326@2\" + 15 )" ), {-125, -125, -125, -125, -126, -124}, true );
_chk( QStringLiteral( "max(-\"landsat@1\", -\"landsat_4326@2\" + 15 )" ), {-124, -123, -124, -124, -125, -122}, false );
_chk( QStringLiteral( "max(-\"landsat@1\", -\"landsat_4326@2\" + 15 )" ), {-124, -123, -124, -124, -125, -122}, true );
}