QGIS API Documentation  2.14.5-Essen
qgsexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpression.cpp
3  -------------------
4  begin : August 2011
5  copyright : (C) 2011 Martin Dobias
6  email : wonder.sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsexpression.h"
17 
18 #include <QtDebug>
19 #include <QDomDocument>
20 #include <QDate>
21 #include <QRegExp>
22 #include <QColor>
23 #include <QUuid>
24 #include <QMutex>
25 
26 #include <math.h>
27 #include <limits>
28 
29 #include "qgsdistancearea.h"
30 #include "qgsfeature.h"
31 #include "qgsgeometry.h"
32 #include "qgsgeometryengine.h"
33 #include "qgsgeometryutils.h"
34 #include "qgslogger.h"
35 #include "qgsmaplayerregistry.h"
36 #include "qgsogcutils.h"
37 #include "qgsvectorlayer.h"
38 #include "qgssymbollayerv2utils.h"
39 #include "qgsvectorcolorrampv2.h"
40 #include "qgsstylev2.h"
41 #include "qgsexpressioncontext.h"
42 #include "qgsproject.h"
43 #include "qgsstringutils.h"
45 #include "qgspointv2.h"
46 #include "qgspolygonv2.h"
47 #include "qgsmultipointv2.h"
48 #include "qgsmultilinestringv2.h"
49 #include "qgscurvepolygonv2.h"
50 #include "qgsexpressionprivate.h"
51 #include "qgsexpressionsorter.h"
52 
53 #if QT_VERSION < 0x050000
54 #include <qtextdocument.h>
55 #endif
56 
57 // from parser
58 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
59 
61 {
63  inter.setValid( false );
64  return inter;
65 }
66 
68 {
69  int seconds = 0;
70  QRegExp rx( "([-+]?\\d?\\.?\\d+\\s+\\S+)", Qt::CaseInsensitive );
71  QStringList list;
72  int pos = 0;
73 
74  while (( pos = rx.indexIn( string, pos ) ) != -1 )
75  {
76  list << rx.cap( 1 );
77  pos += rx.matchedLength();
78  }
79 
81  map.insert( 1, QStringList() << "second" << "seconds" << tr( "second|seconds", "list of words separated by | which reference years" ).split( '|' ) );
82  map.insert( 0 + MINUTE, QStringList() << "minute" << "minutes" << tr( "minute|minutes", "list of words separated by | which reference minutes" ).split( '|' ) );
83  map.insert( 0 + HOUR, QStringList() << "hour" << "hours" << tr( "hour|hours", "list of words separated by | which reference minutes hours" ).split( '|' ) );
84  map.insert( 0 + DAY, QStringList() << "day" << "days" << tr( "day|days", "list of words separated by | which reference days" ).split( '|' ) );
85  map.insert( 0 + WEEKS, QStringList() << "week" << "weeks" << tr( "week|weeks", "wordlist separated by | which reference weeks" ).split( '|' ) );
86  map.insert( 0 + MONTHS, QStringList() << "month" << "months" << tr( "month|months", "list of words separated by | which reference months" ).split( '|' ) );
87  map.insert( 0 + YEARS, QStringList() << "year" << "years" << tr( "year|years", "list of words separated by | which reference years" ).split( '|' ) );
88 
89  Q_FOREACH ( const QString& match, list )
90  {
91  QStringList split = match.split( QRegExp( "\\s+" ) );
92  bool ok;
93  double value = split.at( 0 ).toDouble( &ok );
94  if ( !ok )
95  {
96  continue;
97  }
98 
99  bool matched = false;
101  for ( ; it != map.constEnd(); ++it )
102  {
103  int duration = it.key();
104  Q_FOREACH ( const QString& name, it.value() )
105  {
106  if ( match.contains( name, Qt::CaseInsensitive ) )
107  {
108  matched = true;
109  break;
110  }
111  }
112 
113  if ( matched )
114  {
115  seconds += value * duration;
116  break;
117  }
118  }
119  }
120 
121  // If we can't parse the string at all then we just return invalid
122  if ( seconds == 0 )
124 
125  return QgsExpression::Interval( seconds );
126 }
127 
129 {
130  return qgsDoubleNear( mSeconds, other.mSeconds );
131 }
132 
134 // three-value logic
135 
136 enum TVL
137 {
141 };
142 
143 static TVL AND[3][3] =
144 {
145  // false true unknown
146  { False, False, False }, // false
147  { False, True, Unknown }, // true
148  { False, Unknown, Unknown } // unknown
149 };
150 
151 static TVL OR[3][3] =
152 {
153  { False, True, Unknown }, // false
154  { True, True, True }, // true
155  { Unknown, True, Unknown } // unknown
156 };
157 
158 static TVL NOT[3] = { True, False, Unknown };
159 
161 {
162  switch ( v )
163  {
164  case False:
165  return 0;
166  case True:
167  return 1;
168  case Unknown:
169  default:
170  return QVariant();
171  }
172 }
173 
174 #define TVL_True QVariant(1)
175 #define TVL_False QVariant(0)
176 #define TVL_Unknown QVariant()
177 
179 // QVariant checks and conversions
180 
181 inline bool isIntSafe( const QVariant& v )
182 {
183  if ( v.type() == QVariant::Int ) return true;
184  if ( v.type() == QVariant::UInt ) return true;
185  if ( v.type() == QVariant::LongLong ) return true;
186  if ( v.type() == QVariant::ULongLong ) return true;
187  if ( v.type() == QVariant::Double ) return false;
188  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
189  return false;
190 }
191 inline bool isDoubleSafe( const QVariant& v )
192 {
193  if ( v.type() == QVariant::Double ) return true;
194  if ( v.type() == QVariant::Int ) return true;
195  if ( v.type() == QVariant::UInt ) return true;
196  if ( v.type() == QVariant::LongLong ) return true;
197  if ( v.type() == QVariant::ULongLong ) return true;
198  if ( v.type() == QVariant::String )
199  {
200  bool ok;
201  double val = v.toString().toDouble( &ok );
202  ok = ok && qIsFinite( val ) && !qIsNaN( val );
203  return ok;
204  }
205  return false;
206 }
207 
208 inline bool isDateTimeSafe( const QVariant& v )
209 {
210  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
211  v.type() == QVariant::Time;
212 }
213 
214 inline bool isIntervalSafe( const QVariant& v )
215 {
217  {
218  return true;
219  }
220 
221  if ( v.type() == QVariant::String )
222  {
224  }
225  return false;
226 }
227 
228 inline bool isNull( const QVariant& v ) { return v.isNull(); }
229 
231 // evaluation error macros
232 
233 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
234 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
235 
237 // operators
238 
239 const char* QgsExpression::BinaryOperatorText[] =
240 {
241  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
242  "OR", "AND",
243  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
244  "+", "-", "*", "/", "//", "%", "^",
245  "||"
246 };
247 
248 const char* QgsExpression::UnaryOperatorText[] =
249 {
250  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
251  "NOT", "-"
252 };
253 
255 // functions
256 
257 // implicit conversion to string
259 {
260  return value.toString();
261 }
262 
263 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
264 {
265  bool ok;
266  double x = value.toDouble( &ok );
267  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
268  {
269  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
270  return 0;
271  }
272  return x;
273 }
274 
275 static int getIntValue( const QVariant& value, QgsExpression* parent )
276 {
277  bool ok;
278  qint64 x = value.toLongLong( &ok );
280  {
281  return x;
282  }
283  else
284  {
285  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
286  return 0;
287  }
288 }
289 
290 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
291 {
292  QDateTime d = value.toDateTime();
293  if ( d.isValid() )
294  {
295  return d;
296  }
297  else
298  {
299  QTime t = value.toTime();
300  if ( t.isValid() )
301  {
302  return QDateTime( QDate( 1, 1, 1 ), t );
303  }
304 
305  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
306  return QDateTime();
307  }
308 }
309 
310 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
311 {
312  QDate d = value.toDate();
313  if ( d.isValid() )
314  {
315  return d;
316  }
317  else
318  {
319  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
320  return QDate();
321  }
322 }
323 
324 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
325 {
326  QTime t = value.toTime();
327  if ( t.isValid() )
328  {
329  return t;
330  }
331  else
332  {
333  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
334  return QTime();
335  }
336 }
337 
338 static QgsExpression::Interval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
339 {
340  if ( value.canConvert<QgsExpression::Interval>() )
341  return value.value<QgsExpression::Interval>();
342 
344  if ( inter.isValid() )
345  {
346  return inter;
347  }
348  // If we get here then we can't convert so we just error and return invalid.
349  if ( report_error )
350  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
351 
353 }
354 
355 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
356 {
357  if ( value.canConvert<QgsGeometry>() )
358  return value.value<QgsGeometry>();
359 
360  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
361  return QgsGeometry();
362 }
363 
364 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
365 {
366  if ( value.canConvert<QgsFeature>() )
367  return value.value<QgsFeature>();
368 
369  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
370  return 0;
371 }
372 
373 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
374 {
375  if ( value.canConvert<QgsExpression::Node*>() )
376  return value.value<QgsExpression::Node*>();
377 
378  parent->setEvalErrorString( "Cannot convert to Node" );
379  return nullptr;
380 }
381 
382 // this handles also NULL values
383 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
384 {
385  // we need to convert to TVL
386  if ( value.isNull() )
387  return Unknown;
388 
389  //handle some special cases
390  if ( value.canConvert<QgsGeometry>() )
391  {
392  //geom is false if empty
393  QgsGeometry geom = value.value<QgsGeometry>();
394  return geom.isEmpty() ? False : True;
395  }
396  else if ( value.canConvert<QgsFeature>() )
397  {
398  //feat is false if non-valid
399  QgsFeature feat = value.value<QgsFeature>();
400  return feat.isValid() ? True : False;
401  }
402 
403  if ( value.type() == QVariant::Int )
404  return value.toInt() != 0 ? True : False;
405 
406  bool ok;
407  double x = value.toDouble( &ok );
408  if ( !ok )
409  {
410  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
411  return Unknown;
412  }
413  return !qgsDoubleNear( x, 0.0 ) ? True : False;
414 }
415 
417 
418 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
419 {
420  if ( !context )
421  return QVariant();
422 
423  QString name = getStringValue( values.at( 0 ), parent );
424  return context->variable( name );
425 }
426 
427 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
428 {
429  if ( !context )
430  return QVariant();
431 
432  QString expString = getStringValue( values.at( 0 ), parent );
433  QgsExpression expression( expString );
434  return expression.evaluate( context );
435 }
436 
437 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
438 {
439  double x = getDoubleValue( values.at( 0 ), parent );
440  return QVariant( sqrt( x ) );
441 }
442 
443 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
444 {
445  double val = getDoubleValue( values.at( 0 ), parent );
446  return QVariant( fabs( val ) );
447 }
448 
449 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
450 {
451  double deg = getDoubleValue( values.at( 0 ), parent );
452  return ( deg * M_PI ) / 180;
453 }
454 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
455 {
456  double rad = getDoubleValue( values.at( 0 ), parent );
457  return ( 180 * rad ) / M_PI;
458 }
459 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
460 {
461  double x = getDoubleValue( values.at( 0 ), parent );
462  return QVariant( sin( x ) );
463 }
464 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
465 {
466  double x = getDoubleValue( values.at( 0 ), parent );
467  return QVariant( cos( x ) );
468 }
469 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
470 {
471  double x = getDoubleValue( values.at( 0 ), parent );
472  return QVariant( tan( x ) );
473 }
474 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
475 {
476  double x = getDoubleValue( values.at( 0 ), parent );
477  return QVariant( asin( x ) );
478 }
479 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
480 {
481  double x = getDoubleValue( values.at( 0 ), parent );
482  return QVariant( acos( x ) );
483 }
484 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
485 {
486  double x = getDoubleValue( values.at( 0 ), parent );
487  return QVariant( atan( x ) );
488 }
489 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
490 {
491  double y = getDoubleValue( values.at( 0 ), parent );
492  double x = getDoubleValue( values.at( 1 ), parent );
493  return QVariant( atan2( y, x ) );
494 }
495 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
496 {
497  double x = getDoubleValue( values.at( 0 ), parent );
498  return QVariant( exp( x ) );
499 }
500 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
501 {
502  double x = getDoubleValue( values.at( 0 ), parent );
503  if ( x <= 0 )
504  return QVariant();
505  return QVariant( log( x ) );
506 }
507 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
508 {
509  double x = getDoubleValue( values.at( 0 ), parent );
510  if ( x <= 0 )
511  return QVariant();
512  return QVariant( log10( x ) );
513 }
514 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
515 {
516  double b = getDoubleValue( values.at( 0 ), parent );
517  double x = getDoubleValue( values.at( 1 ), parent );
518  if ( x <= 0 || b <= 0 )
519  return QVariant();
520  return QVariant( log( x ) / log( b ) );
521 }
522 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
523 {
524  double min = getDoubleValue( values.at( 0 ), parent );
525  double max = getDoubleValue( values.at( 1 ), parent );
526  if ( max < min )
527  return QVariant();
528 
529  // Return a random double in the range [min, max] (inclusive)
530  double f = static_cast< double >( qrand() ) / RAND_MAX;
531  return QVariant( min + f * ( max - min ) );
532 }
533 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
534 {
535  int min = getIntValue( values.at( 0 ), parent );
536  int max = getIntValue( values.at( 1 ), parent );
537  if ( max < min )
538  return QVariant();
539 
540  // Return a random integer in the range [min, max] (inclusive)
541  return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
542 }
543 
544 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
545 {
546  double val = getDoubleValue( values.at( 0 ), parent );
547  double domainMin = getDoubleValue( values.at( 1 ), parent );
548  double domainMax = getDoubleValue( values.at( 2 ), parent );
549  double rangeMin = getDoubleValue( values.at( 3 ), parent );
550  double rangeMax = getDoubleValue( values.at( 4 ), parent );
551 
552  if ( domainMin >= domainMax )
553  {
554  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
555  return QVariant();
556  }
557 
558  // outside of domain?
559  if ( val >= domainMax )
560  {
561  return rangeMax;
562  }
563  else if ( val <= domainMin )
564  {
565  return rangeMin;
566  }
567 
568  // calculate linear scale
569  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
570  double c = rangeMin - ( domainMin * m );
571 
572  // Return linearly scaled value
573  return QVariant( m * val + c );
574 }
575 
576 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
577 {
578  double val = getDoubleValue( values.at( 0 ), parent );
579  double domainMin = getDoubleValue( values.at( 1 ), parent );
580  double domainMax = getDoubleValue( values.at( 2 ), parent );
581  double rangeMin = getDoubleValue( values.at( 3 ), parent );
582  double rangeMax = getDoubleValue( values.at( 4 ), parent );
583  double exponent = getDoubleValue( values.at( 5 ), parent );
584 
585  if ( domainMin >= domainMax )
586  {
587  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
588  return QVariant();
589  }
590  if ( exponent <= 0 )
591  {
592  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
593  return QVariant();
594  }
595 
596  // outside of domain?
597  if ( val >= domainMax )
598  {
599  return rangeMax;
600  }
601  else if ( val <= domainMin )
602  {
603  return rangeMin;
604  }
605 
606  // Return exponentially scaled value
607  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
608 }
609 
610 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
611 {
612  //initially set max as first value
613  double maxVal = getDoubleValue( values.at( 0 ), parent );
614 
615  //check against all other values
616  for ( int i = 1; i < values.length(); ++i )
617  {
618  double testVal = getDoubleValue( values[i], parent );
619  if ( testVal > maxVal )
620  {
621  maxVal = testVal;
622  }
623  }
624 
625  return QVariant( maxVal );
626 }
627 
628 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
629 {
630  //initially set min as first value
631  double minVal = getDoubleValue( values.at( 0 ), parent );
632 
633  //check against all other values
634  for ( int i = 1; i < values.length(); ++i )
635  {
636  double testVal = getDoubleValue( values[i], parent );
637  if ( testVal < minVal )
638  {
639  minVal = testVal;
640  }
641  }
642 
643  return QVariant( minVal );
644 }
645 
646 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
647 {
648  double minValue = getDoubleValue( values.at( 0 ), parent );
649  double testValue = getDoubleValue( values.at( 1 ), parent );
650  double maxValue = getDoubleValue( values.at( 2 ), parent );
651 
652  // force testValue to sit inside the range specified by the min and max value
653  if ( testValue <= minValue )
654  {
655  return QVariant( minValue );
656  }
657  else if ( testValue >= maxValue )
658  {
659  return QVariant( maxValue );
660  }
661  else
662  {
663  return QVariant( testValue );
664  }
665 }
666 
667 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
668 {
669  double x = getDoubleValue( values.at( 0 ), parent );
670  return QVariant( floor( x ) );
671 }
672 
673 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
674 {
675  double x = getDoubleValue( values.at( 0 ), parent );
676  return QVariant( ceil( x ) );
677 }
678 
679 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
680 {
681  return QVariant( getIntValue( values.at( 0 ), parent ) );
682 }
683 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
684 {
685  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
686 }
687 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
688 {
689  return QVariant( getStringValue( values.at( 0 ), parent ) );
690 }
691 
692 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
693 {
694  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
695 }
696 
697 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
698 {
699  Q_FOREACH ( const QVariant &value, values )
700  {
701  if ( value.isNull() )
702  continue;
703  return value;
704  }
705  return QVariant();
706 }
707 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
708 {
709  QString str = getStringValue( values.at( 0 ), parent );
710  return QVariant( str.toLower() );
711 }
712 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
713 {
714  QString str = getStringValue( values.at( 0 ), parent );
715  return QVariant( str.toUpper() );
716 }
717 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
718 {
719  QString str = getStringValue( values.at( 0 ), parent );
720  QStringList elems = str.split( ' ' );
721  for ( int i = 0; i < elems.size(); i++ )
722  {
723  if ( elems[i].size() > 1 )
724  elems[i] = elems[i].left( 1 ).toUpper() + elems[i].mid( 1 ).toLower();
725  }
726  return QVariant( elems.join( " " ) );
727 }
728 
729 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
730 {
731  QString str = getStringValue( values.at( 0 ), parent );
732  return QVariant( str.trimmed() );
733 }
734 
735 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
736 {
737  QString string1 = getStringValue( values.at( 0 ), parent );
738  QString string2 = getStringValue( values.at( 1 ), parent );
739  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
740 }
741 
742 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
743 {
744  QString string1 = getStringValue( values.at( 0 ), parent );
745  QString string2 = getStringValue( values.at( 1 ), parent );
746  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
747 }
748 
749 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
750 {
751  QString string1 = getStringValue( values.at( 0 ), parent );
752  QString string2 = getStringValue( values.at( 1 ), parent );
753  int dist = QgsStringUtils::hammingDistance( string1, string2 );
754  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
755 }
756 
757 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
758 {
759  QString string = getStringValue( values.at( 0 ), parent );
760  return QVariant( QgsStringUtils::soundex( string ) );
761 }
762 
763 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
764 {
765  if ( values.length() == 2 || values.length() == 3 )
766  {
767  QString str = getStringValue( values.at( 0 ), parent );
768  int wrap = getIntValue( values.at( 1 ), parent );
769 
770  if ( !str.isEmpty() && wrap != 0 )
771  {
772  QString newstr;
773  QString delimiterstr;
774  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
775  if ( delimiterstr.isEmpty() ) delimiterstr = ' ';
776  int delimiterlength = delimiterstr.length();
777 
778  QStringList lines = str.split( '\n' );
779  int strlength, strcurrent, strhit, lasthit;
780 
781  for ( int i = 0; i < lines.size(); i++ )
782  {
783  strlength = lines[i].length();
784  strcurrent = 0;
785  strhit = 0;
786  lasthit = 0;
787 
788  while ( strcurrent < strlength )
789  {
790  // positive wrap value = desired maximum line width to wrap
791  // negative wrap value = desired minimum line width before wrap
792  if ( wrap > 0 )
793  {
794  //first try to locate delimiter backwards
795  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
796  if ( strhit == lasthit || strhit == -1 )
797  {
798  //if no new backward delimiter found, try to locate forward
799  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
800  }
801  lasthit = strhit;
802  }
803  else
804  {
805  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
806  }
807  if ( strhit > -1 )
808  {
809  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
810  newstr.append( '\n' );
811  strcurrent = strhit + delimiterlength;
812  }
813  else
814  {
815  newstr.append( lines[i].midRef( strcurrent ) );
816  strcurrent = strlength;
817  }
818  }
819  if ( i < lines.size() - 1 ) newstr.append( '\n' );
820  }
821 
822  return QVariant( newstr );
823  }
824  }
825 
826  return QVariant();
827 }
828 
829 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
830 {
831  // two variants, one for geometry, one for string
832  if ( values.at( 0 ).canConvert<QgsGeometry>() )
833  {
834  //geometry variant
835  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
836  if ( geom.type() != QGis::Line )
837  return QVariant();
838 
839  return QVariant( geom.length() );
840  }
841 
842  //otherwise fall back to string variant
843  QString str = getStringValue( values.at( 0 ), parent );
844  return QVariant( str.length() );
845 }
846 
847 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
848 {
849  QString str = getStringValue( values.at( 0 ), parent );
850  QString before = getStringValue( values.at( 1 ), parent );
851  QString after = getStringValue( values.at( 2 ), parent );
852  return QVariant( str.replace( before, after ) );
853 }
854 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
855 {
856  QString str = getStringValue( values.at( 0 ), parent );
857  QString regexp = getStringValue( values.at( 1 ), parent );
858  QString after = getStringValue( values.at( 2 ), parent );
859 
860  QRegExp re( regexp );
861  if ( !re.isValid() )
862  {
863  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
864  return QVariant();
865  }
866  return QVariant( str.replace( re, after ) );
867 }
868 
869 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
870 {
871  QString str = getStringValue( values.at( 0 ), parent );
872  QString regexp = getStringValue( values.at( 1 ), parent );
873 
874  QRegExp re( regexp );
875  if ( !re.isValid() )
876  {
877  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
878  return QVariant();
879  }
880  return QVariant( str.contains( re ) ? 1 : 0 );
881 }
882 
883 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
884 {
885  QString str = getStringValue( values.at( 0 ), parent );
886  QString regexp = getStringValue( values.at( 1 ), parent );
887 
888  QRegExp re( regexp );
889  if ( !re.isValid() )
890  {
891  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
892  return QVariant();
893  }
894 
895  // extract substring
896  ( void )re.indexIn( str );
897  if ( re.captureCount() > 0 )
898  {
899  // return first capture
900  return QVariant( re.capturedTexts().at( 1 ) );
901  }
902  else
903  {
904  return QVariant( "" );
905  }
906 }
907 
908 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
909 {
910  return QUuid::createUuid().toString();
911 }
912 
913 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
914 {
915  QString str = getStringValue( values.at( 0 ), parent );
916  int from = getIntValue( values.at( 1 ), parent );
917  int len = getIntValue( values.at( 2 ), parent );
918  return QVariant( str.mid( from -1, len ) );
919 }
920 
921 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
922 {
923  if ( context && context->hasVariable( "row_number" ) )
924  return context->variable( "row_number" );
925 
927  return QVariant( parent->currentRowNumber() );
929  //when above is removed - return QVariant()
930 }
931 
932 static QVariant fcnMapId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
933 {
934  if ( context && context->hasVariable( "map_id" ) )
935  return context->variable( "map_id" );
936 
938  return QgsExpression::specialColumn( "$map" );
940 }
941 
942 static QVariant fcnComposerNumPages( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
943 {
944  if ( context && context->hasVariable( "layout_numpages" ) )
945  return context->variable( "layout_numpages" );
946 
948  return QgsExpression::specialColumn( "$numpages" );
950 }
951 
952 static QVariant fcnComposerPage( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
953 {
954  if ( context && context->hasVariable( "layout_page" ) )
955  return context->variable( "layout_page" );
956 
958  return QgsExpression::specialColumn( "$page" );
960 }
961 
962 static QVariant fcnAtlasFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
963 {
964  if ( context && context->hasVariable( "atlas_featurenumber" ) )
965  return context->variable( "atlas_featurenumber" );
966 
968  return QgsExpression::specialColumn( "$feature" );
970 }
971 
972 static QVariant fcnAtlasFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
973 {
974  if ( context && context->hasVariable( "atlas_featureid" ) )
975  return context->variable( "atlas_featureid" );
976 
978  return QgsExpression::specialColumn( "$atlasfeatureid" );
980 }
981 
982 
983 static QVariant fcnAtlasCurrentFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
984 {
985  if ( context && context->hasVariable( "atlas_feature" ) )
986  return context->variable( "atlas_feature" );
987 
989  return QgsExpression::specialColumn( "$atlasfeature" );
991 }
992 
993 static QVariant fcnAtlasCurrentGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
994 {
995  if ( context && context->hasVariable( "atlas_geometry" ) )
996  return context->variable( "atlas_geometry" );
997 
999  return QgsExpression::specialColumn( "$atlasgeometry" );
1001 }
1002 
1003 static QVariant fcnAtlasNumFeatures( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1004 {
1005  if ( context && context->hasVariable( "atlas_totalfeatures" ) )
1006  return context->variable( "atlas_totalfeatures" );
1007 
1009  return QgsExpression::specialColumn( "$numfeatures" );
1011 }
1012 
1013 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
1014  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
1015 
1016 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1017 {
1018  FEAT_FROM_CONTEXT( context, f );
1019  // TODO: handling of 64-bit feature ids?
1020  return QVariant( static_cast< int >( f.id() ) );
1021 }
1022 
1023 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1024 {
1025  if ( !context )
1026  return QVariant();
1027 
1028  return context->variable( QgsExpressionContext::EXPR_FEATURE );
1029 }
1030 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1031 {
1032  QgsFeature feat = getFeature( values.at( 0 ), parent );
1033  QString attr = getStringValue( values.at( 1 ), parent );
1034 
1035  return feat.attribute( attr );
1036 }
1037 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1038 {
1039  QString concat;
1040  Q_FOREACH ( const QVariant &value, values )
1041  {
1042  concat += getStringValue( value, parent );
1043  }
1044  return concat;
1045 }
1046 
1047 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1048 {
1049  QString string = getStringValue( values.at( 0 ), parent );
1050  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) ) + 1;
1051 }
1052 
1053 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1054 {
1055  QString string = getStringValue( values.at( 0 ), parent );
1056  int pos = getIntValue( values.at( 1 ), parent );
1057  return string.right( pos );
1058 }
1059 
1060 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1061 {
1062  QString string = getStringValue( values.at( 0 ), parent );
1063  int pos = getIntValue( values.at( 1 ), parent );
1064  return string.left( pos );
1065 }
1066 
1067 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1068 {
1069  QString string = getStringValue( values.at( 0 ), parent );
1070  int length = getIntValue( values.at( 1 ), parent );
1071  QString fill = getStringValue( values.at( 2 ), parent );
1072  return string.leftJustified( length, fill.at( 0 ), true );
1073 }
1074 
1075 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1076 {
1077  QString string = getStringValue( values.at( 0 ), parent );
1078  int length = getIntValue( values.at( 1 ), parent );
1079  QString fill = getStringValue( values.at( 2 ), parent );
1080  return string.rightJustified( length, fill.at( 0 ), true );
1081 }
1082 
1083 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1084 {
1085  QString string = getStringValue( values.at( 0 ), parent );
1086  for ( int n = 1; n < values.length(); n++ )
1087  {
1088  string = string.arg( getStringValue( values.at( n ), parent ) );
1089  }
1090  return string;
1091 }
1092 
1093 
1094 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1095 {
1097 }
1098 
1099 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1100 {
1101  return QVariant( getDateValue( values.at( 0 ), parent ) );
1102 }
1103 
1104 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1105 {
1106  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1107 }
1108 
1109 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1110 {
1111  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1112 }
1113 
1114 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1115 {
1116  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1117  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1118  int seconds = d2.secsTo( d1 );
1119  return QVariant::fromValue( QgsExpression::Interval( seconds ) );
1120 }
1121 
1122 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1123 {
1124  if ( !values.at( 0 ).canConvert<QDate>() )
1125  return QVariant();
1126 
1127  QDate date = getDateValue( values.at( 0 ), parent );
1128  if ( !date.isValid() )
1129  return QVariant();
1130 
1131  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1132  // (to match PostgreSQL behaviour)
1133  return date.dayOfWeek() % 7;
1134 }
1135 
1136 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1137 {
1138  QVariant value = values.at( 0 );
1139  QgsExpression::Interval inter = getInterval( value, parent, false );
1140  if ( inter.isValid() )
1141  {
1142  return QVariant( inter.days() );
1143  }
1144  else
1145  {
1146  QDateTime d1 = getDateTimeValue( value, parent );
1147  return QVariant( d1.date().day() );
1148  }
1149 }
1150 
1151 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1152 {
1153  QVariant value = values.at( 0 );
1154  QgsExpression::Interval inter = getInterval( value, parent, false );
1155  if ( inter.isValid() )
1156  {
1157  return QVariant( inter.years() );
1158  }
1159  else
1160  {
1161  QDateTime d1 = getDateTimeValue( value, parent );
1162  return QVariant( d1.date().year() );
1163  }
1164 }
1165 
1166 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1167 {
1168  QVariant value = values.at( 0 );
1169  QgsExpression::Interval inter = getInterval( value, parent, false );
1170  if ( inter.isValid() )
1171  {
1172  return QVariant( inter.months() );
1173  }
1174  else
1175  {
1176  QDateTime d1 = getDateTimeValue( value, parent );
1177  return QVariant( d1.date().month() );
1178  }
1179 }
1180 
1181 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1182 {
1183  QVariant value = values.at( 0 );
1184  QgsExpression::Interval inter = getInterval( value, parent, false );
1185  if ( inter.isValid() )
1186  {
1187  return QVariant( inter.weeks() );
1188  }
1189  else
1190  {
1191  QDateTime d1 = getDateTimeValue( value, parent );
1192  return QVariant( d1.date().weekNumber() );
1193  }
1194 }
1195 
1196 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1197 {
1198  QVariant value = values.at( 0 );
1199  QgsExpression::Interval inter = getInterval( value, parent, false );
1200  if ( inter.isValid() )
1201  {
1202  return QVariant( inter.hours() );
1203  }
1204  else
1205  {
1206  QTime t1 = getTimeValue( value, parent );
1207  return QVariant( t1.hour() );
1208  }
1209 }
1210 
1211 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1212 {
1213  QVariant value = values.at( 0 );
1214  QgsExpression::Interval inter = getInterval( value, parent, false );
1215  if ( inter.isValid() )
1216  {
1217  return QVariant( inter.minutes() );
1218  }
1219  else
1220  {
1221  QTime t1 = getTimeValue( value, parent );
1222  return QVariant( t1.minute() );
1223  }
1224 }
1225 
1226 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1227 {
1228  QVariant value = values.at( 0 );
1229  QgsExpression::Interval inter = getInterval( value, parent, false );
1230  if ( inter.isValid() )
1231  {
1232  return QVariant( inter.seconds() );
1233  }
1234  else
1235  {
1236  QTime t1 = getTimeValue( value, parent );
1237  return QVariant( t1.second() );
1238  }
1239 }
1240 
1241 
1242 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1243  if (!g || g->type() != geomtype) return QVariant();
1244 
1245 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1246 {
1247  FEAT_FROM_CONTEXT( context, f );
1248  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1249  if ( g->isMultipart() )
1250  {
1251  return g->asMultiPoint().at( 0 ).x();
1252  }
1253  else
1254  {
1255  return g->asPoint().x();
1256  }
1257 }
1258 
1259 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1260 {
1261  FEAT_FROM_CONTEXT( context, f );
1262  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1263  if ( g->isMultipart() )
1264  {
1265  return g->asMultiPoint().at( 0 ).y();
1266  }
1267  else
1268  {
1269  return g->asPoint().y();
1270  }
1271 }
1272 
1273 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1274 {
1275  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1276  if ( geom.isEmpty() )
1277  return QVariant();
1278 
1279  //if single point, return the point's x coordinate
1280  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1281  {
1282  return geom.asPoint().x();
1283  }
1284 
1285  //otherwise return centroid x
1286  QgsGeometry* centroid = geom.centroid();
1287  QVariant result( centroid->asPoint().x() );
1288  delete centroid;
1289  return result;
1290 }
1291 
1292 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1293 {
1294  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1295  if ( geom.isEmpty() )
1296  return QVariant();
1297 
1298  //if single point, return the point's y coordinate
1299  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1300  {
1301  return geom.asPoint().y();
1302  }
1303 
1304  //otherwise return centroid y
1305  QgsGeometry* centroid = geom.centroid();
1306  QVariant result( centroid->asPoint().y() );
1307  delete centroid;
1308  return result;
1309 }
1310 
1311 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1312 {
1313  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1314  if ( geom.isEmpty() )
1315  return QVariant(); //or 0?
1316 
1317  //if single point, return the point's z coordinate
1318  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1319  {
1320  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1321  if ( point )
1322  return point->z();
1323  }
1324 
1325  return QVariant();
1326 }
1327 
1328 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1329 {
1330  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1331  if ( geom.isEmpty() )
1332  return QVariant(); //or 0?
1333 
1334  //if single point, return the point's m value
1335  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1336  {
1337  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1338  if ( point )
1339  return point->m();
1340  }
1341 
1342  return QVariant();
1343 }
1344 
1345 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1346 {
1347  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1348 
1349  if ( geom.isEmpty() )
1350  return QVariant();
1351 
1352  //idx is 1 based
1353  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1354 
1355  QgsVertexId vId;
1356  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1357  {
1358  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1359  return QVariant();
1360  }
1361 
1362  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1363  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1364 }
1365 
1366 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1367 {
1368  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1369 
1370  if ( geom.isEmpty() )
1371  return QVariant();
1372 
1373  QgsVertexId vId;
1374  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1375  {
1376  return QVariant();
1377  }
1378 
1379  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1380  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1381 }
1382 
1383 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1384 {
1385  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1386 
1387  if ( geom.isEmpty() )
1388  return QVariant();
1389 
1390  QgsVertexId vId;
1391  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1392  {
1393  return QVariant();
1394  }
1395 
1396  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1397  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1398 }
1399 
1400 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1401 {
1402  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1403 
1404  if ( geom.isEmpty() )
1405  return QVariant();
1406 
1407  bool ignoreClosing = false;
1408  if ( values.length() > 1 )
1409  {
1410  ignoreClosing = getIntValue( values.at( 1 ), parent );
1411  }
1412 
1413  QgsMultiPointV2* mp = new QgsMultiPointV2();
1414 
1415  Q_FOREACH ( const QgsRingSequenceV2 &part, geom.geometry()->coordinateSequence() )
1416  {
1417  Q_FOREACH ( const QgsPointSequenceV2 &ring, part )
1418  {
1419  bool skipLast = false;
1420  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1421  {
1422  skipLast = true;
1423  }
1424 
1425  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1426  {
1427  mp->addGeometry( ring.at( i ).clone() );
1428  }
1429  }
1430  }
1431 
1432  return QVariant::fromValue( QgsGeometry( mp ) );
1433 }
1434 
1435 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1436 {
1437  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1438 
1439  if ( geom.isEmpty() )
1440  return QVariant();
1441 
1443 
1444  //ok, now we have a complete list of segmentized lines from the geometry
1446  Q_FOREACH ( QgsLineStringV2* line, linesToProcess )
1447  {
1448  for ( int i = 0; i < line->numPoints() - 1; ++i )
1449  {
1450  QgsLineStringV2* segment = new QgsLineStringV2();
1451  segment->setPoints( QgsPointSequenceV2()
1452  << line->pointN( i )
1453  << line->pointN( i + 1 ) );
1454  ml->addGeometry( segment );
1455  }
1456  delete line;
1457  }
1458 
1459  return QVariant::fromValue( QgsGeometry( ml ) );
1460 }
1461 
1462 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1463 {
1464  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1465 
1466  if ( geom.isEmpty() )
1467  return QVariant();
1468 
1469  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1470  if ( !curvePolygon )
1471  return QVariant();
1472 
1473  //idx is 1 based
1474  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1475 
1476  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1477  return QVariant();
1478 
1479  QgsCurveV2* curve = static_cast< QgsCurveV2* >( curvePolygon->interiorRing( idx )->clone() );
1480  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1481  return result;
1482 }
1483 
1484 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1485 {
1486  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1487 
1488  if ( geom.isEmpty() )
1489  return QVariant();
1490 
1491  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1492  if ( !collection )
1493  return QVariant();
1494 
1495  //idx is 1 based
1496  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1497 
1498  if ( idx < 0 || idx >= collection->numGeometries() )
1499  return QVariant();
1500 
1501  QgsAbstractGeometryV2* part = collection->geometryN( idx )->clone();
1502  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
1503  return result;
1504 }
1505 
1506 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1507 {
1508  if ( values.count() < 2 || values.count() > 4 )
1509  {
1510  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
1511  return QVariant();
1512  }
1513 
1514  double x = getDoubleValue( values.at( 0 ), parent );
1515  double y = getDoubleValue( values.at( 1 ), parent );
1516  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
1517  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
1518  switch ( values.count() )
1519  {
1520  case 2:
1521  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1522  case 3:
1523  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
1524  case 4:
1525  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
1526  }
1527  return QVariant(); //avoid warning
1528 }
1529 
1530 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1531 {
1532  double x = getDoubleValue( values.at( 0 ), parent );
1533  double y = getDoubleValue( values.at( 1 ), parent );
1534  double m = getDoubleValue( values.at( 2 ), parent );
1535  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
1536 }
1537 
1538 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1539 {
1540  if ( values.count() < 2 )
1541  {
1542  return QVariant();
1543  }
1544 
1545  QgsLineStringV2* lineString = new QgsLineStringV2();
1546  lineString->clear();
1547 
1548  Q_FOREACH ( const QVariant& value, values )
1549  {
1550  QgsGeometry geom = getGeometry( value, parent );
1551  if ( geom.isEmpty() )
1552  continue;
1553 
1554  if ( geom.type() != QGis::Point || geom.isMultipart() )
1555  continue;
1556 
1557  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1558  if ( !point )
1559  continue;
1560 
1561  lineString->addVertex( *point );
1562  }
1563 
1564  return QVariant::fromValue( QgsGeometry( lineString ) );
1565 }
1566 
1567 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1568 {
1569  if ( values.count() < 1 )
1570  {
1571  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
1572  return QVariant();
1573  }
1574 
1575  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
1576  if ( outerRing.type() != QGis::Line || outerRing.isMultipart() || outerRing.isEmpty() )
1577  return QVariant();
1578 
1579  QgsPolygonV2* polygon = new QgsPolygonV2();
1580  polygon->setExteriorRing( dynamic_cast< QgsCurveV2* >( outerRing.geometry()->clone() ) );
1581 
1582  for ( int i = 1; i < values.count(); ++i )
1583  {
1584  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
1585  if ( ringGeom.isEmpty() )
1586  continue;
1587 
1588  if ( ringGeom.type() != QGis::Line || ringGeom.isMultipart() || ringGeom.isEmpty() )
1589  continue;
1590 
1591  polygon->addInteriorRing( dynamic_cast< QgsCurveV2* >( ringGeom.geometry()->clone() ) );
1592  }
1593 
1594  return QVariant::fromValue( QgsGeometry( polygon ) );
1595 }
1596 
1597 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1598 {
1599  FEAT_FROM_CONTEXT( context, f );
1600  int idx = getIntValue( values.at( 0 ), parent );
1601  const QgsGeometry* g = f.constGeometry();
1602  if ( !g || g->isEmpty() )
1603  return QVariant();
1604 
1605  if ( idx < 0 )
1606  {
1607  idx += g->geometry()->nCoordinates();
1608  }
1609  if ( idx < 0 || idx >= g->geometry()->nCoordinates() )
1610  {
1611  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1612  return QVariant();
1613  }
1614 
1615  QgsPoint p = g->vertexAt( idx );
1616  return QVariant( QPointF( p.x(), p.y() ) );
1617 }
1618 
1619 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1620 {
1621  QVariant v = pointAt( values, f, parent );
1622  if ( v.type() == QVariant::PointF )
1623  return QVariant( v.toPointF().x() );
1624  else
1625  return QVariant();
1626 }
1627 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1628 {
1629  QVariant v = pointAt( values, f, parent );
1630  if ( v.type() == QVariant::PointF )
1631  return QVariant( v.toPointF().y() );
1632  else
1633  return QVariant();
1634 }
1635 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1636 {
1637  FEAT_FROM_CONTEXT( context, f );
1638  const QgsGeometry* geom = f.constGeometry();
1639  if ( geom )
1640  return QVariant::fromValue( *geom );
1641  else
1642  return QVariant();
1643 }
1644 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1645 {
1646  QString wkt = getStringValue( values.at( 0 ), parent );
1647  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1648  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1649  delete geom;
1650  return result;
1651 }
1652 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1653 {
1654  QString gml = getStringValue( values.at( 0 ), parent );
1656  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1657  delete geom;
1658  return result;
1659 }
1660 
1661 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1662 {
1663  FEAT_FROM_CONTEXT( context, f );
1665  QgsDistanceArea* calc = parent->geomCalculator();
1666  if ( calc )
1667  {
1668  double area = calc->measureArea( f.constGeometry() );
1669  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
1670  return QVariant( area );
1671  }
1672  else
1673  {
1674  return QVariant( f.constGeometry()->area() );
1675  }
1676 }
1677 
1678 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1679 {
1680  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1681 
1682  if ( geom.type() != QGis::Polygon )
1683  return QVariant();
1684 
1685  return QVariant( geom.area() );
1686 }
1687 
1688 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1689 {
1690  FEAT_FROM_CONTEXT( context, f );
1691  ENSURE_GEOM_TYPE( f, g, QGis::Line );
1692  QgsDistanceArea* calc = parent->geomCalculator();
1693  if ( calc )
1694  {
1695  double len = calc->measureLength( f.constGeometry() );
1696  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
1697  return QVariant( len );
1698  }
1699  else
1700  {
1701  return QVariant( f.constGeometry()->length() );
1702  }
1703 }
1704 
1705 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1706 {
1707  FEAT_FROM_CONTEXT( context, f );
1709  QgsDistanceArea* calc = parent->geomCalculator();
1710  if ( calc )
1711  {
1712  double len = calc->measurePerimeter( f.constGeometry() );
1713  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
1714  return QVariant( len );
1715  }
1716  else
1717  {
1718  return f.constGeometry()->isEmpty() ? QVariant( 0 ) : QVariant( f.constGeometry()->geometry()->perimeter() );
1719  }
1720 }
1721 
1722 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1723 {
1724  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1725 
1726  if ( geom.type() != QGis::Polygon )
1727  return QVariant();
1728 
1729  //length for polygons = perimeter
1730  return QVariant( geom.length() );
1731 }
1732 
1733 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1734 {
1735  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1736  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
1737 }
1738 
1739 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1740 {
1741  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1742  if ( geom.isEmpty() )
1743  return QVariant();
1744 
1745  return QVariant( geom.geometry()->partCount() );
1746 }
1747 
1748 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1749 {
1750  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1751 
1752  if ( geom.isEmpty() )
1753  return QVariant();
1754 
1755  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1756  if ( curvePolygon )
1757  return QVariant( curvePolygon->numInteriorRings() );
1758 
1759  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1760  if ( collection )
1761  {
1762  //find first CurvePolygon in collection
1763  for ( int i = 0; i < collection->numGeometries(); ++i )
1764  {
1765  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
1766  if ( !curvePolygon )
1767  continue;
1768 
1769  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
1770  }
1771  }
1772 
1773  return QVariant();
1774 }
1775 
1776 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1777 {
1778  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1779 
1780  if ( geom.isEmpty() )
1781  return QVariant();
1782 
1783  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1784  if ( curvePolygon )
1785  return QVariant( curvePolygon->ringCount() );
1786 
1787  bool foundPoly = false;
1788  int ringCount = 0;
1789  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1790  if ( collection )
1791  {
1792  //find CurvePolygons in collection
1793  for ( int i = 0; i < collection->numGeometries(); ++i )
1794  {
1795  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
1796  if ( !curvePolygon )
1797  continue;
1798 
1799  foundPoly = true;
1800  ringCount += curvePolygon->ringCount();
1801  }
1802  }
1803 
1804  if ( !foundPoly )
1805  return QVariant();
1806 
1807  return QVariant( ringCount );
1808 }
1809 
1810 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1811 {
1812  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1813  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
1814  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
1815  delete geomBounds;
1816  return result;
1817 }
1818 
1819 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1820 {
1821  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1822  return QVariant::fromValue( geom.boundingBox().width() );
1823 }
1824 
1825 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1826 {
1827  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1828  return QVariant::fromValue( geom.boundingBox().height() );
1829 }
1830 
1831 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1832 {
1833  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1834  return QVariant::fromValue( geom.boundingBox().xMinimum() );
1835 }
1836 
1837 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1838 {
1839  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1840  return QVariant::fromValue( geom.boundingBox().xMaximum() );
1841 }
1842 
1843 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1844 {
1845  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1846  return QVariant::fromValue( geom.boundingBox().yMinimum() );
1847 }
1848 
1849 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1850 {
1851  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1852  return QVariant::fromValue( geom.boundingBox().yMaximum() );
1853 }
1854 
1855 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1856 {
1857  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1858  if ( fGeom.isEmpty() )
1859  return QVariant();
1860 
1861  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
1862  if ( !curve )
1863  return QVariant();
1864 
1865  return QVariant::fromValue( curve->isClosed() );
1866 }
1867 
1868 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1869 {
1870  if ( values.length() < 2 || values.length() > 3 )
1871  return QVariant();
1872 
1873  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1874  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1875 
1876  if ( fGeom.isEmpty() || sGeom.isEmpty() )
1877  return QVariant();
1878 
1880 
1881  if ( values.length() == 2 )
1882  {
1883  //two geometry arguments, return relation
1884  QString result = engine->relate( *sGeom.geometry() );
1885  return QVariant::fromValue( result );
1886  }
1887  else
1888  {
1889  //three arguments, test pattern
1890  QString pattern = getStringValue( values.at( 2 ), parent );
1891  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
1892  return QVariant::fromValue( result );
1893  }
1894 }
1895 
1896 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1897 {
1898  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1899  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1900  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
1901 }
1902 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1903 {
1904  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1905  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1906  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
1907 }
1908 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1909 {
1910  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1911  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1912  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
1913 }
1914 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1915 {
1916  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1917  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1918  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
1919 }
1920 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1921 {
1922  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1923  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1924  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
1925 }
1926 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1927 {
1928  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1929  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1930  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
1931 }
1932 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1933 {
1934  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1935  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1936  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
1937 }
1938 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1939 {
1940  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1941  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1942  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
1943 }
1944 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1945 {
1946  if ( values.length() < 2 || values.length() > 3 )
1947  return QVariant();
1948 
1949  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1950  double dist = getDoubleValue( values.at( 1 ), parent );
1951  int seg = 8;
1952  if ( values.length() == 3 )
1953  seg = getIntValue( values.at( 2 ), parent );
1954 
1955  QgsGeometry* geom = fGeom.buffer( dist, seg );
1956  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1957  delete geom;
1958  return result;
1959 }
1960 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1961 {
1962  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1963  double dx = getDoubleValue( values.at( 1 ), parent );
1964  double dy = getDoubleValue( values.at( 2 ), parent );
1965  fGeom.translate( dx, dy );
1966  return QVariant::fromValue( fGeom );
1967 }
1968 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1969 {
1970  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1971  QgsGeometry* geom = fGeom.centroid();
1972  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1973  delete geom;
1974  return result;
1975 }
1976 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1977 {
1978  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1979  QgsGeometry* geom = fGeom.pointOnSurface();
1980  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1981  delete geom;
1982  return result;
1983 }
1984 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1985 {
1986  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1987  QgsGeometry* geom = fGeom.convexHull();
1988  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1989  delete geom;
1990  return result;
1991 }
1992 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1993 {
1994  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
1995  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
1996  QgsGeometry* geom = fGeom.difference( &sGeom );
1997  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
1998  delete geom;
1999  return result;
2000 }
2001 
2002 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2003 {
2004  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2005  if ( fGeom.isEmpty() )
2006  return QVariant();
2007 
2008  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2009  if ( !curve )
2010  return QVariant();
2011 
2012  QgsCurveV2* reversed = curve->reversed();
2013  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2014  return result;
2015 }
2016 
2017 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2018 {
2019  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2020  if ( fGeom.isEmpty() )
2021  return QVariant();
2022 
2023  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( fGeom.geometry() );
2024  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2025  return QVariant();
2026 
2027  QgsCurveV2* exterior = static_cast< QgsCurveV2* >( curvePolygon->exteriorRing()->clone() );
2028  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2029  return result;
2030 }
2031 
2032 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2033 {
2034  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2035  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2036  return QVariant( fGeom.distance( sGeom ) );
2037 }
2038 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2039 {
2040  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2041  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2042  QgsGeometry* geom = fGeom.intersection( &sGeom );
2043  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2044  delete geom;
2045  return result;
2046 }
2047 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2048 {
2049  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2050  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2051  QgsGeometry* geom = fGeom.symDifference( &sGeom );
2052  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2053  delete geom;
2054  return result;
2055 }
2056 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2057 {
2058  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2059  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2060  QgsGeometry* geom = fGeom.combine( &sGeom );
2061  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2062  delete geom;
2063  return result;
2064 }
2065 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2066 {
2067  if ( values.length() < 1 || values.length() > 2 )
2068  return QVariant();
2069 
2070  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2071  int prec = 8;
2072  if ( values.length() == 2 )
2073  prec = getIntValue( values.at( 1 ), parent );
2074  QString wkt = fGeom.exportToWkt( prec );
2075  return QVariant( wkt );
2076 }
2077 
2078 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2079 {
2080  if ( values.length() != 2 )
2081  {
2082  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2083  return QVariant();
2084  }
2085 
2086  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2087  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2088 
2089  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2090  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2091 
2092  if ( !pt1 || !pt2 )
2093  {
2094  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2095  return QVariant();
2096  }
2097 
2098  // Code from postgis
2099  if ( pt1->x() == pt2->x() )
2100  {
2101  if ( pt1->y() < pt2->y() )
2102  return 0.0;
2103  else if ( pt1->y() > pt2->y() )
2104  return M_PI;
2105  else
2106  return 0;
2107  }
2108 
2109  if ( pt1->y() == pt2->y() )
2110  {
2111  if ( pt1->x() < pt2->x() )
2112  return M_PI / 2;
2113  else if ( pt1->x() > pt2->x() )
2114  return M_PI + ( M_PI / 2 );
2115  else
2116  return 0;
2117  }
2118 
2119  if ( pt1->x() < pt2->x() )
2120  {
2121  if ( pt1->y() < pt2->y() )
2122  {
2123  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2124  }
2125  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2126  {
2127  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2128  + ( M_PI / 2 );
2129  }
2130  }
2131 
2132  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2133  {
2134  if ( pt1->y() > pt2->y() )
2135  {
2136  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2137  + M_PI;
2138  }
2139  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2140  {
2141  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2142  + ( M_PI + ( M_PI / 2 ) );
2143  }
2144  }
2145 }
2146 
2147 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2148 {
2149  if ( values.length() != 3 )
2150  return QVariant();
2151 
2152  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2153  double x = getDoubleValue( values.at( 1 ), parent );
2154  double y = getDoubleValue( values.at( 2 ), parent );
2155 
2156  QgsGeometry geom = fGeom.extrude( x, y );
2157 
2158  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2159  return result;
2160 }
2161 
2162 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2163 {
2164  if ( values.length() < 2 )
2165  return QVariant();
2166 
2167  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2168 
2169  if ( !fGeom.isMultipart() )
2170  return values.at( 0 );
2171 
2172  QString expString = getStringValue( values.at( 1 ), parent );
2173  bool asc = values.value( 2 ).toBool();
2174 
2175  QgsExpressionContext* unconstedContext;
2176  QgsFeature f;
2177  if ( ctx )
2178  {
2179  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2180  // so no reason to worry
2181  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2182  f = ctx->feature();
2183  }
2184  else
2185  {
2186  // If there's no context provided, create a fake one
2187  unconstedContext = new QgsExpressionContext();
2188  }
2189 
2190  QgsGeometryCollectionV2* collection = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry() );
2191  Q_ASSERT( collection ); // Should have failed the multipart check above
2192 
2194  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2195  QgsExpressionSorter sorter( orderBy );
2196 
2197  QList<QgsFeature> partFeatures;
2198  for ( int i = 0; i < collection->partCount(); ++i )
2199  {
2200  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2201  partFeatures << f;
2202  }
2203 
2204  sorter.sortFeatures( partFeatures, unconstedContext );
2205 
2206  QgsGeometryCollectionV2* orderedGeom = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry()->clone() );
2207 
2208  Q_ASSERT( orderedGeom );
2209 
2210  while ( orderedGeom->partCount() )
2211  orderedGeom->removeGeometry( 0 );
2212 
2213  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2214  {
2215  orderedGeom->addGeometry( feature.constGeometry()->geometry()->clone() );
2216  }
2217 
2218  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2219 
2220  if ( !ctx )
2221  delete unconstedContext;
2222 
2223  return result;
2224 }
2225 
2226 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2227 {
2228  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2229  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2230 
2231  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2232 
2233  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2234  return result;
2235 }
2236 
2237 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2238 {
2239  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2240  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2241 
2242  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2243 
2244  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2245  return result;
2246 }
2247 
2248 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2249 {
2250  if ( values.length() == 2 )
2251  {
2252  double number = getDoubleValue( values.at( 0 ), parent );
2253  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2254  return QVariant( qRound( number * scaler ) / scaler );
2255  }
2256 
2257  if ( values.length() == 1 )
2258  {
2259  double number = getIntValue( values.at( 0 ), parent );
2260  return QVariant( qRound( number ) ).toInt();
2261  }
2262 
2263  return QVariant();
2264 }
2265 
2266 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2267 {
2268  Q_UNUSED( values );
2269  Q_UNUSED( parent );
2270  return M_PI;
2271 }
2272 
2273 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
2274 {
2275  return QVariant( parent->scale() );
2276 }
2277 
2278 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2279 {
2280  double value = getDoubleValue( values.at( 0 ), parent );
2281  int places = getIntValue( values.at( 1 ), parent );
2282  if ( places < 0 )
2283  {
2284  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2285  return QVariant();
2286  }
2287  return QString( "%L1" ).arg( value, 0, 'f', places );
2288 }
2289 
2290 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2291 {
2292  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2293  QString format = getStringValue( values.at( 1 ), parent );
2294  return dt.toString( format );
2295 }
2296 
2297 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2298 {
2299  int red = getIntValue( values.at( 0 ), parent );
2300  int green = getIntValue( values.at( 1 ), parent );
2301  int blue = getIntValue( values.at( 2 ), parent );
2302  QColor color = QColor( red, green, blue );
2303  if ( ! color.isValid() )
2304  {
2305  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
2306  color = QColor( 0, 0, 0 );
2307  }
2308 
2309  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2310 }
2311 
2312 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
2313 {
2314  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
2316  QVariant value = node->eval( parent, context );
2318  if ( value.toBool() )
2319  {
2320  node = getNode( values.at( 1 ), parent );
2322  value = node->eval( parent, context );
2324  }
2325  else
2326  {
2327  node = getNode( values.at( 2 ), parent );
2329  value = node->eval( parent, context );
2331  }
2332  return value;
2333 }
2334 
2335 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2336 {
2337  int red = getIntValue( values.at( 0 ), parent );
2338  int green = getIntValue( values.at( 1 ), parent );
2339  int blue = getIntValue( values.at( 2 ), parent );
2340  int alpha = getIntValue( values.at( 3 ), parent );
2341  QColor color = QColor( red, green, blue, alpha );
2342  if ( ! color.isValid() )
2343  {
2344  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
2345  color = QColor( 0, 0, 0 );
2346  }
2347  return QgsSymbolLayerV2Utils::encodeColor( color );
2348 }
2349 
2350 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2351 {
2352  QString rampName = getStringValue( values.at( 0 ), parent );
2353  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
2354  if ( ! mRamp )
2355  {
2356  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2357  return QColor( 0, 0, 0 ).name();
2358  }
2359  double value = getDoubleValue( values.at( 1 ), parent );
2360  QColor color = mRamp->color( value );
2361  return QgsSymbolLayerV2Utils::encodeColor( color );
2362 }
2363 
2364 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2365 {
2366  // Hue ranges from 0 - 360
2367  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2368  // Saturation ranges from 0 - 100
2369  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2370  // Lightness ranges from 0 - 100
2371  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2372 
2373  QColor color = QColor::fromHslF( hue, saturation, lightness );
2374 
2375  if ( ! color.isValid() )
2376  {
2377  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
2378  color = QColor( 0, 0, 0 );
2379  }
2380 
2381  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2382 }
2383 
2384 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2385 {
2386  // Hue ranges from 0 - 360
2387  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2388  // Saturation ranges from 0 - 100
2389  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2390  // Lightness ranges from 0 - 100
2391  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2392  // Alpha ranges from 0 - 255
2393  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2394 
2395  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
2396  if ( ! color.isValid() )
2397  {
2398  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
2399  color = QColor( 0, 0, 0 );
2400  }
2401  return QgsSymbolLayerV2Utils::encodeColor( color );
2402 }
2403 
2404 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2405 {
2406  // Hue ranges from 0 - 360
2407  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2408  // Saturation ranges from 0 - 100
2409  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2410  // Value ranges from 0 - 100
2411  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2412 
2413  QColor color = QColor::fromHsvF( hue, saturation, value );
2414 
2415  if ( ! color.isValid() )
2416  {
2417  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
2418  color = QColor( 0, 0, 0 );
2419  }
2420 
2421  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2422 }
2423 
2424 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2425 {
2426  // Hue ranges from 0 - 360
2427  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2428  // Saturation ranges from 0 - 100
2429  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2430  // Value ranges from 0 - 100
2431  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2432  // Alpha ranges from 0 - 255
2433  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2434 
2435  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
2436  if ( ! color.isValid() )
2437  {
2438  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
2439  color = QColor( 0, 0, 0 );
2440  }
2441  return QgsSymbolLayerV2Utils::encodeColor( color );
2442 }
2443 
2444 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2445 {
2446  // Cyan ranges from 0 - 100
2447  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2448  // Magenta ranges from 0 - 100
2449  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2450  // Yellow ranges from 0 - 100
2451  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2452  // Black ranges from 0 - 100
2453  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2454 
2455  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
2456 
2457  if ( ! color.isValid() )
2458  {
2459  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
2460  color = QColor( 0, 0, 0 );
2461  }
2462 
2463  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2464 }
2465 
2466 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2467 {
2468  // Cyan ranges from 0 - 100
2469  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2470  // Magenta ranges from 0 - 100
2471  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2472  // Yellow ranges from 0 - 100
2473  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2474  // Black ranges from 0 - 100
2475  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2476  // Alpha ranges from 0 - 255
2477  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
2478 
2479  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
2480  if ( ! color.isValid() )
2481  {
2482  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
2483  color = QColor( 0, 0, 0 );
2484  }
2485  return QgsSymbolLayerV2Utils::encodeColor( color );
2486 }
2487 
2488 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2489 {
2490  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2491  if ( ! color.isValid() )
2492  {
2493  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2494  return QVariant();
2495  }
2496 
2497  QString part = getStringValue( values.at( 1 ), parent );
2498  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2499  return color.red();
2500  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2501  return color.green();
2502  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2503  return color.blue();
2504  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2505  return color.alpha();
2506  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2507  return color.hsvHueF() * 360;
2508  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2509  return color.hsvSaturationF() * 100;
2510  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2511  return color.valueF() * 100;
2512  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2513  return color.hslHueF() * 360;
2514  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2515  return color.hslSaturationF() * 100;
2516  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2517  return color.lightnessF() * 100;
2518  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2519  return color.cyanF() * 100;
2520  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2521  return color.magentaF() * 100;
2522  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2523  return color.yellowF() * 100;
2524  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2525  return color.blackF() * 100;
2526 
2527  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2528  return QVariant();
2529 }
2530 
2531 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2532 {
2533  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2534  if ( ! color.isValid() )
2535  {
2536  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2537  return QVariant();
2538  }
2539 
2540  QString part = getStringValue( values.at( 1 ), parent );
2541  int value = getIntValue( values.at( 2 ), parent );
2542  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2543  color.setRed( value );
2544  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2545  color.setGreen( value );
2546  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2547  color.setBlue( value );
2548  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2549  color.setAlpha( value );
2550  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2551  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
2552  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2553  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
2554  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2555  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
2556  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2557  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
2558  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2559  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
2560  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2561  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
2562  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2563  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
2564  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2565  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
2566  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2567  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
2568  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2569  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
2570  else
2571  {
2572  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2573  return QVariant();
2574  }
2575  return QgsSymbolLayerV2Utils::encodeColor( color );
2576 }
2577 
2578 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2579 {
2580  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2581  if ( ! color.isValid() )
2582  {
2583  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2584  return QVariant();
2585  }
2586 
2587  color = color.darker( getIntValue( values.at( 1 ), parent ) );
2588 
2589  return QgsSymbolLayerV2Utils::encodeColor( color );
2590 }
2591 
2592 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2593 {
2594  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2595  if ( ! color.isValid() )
2596  {
2597  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2598  return QVariant();
2599  }
2600 
2601  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
2602 
2603  return QgsSymbolLayerV2Utils::encodeColor( color );
2604 }
2605 
2606 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2607 {
2608  QString varName = getStringValue( values.at( 0 ), parent );
2610  return QgsExpression::specialColumn( varName );
2612 }
2613 
2614 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2615 {
2616  QgsFeature feat = getFeature( values.at( 0 ), parent );
2617  const QgsGeometry* geom = feat.constGeometry();
2618  if ( geom )
2619  return QVariant::fromValue( *geom );
2620  return QVariant();
2621 }
2622 
2623 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2624 {
2625  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2626  QString sAuthId = getStringValue( values.at( 1 ), parent );
2627  QString dAuthId = getStringValue( values.at( 2 ), parent );
2628 
2630  if ( ! s.createFromOgcWmsCrs( sAuthId ) )
2631  return QVariant::fromValue( fGeom );
2633  if ( ! d.createFromOgcWmsCrs( dAuthId ) )
2634  return QVariant::fromValue( fGeom );
2635 
2636  QgsCoordinateTransform t( s, d );
2637  if ( fGeom.transform( t ) == 0 )
2638  return QVariant::fromValue( fGeom );
2639  return QVariant();
2640 }
2641 
2642 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2643 {
2644  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
2645  QString layerString = getStringValue( values.at( 0 ), parent );
2646  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
2647  if ( !vl )
2648  {
2649  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
2650  if ( !layersByName.isEmpty() )
2651  {
2652  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
2653  }
2654  }
2655 
2656  //no layer found
2657  if ( !vl )
2658  {
2659  return QVariant();
2660  }
2661 
2662  QString attribute = getStringValue( values.at( 1 ), parent );
2663  int attributeId = vl->fieldNameIndex( attribute );
2664  if ( attributeId == -1 )
2665  {
2666  return QVariant();
2667  }
2668 
2669  const QVariant& attVal = values.at( 2 );
2670  QgsFeatureRequest req;
2671  req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
2672  QgsExpression::quotedString( attVal.toString() ) ) );
2673  req.setLimit( 1 );
2674  if ( !parent->needsGeometry() )
2675  {
2677  }
2678  QgsFeatureIterator fIt = vl->getFeatures( req );
2679 
2680  QgsFeature fet;
2681  if ( fIt.nextFeature( fet ) )
2682  return QVariant::fromValue( fet );
2683 
2684  return QVariant();
2685 }
2686 
2687 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2688 {
2689  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
2690 
2691  //try to find a matching layer by name
2692  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
2693  if ( !layer )
2694  {
2695  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
2696  if ( !layersByName.isEmpty() )
2697  {
2698  layer = layersByName.at( 0 );
2699  }
2700  }
2701 
2702  if ( !layer )
2703  return QVariant();
2704 
2705  QString layerProperty = getStringValue( values.at( 1 ), parent );
2706  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
2707  return layer->name();
2708  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
2709  return layer->id();
2710  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
2711  return layer->title();
2712  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
2713  return layer->abstract();
2714  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
2715  return layer->keywordList();
2716  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
2717  return layer->dataUrl();
2718  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
2719  return layer->attribution();
2720  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
2721  return layer->attributionUrl();
2722  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
2723  return layer->publicSource();
2724  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
2725  return static_cast< double >( layer->minimumScale() );
2726  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
2727  return static_cast< double >( layer->maximumScale() );
2728  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
2729  return layer->crs().authid();
2730  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
2731  return layer->crs().toProj4();
2732  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
2733  {
2734  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
2735  QVariant result = QVariant::fromValue( *extentGeom );
2736  delete extentGeom;
2737  return result;
2738  }
2739  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
2740  {
2741  switch ( layer->type() )
2742  {
2744  return QCoreApplication::translate( "expressions", "Vector" );
2746  return QCoreApplication::translate( "expressions", "Raster" );
2748  return QCoreApplication::translate( "expressions", "Plugin" );
2749  }
2750  }
2751  else
2752  {
2753  //vector layer methods
2754  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
2755  if ( vLayer )
2756  {
2757  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
2758  return vLayer->storageType();
2759  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
2760  return QGis::vectorGeometryType( vLayer->geometryType() );
2761  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
2762  return QVariant::fromValue( vLayer->featureCount() );
2763  }
2764  }
2765 
2766  return QVariant();
2767 }
2768 
2769 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
2770 {
2771  int fnIdx = functionIndex( function->name() );
2772  if ( fnIdx != -1 )
2773  {
2774  return false;
2775  }
2776  QgsExpression::gmFunctions.append( function );
2777  if ( transferOwnership )
2778  QgsExpression::gmOwnedFunctions.append( function );
2779  return true;
2780 }
2781 
2783 {
2784  // You can never override the built in functions.
2785  if ( QgsExpression::BuiltinFunctions().contains( name ) )
2786  {
2787  return false;
2788  }
2789  int fnIdx = functionIndex( name );
2790  if ( fnIdx != -1 )
2791  {
2792  QgsExpression::gmFunctions.removeAt( fnIdx );
2793  return true;
2794  }
2795  return false;
2796 }
2797 
2799 {
2800  qDeleteAll( QgsExpression::gmOwnedFunctions );
2802 }
2803 
2805 
2807 {
2808  if ( gmBuiltinFunctions.isEmpty() )
2809  {
2811  << "abs" << "sqrt" << "cos" << "sin" << "tan"
2812  << "asin" << "acos" << "atan" << "atan2"
2813  << "exp" << "ln" << "log10" << "log"
2814  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
2815  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
2816  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
2817  << "todatetime" << "to_datetime" << "todate" << "to_date"
2818  << "totime" << "to_time" << "tointerval" << "to_interval"
2819  << "coalesce" << "if" << "regexp_match" << "age" << "year"
2820  << "month" << "week" << "day" << "hour" << "day_of_week"
2821  << "minute" << "second" << "lower" << "upper"
2822  << "title" << "length" << "replace" << "trim" << "wordwrap"
2823  << "regexp_replace" << "regexp_substr"
2824  << "substr" << "concat" << "strpos" << "left"
2825  << "right" << "rpad" << "lpad" << "format"
2826  << "format_number" << "format_date"
2827  << "color_rgb" << "color_rgba" << "ramp_color"
2828  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
2829  << "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
2830  << "xat" << "yat" << "$area" << "area" << "perimeter"
2831  << "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
2832  << "num_interior_rings" << "num_rings" << "num_geometries"
2833  << "geometry_n" << "interior_ring_n"
2834  << "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
2835  << "nodes_to_points" << "segments_to_lines"
2836  << "make_line" << "make_polygon"
2837  << "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
2838  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
2839  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
2840  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
2841  << "relate"
2842  << "overlaps" << "within" << "buffer" << "centroid" << "bounds" << "reverse" << "exterior_ring"
2843  << "bounds_width" << "bounds_height" << "is_closed" << "convex_hull" << "difference"
2844  << "distance" << "intersection" << "sym_difference" << "combine"
2845  << "extrude" << "azimuth" << "closest_point" << "shortest_line"
2846  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
2847  << "transform" << "get_feature" << "getFeature"
2848  << "levenshtein" << "longest_common_substring" << "hamming_distance"
2849  << "soundex"
2850  << "attribute" << "var" << "layer_property"
2851  << "$id" << "$scale" << "_specialcol_";
2852  }
2853  return gmBuiltinFunctions;
2854 }
2855 
2858 
2860 {
2861  // The construction of the list isn't thread-safe, and without the mutex,
2862  // crashes in the WFS provider may occur, since it can parse expressions
2863  // in parallel.
2864  // The mutex needs to be recursive.
2865  static QMutex sFunctionsMutex( QMutex::Recursive );
2866  QMutexLocker locker( &sFunctionsMutex );
2867 
2868  if ( gmFunctions.isEmpty() )
2869  {
2870  gmFunctions
2871  << new StaticFunction( "sqrt", 1, fcnSqrt, "Math" )
2872  << new StaticFunction( "radians", 1, fcnRadians, "Math" )
2873  << new StaticFunction( "degrees", 1, fcnDegrees, "Math" )
2874  << new StaticFunction( "azimuth", 2, fcnAzimuth, "Math" )
2875  << new StaticFunction( "abs", 1, fcnAbs, "Math" )
2876  << new StaticFunction( "cos", 1, fcnCos, "Math" )
2877  << new StaticFunction( "sin", 1, fcnSin, "Math" )
2878  << new StaticFunction( "tan", 1, fcnTan, "Math" )
2879  << new StaticFunction( "asin", 1, fcnAsin, "Math" )
2880  << new StaticFunction( "acos", 1, fcnAcos, "Math" )
2881  << new StaticFunction( "atan", 1, fcnAtan, "Math" )
2882  << new StaticFunction( "atan2", 2, fcnAtan2, "Math" )
2883  << new StaticFunction( "exp", 1, fcnExp, "Math" )
2884  << new StaticFunction( "ln", 1, fcnLn, "Math" )
2885  << new StaticFunction( "log10", 1, fcnLog10, "Math" )
2886  << new StaticFunction( "log", 2, fcnLog, "Math" )
2887  << new StaticFunction( "round", -1, fcnRound, "Math" )
2888  << new StaticFunction( "rand", 2, fcnRnd, "Math" )
2889  << new StaticFunction( "randf", 2, fcnRndF, "Math" )
2890  << new StaticFunction( "max", -1, fcnMax, "Math" )
2891  << new StaticFunction( "min", -1, fcnMin, "Math" )
2892  << new StaticFunction( "clamp", 3, fcnClamp, "Math" )
2893  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
2894  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
2895  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
2896  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
2897  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
2898  << new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
2899  << new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
2900  << new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QStringList(), false, QStringList() << "tostring" )
2901  << new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "todatetime" )
2902  << new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
2903  << new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
2904  << new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
2905  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
2906  << new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QStringList(), true )
2907  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
2908  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
2909  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
2910  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
2911  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
2912  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
2913  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
2914  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
2915  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
2916  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
2917  << new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
2918  << new StaticFunction( "lower", 1, fcnLower, "String" )
2919  << new StaticFunction( "upper", 1, fcnUpper, "String" )
2920  << new StaticFunction( "title", 1, fcnTitle, "String" )
2921  << new StaticFunction( "trim", 1, fcnTrim, "String" )
2922  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
2923  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
2924  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
2925  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
2926  << new StaticFunction( "wordwrap", -1, fcnWordwrap, "String" )
2927  << new StaticFunction( "length", 1, fcnLength, "String" )
2928  << new StaticFunction( "replace", 3, fcnReplace, "String" )
2929  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
2930  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
2931  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
2932  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
2933  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
2934  << new StaticFunction( "left", 2, fcnLeft, "String" )
2935  << new StaticFunction( "right", 2, fcnRight, "String" )
2936  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
2937  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
2938  << new StaticFunction( "format", -1, fcnFormatString, "String" )
2939  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
2940  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
2941  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
2942  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
2943  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
2944  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
2945  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
2946  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
2947  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
2948  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
2949  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
2950  << new StaticFunction( "color_part", 2, fncColorPart, "Color" )
2951  << new StaticFunction( "darker", 2, fncDarker, "Color" )
2952  << new StaticFunction( "lighter", 2, fncLighter, "Color" )
2953  << new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
2954  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
2955  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
2956  << new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
2957  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", QString(), true )
2958  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", QString(), true )
2959  << new StaticFunction( "perimeter", 1, fcnPerimeter, "GeometryGroup" )
2960  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", QString(), true )
2961  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
2962  << new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
2963  << new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
2964  << new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
2965  << new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
2966  << new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
2967  << new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
2968  << new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
2969  << new StaticFunction( "nodes_to_points", -1, fcnNodesToPoints, "GeometryGroup" )
2970  << new StaticFunction( "segments_to_lines", 1, fcnSegmentsToLines, "GeometryGroup" )
2971  << new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
2972  << new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
2973  << new StaticFunction( "make_line", -1, fcnMakeLine, "GeometryGroup" )
2974  << new StaticFunction( "make_polygon", -1, fcnMakePolygon, "GeometryGroup" )
2975  << new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
2976  << new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
2977  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
2978  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmax" )
2979  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymin" )
2980  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
2981  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
2982  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
2983  << new StaticFunction( "relate", -1, fcnRelate, "GeometryGroup" )
2984  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
2985  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
2986  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
2987  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
2988  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
2989  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
2990  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
2991  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
2992  << new StaticFunction( "translate", 3, fcnTranslate, "GeometryGroup" )
2993  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
2994  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
2995  << new StaticFunction( "point_on_surface", 1, fcnPointOnSurface, "GeometryGroup" )
2996  << new StaticFunction( "reverse", 1, fcnReverse, "GeometryGroup" )
2997  << new StaticFunction( "exterior_ring", 1, fcnExteriorRing, "GeometryGroup" )
2998  << new StaticFunction( "interior_ring_n", 2, fcnInteriorRingN, "GeometryGroup" )
2999  << new StaticFunction( "geometry_n", 2, fcnGeometryN, "GeometryGroup" )
3000  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup" )
3001  << new StaticFunction( "num_points", 1, fcnGeomNumPoints, "GeometryGroup" )
3002  << new StaticFunction( "num_interior_rings", 1, fcnGeomNumInteriorRings, "GeometryGroup" )
3003  << new StaticFunction( "num_rings", 1, fcnGeomNumRings, "GeometryGroup" )
3004  << new StaticFunction( "num_geometries", 1, fcnGeomNumGeometries, "GeometryGroup" )
3005  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup" )
3006  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup" )
3007  << new StaticFunction( "is_closed", 1, fcnIsClosed, "GeometryGroup" )
3008  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
3009  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
3010  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
3011  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
3012  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
3013  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
3014  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
3015  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
3016  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
3017  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
3018  << new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
3019  << new StaticFunction( "order_parts", 3, fcnOrderParts, "GeometryGroup", QString() )
3020  << new StaticFunction( "closest_point", 2, fcnClosestPoint, "GeometryGroup" )
3021  << new StaticFunction( "shortest_line", 2, fcnShortestLine, "GeometryGroup" )
3022  << new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
3023  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
3024  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
3025  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
3026  << new StaticFunction( "$map", 0, fcnMapId, "deprecated" )
3027  << new StaticFunction( "$numpages", 0, fcnComposerNumPages, "deprecated" )
3028  << new StaticFunction( "$page", 0, fcnComposerPage, "deprecated" )
3029  << new StaticFunction( "$feature", 0, fcnAtlasFeature, "deprecated" )
3030  << new StaticFunction( "$atlasfeatureid", 0, fcnAtlasFeatureId, "deprecated" )
3031  << new StaticFunction( "$atlasfeature", 0, fcnAtlasCurrentFeature, "deprecated" )
3032  << new StaticFunction( "$atlasgeometry", 0, fcnAtlasCurrentGeometry, "deprecated" )
3033  << new StaticFunction( "$numfeatures", 0, fcnAtlasNumFeatures, "deprecated" )
3034  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
3035  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
3036  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
3037  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
3038 
3039  //return all attributes string for referencedColumns - this is caught by
3040  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
3041  // feature request
3042  << new StaticFunction( "eval", 1, fcnEval, "General", QString(), true, QStringList( QgsFeatureRequest::AllAttributes ) )
3043  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
3044 
3045  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
3046  ;
3047 
3049 
3050  //QgsExpression has ownership of all built-in functions
3051  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
3052  {
3053  gmOwnedFunctions << func;
3054  }
3055  }
3056  return gmFunctions;
3057 }
3058 
3061 
3062 void QgsExpression::setSpecialColumn( const QString& name, const QVariant& variant )
3063 {
3064  int fnIdx = functionIndex( name );
3065  if ( fnIdx != -1 )
3066  {
3067  // function of the same name already exists
3068  return;
3069  }
3070  gmSpecialColumns[ name ] = variant;
3071 }
3072 
3074 {
3076  if ( fit != gmSpecialColumns.end() )
3077  {
3078  gmSpecialColumns.erase( fit );
3079  }
3080 }
3081 
3083 {
3084  int fnIdx = functionIndex( name );
3085  if ( fnIdx != -1 )
3086  {
3087  // function of the same name already exists
3088  return QVariant();
3089  }
3091  if ( it == gmSpecialColumns.constEnd() )
3092  {
3093  return QVariant();
3094  }
3095  return it.value();
3096 }
3097 
3099 {
3100  if ( functionIndex( name ) != -1 )
3101  return false;
3102  return gmSpecialColumns.contains( name );
3103 }
3104 
3105 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
3106 {
3108  return isValid( text, &context, errorMessage );
3109 }
3110 
3111 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
3112 {
3113  QgsExpression exp( text );
3114  exp.prepare( context );
3115  errorMessage = exp.parserErrorString();
3116  return !exp.hasParserError();
3117 }
3118 
3119 void QgsExpression::setScale( double scale ) { d->mScale = scale; }
3120 
3121 double QgsExpression::scale() { return d->mScale; }
3122 
3124 {
3125  if ( !d->mExp.isNull() )
3126  return d->mExp;
3127  else
3128  return dump();
3129 }
3130 
3132 {
3133  QList<Function*> defs;
3135  {
3136  //check for special column group name
3137  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
3138  defs << new StaticFunction( it.key(), 0, static_cast< FcnEvalContext >( nullptr ), group );
3139  }
3140  return defs;
3141 }
3142 
3144 {
3145  return QString( "\"%1\"" ).arg( name.replace( '\"', "\"\"" ) );
3146 }
3147 
3149 {
3150  text.replace( '\'', "''" );
3151  text.replace( '\\', "\\\\" );
3152  text.replace( '\n', "\\n" );
3153  text.replace( '\t', "\\t" );
3154  return QString( "'%1'" ).arg( text );
3155 }
3156 
3158 {
3159  return quotedValue( value, value.type() );
3160 }
3161 
3162 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
3163 {
3164  if ( value.isNull() )
3165  return "NULL";
3166 
3167  switch ( type )
3168  {
3169  case QVariant::Int:
3170  case QVariant::LongLong:
3171  case QVariant::Double:
3172  return value.toString();
3173 
3174  case QVariant::Bool:
3175  return value.toBool() ? "TRUE" : "FALSE";
3176 
3177  default:
3178  case QVariant::String:
3179  return quotedString( value.toString() );
3180  }
3181 
3182 }
3183 
3185 {
3186  return functionIndex( name ) != -1;
3187 }
3188 
3190 {
3191  int count = functionCount();
3192  for ( int i = 0; i < count; i++ )
3193  {
3194  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
3195  return i;
3196  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
3197  {
3198  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
3199  return i;
3200  }
3201  }
3202  return -1;
3203 }
3204 
3206 {
3207  return Functions().size();
3208 }
3209 
3210 
3212  : d( new QgsExpressionPrivate )
3213 {
3214  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
3215  d->mExp = expr;
3216  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
3217 }
3218 
3220  : d( other.d )
3221 {
3222  d->ref.ref();
3223 }
3224 
3226 {
3227  d = other.d;
3228  d->ref.ref();
3229  return *this;
3230 }
3231 
3233  : d( new QgsExpressionPrivate )
3234 {
3235 }
3236 
3238 {
3239  Q_ASSERT( d );
3240  if ( !d->ref.deref() )
3241  delete d;
3242 }
3243 
3244 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
3245 
3246 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
3247 
3249 {
3250  if ( !d->mRootNode )
3251  return QStringList();
3252 
3253  QStringList columns = d->mRootNode->referencedColumns();
3254 
3255  // filter out duplicates
3256  for ( int i = 0; i < columns.count(); i++ )
3257  {
3258  QString col = columns.at( i );
3259  for ( int j = i + 1; j < columns.count(); j++ )
3260  {
3261  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
3262  {
3263  // this column is repeated: remove it!
3264  columns.removeAt( j-- );
3265  }
3266  }
3267  }
3268 
3269  return columns;
3270 }
3271 
3273 {
3274  if ( !d->mRootNode )
3275  return false;
3276  return d->mRootNode->needsGeometry();
3277 }
3278 
3280 {
3281  if ( d->mCalc.data() )
3282  return;
3283 
3284  // Use planimetric as default
3286  d->mCalc->setEllipsoidalMode( false );
3287 }
3288 
3290 {
3291  Q_ASSERT( d );
3292 
3293  if ( d->ref > 1 )
3294  {
3295  ( void )d->ref.deref();
3296 
3297  d = new QgsExpressionPrivate( *d );
3298  }
3299 }
3300 
3302 {
3303  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea( calc ) );
3304 }
3305 
3306 bool QgsExpression::prepare( const QgsFields& fields )
3307 {
3308  detach();
3310  return prepare( &fc );
3311 }
3312 
3314 {
3315  detach();
3316  d->mEvalErrorString = QString();
3317  if ( !d->mRootNode )
3318  {
3319  //re-parse expression. Creation of QgsExpressionContexts may have added extra
3320  //known functions since this expression was created, so we have another try
3321  //at re-parsing it now that the context must have been created
3322  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
3323  }
3324 
3325  if ( !d->mRootNode )
3326  {
3327  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3328  return false;
3329  }
3330 
3331  return d->mRootNode->prepare( this, context );
3332 }
3333 
3335 {
3336  d->mEvalErrorString = QString();
3337  if ( !d->mRootNode )
3338  {
3339  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3340  return QVariant();
3341  }
3342 
3344  return d->mRootNode->eval( this, &context );
3345 }
3346 
3348 {
3350  return evaluate( &f );
3352 }
3353 
3355 {
3356  // first prepare
3358  bool res = prepare( &context );
3359  if ( !res )
3360  return QVariant();
3361 
3362  // then evaluate
3363  return evaluate( &context );
3364 }
3365 
3366 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
3367 {
3369  return evaluate( &f, fields );
3371 }
3372 
3374 {
3375  d->mEvalErrorString = QString();
3376  if ( !d->mRootNode )
3377  {
3378  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3379  return QVariant();
3380  }
3381 
3382  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
3383 }
3384 
3386 {
3387  d->mEvalErrorString = QString();
3388  if ( !d->mRootNode )
3389  {
3390  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3391  return QVariant();
3392  }
3393 
3394  return d->mRootNode->eval( this, context );
3395 }
3396 
3398 {
3399  return !d->mEvalErrorString.isNull();
3400 }
3401 
3403 {
3404  return d->mEvalErrorString;
3405 }
3406 
3408 {
3409  d->mEvalErrorString = str;
3410 }
3411 
3413 {
3414  d->mRowNumber = rowNumber;
3415 }
3416 
3417 int QgsExpression::currentRowNumber() { return d->mRowNumber; }
3418 
3420 {
3421  if ( !d->mRootNode )
3422  return tr( "(no root)" );
3423 
3424  return d->mRootNode->dump();
3425 }
3426 
3428 {
3429  return d->mCalc.data();
3430 }
3431 
3433 {
3434  return d->mDistanceUnit;
3435 }
3436 
3438 {
3439  d->mDistanceUnit = unit;
3440 }
3441 
3443 {
3444  return d->mAreaUnit;
3445 }
3446 
3448 {
3449  d->mAreaUnit = unit;
3450 }
3451 
3453 {
3454  if ( d->mRootNode )
3455  d->mRootNode->accept( v );
3456 }
3457 
3459  QgsVectorLayer *layer,
3460  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3461 {
3462  QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( feat ? *feat : QgsFeature(), layer ? layer->fields() : QgsFields() );
3463  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
3464 }
3465 
3466 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3467 {
3468  QString expr_action;
3469 
3470  QMap<QString, QVariant> savedValues;
3471  if ( substitutionMap )
3472  {
3473  // variables with a local scope (must be restored after evaluation)
3474  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
3475  {
3477  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
3478  if ( !oldValue.isNull() )
3479  savedValues.insert( sit.key(), oldValue );
3480 
3481  // set the new value
3482  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3484  }
3485  }
3486 
3487  int index = 0;
3488  while ( index < action.size() )
3489  {
3490  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
3491 
3492  int pos = rx.indexIn( action, index );
3493  if ( pos < 0 )
3494  break;
3495 
3496  int start = index;
3497  index = pos + rx.matchedLength();
3498  QString to_replace = rx.cap( 1 ).trimmed();
3499  QgsDebugMsg( "Found expression: " + to_replace );
3500 
3501  QgsExpression exp( to_replace );
3502  if ( exp.hasParserError() )
3503  {
3504  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
3505  expr_action += action.midRef( start, index - start );
3506  continue;
3507  }
3508 
3509  if ( distanceArea )
3510  {
3511  //if QgsDistanceArea specified for area/distance conversion, use it
3512  exp.setGeomCalculator( *distanceArea );
3513  }
3514 
3515  QVariant result = exp.evaluate( context );
3516 
3517  if ( exp.hasEvalError() )
3518  {
3519  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
3520  expr_action += action.midRef( start, index - start );
3521  continue;
3522  }
3523 
3524  QgsDebugMsg( "Expression result is: " + result.toString() );
3525  expr_action += action.mid( start, pos - start ) + result.toString();
3526  }
3527 
3528  expr_action += action.midRef( index );
3529 
3530  // restore overwritten local values
3532  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
3533  {
3534  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3535  }
3537 
3538  return expr_action;
3539 }
3540 
3541 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
3542 {
3543  bool ok;
3544  //first test if text is directly convertible to double
3545  double convertedValue = text.toDouble( &ok );
3546  if ( ok )
3547  {
3548  return convertedValue;
3549  }
3550 
3551  //otherwise try to evalute as expression
3552  QgsExpression expr( text );
3553 
3554  QgsExpressionContext context;
3557 
3558  QVariant result = expr.evaluate( &context );
3559  convertedValue = result.toDouble( &ok );
3560  if ( expr.hasEvalError() || !ok )
3561  {
3562  return fallbackValue;
3563  }
3564  return convertedValue;
3565 }
3566 
3567 
3569 // nodes
3570 
3572 {
3573  NodeList* nl = new NodeList;
3574  Q_FOREACH ( Node* node, mList )
3575  {
3576  nl->mList.append( node->clone() );
3577  }
3578 
3579  return nl;
3580 }
3581 
3583 {
3584  QString msg;
3585  bool first = true;
3586  Q_FOREACH ( Node* n, mList )
3587  {
3588  if ( !first ) msg += ", ";
3589  else first = false;
3590  msg += n->dump();
3591  }
3592  return msg;
3593 }
3594 
3595 
3596 //
3597 
3599 {
3600  QVariant val = mOperand->eval( parent, context );
3602 
3603  switch ( mOp )
3604  {
3605  case uoNot:
3606  {
3607  TVL tvl = getTVLValue( val, parent );
3609  return tvl2variant( NOT[tvl] );
3610  }
3611 
3612  case uoMinus:
3613  if ( isIntSafe( val ) )
3614  return QVariant( - getIntValue( val, parent ) );
3615  else if ( isDoubleSafe( val ) )
3616  return QVariant( - getDoubleValue( val, parent ) );
3617  else
3618  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
3619  default:
3620  Q_ASSERT( 0 && "unknown unary operation" );
3621  }
3622  return QVariant();
3623 }
3624 
3626 {
3627  return mOperand->prepare( parent, context );
3628 }
3629 
3631 {
3632  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
3633 }
3634 
3636 {
3637  return new NodeUnaryOperator( mOp, mOperand->clone() );
3638 }
3639 
3640 //
3641 
3643 {
3644  QVariant vL = mOpLeft->eval( parent, context );
3646  QVariant vR = mOpRight->eval( parent, context );
3648 
3649  switch ( mOp )
3650  {
3651  case boPlus:
3652  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
3653  {
3654  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
3656  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
3658  return QVariant( sL + sR );
3659  }
3660  //intentional fall-through
3661  FALLTHROUGH;
3662  case boMinus:
3663  case boMul:
3664  case boDiv:
3665  case boMod:
3666  {
3667  if ( isNull( vL ) || isNull( vR ) )
3668  return QVariant();
3669  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
3670  {
3671  // both are integers - let's use integer arithmetics
3672  int iL = getIntValue( vL, parent );
3674  int iR = getIntValue( vR, parent );
3676 
3677  if ( mOp == boMod && iR == 0 )
3678  return QVariant();
3679 
3680  return QVariant( computeInt( iL, iR ) );
3681  }
3682  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
3683  {
3684  QDateTime dL = getDateTimeValue( vL, parent );
3686  QgsExpression::Interval iL = getInterval( vR, parent );
3688  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
3689  {
3690  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
3691  return QVariant();
3692  }
3693  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
3694  }
3695  else
3696  {
3697  // general floating point arithmetic
3698  double fL = getDoubleValue( vL, parent );
3700  double fR = getDoubleValue( vR, parent );
3702  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
3703  return QVariant(); // silently handle division by zero and return NULL
3704  return QVariant( computeDouble( fL, fR ) );
3705  }
3706  }
3707  case boIntDiv:
3708  {
3709  //integer division
3710  double fL = getDoubleValue( vL, parent );
3712  double fR = getDoubleValue( vR, parent );
3714  if ( fR == 0. )
3715  return QVariant(); // silently handle division by zero and return NULL
3716  return QVariant( qFloor( fL / fR ) );
3717  }
3718  case boPow:
3719  if ( isNull( vL ) || isNull( vR ) )
3720  return QVariant();
3721  else
3722  {
3723  double fL = getDoubleValue( vL, parent );
3725  double fR = getDoubleValue( vR, parent );
3727  return QVariant( pow( fL, fR ) );
3728  }
3729 
3730  case boAnd:
3731  {
3732  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
3734  return tvl2variant( AND[tvlL][tvlR] );
3735  }
3736 
3737  case boOr:
3738  {
3739  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
3741  return tvl2variant( OR[tvlL][tvlR] );
3742  }
3743 
3744  case boEQ:
3745  case boNE:
3746  case boLT:
3747  case boGT:
3748  case boLE:
3749  case boGE:
3750  if ( isNull( vL ) || isNull( vR ) )
3751  {
3752  return TVL_Unknown;
3753  }
3754  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
3755  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
3756  {
3757  // do numeric comparison if both operators can be converted to numbers,
3758  // and they aren't both string
3759  double fL = getDoubleValue( vL, parent );
3761  double fR = getDoubleValue( vR, parent );
3763  return compare( fL - fR ) ? TVL_True : TVL_False;
3764  }
3765  else
3766  {
3767  // do string comparison otherwise
3768  QString sL = getStringValue( vL, parent );
3770  QString sR = getStringValue( vR, parent );
3772  int diff = QString::compare( sL, sR );
3773  return compare( diff ) ? TVL_True : TVL_False;
3774  }
3775 
3776  case boIs:
3777  case boIsNot:
3778  if ( isNull( vL ) && isNull( vR ) ) // both operators null
3779  return ( mOp == boIs ? TVL_True : TVL_False );
3780  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
3781  return ( mOp == boIs ? TVL_False : TVL_True );
3782  else // both operators non-null
3783  {
3784  bool equal = false;
3785  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
3786  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
3787  {
3788  double fL = getDoubleValue( vL, parent );
3790  double fR = getDoubleValue( vR, parent );
3792  equal = qgsDoubleNear( fL, fR );
3793  }
3794  else
3795  {
3796  QString sL = getStringValue( vL, parent );
3798  QString sR = getStringValue( vR, parent );
3800  equal = QString::compare( sL, sR ) == 0;
3801  }
3802  if ( equal )
3803  return mOp == boIs ? TVL_True : TVL_False;
3804  else
3805  return mOp == boIs ? TVL_False : TVL_True;
3806  }
3807 
3808  case boRegexp:
3809  case boLike:
3810  case boNotLike:
3811  case boILike:
3812  case boNotILike:
3813  if ( isNull( vL ) || isNull( vR ) )
3814  return TVL_Unknown;
3815  else
3816  {
3817  QString str = getStringValue( vL, parent );
3819  QString regexp = getStringValue( vR, parent );
3821  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
3822  bool matches;
3823  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
3824  {
3825  QString esc_regexp = QRegExp::escape( regexp );
3826  // XXX escape % and _ ???
3827  esc_regexp.replace( '%', ".*" );
3828  esc_regexp.replace( '_', '.' );
3829  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
3830  }
3831  else
3832  {
3833  matches = QRegExp( regexp ).indexIn( str ) != -1;
3834  }
3835 
3836  if ( mOp == boNotLike || mOp == boNotILike )
3837  {
3838  matches = !matches;
3839  }
3840 
3841  return matches ? TVL_True : TVL_False;
3842  }
3843 
3844  case boConcat:
3845  if ( isNull( vL ) || isNull( vR ) )
3846  return QVariant();
3847  else
3848  {
3849  QString sL = getStringValue( vL, parent );
3851  QString sR = getStringValue( vR, parent );
3853  return QVariant( sL + sR );
3854  }
3855 
3856  default:
3857  break;
3858  }
3859  Q_ASSERT( false );
3860  return QVariant();
3861 }
3862 
3864 {
3865  switch ( mOp )
3866  {
3867  case boEQ:
3868  return qgsDoubleNear( diff, 0.0 );
3869  case boNE:
3870  return !qgsDoubleNear( diff, 0.0 );
3871  case boLT:
3872  return diff < 0;
3873  case boGT:
3874  return diff > 0;
3875  case boLE:
3876  return diff <= 0;
3877  case boGE:
3878  return diff >= 0;
3879  default:
3880  Q_ASSERT( false );
3881  return false;
3882  }
3883 }
3884 
3886 {
3887  switch ( mOp )
3888  {
3889  case boPlus:
3890  return x + y;
3891  case boMinus:
3892  return x -y;
3893  case boMul:
3894  return x*y;
3895  case boDiv:
3896  return x / y;
3897  case boMod:
3898  return x % y;
3899  default:
3900  Q_ASSERT( false );
3901  return 0;
3902  }
3903 }
3904 
3906 {
3907  switch ( mOp )
3908  {
3909  case boPlus:
3910  return d.addSecs( i->seconds() );
3911  case boMinus:
3912  return d.addSecs( -i->seconds() );
3913  default:
3914  Q_ASSERT( false );
3915  return QDateTime();
3916  }
3917 }
3918 
3920 {
3921  switch ( mOp )
3922  {
3923  case boPlus:
3924  return x + y;
3925  case boMinus:
3926  return x -y;
3927  case boMul:
3928  return x*y;
3929  case boDiv:
3930  return x / y;
3931  case boMod:
3932  return fmod( x, y );
3933  default:
3934  Q_ASSERT( false );
3935  return 0;
3936  }
3937 }
3938 
3940 {
3941  bool resL = mOpLeft->prepare( parent, context );
3942  bool resR = mOpRight->prepare( parent, context );
3943  return resL && resR;
3944 }
3945 
3947 {
3948  // see left/right in qgsexpressionparser.yy
3949  switch ( mOp )
3950  {
3951  case boOr:
3952  return 1;
3953 
3954  case boAnd:
3955  return 2;
3956 
3957  case boEQ:
3958  case boNE:
3959  case boLE:
3960  case boGE:
3961  case boLT:
3962  case boGT:
3963  case boRegexp:
3964  case boLike:
3965  case boILike:
3966  case boNotLike:
3967  case boNotILike:
3968  case boIs:
3969  case boIsNot:
3970  return 3;
3971 
3972  case boPlus:
3973  case boMinus:
3974  return 4;
3975 
3976  case boMul:
3977  case boDiv:
3978  case boIntDiv:
3979  case boMod:
3980  return 5;
3981 
3982  case boPow:
3983  return 6;
3984 
3985  case boConcat:
3986  return 7;
3987  }
3988  Q_ASSERT( 0 && "unexpected binary operator" );
3989  return -1;
3990 }
3991 
3993 {
3994  // see left/right in qgsexpressionparser.yy
3995  switch ( mOp )
3996  {
3997  case boOr:
3998  case boAnd:
3999  case boEQ:
4000  case boNE:
4001  case boLE:
4002  case boGE:
4003  case boLT:
4004  case boGT:
4005  case boRegexp:
4006  case boLike:
4007  case boILike:
4008  case boNotLike:
4009  case boNotILike:
4010  case boIs:
4011  case boIsNot:
4012  case boPlus:
4013  case boMinus:
4014  case boMul:
4015  case boDiv:
4016  case boIntDiv:
4017  case boMod:
4018  case boConcat:
4019  return true;
4020 
4021  case boPow:
4022  return false;
4023  }
4024  Q_ASSERT( 0 && "unexpected binary operator" );
4025  return false;
4026 }
4027 
4029 {
4030  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
4031  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
4032  QgsExpression::NodeUnaryOperator *ruOp = dynamic_cast<QgsExpression::NodeUnaryOperator *>( mOpRight );
4033 
4034  QString rdump( mOpRight->dump() );
4035 
4036  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
4037  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
4038  {
4039  rdump.prepend( '(' ).append( ')' );
4040  }
4041 
4042  QString fmt;
4043  if ( leftAssociative() )
4044  {
4045  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
4046  fmt += " %2 ";
4047  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
4048  }
4049  else
4050  {
4051  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
4052  fmt += " %2 ";
4053  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
4054  }
4055 
4056  return fmt.arg( mOpLeft->dump(), BinaryOperatorText[mOp], rdump );
4057 }
4058 
4060 {
4061  return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
4062 }
4063 
4064 //
4065 
4067 {
4068  if ( mList->count() == 0 )
4069  return mNotIn ? TVL_True : TVL_False;
4070  QVariant v1 = mNode->eval( parent, context );
4072  if ( isNull( v1 ) )
4073  return TVL_Unknown;
4074 
4075  bool listHasNull = false;
4076 
4077  Q_FOREACH ( Node* n, mList->list() )
4078  {
4079  QVariant v2 = n->eval( parent, context );
4081  if ( isNull( v2 ) )
4082  listHasNull = true;
4083  else
4084  {
4085  bool equal = false;
4086  // check whether they are equal
4087  if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
4088  {
4089  double f1 = getDoubleValue( v1, parent );
4091  double f2 = getDoubleValue( v2, parent );
4093  equal = qgsDoubleNear( f1, f2 );
4094  }
4095  else
4096  {
4097  QString s1 = getStringValue( v1, parent );
4099  QString s2 = getStringValue( v2, parent );
4101  equal = QString::compare( s1, s2 ) == 0;
4102  }
4103 
4104  if ( equal ) // we know the result
4105  return mNotIn ? TVL_False : TVL_True;
4106  }
4107  }
4108 
4109  // item not found
4110  if ( listHasNull )
4111  return TVL_Unknown;
4112  else
4113  return mNotIn ? TVL_True : TVL_False;
4114 }
4115 
4117 {
4118  bool res = mNode->prepare( parent, context );
4119  Q_FOREACH ( Node* n, mList->list() )
4120  {
4121  res = res && n->prepare( parent, context );
4122  }
4123  return res;
4124 }
4125 
4127 {
4128  return QString( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
4129 }
4130 
4132 {
4133  return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
4134 }
4135 
4136 //
4137 
4139 {
4140  QString name = Functions()[mFnIndex]->name();
4141  Function* fd = context && context->hasFunction( name ) ? context->function( name ) : Functions()[mFnIndex];
4142 
4143  // evaluate arguments
4144  QVariantList argValues;
4145  if ( mArgs )
4146  {
4147  Q_FOREACH ( Node* n, mArgs->list() )
4148  {
4149  QVariant v;
4150  if ( fd->lazyEval() )
4151  {
4152  // Pass in the node for the function to eval as it needs.
4153  v = QVariant::fromValue( n );
4154  }
4155  else
4156  {
4157  v = n->eval( parent, context );
4159  if ( isNull( v ) && !fd->handlesNull() )
4160  return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
4161  }
4162  argValues.append( v );
4163  }
4164  }
4165 
4166  // run the function
4167  QVariant res = fd->func( argValues, context, parent );
4169 
4170  // everything went fine
4171  return res;
4172 }
4173 
4175 {
4176  bool res = true;
4177  if ( mArgs )
4178  {
4179  Q_FOREACH ( Node* n, mArgs->list() )
4180  {
4181  res = res && n->prepare( parent, context );
4182  }
4183  }
4184  return res;
4185 }
4186 
4188 {
4189  Function* fd = Functions()[mFnIndex];
4190  if ( fd->params() == 0 )
4191  return QString( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? "" : "()" ); // special column
4192  else
4193  return QString( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
4194 }
4195 
4197 {
4198  Function* fd = Functions()[mFnIndex];
4199  QStringList functionColumns = fd->referencedColumns();
4200 
4201  if ( !mArgs )
4202  {
4203  //no referenced columns in arguments, just return function's referenced columns
4204  return functionColumns;
4205  }
4206 
4207  Q_FOREACH ( Node* n, mArgs->list() )
4208  {
4209  functionColumns.append( n->referencedColumns() );
4210  }
4211 
4212  //remove duplicates and return
4213  return functionColumns.toSet().toList();
4214 }
4215 
4217 {
4218  return new NodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
4219 }
4220 
4221 //
4222 
4224 {
4225  Q_UNUSED( context );
4226  Q_UNUSED( parent );
4227  return mValue;
4228 }
4229 
4231 {
4232  Q_UNUSED( parent );
4233  Q_UNUSED( context );
4234  return true;
4235 }
4236 
4237 
4239 {
4240  if ( mValue.isNull() )
4241  return "NULL";
4242 
4243  switch ( mValue.type() )
4244  {
4245  case QVariant::Int:
4246  return QString::number( mValue.toInt() );
4247  case QVariant::Double:
4248  return QString::number( mValue.toDouble() );
4249  case QVariant::String:
4250  return quotedString( mValue.toString() );
4251  case QVariant::Bool:
4252  return mValue.toBool() ? "TRUE" : "FALSE";
4253  default:
4254  return tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName(), mValue.toString() );
4255  }
4256 }
4257 
4259 {
4260  return new NodeLiteral( mValue );
4261 }
4262 
4263 //
4264 
4266 {
4267  Q_UNUSED( parent );
4268  int index = mIndex;
4269 
4270  if ( index < 0 )
4271  {
4272  // have not yet found field index - first check explicitly set fields collection
4273  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
4274  {
4275  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
4276  index = fields.fieldNameIndex( mName );
4277  }
4278  }
4279 
4280  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
4281  {
4282  QgsFeature feature = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
4283  if ( index >= 0 )
4284  return feature.attribute( index );
4285  else
4286  return feature.attribute( mName );
4287  }
4288  return QVariant( '[' + mName + ']' );
4289 }
4290 
4292 {
4293  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
4294  return false;
4295 
4296  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
4297 
4298  mIndex = fields.fieldNameIndex( mName );
4299  if ( mIndex >= 0 )
4300  {
4301  return true;
4302  }
4303  else
4304  {
4305  parent->d->mEvalErrorString = tr( "Column '%1' not found" ).arg( mName );
4306  mIndex = -1;
4307  return false;
4308  }
4309 }
4310 
4312 {
4313  return QRegExp( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ).exactMatch( mName ) ? mName : quotedColumnRef( mName );
4314 }
4315 
4317 {
4318  return new NodeColumnRef( mName );
4319 }
4320 
4321 //
4322 
4324 {
4325  Q_FOREACH ( WhenThen* cond, mConditions )
4326  {
4327  QVariant vWhen = cond->mWhenExp->eval( parent, context );
4328  TVL tvl = getTVLValue( vWhen, parent );
4330  if ( tvl == True )
4331  {
4332  QVariant vRes = cond->mThenExp->eval( parent, context );
4334  return vRes;
4335  }
4336  }
4337 
4338  if ( mElseExp )
4339  {
4340  QVariant vElse = mElseExp->eval( parent, context );
4342  return vElse;
4343  }
4344 
4345  // return NULL if no condition is matching
4346  return QVariant();
4347 }
4348 
4350 {
4351  bool res;
4352  Q_FOREACH ( WhenThen* cond, mConditions )
4353  {
4354  res = cond->mWhenExp->prepare( parent, context )
4355  & cond->mThenExp->prepare( parent, context );
4356  if ( !res ) return false;
4357  }
4358 
4359  if ( mElseExp )
4360  return mElseExp->prepare( parent, context );
4361 
4362  return true;
4363 }
4364 
4366 {
4367  QString msg( "CASE" );
4368  Q_FOREACH ( WhenThen* cond, mConditions )
4369  {
4370  msg += QString( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
4371  }
4372  if ( mElseExp )
4373  msg += QString( " ELSE %1" ).arg( mElseExp->dump() );
4374  msg += QString( " END" );
4375  return msg;
4376 }
4377 
4379 {
4380  QStringList lst;
4381  Q_FOREACH ( WhenThen* cond, mConditions )
4382  {
4383  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
4384  }
4385 
4386  if ( mElseExp )
4387  lst += mElseExp->referencedColumns();
4388 
4389  return lst;
4390 }
4391 
4393 {
4394  Q_FOREACH ( WhenThen* cond, mConditions )
4395  {
4396  if ( cond->mWhenExp->needsGeometry() ||
4397  cond->mThenExp->needsGeometry() )
4398  return true;
4399  }
4400 
4401  if ( mElseExp && mElseExp->needsGeometry() )
4402  return true;
4403 
4404  return false;
4405 }
4406 
4408 {
4409  WhenThenList conditions;
4410  Q_FOREACH ( WhenThen* wt, mConditions )
4411  conditions.append( new WhenThen( wt->mWhenExp->clone(), wt->mThenExp->clone() ) );
4412  return new NodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
4413 }
4414 
4415 
4417 {
4419 
4420  if ( !gFunctionHelpTexts.contains( name ) )
4421  return tr( "function help for %1 missing" ).arg( name );
4422 
4423  const Help &f = gFunctionHelpTexts[ name ];
4424 
4425  name = f.mName;
4426  if ( f.mType == tr( "group" ) )
4427  name = group( name );
4428 
4429 #if QT_VERSION < 0x050000
4430  name = Qt::escape( name );
4431 #else
4432  name = name.toHtmlEscaped();
4433 #endif
4434 
4435  QString helpContents( QString( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
4436  .arg( tr( "%1 %2" ).arg( f.mType, name ),
4437  f.mDescription ) );
4438 
4439  Q_FOREACH ( const HelpVariant &v, f.mVariants )
4440  {
4441  if ( f.mVariants.size() > 1 )
4442  {
4443  helpContents += QString( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
4444  }
4445 
4446  if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
4447  helpContents += QString( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
4448 
4449  if ( f.mType == tr( "operator" ) )
4450  {
4451  if ( v.mArguments.size() == 1 )
4452  {
4453  helpContents += QString( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
4454  .arg( name, v.mArguments[0].mArg );
4455  }
4456  else if ( v.mArguments.size() == 2 )
4457  {
4458  helpContents += QString( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
4459  .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
4460  }
4461  }
4462  else if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
4463  {
4464  helpContents += QString( "<code><span class=\"functionname\">%1</span>" ).arg( name );
4465 
4466  if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
4467  {
4468  helpContents += '(';
4469 
4470  QString delim;
4471  Q_FOREACH ( const HelpArg &a, v.mArguments )
4472  {
4473  helpContents += delim;
4474  delim = ", ";
4475  if ( !a.mDescOnly )
4476  helpContents += QString( "<span class=\"argument\">%1</span>" ).arg( a.mArg );
4477  }
4478 
4479  if ( v.mVariableLenArguments )
4480  {
4481  helpContents += "...";
4482  }
4483 
4484  helpContents += ')';
4485  }
4486 
4487  helpContents += "</code>";
4488  }
4489 
4490  if ( !v.mArguments.isEmpty() )
4491  {
4492  helpContents += QString( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
4493 
4494  Q_FOREACH ( const HelpArg &a, v.mArguments )
4495  {
4496  if ( a.mSyntaxOnly )
4497  continue;
4498 
4499  helpContents += QString( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
4500  }
4501 
4502  helpContents += "</table>\n</div>\n";
4503  }
4504 
4505  if ( !v.mExamples.isEmpty() )
4506  {
4507  helpContents += QString( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
4508 
4509  Q_FOREACH ( const HelpExample &e, v.mExamples )
4510  {
4511  helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
4512 
4513  if ( !e.mNote.isEmpty() )
4514  helpContents += QString( " (%1)" ).arg( e.mNote );
4515 
4516  helpContents += "</li>\n";
4517  }
4518 
4519  helpContents += "</ul>\n</div>\n";
4520  }
4521 
4522  if ( !v.mNotes.isEmpty() )
4523  {
4524  helpContents += QString( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
4525  }
4526  }
4527 
4528  return helpContents;
4529 }
4530 
4532 
4534 {
4535  if ( !gVariableHelpTexts.isEmpty() )
4536  return;
4537 
4538  //global variables
4539  gVariableHelpTexts.insert( "qgis_version", QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
4540  gVariableHelpTexts.insert( "qgis_version_no", QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
4541  gVariableHelpTexts.insert( "qgis_release_name", QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
4542  gVariableHelpTexts.insert( "qgis_os_name", QCoreApplication::translate( "variable_help", "Operating system name, eg 'windows', 'linux' or 'osx'." ) );
4543  gVariableHelpTexts.insert( "qgis_platform", QCoreApplication::translate( "variable_help", "QGIS platform, eg 'desktop' or 'server'." ) );
4544  gVariableHelpTexts.insert( "user_account_name", QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
4545  gVariableHelpTexts.insert( "user_full_name", QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
4546 
4547  //project variables
4548  gVariableHelpTexts.insert( "project_title", QCoreApplication::translate( "variable_help", "Title of current project." ) );
4549  gVariableHelpTexts.insert( "project_path", QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
4550  gVariableHelpTexts.insert( "project_folder", QCoreApplication::translate( "variable_help", "Folder for current project." ) );
4551  gVariableHelpTexts.insert( "project_filename", QCoreApplication::translate( "variable_help", "Filename of current project." ) );
4552 
4553  //layer variables
4554  gVariableHelpTexts.insert( "layer_name", QCoreApplication::translate( "variable_help", "Name of current layer." ) );
4555  gVariableHelpTexts.insert( "layer_id", QCoreApplication::translate( "variable_help", "ID of current layer." ) );
4556 
4557  //composition variables
4558  gVariableHelpTexts.insert( "layout_numpages", QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
4559  gVariableHelpTexts.insert( "layout_pageheight", QCoreApplication::translate( "variable_help", "Composition page height in mm." ) );
4560  gVariableHelpTexts.insert( "layout_pagewidth", QCoreApplication::translate( "variable_help", "Composition page width in mm." ) );
4561  gVariableHelpTexts.insert( "layout_dpi", QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
4562 
4563  //atlas variables
4564  gVariableHelpTexts.insert( "atlas_totalfeatures", QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
4565  gVariableHelpTexts.insert( "atlas_featurenumber", QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
4566  gVariableHelpTexts.insert( "atlas_filename", QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
4567  gVariableHelpTexts.insert( "atlas_pagename", QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
4568  gVariableHelpTexts.insert( "atlas_feature", QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
4569  gVariableHelpTexts.insert( "atlas_featureid", QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
4570  gVariableHelpTexts.insert( "atlas_geometry", QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
4571 
4572  //composer item variables
4573  gVariableHelpTexts.insert( "item_id", QCoreApplication::translate( "variable_help", "Composer item user ID (not necessarily unique)." ) );
4574  gVariableHelpTexts.insert( "item_uuid", QCoreApplication::translate( "variable_help", "Composer item unique ID." ) );
4575  gVariableHelpTexts.insert( "item_left", QCoreApplication::translate( "variable_help", "Left position of composer item (in mm)." ) );
4576  gVariableHelpTexts.insert( "item_top", QCoreApplication::translate( "variable_help", "Top position of composer item (in mm)." ) );
4577  gVariableHelpTexts.insert( "item_width", QCoreApplication::translate( "variable_help", "Width of composer item (in mm)." ) );
4578  gVariableHelpTexts.insert( "item_height", QCoreApplication::translate( "variable_help", "Height of composer item (in mm)." ) );
4579 
4580  //map settings item variables
4581  gVariableHelpTexts.insert( "map_id", QCoreApplication::translate( "variable_help", "ID of current map destination. This will be 'canvas' for canvas renders, and the item ID for composer map renders." ) );
4582  gVariableHelpTexts.insert( "map_rotation", QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
4583  gVariableHelpTexts.insert( "map_scale", QCoreApplication::translate( "variable_help", "Current scale of map." ) );
4584  gVariableHelpTexts.insert( "map_extent_center", QCoreApplication::translate( "variable_help", "Center of map." ) );
4585  gVariableHelpTexts.insert( "map_extent_width", QCoreApplication::translate( "variable_help", "Width of map." ) );
4586  gVariableHelpTexts.insert( "map_extent_height", QCoreApplication::translate( "variable_help", "Height of map." ) );
4587 
4588  gVariableHelpTexts.insert( "row_number", QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
4589  gVariableHelpTexts.insert( "grid_number", QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
4590  gVariableHelpTexts.insert( "grid_axis", QCoreApplication::translate( "variable_help", "Current grid annotation axis (eg, 'x' for longitude, 'y' for latitude)." ) );
4591 
4592  //symbol variables
4593  gVariableHelpTexts.insert( "geometry_part_count", QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
4594  gVariableHelpTexts.insert( "geometry_part_num", QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
4595 
4596  gVariableHelpTexts.insert( "symbol_color", QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
4597  gVariableHelpTexts.insert( "symbol_angle", QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
4598 }
4599 
4600 QString QgsExpression::variableHelpText( const QString &variableName, bool showValue, const QVariant &value )
4601 {
4603  QString text = gVariableHelpTexts.contains( variableName ) ? QString( "<p>%1</p>" ).arg( gVariableHelpTexts.value( variableName ) ) : QString();
4604  if ( showValue )
4605  {
4606  QString valueString;
4607  if ( !value.isValid() )
4608  {
4609  valueString = QCoreApplication::translate( "variable_help", "not set" );
4610  }
4611  else
4612  {
4613  valueString = QString( "<b>%1</b>" ).arg( formatPreviewString( value ) );
4614  }
4615  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
4616  }
4617  return text;
4618 }
4619 
4621 
4623 {
4624  if ( gGroups.isEmpty() )
4625  {
4626  gGroups.insert( "General", tr( "General" ) );
4627  gGroups.insert( "Operators", tr( "Operators" ) );
4628  gGroups.insert( "Conditionals", tr( "Conditionals" ) );
4629  gGroups.insert( "Fields and Values", tr( "Fields and Values" ) );
4630  gGroups.insert( "Math", tr( "Math" ) );
4631  gGroups.insert( "Conversions", tr( "Conversions" ) );
4632  gGroups.insert( "Date and Time", tr( "Date and Time" ) );
4633  gGroups.insert( "String", tr( "String" ) );
4634  gGroups.insert( "Color", tr( "Color" ) );
4635  gGroups.insert( "GeometryGroup", tr( "Geometry" ) );
4636  gGroups.insert( "Record", tr( "Record" ) );
4637  gGroups.insert( "Variables", tr( "Variables" ) );
4638  gGroups.insert( "Fuzzy Matching", tr( "Fuzzy Matching" ) );
4639  gGroups.insert( "Recent (%1)", tr( "Recent (%1)" ) );
4640  }
4641 
4642  //return the translated name for this group. If group does not
4643  //have a translated name in the gGroups hash, return the name
4644  //unchanged
4645  return gGroups.value( name, name );
4646 }
4647 
4649 {
4650  if ( value.canConvert<QgsGeometry>() )
4651  {
4652  //result is a geometry
4653  QgsGeometry geom = value.value<QgsGeometry>();
4654  if ( geom.isEmpty() )
4655  return tr( "<i>&lt;empty geometry&gt;</i>" );
4656  else
4657  return tr( "<i>&lt;geometry: %1&gt;</i>" ).arg( QgsWKBTypes::displayString( geom.geometry()->wkbType() ) );
4658  }
4659  else if ( value.canConvert< QgsFeature >() )
4660  {
4661  //result is a feature
4662  QgsFeature feat = value.value<QgsFeature>();
4663  return tr( "<i>&lt;feature: %1&gt;</i>" ).arg( feat.id() );
4664  }
4665  else if ( value.canConvert< QgsExpression::Interval >() )
4666  {
4667  //result is a feature
4669  return tr( "<i>&lt;interval: %1 days&gt;</i>" ).arg( interval.days() );
4670  }
4671  else if ( value.type() == QVariant::Date )
4672  {
4673  QDate dt = value.toDate();
4674  return tr( "<i>&lt;date: %1&gt;</i>" ).arg( dt.toString( "yyyy-MM-dd" ) );
4675  }
4676  else if ( value.type() == QVariant::Time )
4677  {
4678  QTime tm = value.toTime();
4679  return tr( "<i>&lt;time: %1&gt;</i>" ).arg( tm.toString( "hh:mm:ss" ) );
4680  }
4681  else if ( value.type() == QVariant::DateTime )
4682  {
4683  QDateTime dt = value.toDateTime();
4684  return tr( "<i>&lt;datetime: %1&gt;</i>" ).arg( dt.toString( "yyyy-MM-dd hh:mm:ss" ) );
4685  }
4686  else if ( value.type() == QVariant::String )
4687  {
4688  QString previewString = value.toString();
4689  if ( previewString.length() > 63 )
4690  {
4691  return QString( tr( "'%1...'" ) ).arg( previewString.left( 60 ) );
4692  }
4693  else
4694  {
4695  return previewString.prepend( '\'' ).append( '\'' );
4696  }
4697  }
4698  else
4699  {
4700  return value.toString();
4701  }
4702 }
4703 
4704 QVariant QgsExpression::Function::func( const QVariantList& values, const QgsFeature* feature, QgsExpression* parent )
4705 {
4706  //default implementation creates a QgsFeatureBasedExpressionContext
4708  return func( values, &c, parent );
4709 }
4710 
4711 QVariant QgsExpression::Function::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
4712 {
4713  //base implementation calls deprecated func to avoid API breakage
4714  QgsFeature f;
4715  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
4716  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
4717 
4719  return func( values, &f, parent );
4721 }
4722 
4724 {
4725  //default implementation creates a QgsFeatureBasedExpressionContext
4727  return eval( parent, &c );
4728 }
4729 
4731 {
4732  //base implementation calls deprecated eval to avoid API breakage
4733  QgsFeature f;
4734  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
4735  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
4736 
4738  return eval( parent, &f );
4740 }
4741 
4743 {
4745  return prepare( parent, &c );
4746 }
4747 
4749 {
4750  //base implementation calls deprecated prepare to avoid API breakage
4751  QgsFields f;
4752  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
4753  f = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
4754 
4756  return prepare( parent, f );
4758 }
4759 
4760 QVariant QgsExpression::StaticFunction::func( const QVariantList &values, const QgsFeature* f, QgsExpression* parent )
4761 {
4763  return mFnc ? mFnc( values, f, parent ) : QVariant();
4765 }
4766 
4768 {
4769  return d->mRootNode;
4770 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), eg "$area".
static bool isFunctionName(const QString &name)
tells whether the identifier is a name of existing function
static QVariant fcnDisjoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnConvexHull(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString longestCommonSubstring(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the longest common substring between two strings.
const QgsCurveV2 * exteriorRing() const
bool canConvert(Type t) const
Class for parsing and evaluation of expressions (formerly called "search strings").
double years()
interval length in years
qlonglong toLongLong(bool *ok) const
virtual QStringList referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node...
static QVariant fcnNodesToPoints(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
static QVariant fcnGeomNumInteriorRings(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Wrapper for iterator of features from vector data provider or vector layer.
QString toString(Qt::DateFormat format) const
const QgsVectorColorRampV2 * colorRampRef(const QString &name) const
return a const pointer to a symbol (doesn&#39;t create new instance)
Definition: qgsstylev2.cpp:263
static QVariant fcnGeomLength(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
int minute() const
QColor fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static QVariant fcnSin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static unsigned index
static QVariant fcnClosestPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
virtual Q_DECL_DEPRECATED QVariant eval(QgsExpression *parent, const QgsFeature *f)
Abstract virtual eval method Errors are reported to the parent.
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
Base class for all map layer types.
Definition: qgsmaplayer.h:49
static QVariant fcnBoundsWidth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnY(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QString cap(int nth) const
static QVariant fcnGeomPerimeter(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
QString & append(QChar ch)
virtual Node * clone() const =0
Generate a clone of this node.
iterator insert(const Key &key, const T &value)
QString toUpper() const
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static QVariant fcnAtlasCurrentGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnGeomFromWKT(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsPointV2 pointN(int i) const
Returns the specified point from inside the line string.
QColor darker(int factor) const
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
virtual Q_DECL_DEPRECATED QVariant func(const QVariantList &values, const QgsFeature *f, QgsExpression *parent) override
static QVariant fcnFormatDate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
iterator erase(iterator pos)
QStringList referencedColumns() const
Get list of columns referenced by the expression.
static QVariant fncLighter(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QPointF toPointF() const
static QVariant fcnFormatString(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
bool contains(const Key &key) const
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
virtual bool handlesNull() const
static QVariant fcnBuffer(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double months()
interval length in months
virtual QgsCoordinateSequenceV2 coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
QgsGeometry * symDifference(const QgsGeometry *geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
qreal alphaF() const
static QVariant fcnGeomNumRings(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnShortestLine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnClamp(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
static QVariant fcnGetGeometry(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool lazyEval()
True if this function should use lazy evaluation.
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:199
QString toString(Qt::DateFormat format) const
static QVariant fcnMakeLine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString toString(Qt::DateFormat format) const
static QVariant fcnStrpos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
static void initVariableHelp()
QString name() const
static QVariant fcnXat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
QgsGeometry * difference(const QgsGeometry *geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry, using GEOS.
static QString group(const QString &group)
Returns the translated name for a function group.
void initGeomCalculator()
static QVariant fcnWordwrap(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int length() const
A abstract base class for defining QgsExpression functions.
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
static QVariant fcnCentroid(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:197
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
double computeDouble(double x, double y)
static QVariant fcnIf(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static QString encodeColor(const QColor &color)
QDateTime toDateTime() const
static QgsExpressionContext createFeatureBasedContext(const QgsFeature &feature, const QgsFields &fields)
Helper function for creating an expression context which contains just a feature and fields collectio...
int fieldNameIndex(const QString &fieldName) const
Look up field&#39;s index from name also looks up case-insensitive if there is no match otherwise...
Definition: qgsfield.cpp:503
QString & prepend(QChar ch)
virtual QString dump() const =0
Abstract virtual dump method.
int value() const
static QVariant fcnPi(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QDate getDateValue(const QVariant &value, QgsExpression *parent)
virtual Node * clone() const override
Generate a clone of this node.
static QVariant pointAt(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QString escape(const QString &str)
static QVariant fcnAtan2(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString helptext(QString name)
Returns the help text for a specified function.
double weeks()
interval length in weeks
#define FEAT_FROM_CONTEXT(c, f)
static QVariant fcnMapId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
const_iterator constBegin() const
static QVariant fcnRegexpMatch(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const T & at(int i) const
static QVariant fcnFloor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QTime toTime() const
QVariant evaluate()
Evaluate the feature and return the result.
int size() const
static QVariant fncColorCmyka(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAcos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAbs(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void removeAt(int i)
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:415
QgsExpression()
Used by QgsOgcUtils to create an empty.
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
bool isValid() const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
Abstract base class for all geometries.
bool crosses(const QgsGeometry *geometry) const
Test for if geometry crosses another (uses GEOS)
T value() const
static QVariant fncColorHsva(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setBlue(int blue)
Container of fields for a vector layer.
Definition: qgsfield.h:187
static QVariant fcnAge(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToTime(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * pointOnSurface() const
Returns a point within a geometry.
virtual Q_DECL_DEPRECATED bool prepare(QgsExpression *parent, const QgsFields &fields)
Abstract virtual preparation method Errors are reported to the parent.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void setAlpha(int alpha)
static const char * vectorGeometryType(GeometryType type)
description strings for geometry types
Definition: qgis.cpp:439
const_iterator constFind(const Key &key) const
QgsExpression::Node * parseExpression(const QString &str, QString &parserErrorMsg)
QSet< T > toSet() const
static QVariant fcnTouches(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QTime getTimeValue(const QVariant &value, QgsExpression *parent)
QString dump() const
Return an expression string, constructed from the internal abstract syntax tree.
bool isDoubleSafe(const QVariant &v)
static QVariant fcnWithin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnExpScale(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Multi point geometry collection.
c++ helper class for defining QgsExpression functions.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
static QString formatPreviewString(const QVariant &value)
Formats an expression result for friendly display to the user.
static QVariant fcnMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpVariant > mVariants
static QVariant fcnLCS(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QgsCurveV2 * clone() const override=0
Clones the geometry by performing a deep copy.
static QVariant fcnXMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setRed(int red)
static TVL getTVLValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnFormatNumber(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int month() const
Q_DECL_DEPRECATED int currentRowNumber()
Return the number used for $rownum special column.
qreal hslHueF() const
double toDouble(bool *ok) const
static Q_DECL_DEPRECATED bool isValid(const QString &text, const QgsFields &fields, QString &errorMessage)
static QVariant fcnToDateTime(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal cyanF() const
static QVariant fncColorHsla(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int weekNumber(int *yearNumber) const
Multi line string geometry collection.
QString tr(const char *sourceText, const char *disambiguation, int n)
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
static QVariant fncColorPart(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAzimuth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString soundex(const QString &string)
Returns the Soundex representation of a string.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
QGis::UnitType distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), eg "$length" and "$pe...
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
int second() const
static QVariant fcnComposerPage(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
virtual Node * clone() const override
Generate a clone of this node.
static QVariant fncDarker(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnGeomArea(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnLevenshtein(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
int size() const
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
void setEvalErrorString(const QString &str)
Set evaluation error (used internally by evaluation functions)
static QgsGeometry getGeometry(const QVariant &value, QgsExpression *parent)
#define ENSURE_NO_EVAL_ERROR
static QVariant fcnToReal(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static Q_DECL_DEPRECATED void setSpecialColumn(const QString &name, const QVariant &value)
Assign a special column.
static QVariant fcnYat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
int lightness() const
static QVariant fcnCos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QStringList & BuiltinFunctions()
int dayOfWeek() const
static QVariant fcnSymDifference(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
static bool unregisterFunction(const QString &name)
Unregisters a function from the expression engine.
static const QList< Function * > & Functions()
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
int matchedLength() const
static QVariant fcnGetLayerProperty(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnSegmentsToLines(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnColorHsl(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnExteriorRing(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid()
getter interval validity
int indexIn(const QString &str, int offset, CaretMode caretMode) const
static QVariant fcnMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Polygon geometry type.
Definition: qgspolygonv2.h:29
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
static QVariant fncSetColorPart(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static QVariant fcnAtlasFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static int functionCount()
Returns the number of functions defined in the parser.
static QVariant fcnRndF(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression...
NodeList * clone() const
Creates a deep copy of this list.
static QVariant fcnMinute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void acceptVisitor(Visitor &v) const
Entry function for the visitor pattern.
void setGeometry(const QgsGeometry &geom)
Set this feature&#39;s geometry from another QgsGeometry object.
Definition: qgsfeature.cpp:124
static QVariant fcnTrim(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool contains(const QgsPoint *p) const
Test for containment of a point (uses GEOS)
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QString number(int n, int base)
int count(const T &value) const
static QVariant fcnMonth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsDistanceArea * geomCalculator()
Return calculator used for distance and area calculations (used by $length, $area and $perimeter func...
static QVariant fcnTranslate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnStartPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal x() const
qreal y() const
void setGreen(int green)
void append(const T &value)
static QVariant fcnLn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnMakePoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsExpressionPrivate * d
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
static QVariant fcnGeomY(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define TVL_Unknown
virtual void setExteriorRing(QgsCurveV2 *ring) override
Sets the exterior ring of the polygon.
virtual Node * clone() const override
Generate a clone of this node.
#define FALLTHROUGH
Definition: qgis.h:439
virtual QgsCurveV2 * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
int toInt(bool *ok) const
bool isNull() const
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:202
const Key & key() const
static QVariant fcnIntersects(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnColorHsv(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnCoalesce(const QVariantList &values, const QgsExpressionContext *, QgsExpression *)
static int functionIndex(const QString &name)
return index of the function in Functions array
static QVariant fcnRelate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:187
static QVariant fcnWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString rightJustified(int width, QChar fill, bool truncate) const
Utility class for identifying a unique vertex within a geometry.
virtual Q_DECL_DEPRECATED QVariant func(const QVariantList &, const QgsFeature *, QgsExpression *)
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
virtual QString dump() const override
Abstract virtual dump method.
Line string geometry type, with support for z-dimension and m-values.
static QVariant fcnScale(const QVariantList &, const QgsExpressionContext *, QgsExpression *parent)
int red() const
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
bool isEmpty() const
Returns true if the geometry is empty.
static QVariant fcnRowNumber(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
qreal valueF() const
static QVariant fcnConcat(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setPoints(const QgsPointSequenceV2 &points)
Resets the line string to match the specified list of points.
static QVariant fcnGeomNumGeometries(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnHamming(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnOrderParts(const QVariantList &values, const QgsExpressionContext *ctx, QgsExpression *parent)
static QgsGeometry * geometryFromGML(const QString &xmlString)
Static method that creates geometry from GML.
Definition: qgsogcutils.cpp:97
#define SET_EVAL_ERROR(x)
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QList< Node * > mList
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine...
bool overlaps(const QgsGeometry *geometry) const
Test for if geometry overlaps another (uses GEOS)
QgsExpression & operator=(const QgsExpression &other)
Create a copy of this expression.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
int toInt(bool *ok, int base) const
static QHash< QString, QString > gGroups
bool isEmpty() const
static QVariant fcnAtlasFeatureId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static bool registerFunction(Function *function, bool transferOwnership=false)
Registers a function to the expression engine.
static QgsStyleV2 * defaultStyle()
return default application-wide style
Definition: qgsstylev2.cpp:51
bool isEmpty() const
static bool hasSpecialColumn(const QString &name)
Check whether a special column exists.
QString trimmed() const
static QVariant fcnIntersection(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double minutes()
interval length in minutus
const_iterator constEnd() const
int day() const
static QVariant fcnRadians(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
static QVariant fcnUpper(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define M_PI
static QVariant fcnToInt(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToDate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
qreal lightnessF() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static QVariant fcnGeomX(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual Node * clone() const override
Generate a clone of this node.
bool isValid() const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
double hours()
interval length in hours
void addInteriorRing(QgsCurveV2 *ring) override
Adds an interior ring to the geometry (takes ownership)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
static const QString AllAttributes
A special attribute that if set matches all attributes.
static QVariant fcnExp(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnPointOnSurface(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
virtual Node * clone() const override
Generate a clone of this node.
static QHash< QString, QString > gVariableHelpTexts
const T & value() const
static QVariant fcnContains(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToInterval(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define TVL_False
QGis::GeometryType geometryType() const
Returns point, line or polygon.
virtual int partCount() const override
Returns count of parts contained in the geometry.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
int year() const
static QVariant fcnLog10(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnBoundsHeight(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
T & first()
static QVariant fcnRight(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpArg > mArguments
static QList< Function * > gmFunctions
static QVariant fcnDifference(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * centroid() const
Returns the center of mass of a geometry.
iterator end()
static QVariant fcnCrosses(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QString EXPR_FIELDS
Inbuilt variable name for fields storage.
QgsUnitTypes::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), eg "$area".
virtual QString dump() const
QString name()
The name of the function.
Q_DECL_DEPRECATED void setCurrentRowNumber(int rowNumber)
Set the number for $rownum special column.
static QVariant tvl2variant(TVL v)
#define ENSURE_GEOM_TYPE(f, g, geomtype)
qreal hsvHueF() const
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings.
static QVariant fcnAsin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnYMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGetFeature(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool operator==(QgsExpression::Interval other) const
compare two intervals
QList< HelpExample > mExamples
static QVariant fcnToString(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int alpha() const
bool isIntervalSafe(const QVariant &v)
QgsGeometry * buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
A class to represent a point.
Definition: qgspoint.h:65
static QVariant fcnNow(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
iterator begin()
static QVariant fcnFeatureId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnEval(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnIsClosed(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnDistance(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static int getIntValue(const QVariant &value, QgsExpression *parent)
QList< QgsMapLayer * > mapLayersByName(const QString &layerName)
Retrieve a pointer to a loaded layer by name.
int translate(double dx, double dy)
Translate this geometry by dx, dy.
virtual int ringCount(int=0) const override
static QVariant fcnBbox(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnRound(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int hour() const
int green() const
static QVariant fcnGeomZ(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString toLower() const
const T value(const Key &key) const
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometryV2 *geometry)
Creates and returns a new geometry engine.
static QVariant fcnGeomFromGML(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool contains(QChar ch, Qt::CaseSensitivity cs) const
void setHslF(qreal h, qreal s, qreal l, qreal a)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static QVariant fcnSeconds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnMakePointM(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setHsvF(qreal h, qreal s, qreal v, qreal a)
static QVariant fcnExtrude(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnArea(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnCeil(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnHour(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGeomNumPoints(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QColor lighter(int factor) const
QStringRef midRef(int position, int n) const
const QgsCurveV2 * interiorRing(int i) const
static QVariant fcnLeft(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fromValue(const T &value)
double length() const
Returns the length of geometry using GEOS.
static QString getStringValue(const QVariant &value, QgsExpression *)
The OrderByClause class represents an order by clause for a QgsFeatureRequest.
static QVariant fcnDegrees(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double days()
interval length in days
static QVariant fcnSoundex(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsFeature getFeature(const QVariant &value, QgsExpression *parent)
virtual QStringList referencedColumns() const
static QVariant fcnRPad(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLog(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
static double getDoubleValue(const QVariant &value, QgsExpression *parent)
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:416
General purpose distance and area calculator.
static QVariant fcnAtlasCurrentFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QgsGeometry * intersection(const QgsGeometry *geometry) const
Returns a geometry representing the points shared by this geometry and other.
bool vertexIdFromVertexNr(int nr, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
virtual Node * clone() const override
Generate a clone of this node.
QgsGeometry * combine(const QgsGeometry *geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
static QVariant fcnX(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QDate toDate() const
QString & replace(int position, int n, QChar after)
static QMap< QString, QString > gmSpecialColumnGroups
virtual QString dump() const override
Abstract virtual dump method.
static void registerContextFunctions()
Registers all known core functions provided by QgsExpressionContextScope objects. ...
int numGeometries() const
Returns the number of geometries within the collection.
void addVertex(const QgsPointV2 &pt)
Adds a new vertex to the end of the line string.
int blue() const
double measureLength(const QgsGeometry *geometry) const
Measures the length of a geometry.
static QVariant fcnPointN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnBounds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal yellowF() const
static QVariant fcnFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnGetVariable(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QVariant(* FcnEvalContext)(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Function definition for evaluation against an expression context.
static QVariant fcnOverlaps(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QDateTime currentDateTime()
bool isIntSafe(const QVariant &v)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QString mid(int position, int n) const
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
QDate date() const
bool isDateTimeSafe(const QVariant &v)
static const char * UnaryOperatorText[]
static QVariant fcnDay(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsExpression::Interval invalidInterVal()
return an invalid interval
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest point on this geometry to another geometry.
static QVariant fcnGeometryN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QString EXPR_FEATURE
Inbuilt variable name for feature storage.
static QVariant fcnTransformGeometry(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QList< QgsLineStringV2 * > extractLineStrings(const QgsAbstractGeometryV2 *geom)
Returns list of linestrings extracted from the passed geometry.
static QVariant fcnComposerNumPages(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnLPad(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isEmpty() const
static QgsExpression::Node * getNode(const QVariant &value, QgsExpression *parent)
double seconds()
interval length in seconds
QString escape(const QString &plain)
static QVariant fcnReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsExpression::Interval fromString(const QString &string)
convert a string to an interval
qreal hsvSaturationF() const
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:27
static QList< Function * > specialColumns()
Returns a list of special Column definitions.
static TVL OR[3][3]
int params()
The number of parameters this function takes.
static TVL NOT[3]
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
static QVariant fcnAtan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
T & last()
Class for storing a coordinate reference system (CRS)
virtual bool addGeometry(QgsAbstractGeometryV2 *g)
Adds a geometry and takes ownership.
QString translate(const char *context, const char *sourceText, const char *disambiguation, Encoding encoding)
static QVariant fcnAttribute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QStringList referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node...
bool within(const QgsGeometry *geometry) const
Test for if geometry is within another (uses GEOS)
void setDistanceUnits(QGis::UnitType unit)
Sets the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perim...
static QVariant fcnMakePolygon(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
static QVariant fcnAtlasNumFeatures(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QList< T > mid(int pos, int length) const
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
static QVariant fcnXMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Class for doing transforms between two map coordinate systems.
#define TVL_True
int length() const
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Support for visitor pattern - algorithms dealing with the expressions may be implemented without modi...
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
bool toBool() const
QString leftJustified(int width, QChar fill, bool truncate) const
int lastIndexOf(const QRegExp &rx, int from) const
UnitType
Map units that qgis supports.
Definition: qgis.h:155
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
static QVariant fcnInteriorRingN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
qreal hslSaturationF() const
void setHsl(int h, int s, int l, int a)
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression...
void setHsv(int h, int s, int v, int a)
QString left(int n) const
static QVariant fcnGeomToWKT(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QHash< QString, Help > gFunctionHelpTexts
static Q_DECL_DEPRECATED QString replaceExpressionText(const QString &action, const QgsFeature *feat, QgsVectorLayer *layer, const QMap< QString, QVariant > *substitutionMap=nullptr, const QgsDistanceArea *distanceArea=nullptr)
This function currently replaces each expression between [% and %] in the string with the result of i...
QString expression() const
Return the original, unmodified expression string.
void setGeomCalculator(const QgsDistanceArea &calc)
Sets the geometry calculator used for distance and area calculations in expressions.
static QVariant fcnColorCmyk(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
static QVariant fcnSqrt(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
static QVariant fcnTitle(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QStringList gmBuiltinFunctions
int indexOf(const QRegExp &rx, int from) const
static QVariant fcnRnd(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
static QString variableHelpText(const QString &variableName, bool showValue=true, const QVariant &value=QVariant())
Returns the help text for a specified variable.
bool disjoint(const QgsGeometry *geometry) const
Test for if geometry is disjoint of another (uses GEOS)
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
static QVariant fcnYMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
static QVariant fcnGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnUuid(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
qreal magentaF() const
bool touches(const QgsGeometry *geometry) const
Test for if geometry touch another (uses GEOS)
static Q_DECL_DEPRECATED QVariant specialColumn(const QString &name)
Return the value of the given special column or a null QVariant if undefined.
UnaryOperator op() const
Curve polygon geometry type.
static void initFunctionHelp()
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
static QgsGeometry * fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static QVariant fcnReverse(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnEndPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsExpression::Function * function(const QString &name) const
Fetches a matching function from the context.
QString exportToWkt(int precision=17) const
Exports the geometry to WKT.
void setValid(bool valid)
setter interval validity
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
int numInteriorRings() const
bool nextFeature(QgsFeature &f)
QDateTime computeDateTimeFromInterval(const QDateTime &d, QgsExpression::Interval *i)
static QList< Function * > gmOwnedFunctions
List of functions owned by the expression engine.
static QVariant fcnTan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
QDateTime addSecs(int s) const
virtual QgsAbstractGeometryV2 * clone() const =0
Clones the geometry by performing a deep copy.
static QString displayString(Type type)
Returns a display string type for a WKB type, eg the geometry name used in WKT geometry representatio...
Definition: qgswkbtypes.cpp:48
Type type() const
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
static QVariant fcnPerimeter(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
void setScale(double scale)
static TVL AND[3][3]
double convertLengthMeasurement(double length, QGis::UnitType toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
static QVariant fcnRegexpReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
Represents a vector layer which manages a vector based data sets.
int hslSaturation() const
int compare(const QString &other) const
void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
QString parserErrorString() const
Returns parser error.
static QVariant fcnLinearScale(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool exactMatch(const QString &str) const
static double evaluateToDouble(const QString &text, const double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:192
QString toString() const
QString toString() const
virtual QStringList referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node...
void detach()
Helper for implicit sharing.
QString evalErrorString() const
Returns evaluation error.
iterator find(const Key &key)
static QVariant fcnGeomM(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
AreaUnit
Units of area.
Definition: qgsunittypes.h:49
bool isNull(const QVariant &v)
static QVariant fcnDayOfWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
virtual void clear() override
Clears the geometry, ie reset it to a null geometry.
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
double area() const
Returns the area of the geometry using GEOS.
static QVariant fcnSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QUuid createUuid()
virtual QgsPointV2 vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
QColor fromHsvF(qreal h, qreal s, qreal v, qreal a)
static QVariant fcnYear(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static int hammingDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Hamming distance between two strings.
int hsvSaturation() const
qreal blackF() const
Represents a list of OrderByClauses, with the most important first and the least important last...
static QVariant fcnRegexpSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual Node * clone() const override
Generate a clone of this node.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:212
int numPoints() const override
Returns the number of points in the curve.
bool isValid() const
QList< QgsPointV2 > QgsPointSequenceV2
QColor fromHslF(qreal h, qreal s, qreal l, qreal a)
static QVariant fcnColorRgb(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fncColorRgba(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsExpression::Interval getInterval(const QVariant &value, QgsExpression *parent, bool report_error=false)
const T value(const Key &key) const
static QDateTime getDateTimeValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnCombine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fcnRampColor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static Q_DECL_DEPRECATED void unsetSpecialColumn(const QString &name)
Unset a special column.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
static QVariant fcnSpecialColumn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define tr(sourceText)
static QVariant fcnLength(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLower(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const char * BinaryOperatorText[]
static QMap< QString, QVariant > gmSpecialColumns