Skip to content

Commit

Permalink
Add a scale_linear function, for linear interpolation between and inp…
Browse files Browse the repository at this point in the history
…ut domain and output range
  • Loading branch information
nyalldawson committed May 12, 2013
1 parent bedd99e commit 23a7ebf
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
19 changes: 19 additions & 0 deletions resources/function_help/scale_linear-en_US
@@ -0,0 +1,19 @@
<h3>scale_linear() function</h3>
Transforms a given value from an input domain to an output range using linear interpolation.

<p><h4>Syntax</h4>
scale_linear(<i>val</i>,<i>domain_min</i>,<i>domain_max</i>,<i>range_min</i>,<i>range_max</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> val</i> &rarr; is a value in the input domain. The function will return a corresponding scaled value in the output range.<br>
<i> domain_min, domain_max</i> &rarr; specify the input domain, the smallest and largest values the input <i>val</i> should take.<br>
<i> range_min, range_max</i> &rarr; sepcify the output range, the smallest and largest values which should be output by the function.<br>

<h4>Example</h4>
<!-- Show example of function.-->
scale_linear(5,0,10,0,100) &rarr; 50<br>
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>
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>


29 changes: 28 additions & 1 deletion src/core/qgsexpression.cpp
Expand Up @@ -439,6 +439,32 @@ static QVariant fcnRnd( const QVariantList& values, QgsFeature* , QgsExpression*
return QVariant( min + ( rand() % ( int )( max - min + 1 ) ) );
}

static QVariant fcnLinearScale( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
double val = getDoubleValue( values.at( 0 ), parent );
double domain_min = getDoubleValue( values.at( 1 ), parent );
double domain_max = getDoubleValue( values.at( 2 ), parent );
double range_min = getDoubleValue( values.at( 3 ), parent );
double range_max = getDoubleValue( values.at( 4 ), parent );

// outside of domain?
if ( val >= domain_max )
{
return range_max;
}
else if ( val <= domain_min )
{
return range_min;
}

// calculate linear scale
double m = ( range_max - range_min ) / ( domain_max - domain_min );
double c = range_min - ( domain_min * m );

// Return linearly scaled value
return QVariant( m * val + c );
}

static QVariant fcnMax( const QVariantList& values, QgsFeature* , QgsExpression *parent )
{
//initially set max as first value
Expand Down Expand Up @@ -1317,7 +1343,7 @@ const QStringList &QgsExpression::BuiltinFunctions()
<< "asin" << "acos" << "atan" << "atan2"
<< "exp" << "ln" << "log10" << "log"
<< "round" << "rand" << "randf" << "max" << "min"
<< "floor" << "ceil"
<< "scale_linear" << "floor" << "ceil"
<< "toint" << "toreal" << "tostring"
<< "todatetime" << "todate" << "totime" << "tointerval"
<< "coalesce" << "regexp_match" << "$now" << "age" << "year"
Expand Down Expand Up @@ -1363,6 +1389,7 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
<< new StaticFunction( "randf", 2, fcnRndF, QObject::tr( "Math" ) )
<< new StaticFunction( "max", -1, fcnMax, QObject::tr( "Math" ) )
<< new StaticFunction( "min", -1, fcnMin, QObject::tr( "Math" ) )
<< new StaticFunction( "scale_linear", 5, fcnLinearScale, QObject::tr( "Math" ) )
<< new StaticFunction( "floor", 1, fcnFloor, QObject::tr( "Math" ) )
<< new StaticFunction( "ceil", 1, fcnCeil, QObject::tr( "Math" ) )
<< new StaticFunction( "$pi", 0, fcnPi, QObject::tr( "Math" ) )
Expand Down
6 changes: 6 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -264,6 +264,12 @@ class TestQgsExpression: public QObject
QTest::newRow( "floor(-4.9)" ) << "floor(-4.9)" << false << QVariant( -5. );
QTest::newRow( "ceil(4.9)" ) << "ceil(4.9)" << false << QVariant( 5. );
QTest::newRow( "ceil(-4.9)" ) << "ceil(-4.9)" << false << QVariant( -4. );
QTest::newRow( "scale_linear(0.5,0,1,0,1)" ) << "scale_linear(0.5,0,1,0,1)" << false << QVariant( 0.5 );
QTest::newRow( "scale_linear(0,0,10,100,200)" ) << "scale_linear(0,0,10,100,200)" << false << QVariant( 100. );
QTest::newRow( "scale_linear(5,0,10,100,200)" ) << "scale_linear(5,0,10,100,200)" << false << QVariant( 150. );
QTest::newRow( "scale_linear(10,0,10,100,200)" ) << "scale_linear(10,0,10,100,200)" << false << QVariant( 200. );
QTest::newRow( "scale_linear(-1,0,10,100,200)" ) << "scale_linear(-1,0,10,100,200)" << false << QVariant( 100. );
QTest::newRow( "scale_linear(11,0,10,100,200)" ) << "scale_linear(11,0,10,100,200)" << false << QVariant( 200. );

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

0 comments on commit 23a7ebf

Please sign in to comment.