Skip to content

Commit

Permalink
Merge pull request #565 from nyalldawson/new_functions
Browse files Browse the repository at this point in the history
New color functions (from hsl, hsv and cmyk), new regexp_match function
  • Loading branch information
NathanW2 committed Apr 28, 2013
2 parents 71c9d96 + 533030f commit 8565ef9
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 5 deletions.
17 changes: 17 additions & 0 deletions resources/function_help/color_cmyk-en_US
@@ -0,0 +1,17 @@

<h3>color_cmyk() function</h3>
Returns a string representation of a color based on its cyan, magenta, yellow and black components

<p><h4>Syntax</h4>
color_cmyk(<i>cyan, magenta, yellow, black</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> cyan</i> &rarr; the cyan component of the color, as a percentage integer value from 0 to 100.<br>
<i> magenta</i> &rarr; the magenta component of the color, as a percentage integer value from 0 to 100.<br>
<i> yellow</i> &rarr; the yellow component of the color, as a percentage integer value from 0 to 100.<br>
<i> black</i> &rarr; the black component of the color, as a percentage integer value from 0 to 100.<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
color_cmyk(100,50,0,10) &rarr; '#0073e6'</p>
18 changes: 18 additions & 0 deletions resources/function_help/color_cmyka-en_US
@@ -0,0 +1,18 @@

<h3>color_cmyka() function</h3>
Returns a string representation of a color based on its cyan, magenta, yellow, black and alpha (transparency) components

<p><h4>Syntax</h4>
color_cmyka(<i>cyan, magenta, yellow, black, alpha</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> cyan</i> &rarr; the cyan component of the color, as a percentage integer value from 0 to 100.<br>
<i> magenta</i> &rarr; the magenta component of the color, as a percentage integer value from 0 to 100.<br>
<i> yellow</i> &rarr; the yellow component of the color, as a percentage integer value from 0 to 100.<br>
<i> black</i> &rarr; the black component of the color, as a percentage integer value from 0 to 100.<br>
<i> alpha</i> &rarr; the alpha component as an integer value from 0 (completely transparent) to 255 (opaque).<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
color_cmyka(100,50,0,10,200) &rarr; '0,115,230,200'</p>
16 changes: 16 additions & 0 deletions resources/function_help/color_hsl-en_US
@@ -0,0 +1,16 @@

<h3>color_hsl() function</h3>
Returns a string representation of a color based on its hue, saturation, and lightness attributes

<p><h4>Syntax</h4>
color_hsl(<i>hue, saturation, lightness</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> hue</i> &rarr; the hue of the color, as an integer value from 0 to 360.<br>
<i> saturation</i> &rarr; the saturation percentage of the color as an integer value from 0 to 100.<br>
<i> lightness</i> &rarr; the lightness percentage of the color as an integer value from 0 to 100.<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
color_hsl(100,50,70) &rarr; '#a6d98c'</p>
17 changes: 17 additions & 0 deletions resources/function_help/color_hsla-en_US
@@ -0,0 +1,17 @@

<h3>color_hsla() function</h3>
Returns a string representation of a color based on its hue, saturation, lightness and alpha (transparency) attributes

<p><h4>Syntax</h4>
color_hsla(<i>hue, saturation, lightness, alpha</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> hue</i> &rarr; the hue of the color, as an integer value from 0 to 360.<br>
<i> saturation</i> &rarr; the saturation percentage of the color as an integer value from 0 to 100.<br>
<i> lightness</i> &rarr; the lightness percentage of the color as an integer value from 0 to 100.<br>
<i> alpha</i> &rarr; the alpha component as an integer value from 0 (completely transparent) to 255 (opaque).<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
color_hsla(100,50,70,200) &rarr; '166,217,140,200'</p>
16 changes: 16 additions & 0 deletions resources/function_help/color_hsv-en_US
@@ -0,0 +1,16 @@

<h3>color_hsv() function</h3>
Returns a string representation of a color based on its hue, saturation, and value attributes

<p><h4>Syntax</h4>
color_hsv(<i>hue, saturation, value</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> hue</i> &rarr; the hue of the color, as an integer value from 0 to 360.<br>
<i> saturation</i> &rarr; the saturation percentage of the color as an integer value from 0 to 100.<br>
<i> value</i> &rarr; the value percentage of the color as an integer from 0 to 100.<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
color_hsv(40,100,100) &rarr; '#ffaa00'</p>
17 changes: 17 additions & 0 deletions resources/function_help/color_hsva-en_US
@@ -0,0 +1,17 @@

<h3>color_hsva() function</h3>
Returns a string representation of a color based on its hue, saturation, value and alpha (transparency) attributes

<p><h4>Syntax</h4>
color_hsva(<i>hue, saturation, value, alpha</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> hue</i> &rarr; the hue of the color, as an integer value from 0 to 360.<br>
<i> saturation</i> &rarr; the saturation percentage of the color as an integer value from 0 to 100.<br>
<i> value</i> &rarr; the value percentage of the color as an integer from 0 to 100.<br>
<i> alpha</i> &rarr; the alpha component as an integer value from 0 (completely transparent) to 255 (opaque).<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
color_hsva(40,100,100,200) &rarr; '255,170,0,200'</p>
14 changes: 14 additions & 0 deletions resources/function_help/regexp_match-en_US
@@ -0,0 +1,14 @@
<h3>regexp_match() function</h3>
Returns true if any part of a string matches the supplied regular expression.

<p><h4>Syntax</h4>
regexp_match(<i>string,regex</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> string</i> &rarr; is string. The string to test against the regular expression.<br>
<i> regex</i> &rarr; is string. The regular expression to test against. Backslash characters must be double escaped (eg "\\s" to match a white space character).<br>

<p><h4>Example</h4>
<!-- Show example of function.-->
regexp_match('QGIS ROCKS','\\sROCKS') &rarr; 1</p>
8 changes: 4 additions & 4 deletions resources/function_help/regexp_replace-en_US
Expand Up @@ -2,14 +2,14 @@
Returns a string with the supplied regular expression replaced.

<p><h4>Syntax</h4>
replace(<i>string,before,after</i>)</p>
regexp_replace(<i>string,regex,after</i>)</p>

<p><h4>Arguments</h4>
<!-- List args for functions here-->
<i> string</i> &rarr; is string. The start string.<br>
<i> before</i> &rarr; is string. The string to replace.<br>
<i> after</i> &rarr; is string. The string that will replace <i>before</i><br></p>
<i> regex</i> &rarr; is string. The regular expression to replace. Backslash characters must be double escaped (eg "\\s" to match a white space character).<br>
<i> after</i> &rarr; is string. The string that will replace any matching occurences of the supplied regular expression. Captured groups can be inserted into the replacement string using \\1, \\2, etc. <br></p>

<p><h4>Example</h4>
<!-- Show example of function.-->
replace('QGIS SHOULD ROCK','SHOULD','DOES') &rarr; 'QGIS DOES ROCK'</p>
regexp_replace('QGIS SHOULD ROCK','\\sSHOULD\\s',' DOES ') &rarr; 'QGIS DOES ROCK'</p>
150 changes: 149 additions & 1 deletion src/core/qgsexpression.cpp
Expand Up @@ -485,6 +485,21 @@ static QVariant fcnRegexpReplace( const QVariantList& values, QgsFeature* , QgsE
}
return QVariant( str.replace( re, after ) );
}

static QVariant fcnRegexpMatch( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QString str = getStringValue( values.at( 0 ), parent );
QString regexp = getStringValue( values.at( 1 ), parent );

QRegExp re( regexp );
if ( !re.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) );
return QVariant();
}
return QVariant( str.contains( re ) ? 1 : 0 );
}

static QVariant fcnSubstr( const QVariantList& values, QgsFeature* , QgsExpression* parent )
{
QString str = getStringValue( values.at( 0 ), parent );
Expand Down Expand Up @@ -1023,6 +1038,130 @@ QVariant fcnRampColor( const QVariantList &values, QgsFeature *, QgsExpression *
return color.name();
}

static QVariant fcnColorHsl( const QVariantList &values, QgsFeature *, QgsExpression *parent )
{
// Hue ranges from 0 - 360
double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
// Saturation ranges from 0 - 100
double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
// Lightness ranges from 0 - 100
double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;

QColor color = QColor::fromHslF( hue, saturation, lightness );

if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
color = QColor( 0, 0, 0 );
}

return color.name();
}

static QVariant fncColorHsla( const QVariantList &values, QgsFeature *, QgsExpression *parent )
{
// Hue ranges from 0 - 360
double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
// Saturation ranges from 0 - 100
double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
// Lightness ranges from 0 - 100
double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
// Alpha ranges from 0 - 255
double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;

QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
color = QColor( 0, 0, 0 );
}
return QgsSymbolLayerV2Utils::encodeColor( color );
}

static QVariant fcnColorHsv( const QVariantList &values, QgsFeature *, QgsExpression *parent )
{
// Hue ranges from 0 - 360
double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
// Saturation ranges from 0 - 100
double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
// Value ranges from 0 - 100
double value = getIntValue( values.at( 2 ), parent ) / 100.0;

QColor color = QColor::fromHsvF( hue, saturation, value );

if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
color = QColor( 0, 0, 0 );
}

return color.name();
}

static QVariant fncColorHsva( const QVariantList &values, QgsFeature *, QgsExpression *parent )
{
// Hue ranges from 0 - 360
double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
// Saturation ranges from 0 - 100
double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
// Value ranges from 0 - 100
double value = getIntValue( values.at( 2 ), parent ) / 100.0;
// Alpha ranges from 0 - 255
double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;

QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
color = QColor( 0, 0, 0 );
}
return QgsSymbolLayerV2Utils::encodeColor( color );
}

static QVariant fcnColorCmyk( const QVariantList &values, QgsFeature *, QgsExpression *parent )
{
// Cyan ranges from 0 - 100
double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
// Magenta ranges from 0 - 100
double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
// Yellow ranges from 0 - 100
double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
// Black ranges from 0 - 100
double black = getIntValue( values.at( 3 ), parent ) / 100.0;

QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );

if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
color = QColor( 0, 0, 0 );
}

