mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-07 00:15:48 -04:00
350 lines
10 KiB
C++
350 lines
10 KiB
C++
/***************************************************************************
|
|
qgsrastercalcnode.cpp
|
|
---------------------
|
|
begin : October 2010
|
|
copyright : (C) 2010 by Marco Hugentobler
|
|
email : marco dot hugentobler at sourcepole dot ch
|
|
***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
#include "qgsrastercalcnode.h"
|
|
#include "qgsrasterblock.h"
|
|
#include "qgsrastermatrix.h"
|
|
|
|
QgsRasterCalcNode::QgsRasterCalcNode( double number )
|
|
: mNumber( number )
|
|
{
|
|
}
|
|
|
|
QgsRasterCalcNode::QgsRasterCalcNode( QgsRasterMatrix *matrix )
|
|
: mType( tMatrix )
|
|
, mMatrix( matrix )
|
|
{
|
|
|
|
}
|
|
|
|
QgsRasterCalcNode::QgsRasterCalcNode( Operator op, QgsRasterCalcNode *left, QgsRasterCalcNode *right )
|
|
: mType( tOperator )
|
|
, mLeft( left )
|
|
, mRight( right )
|
|
, mOperator( op )
|
|
{
|
|
}
|
|
|
|
QgsRasterCalcNode::QgsRasterCalcNode( const QString &rasterName )
|
|
: mType( tRasterRef )
|
|
, mRasterName( rasterName )
|
|
{
|
|
if ( mRasterName.startsWith( '"' ) && mRasterName.endsWith( '"' ) )
|
|
mRasterName = mRasterName.mid( 1, mRasterName.size() - 2 );
|
|
}
|
|
|
|
QgsRasterCalcNode::~QgsRasterCalcNode()
|
|
{
|
|
delete mLeft;
|
|
delete mRight;
|
|
}
|
|
|
|
bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterBlock * > &rasterData, QgsRasterMatrix &result, int row ) const
|
|
{
|
|
//if type is raster ref: return a copy of the corresponding matrix
|
|
|
|
//if type is operator, call the proper matrix operations
|
|
if ( mType == tRasterRef )
|
|
{
|
|
QMap<QString, QgsRasterBlock *>::iterator it = rasterData.find( mRasterName );
|
|
if ( it == rasterData.end() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int nRows = ( row >= 0 ? 1 : ( *it )->height() );
|
|
int startRow = ( row >= 0 ? row : 0 );
|
|
int endRow = startRow + nRows;
|
|
int nCols = ( *it )->width();
|
|
int nEntries = nCols * nRows;
|
|
double *data = new double[nEntries];
|
|
|
|
//convert input raster values to double, also convert input no data to result no data
|
|
|
|
int outRow = 0;
|
|
bool isNoData = false;
|
|
for ( int dataRow = startRow; dataRow < endRow ; ++dataRow, ++outRow )
|
|
{
|
|
for ( int dataCol = 0; dataCol < nCols; ++dataCol )
|
|
{
|
|
const double value = ( *it )->valueAndNoData( dataRow, dataCol, isNoData );
|
|
data[ dataCol + nCols * outRow] = isNoData ? result.nodataValue() : value;
|
|
}
|
|
}
|
|
result.setData( nCols, nRows, data, result.nodataValue() );
|
|
return true;
|
|
}
|
|
else if ( mType == tOperator )
|
|
{
|
|
QgsRasterMatrix leftMatrix, rightMatrix;
|
|
leftMatrix.setNodataValue( result.nodataValue() );
|
|
rightMatrix.setNodataValue( result.nodataValue() );
|
|
|
|
if ( !mLeft || !mLeft->calculate( rasterData, leftMatrix, row ) )
|
|
{
|
|
return false;
|
|
}
|
|
if ( mRight && !mRight->calculate( rasterData, rightMatrix, row ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch ( mOperator )
|
|
{
|
|
case opPLUS:
|
|
leftMatrix.add( rightMatrix );
|
|
break;
|
|
case opMINUS:
|
|
leftMatrix.subtract( rightMatrix );
|
|
break;
|
|
case opMUL:
|
|
leftMatrix.multiply( rightMatrix );
|
|
break;
|
|
case opDIV:
|
|
leftMatrix.divide( rightMatrix );
|
|
break;
|
|
case opPOW:
|
|
leftMatrix.power( rightMatrix );
|
|
break;
|
|
case opEQ:
|
|
leftMatrix.equal( rightMatrix );
|
|
break;
|
|
case opNE:
|
|
leftMatrix.notEqual( rightMatrix );
|
|
break;
|
|
case opGT:
|
|
leftMatrix.greaterThan( rightMatrix );
|
|
break;
|
|
case opLT:
|
|
leftMatrix.lesserThan( rightMatrix );
|
|
break;
|
|
case opGE:
|
|
leftMatrix.greaterEqual( rightMatrix );
|
|
break;
|
|
case opLE:
|
|
leftMatrix.lesserEqual( rightMatrix );
|
|
break;
|
|
case opAND:
|
|
leftMatrix.logicalAnd( rightMatrix );
|
|
break;
|
|
case opOR:
|
|
leftMatrix.logicalOr( rightMatrix );
|
|
break;
|
|
case opSQRT:
|
|
leftMatrix.squareRoot();
|
|
break;
|
|
case opSIN:
|
|
leftMatrix.sinus();
|
|
break;
|
|
case opCOS:
|
|
leftMatrix.cosinus();
|
|
break;
|
|
case opTAN:
|
|
leftMatrix.tangens();
|
|
break;
|
|
case opASIN:
|
|
leftMatrix.asinus();
|
|
break;
|
|
case opACOS:
|
|
leftMatrix.acosinus();
|
|
break;
|
|
case opATAN:
|
|
leftMatrix.atangens();
|
|
break;
|
|
case opSIGN:
|
|
leftMatrix.changeSign();
|
|
break;
|
|
case opLOG:
|
|
leftMatrix.log();
|
|
break;
|
|
case opLOG10:
|
|
leftMatrix.log10();
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
int newNColumns = leftMatrix.nColumns();
|
|
int newNRows = leftMatrix.nRows();
|
|
result.setData( newNColumns, newNRows, leftMatrix.takeData(), leftMatrix.nodataValue() );
|
|
return true;
|
|
}
|
|
else if ( mType == tNumber )
|
|
{
|
|
double *data = new double[1];
|
|
data[0] = mNumber;
|
|
result.setData( 1, 1, data, result.nodataValue() );
|
|
return true;
|
|
}
|
|
else if ( mType == tMatrix )
|
|
{
|
|
int nEntries = mMatrix->nColumns() * mMatrix->nRows();
|
|
double *data = new double[nEntries];
|
|
for ( int i = 0; i < nEntries; ++i )
|
|
{
|
|
data[i] = mMatrix->data()[i] == mMatrix->nodataValue() ? result.nodataValue() : mMatrix->data()[i];
|
|
}
|
|
result.setData( mMatrix->nColumns(), mMatrix->nRows(), data, result.nodataValue() );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QString QgsRasterCalcNode::toString( bool cStyle ) const
|
|
{
|
|
QString result;
|
|
QString left;
|
|
QString right;
|
|
if ( mLeft )
|
|
left = mLeft->toString( cStyle );
|
|
if ( mRight )
|
|
right = mRight->toString( cStyle );
|
|
|
|
switch ( mType )
|
|
{
|
|
case tOperator:
|
|
switch ( mOperator )
|
|
{
|
|
case opPLUS:
|
|
result = QStringLiteral( "( %1 + %2 )" ).arg( left ).arg( right );
|
|
break;
|
|
case opMINUS:
|
|
case opSIGN:
|
|
result = QStringLiteral( "( %1 - %2 )" ).arg( left ).arg( right );
|
|
break;
|
|
case opMUL:
|
|
result = QStringLiteral( "%1 * %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opDIV:
|
|
result = QStringLiteral( "%1 / %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opPOW:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "pow( %1, %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1^%2" ).arg( left ).arg( right );
|
|
break;
|
|
case opEQ:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 == %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 = %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opNE:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 != %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 != %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opGT:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 > %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 > %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opLT:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 < %2" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 < %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opGE:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 >= %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 >= %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opLE:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 <= %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 <= %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opAND:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 && %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 AND %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opOR:
|
|
if ( cStyle )
|
|
result = QStringLiteral( "( float ) ( %1 || %2 )" ).arg( left ).arg( right );
|
|
else
|
|
result = QStringLiteral( "%1 OR %2" ).arg( left ).arg( right );
|
|
break;
|
|
case opSQRT:
|
|
result = QStringLiteral( "sqrt( %1 )" ).arg( left );
|
|
break;
|
|
case opSIN:
|
|
result = QStringLiteral( "sin( %1 )" ).arg( left );
|
|
break;
|
|
case opCOS:
|
|
result = QStringLiteral( "cos( %1 )" ).arg( left );
|
|
break;
|
|
case opTAN:
|
|
result = QStringLiteral( "tan( %1 )" ).arg( left );
|
|
break;
|
|
case opASIN:
|
|
result = QStringLiteral( "asin( %1 )" ).arg( left );
|
|
break;
|
|
case opACOS:
|
|
result = QStringLiteral( "acos( %1 )" ).arg( left );
|
|
break;
|
|
case opATAN:
|
|
result = QStringLiteral( "atan( %1 )" ).arg( left );
|
|
break;
|
|
case opLOG:
|
|
result = QStringLiteral( "log( %1 )" ).arg( left );
|
|
break;
|
|
case opLOG10:
|
|
result = QStringLiteral( "log10( %1 )" ).arg( left );
|
|
break;
|
|
case opNONE:
|
|
break;
|
|
}
|
|
break;
|
|
case tRasterRef:
|
|
result = QStringLiteral( "\"%1\"" ).arg( mRasterName );
|
|
break;
|
|
case tNumber:
|
|
result = QString::number( mNumber );
|
|
if ( cStyle )
|
|
{
|
|
result = QStringLiteral( "( float ) ( %1 )" ).arg( result );
|
|
}
|
|
break;
|
|
case tMatrix:
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QList<const QgsRasterCalcNode *> QgsRasterCalcNode::findNodes( const QgsRasterCalcNode::Type type ) const
|
|
{
|
|
QList<const QgsRasterCalcNode *> nodeList;
|
|
if ( mType == type )
|
|
nodeList.push_back( this );
|
|
if ( mLeft )
|
|
nodeList.append( mLeft->findNodes( type ) );
|
|
if ( mRight )
|
|
nodeList.append( mRight->findNodes( type ) );
|
|
return nodeList;
|
|
}
|
|
|
|
QgsRasterCalcNode *QgsRasterCalcNode::parseRasterCalcString( const QString &str, QString &parserErrorMsg )
|
|
{
|
|
extern QgsRasterCalcNode *localParseRasterCalcString( const QString & str, QString & parserErrorMsg );
|
|
return localParseRasterCalcString( str, parserErrorMsg );
|
|
}
|
|
|