Skip to content

Commit 23a7ebf

Browse files
committed
Add a scale_linear function, for linear interpolation between and input domain and output range
1 parent bedd99e commit 23a7ebf

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<h3>scale_linear() function</h3>
2+
Transforms a given value from an input domain to an output range using linear interpolation.
3+
4+
<p><h4>Syntax</h4>
5+
scale_linear(<i>val</i>,<i>domain_min</i>,<i>domain_max</i>,<i>range_min</i>,<i>range_max</i>)</p>
6+
7+
<p><h4>Arguments</h4>
8+
<!-- List args for functions here-->
9+
<i> val</i> &rarr; is a value in the input domain. The function will return a corresponding scaled value in the output range.<br>
10+
<i> domain_min, domain_max</i> &rarr; specify the input domain, the smallest and largest values the input <i>val</i> should take.<br>
11+
<i> range_min, range_max</i> &rarr; sepcify the output range, the smallest and largest values which should be output by the function.<br>
12+
13+
<h4>Example</h4>
14+
<!-- Show example of function.-->
15+
scale_linear(5,0,10,0,100) &rarr; 50<br>
16+
scale_linear(0.2,0,1,0,360) &rarr; 72 <i>(eg, scaling a value between 0 and 1 to an angle between 0 and 360)</i><br>
17+
scale_linear(1500,1000,10000,9,20) &rarr; 10.22 <i>(eg, scaling a population which varies between 1000 and 10000 to a font size between 9 and 20)</i><br>
18+
19+

src/core/qgsexpression.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,32 @@ static QVariant fcnRnd( const QVariantList& values, QgsFeature* , QgsExpression*
439439
return QVariant( min + ( rand() % ( int )( max - min + 1 ) ) );
440440
}
441441

442+
static QVariant fcnLinearScale( const QVariantList& values, QgsFeature* , QgsExpression* parent )
443+
{
444+
double val = getDoubleValue( values.at( 0 ), parent );
445+
double domain_min = getDoubleValue( values.at( 1 ), parent );
446+
double domain_max = getDoubleValue( values.at( 2 ), parent );
447+
double range_min = getDoubleValue( values.at( 3 ), parent );
448+
double range_max = getDoubleValue( values.at( 4 ), parent );
449+
450+
// outside of domain?
451+
if ( val >= domain_max )
452+
{
453+
return range_max;
454+
}
455+
else if ( val <= domain_min )
456+
{
457+
return range_min;
458+
}
459+
460+
// calculate linear scale
461+
double m = ( range_max - range_min ) / ( domain_max - domain_min );
462+
double c = range_min - ( domain_min * m );
463+
464+
// Return linearly scaled value
465+
return QVariant( m * val + c );
466+
}
467+
442468
static QVariant fcnMax( const QVariantList& values, QgsFeature* , QgsExpression *parent )
443469
{
444470
//initially set max as first value
@@ -1317,7 +1343,7 @@ const QStringList &QgsExpression::BuiltinFunctions()
13171343
<< "asin" << "acos" << "atan" << "atan2"
13181344
<< "exp" << "ln" << "log10" << "log"
13191345
<< "round" << "rand" << "randf" << "max" << "min"
1320-
<< "floor" << "ceil"
1346+
<< "scale_linear" << "floor" << "ceil"
13211347
<< "toint" << "toreal" << "tostring"
13221348
<< "todatetime" << "todate" << "totime" << "tointerval"
13231349
<< "coalesce" << "regexp_match" << "$now" << "age" << "year"
@@ -1363,6 +1389,7 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
13631389
<< new StaticFunction( "randf", 2, fcnRndF, QObject::tr( "Math" ) )
13641390
<< new StaticFunction( "max", -1, fcnMax, QObject::tr( "Math" ) )
13651391
<< new StaticFunction( "min", -1, fcnMin, QObject::tr( "Math" ) )
1392+
<< new StaticFunction( "scale_linear", 5, fcnLinearScale, QObject::tr( "Math" ) )
13661393
<< new StaticFunction( "floor", 1, fcnFloor, QObject::tr( "Math" ) )
13671394
<< new StaticFunction( "ceil", 1, fcnCeil, QObject::tr( "Math" ) )
13681395
<< new StaticFunction( "$pi", 0, fcnPi, QObject::tr( "Math" ) )

tests/src/core/testqgsexpression.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,12 @@ class TestQgsExpression: public QObject
264264
QTest::newRow( "floor(-4.9)" ) << "floor(-4.9)" << false << QVariant( -5. );
265265
QTest::newRow( "ceil(4.9)" ) << "ceil(4.9)" << false << QVariant( 5. );
266266
QTest::newRow( "ceil(-4.9)" ) << "ceil(-4.9)" << false << QVariant( -4. );
267+
QTest::newRow( "scale_linear(0.5,0,1,0,1)" ) << "scale_linear(0.5,0,1,0,1)" << false << QVariant( 0.5 );
268+
QTest::newRow( "scale_linear(0,0,10,100,200)" ) << "scale_linear(0,0,10,100,200)" << false << QVariant( 100. );
269+
QTest::newRow( "scale_linear(5,0,10,100,200)" ) << "scale_linear(5,0,10,100,200)" << false << QVariant( 150. );
270+
QTest::newRow( "scale_linear(10,0,10,100,200)" ) << "scale_linear(10,0,10,100,200)" << false << QVariant( 200. );
271+
QTest::newRow( "scale_linear(-1,0,10,100,200)" ) << "scale_linear(-1,0,10,100,200)" << false << QVariant( 100. );
272+
QTest::newRow( "scale_linear(11,0,10,100,200)" ) << "scale_linear(11,0,10,100,200)" << false << QVariant( 200. );
267273

268274
// cast functions
269275
QTest::newRow( "double to int" ) << "toint(3.2)" << false << QVariant( 3 );

0 commit comments

Comments
 (0)