return color.name();
}

static QVariant fncColorCmyka( const QVariantList &values, QgsFeature *, QgsExpression *parent )
{
// Cyan ranges from 0 - 100
double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
// Magenta ranges from 0 - 100
double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
// Yellow ranges from 0 - 100
double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
// Black ranges from 0 - 100
double black = getIntValue( values.at( 3 ), parent ) / 100.0;
// Alpha ranges from 0 - 255
double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;

QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
if ( ! color.isValid() )
{
parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
color = QColor( 0, 0, 0 );
}
return QgsSymbolLayerV2Utils::encodeColor( color );
}

static QVariant fcnSpecialColumn( const QVariantList& values, QgsFeature* /*f*/, QgsExpression* parent )
{
QString varName = getStringValue( values.at( 0 ), parent );
Expand Down Expand Up @@ -1070,14 +1209,16 @@ const QStringList &QgsExpression::BuiltinFunctions()
<< "exp" << "ln" << "log10" << "log"
<< "round" << "toint" << "toreal" << "tostring"
<< "todatetime" << "todate" << "totime" << "tointerval"
<< "coalesce" << "$now" << "age" << "year"
<< "coalesce" << "regexp_match" << "$now" << "age" << "year"
<< "month" << "week" << "day" << "hour"
<< "minute" << "second" << "lower" << "upper"
<< "title" << "length" << "replace" << "regexp_replace"
<< "substr" << "concat" << "strpos" << "left"
<< "right" << "rpad" << "lpad"
<< "format_number" << "format_date"
<< "color_rgb" << "color_rgba" << "ramp_color"
<< "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
<< "color_cymk" << "color_cymka"
<< "xat" << "yat" << "$area"
<< "$length" << "$perimeter" << "$x" << "$y"
<< "$rownum" << "$id" << "$scale" << "_specialcol_";
Expand Down Expand Up @@ -1114,6 +1255,7 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
<< new StaticFunction( "totime", 1, fcnToTime, QObject::tr( "Conversions" ) )
<< new StaticFunction( "tointerval", 1, fcnToInterval, QObject::tr( "Conversions" ) )
<< new StaticFunction( "coalesce", -1, fcnCoalesce, QObject::tr( "Conditionals" ) )
<< new StaticFunction( "regexp_match", 2, fcnRegexpMatch, QObject::tr( "Conditionals" ) )
<< new StaticFunction( "$now", 0, fcnNow, QObject::tr( "Date and Time" ) )
<< new StaticFunction( "age", 2, fcnAge, QObject::tr( "Date and Time" ) )
<< new StaticFunction( "year", 1, fcnYear, QObject::tr( "Date and Time" ) )
Expand Down Expand Up @@ -1142,6 +1284,12 @@ const QList<QgsExpression::Function*> &QgsExpression::Functions()
<< new StaticFunction( "color_rgb", 3, fcnColorRgb, QObject::tr( "Color" ) )
<< new StaticFunction( "color_rgba", 4, fncColorRgba, QObject::tr( "Color" ) )
<< new StaticFunction( "ramp_color", 2, fcnRampColor, QObject::tr( "Color" ) )
<< new StaticFunction( "color_hsl", 3, fcnColorHsl, QObject::tr( "Color" ) )
<< new StaticFunction( "color_hsla", 4, fncColorHsla, QObject::tr( "Color" ) )
<< new StaticFunction( "color_hsv", 3, fcnColorHsv, QObject::tr( "Color" ) )
<< new StaticFunction( "color_hsva", 4, fncColorHsva, QObject::tr( "Color" ) )
<< new StaticFunction( "color_cmyk", 4, fcnColorCmyk, QObject::tr( "Color" ) )
<< new StaticFunction( "color_cmyka", 5, fncColorCmyka, QObject::tr( "Color" ) )
<< new StaticFunction( "xat", 1, fcnXat, QObject::tr( "Geometry" ), "", true )
<< new StaticFunction( "yat", 1, fcnYat, QObject::tr( "Geometry" ), "", true )
<< new StaticFunction( "$area", 0, fcnGeomArea, QObject::tr( "Geometry" ), "", true )
Expand Down
10 changes: 10 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -302,6 +302,10 @@ class TestQgsExpression: public QObject
QTest::newRow( "coalesce null" ) << "coalesce(NULL)" << false << QVariant( );
QTest::newRow( "coalesce mid-null" ) << "coalesce(1, NULL, 3)" << false << QVariant( 1 );
QTest::newRow( "coalesce exp" ) << "coalesce(NULL, 1+1)" << false << QVariant( 2 );
QTest::newRow( "regexp match" ) << "regexp_match('abc','.b.')" << false << QVariant( 1 );
QTest::newRow( "regexp match invalid" ) << "regexp_match('abc DEF','[[[')" << true << QVariant();
QTest::newRow( "regexp match escaped" ) << "regexp_match('abc DEF','\\\\s[A-Z]+')" << false << QVariant( 1 );
QTest::newRow( "regexp match false" ) << "regexp_match('abc DEF','\\\\s[a-z]+')" << false << QVariant( 0 );

// Datetime functions
QTest::newRow( "to date" ) << "todate('2012-06-28')" << false << QVariant( QDate( 2012, 6, 28 ) );
Expand All @@ -319,6 +323,12 @@ class TestQgsExpression: public QObject
QTest::newRow( "ramp color" ) << "ramp_color('Spectral',0.3)" << false << QVariant( "#fdbe73" );
QTest::newRow( "color rgb" ) << "color_rgb(255,127,0)" << false << QVariant( "#ff7f00" );
QTest::newRow( "color rgba" ) << "color_rgba(255,127,0,200)" << false << QVariant( "255,127,0,200" );
QTest::newRow( "color hsl" ) << "color_hsl(100,50,70)" << false << QVariant( "#a6d98c" );
QTest::newRow( "color hsla" ) << "color_hsla(100,50,70,200)" << false << QVariant( "166,217,140,200" );
QTest::newRow( "color hsv" ) << "color_hsv(40,100,100)" << false << QVariant( "#ffaa00" );
QTest::newRow( "color hsva" ) << "color_hsva(40,100,100,200)" << false << QVariant( "255,170,0,200" );
QTest::newRow( "color cmyk" ) << "color_cmyk(100,50,33,10)" << false << QVariant( "#00739a" );
QTest::newRow( "color cmyka" ) << "color_cmyka(50,25,90,60,200)" << false << QVariant( "51,76,10,200" );
}

void evaluation()
Expand Down

0 comments on commit 8565ef9

Please sign in to comment.