Skip to content

Commit 2d96491

Browse files
authoredJul 27, 2018
[FEATURE][expression] add raster_value() function (#7487)
1 parent 2692de6 commit 2d96491

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed
 
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "raster_value",
3+
"type": "function",
4+
"description": "Returns the raster value found at the provided point.",
5+
"arguments": [ {"arg":"layer","description":"the name or id of a raster layer"},
6+
{"arg":"band","description":"the band number to sample the value from."},
7+
{"arg":"point","description":"point geometry (for multipart geometries having more than one part, a null value will be returned)"}],
8+
"examples": [ { "expression":"raster_value('dem', 1, make_point(1,1))", "returns":"25"}]
9+
}
10+

‎src/core/expression/qgsexpressionfunction.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,48 @@ static QVariant fcnFeatureId( const QVariantList &, const QgsExpressionContext *
12831283
return QVariant( static_cast< int >( f.id() ) );
12841284
}
12851285

1286+
static QVariant fcnRasterValue( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1287+
{
1288+
QgsRasterLayer *layer = QgsExpressionUtils::getRasterLayer( values.at( 0 ), parent );
1289+
if ( !layer || !layer->dataProvider() )
1290+
{
1291+
parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid raster layer." ) );
1292+
return QVariant();
1293+
}
1294+
1295+
int bandNb = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1296+
if ( bandNb < 1 || bandNb > layer->bandCount() )
1297+
{
1298+
parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid raster band number." ) );
1299+
return QVariant();
1300+
}
1301+
1302+
QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );
1303+
if ( geom.isNull() || geom.type() != QgsWkbTypes::PointGeometry )
1304+
{
1305+
parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid point geometry." ) );
1306+
return QVariant();
1307+
}
1308+
1309+
QgsPointXY point = geom.asPoint();
1310+
if ( geom.isMultipart() )
1311+
{
1312+
QgsMultiPointXY multiPoint = geom.asMultiPoint();
1313+
if ( multiPoint.count() == 1 )
1314+
{
1315+
point = multiPoint[0];
1316+
}
1317+
else
1318+
{
1319+
// if the geometry contains more than one part, return an undefined value
1320+
return QVariant();
1321+
}
1322+
}
1323+
1324+
double value = layer->dataProvider()->sample( point, bandNb );
1325+
return std::isnan( value ) ? QVariant() : value;
1326+
}
1327+
12861328
static QVariant fcnFeature( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
12871329
{
12881330
if ( !context )
@@ -4559,7 +4601,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
45594601
<< new QgsStaticExpressionFunction( QStringLiteral( "layer_property" ), 2, fcnGetLayerProperty, QStringLiteral( "General" ) )
45604602
<< new QgsStaticExpressionFunction( QStringLiteral( "raster_statistic" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
45614603
<< QgsExpressionFunction::Parameter( QStringLiteral( "band" ) )
4562-
<< QgsExpressionFunction::Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "General" ) );
4604+
<< QgsExpressionFunction::Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "Rasters" ) );
45634605

45644606
// **var** function
45654607
QgsStaticExpressionFunction *varFunction = new QgsStaticExpressionFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) );
@@ -4617,6 +4659,7 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
46174659
<< new QgsStaticExpressionFunction( QStringLiteral( "env" ), 1, fcnEnvVar, QStringLiteral( "General" ), QString() )
46184660
<< new QgsWithVariableExpressionFunction()
46194661
<< new QgsStaticExpressionFunction( QStringLiteral( "attribute" ), 2, fcnAttribute, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES )
4662+
<< new QgsStaticExpressionFunction( QStringLiteral( "raster_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterValue, QStringLiteral( "Rasters" ) )
46204663

46214664
// functions for arrays
46224665
<< new QgsStaticExpressionFunction( QStringLiteral( "array" ), -1, fcnArray, QStringLiteral( "Arrays" ), QString(), false, QSet<QString>(), false, QStringList(), true )

‎src/core/expression/qgsexpressionutils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "qgsexpression.h"
2424
#include "qgscolorramp.h"
2525
#include "qgsvectorlayer.h"
26+
#include "qgsrasterlayer.h"
2627
#include "qgsproject.h"
2728
#include "qgsrelationmanager.h"
2829

@@ -355,6 +356,10 @@ class QgsExpressionUtils
355356
return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) );
356357
}
357358

359+
static QgsRasterLayer *getRasterLayer( const QVariant &value, QgsExpression *e )
360+
{
361+
return qobject_cast<QgsRasterLayer *>( getMapLayer( value, e ) );
362+
}
358363

359364
static QVariantList getListValue( const QVariant &value, QgsExpression *parent )
360365
{

‎tests/src/core/testqgsexpression.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,15 @@ class TestQgsExpression: public QObject
12461246
QTest::newRow( "raster_statistic range" ) << QStringLiteral( "raster_statistic('%1',1,'range')" ).arg( mRasterLayer->id() ) << false << QVariant( 9.0 );
12471247
QTest::newRow( "raster_statistic sum" ) << QStringLiteral( "round(raster_statistic('%1',1,'sum'))" ).arg( mRasterLayer->id() ) << false << QVariant( 450 );
12481248

1249+
// raster_value tests
1250+
QTest::newRow( "raster_value no layer" ) << "raster_value('',1,make_point(1,1))" << true << QVariant();
1251+
QTest::newRow( "raster_value bad layer" ) << "raster_value('bad',1,make_point(1,1))" << true << QVariant();
1252+
QTest::newRow( "raster_value bad band" ) << QStringLiteral( "raster_value('%1',0,make_point(1,1))" ).arg( mRasterLayer->name() ) << true << QVariant();
1253+
QTest::newRow( "raster_value bad band 2" ) << QStringLiteral( "raster_value('%1',100,make_point(1,1))" ).arg( mRasterLayer->name() ) << true << QVariant();
1254+
QTest::newRow( "raster_value invalid geometry" ) << QStringLiteral( "raster_value('%1',1,'invalid geom')" ).arg( mRasterLayer->name() ) << true << QVariant();
1255+
QTest::newRow( "raster_value valid" ) << QStringLiteral( "raster_value('%1',1,make_point(1535390,5083270))" ).arg( mRasterLayer->name() ) << false << QVariant( 1.0 );
1256+
QTest::newRow( "raster_value outside extent" ) << QStringLiteral( "raster_value('%1',1,make_point(1535370,5083250))" ).arg( mRasterLayer->name() ) << false << QVariant();
1257+
12491258
//test conversions to bool
12501259
QTest::newRow( "feature to bool false" ) << QStringLiteral( "case when get_feature('none','none',499) then true else false end" ) << false << QVariant( false );
12511260
QTest::newRow( "feature to bool true" ) << QStringLiteral( "case when get_feature('test','col1',10) then true else false end" ) << false << QVariant( true );

0 commit comments

Comments
 (0)
Please sign in to comment.