QGIS API Documentation  2.99.0-Master (37c43df)
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 #include "qgsrelationmanager.h"
18 
19 #include <QtDebug>
20 #include <QDomDocument>
21 #include <QDate>
22 #include <QRegExp>
23 #include <QColor>
24 #include <QUuid>
25 #include <QMutex>
26 
27 #include <math.h>
28 #include <limits>
29 
30 #include "qgsdistancearea.h"
31 #include "qgsfeature.h"
32 #include "qgsfeatureiterator.h"
33 #include "qgsgeometry.h"
34 #include "qgsgeometryengine.h"
35 #include "qgsgeometryutils.h"
36 #include "qgslogger.h"
37 #include "qgsmaplayerregistry.h"
38 #include "qgsogcutils.h"
39 #include "qgsvectorlayer.h"
40 #include "qgssymbollayerutils.h"
41 #include "qgscolorramp.h"
42 #include "qgsstyle.h"
43 #include "qgsexpressioncontext.h"
44 #include "qgsproject.h"
45 #include "qgsstringutils.h"
46 #include "qgsgeometrycollection.h"
47 #include "qgspointv2.h"
48 #include "qgspolygon.h"
49 #include "qgsmultipoint.h"
50 #include "qgsmultilinestring.h"
51 #include "qgscurvepolygon.h"
52 #include "qgsexpressionprivate.h"
53 #include "qgsexpressionsorter.h"
55 #include "qgsmessagelog.h"
56 #include "qgscsexception.h"
57 #include "qgsrasterlayer.h"
58 #include "qgsrasterdataprovider.h"
59 
60 // from parser
61 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
62 
64 // three-value logic
65 
66 enum TVL
67 {
71 };
72 
73 static TVL AND[3][3] =
74 {
75  // false true unknown
76  { False, False, False }, // false
77  { False, True, Unknown }, // true
78  { False, Unknown, Unknown } // unknown
79 };
80 
81 static TVL OR[3][3] =
82 {
83  { False, True, Unknown }, // false
84  { True, True, True }, // true
85  { Unknown, True, Unknown } // unknown
86 };
87 
88 static TVL NOT[3] = { True, False, Unknown };
89 
90 static QVariant tvl2variant( TVL v )
91 {
92  switch ( v )
93  {
94  case False:
95  return 0;
96  case True:
97  return 1;
98  case Unknown:
99  default:
100  return QVariant();
101  }
102 }
103 
104 #define TVL_True QVariant(1)
105 #define TVL_False QVariant(0)
106 #define TVL_Unknown QVariant()
107 
109 // QVariant checks and conversions
110 
111 inline bool isIntSafe( const QVariant& v )
112 {
113  if ( v.type() == QVariant::Int )
114  return true;
115  if ( v.type() == QVariant::UInt )
116  return true;
117  if ( v.type() == QVariant::LongLong )
118  return true;
119  if ( v.type() == QVariant::ULongLong )
120  return true;
121  if ( v.type() == QVariant::Double )
122  return false;
123  if ( v.type() == QVariant::String )
124  {
125  bool ok;
126  v.toString().toInt( &ok );
127  return ok;
128  }
129  return false;
130 }
131 inline bool isDoubleSafe( const QVariant& v )
132 {
133  if ( v.type() == QVariant::Double )
134  return true;
135  if ( v.type() == QVariant::Int )
136  return true;
137  if ( v.type() == QVariant::UInt )
138  return true;
139  if ( v.type() == QVariant::LongLong )
140  return true;
141  if ( v.type() == QVariant::ULongLong )
142  return true;
143  if ( v.type() == QVariant::String )
144  {
145  bool ok;
146  double val = v.toString().toDouble( &ok );
147  ok = ok && qIsFinite( val ) && !qIsNaN( val );
148  return ok;
149  }
150  return false;
151 }
152 
153 inline bool isDateTimeSafe( const QVariant& v )
154 {
155  return v.type() == QVariant::DateTime
156  || v.type() == QVariant::Date
157  || v.type() == QVariant::Time;
158 }
159 
160 inline bool isIntervalSafe( const QVariant& v )
161 {
162  if ( v.canConvert<QgsInterval>() )
163  {
164  return true;
165  }
166 
167  if ( v.type() == QVariant::String )
168  {
169  return QgsInterval::fromString( v.toString() ).isValid();
170  }
171  return false;
172 }
173 
174 inline bool isNull( const QVariant& v )
175 {
176  return v.isNull();
177 }
178 
180 // evaluation error macros
181 
182 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
183 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
184 
186 // operators
187 
188 const char* QgsExpression::BinaryOperatorText[] =
189 {
190  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
191  "OR", "AND",
192  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
193  "+", "-", "*", "/", "//", "%", "^",
194  "||"
195 };
196 
197 const char* QgsExpression::UnaryOperatorText[] =
198 {
199  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
200  "NOT", "-"
201 };
202 
204 // functions
205 
206 // implicit conversion to string
207 static QString getStringValue( const QVariant& value, QgsExpression* )
208 {
209  return value.toString();
210 }
211 
212 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
213 {
214  bool ok;
215  double x = value.toDouble( &ok );
216  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
217  {
218  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
219  return 0;
220  }
221  return x;
222 }
223 
224 static int getIntValue( const QVariant& value, QgsExpression* parent )
225 {
226  bool ok;
227  qint64 x = value.toLongLong( &ok );
229  {
230  return x;
231  }
232  else
233  {
234  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
235  return 0;
236  }
237 }
238 
239 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
240 {
241  QDateTime d = value.toDateTime();
242  if ( d.isValid() )
243  {
244  return d;
245  }
246  else
247  {
248  QTime t = value.toTime();
249  if ( t.isValid() )
250  {
251  return QDateTime( QDate( 1, 1, 1 ), t );
252  }
253 
254  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
255  return QDateTime();
256  }
257 }
258 
259 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
260 {
261  QDate d = value.toDate();
262  if ( d.isValid() )
263  {
264  return d;
265  }
266  else
267  {
268  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
269  return QDate();
270  }
271 }
272 
273 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
274 {
275  QTime t = value.toTime();
276  if ( t.isValid() )
277  {
278  return t;
279  }
280  else
281  {
282  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
283  return QTime();
284  }
285 }
286 
287 static QgsInterval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
288 {
289  if ( value.canConvert<QgsInterval>() )
290  return value.value<QgsInterval>();
291 
292  QgsInterval inter = QgsInterval::fromString( value.toString() );
293  if ( inter.isValid() )
294  {
295  return inter;
296  }
297  // If we get here then we can't convert so we just error and return invalid.
298  if ( report_error )
299  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
300 
301  return QgsInterval();
302 }
303 
304 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
305 {
306  if ( value.canConvert<QgsGeometry>() )
307  return value.value<QgsGeometry>();
308 
309  parent->setEvalErrorString( QStringLiteral( "Cannot convert to QgsGeometry" ) );
310  return QgsGeometry();
311 }
312 
313 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
314 {
315  if ( value.canConvert<QgsFeature>() )
316  return value.value<QgsFeature>();
317 
318  parent->setEvalErrorString( QStringLiteral( "Cannot convert to QgsFeature" ) );
319  return 0;
320 }
321 
322 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
323  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
324 
325 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
326 {
327  if ( value.canConvert<QgsExpression::Node*>() )
328  return value.value<QgsExpression::Node*>();
329 
330  parent->setEvalErrorString( QStringLiteral( "Cannot convert to Node" ) );
331  return nullptr;
332 }
333 
334 QgsVectorLayer* getVectorLayer( const QVariant& value, QgsExpression* )
335 {
336  QgsMapLayer* ml = value.value< QPointer<QgsMapLayer> >().data();
337  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( ml );
338  if ( !vl )
339  {
340  QString layerString = value.toString();
341  vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
342 
343  if ( !vl )
344  {
345  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
346  if ( !layersByName.isEmpty() )
347  {
348  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
349  }
350  }
351  }
352 
353  return vl;
354 }
355 
356 
357 // this handles also NULL values
358 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
359 {
360  // we need to convert to TVL
361  if ( value.isNull() )
362  return Unknown;
363 
364  //handle some special cases
365  if ( value.canConvert<QgsGeometry>() )
366  {
367  //geom is false if empty
368  QgsGeometry geom = value.value<QgsGeometry>();
369  return geom.isEmpty() ? False : True;
370  }
371  else if ( value.canConvert<QgsFeature>() )
372  {
373  //feat is false if non-valid
374  QgsFeature feat = value.value<QgsFeature>();
375  return feat.isValid() ? True : False;
376  }
377 
378  if ( value.type() == QVariant::Int )
379  return value.toInt() != 0 ? True : False;
380 
381  bool ok;
382  double x = value.toDouble( &ok );
383  if ( !ok )
384  {
385  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
386  return Unknown;
387  }
388  return !qgsDoubleNear( x, 0.0 ) ? True : False;
389 }
390 
391 static QVariantList getListValue( const QVariant& value, QgsExpression* parent )
392 {
393  if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
394  {
395  return value.toList();
396  }
397  else
398  {
399  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to array" ).arg( value.toString() ) );
400  return QVariantList();
401  }
402 }
403 
404 static QVariantMap getMapValue( const QVariant& value, QgsExpression* parent )
405 {
406  if ( value.type() == QVariant::Map )
407  {
408  return value.toMap();
409  }
410  else
411  {
412  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to map" ).arg( value.toString() ) );
413  return QVariantMap();
414  }
415 }
416 
418 
419 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
420 {
421  if ( !context )
422  return QVariant();
423 
424  QString name = getStringValue( values.at( 0 ), parent );
425  return context->variable( name );
426 }
427 
428 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
429 {
430  if ( !context )
431  return QVariant();
432 
433  QString expString = getStringValue( values.at( 0 ), parent );
434  QgsExpression expression( expString );
435  return expression.evaluate( context );
436 }
437 
438 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
439 {
440  double x = getDoubleValue( values.at( 0 ), parent );
441  return QVariant( sqrt( x ) );
442 }
443 
444 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
445 {
446  double val = getDoubleValue( values.at( 0 ), parent );
447  return QVariant( fabs( val ) );
448 }
449 
450 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
451 {
452  double deg = getDoubleValue( values.at( 0 ), parent );
453  return ( deg * M_PI ) / 180;
454 }
455 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
456 {
457  double rad = getDoubleValue( values.at( 0 ), parent );
458  return ( 180 * rad ) / M_PI;
459 }
460 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
461 {
462  double x = getDoubleValue( values.at( 0 ), parent );
463  return QVariant( sin( x ) );
464 }
465 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
466 {
467  double x = getDoubleValue( values.at( 0 ), parent );
468  return QVariant( cos( x ) );
469 }
470 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
471 {
472  double x = getDoubleValue( values.at( 0 ), parent );
473  return QVariant( tan( x ) );
474 }
475 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
476 {
477  double x = getDoubleValue( values.at( 0 ), parent );
478  return QVariant( asin( x ) );
479 }
480 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
481 {
482  double x = getDoubleValue( values.at( 0 ), parent );
483  return QVariant( acos( x ) );
484 }
485 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
486 {
487  double x = getDoubleValue( values.at( 0 ), parent );
488  return QVariant( atan( x ) );
489 }
490 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
491 {
492  double y = getDoubleValue( values.at( 0 ), parent );
493  double x = getDoubleValue( values.at( 1 ), parent );
494  return QVariant( atan2( y, x ) );
495 }
496 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
497 {
498  double x = getDoubleValue( values.at( 0 ), parent );
499  return QVariant( exp( x ) );
500 }
501 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
502 {
503  double x = getDoubleValue( values.at( 0 ), parent );
504  if ( x <= 0 )
505  return QVariant();
506  return QVariant( log( x ) );
507 }
508 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
509 {
510  double x = getDoubleValue( values.at( 0 ), parent );
511  if ( x <= 0 )
512  return QVariant();
513  return QVariant( log10( x ) );
514 }
515 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
516 {
517  double b = getDoubleValue( values.at( 0 ), parent );
518  double x = getDoubleValue( values.at( 1 ), parent );
519  if ( x <= 0 || b <= 0 )
520  return QVariant();
521  return QVariant( log( x ) / log( b ) );
522 }
523 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
524 {
525  double min = getDoubleValue( values.at( 0 ), parent );
526  double max = getDoubleValue( values.at( 1 ), parent );
527  if ( max < min )
528  return QVariant();
529 
530  // Return a random double in the range [min, max] (inclusive)
531  double f = static_cast< double >( qrand() ) / RAND_MAX;
532  return QVariant( min + f * ( max - min ) );
533 }
534 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
535 {
536  int min = getIntValue( values.at( 0 ), parent );
537  int max = getIntValue( values.at( 1 ), parent );
538  if ( max < min )
539  return QVariant();
540 
541  // Return a random integer in the range [min, max] (inclusive)
542  return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
543 }
544 
545 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
546 {
547  double val = getDoubleValue( values.at( 0 ), parent );
548  double domainMin = getDoubleValue( values.at( 1 ), parent );
549  double domainMax = getDoubleValue( values.at( 2 ), parent );
550  double rangeMin = getDoubleValue( values.at( 3 ), parent );
551  double rangeMax = getDoubleValue( values.at( 4 ), parent );
552 
553  if ( domainMin >= domainMax )
554  {
555  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
556  return QVariant();
557  }
558 
559  // outside of domain?
560  if ( val >= domainMax )
561  {
562  return rangeMax;
563  }
564  else if ( val <= domainMin )
565  {
566  return rangeMin;
567  }
568 
569  // calculate linear scale
570  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
571  double c = rangeMin - ( domainMin * m );
572 
573  // Return linearly scaled value
574  return QVariant( m * val + c );
575 }
576 
577 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
578 {
579  double val = getDoubleValue( values.at( 0 ), parent );
580  double domainMin = getDoubleValue( values.at( 1 ), parent );
581  double domainMax = getDoubleValue( values.at( 2 ), parent );
582  double rangeMin = getDoubleValue( values.at( 3 ), parent );
583  double rangeMax = getDoubleValue( values.at( 4 ), parent );
584  double exponent = getDoubleValue( values.at( 5 ), parent );
585 
586  if ( domainMin >= domainMax )
587  {
588  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
589  return QVariant();
590  }
591  if ( exponent <= 0 )
592  {
593  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
594  return QVariant();
595  }
596 
597  // outside of domain?
598  if ( val >= domainMax )
599  {
600  return rangeMax;
601  }
602  else if ( val <= domainMin )
603  {
604  return rangeMin;
605  }
606 
607  // Return exponentially scaled value
608  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
609 }
610 
611 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
612 {
613  //initially set max as first value
614  double maxVal = getDoubleValue( values.at( 0 ), parent );
615 
616  //check against all other values
617  for ( int i = 1; i < values.length(); ++i )
618  {
619  double testVal = getDoubleValue( values[i], parent );
620  if ( testVal > maxVal )
621  {
622  maxVal = testVal;
623  }
624  }
625 
626  return QVariant( maxVal );
627 }
628 
629 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
630 {
631  //initially set min as first value
632  double minVal = getDoubleValue( values.at( 0 ), parent );
633 
634  //check against all other values
635  for ( int i = 1; i < values.length(); ++i )
636  {
637  double testVal = getDoubleValue( values[i], parent );
638  if ( testVal < minVal )
639  {
640  minVal = testVal;
641  }
642  }
643 
644  return QVariant( minVal );
645 }
646 
647 static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
648 {
649  //lazy eval, so we need to evaluate nodes now
650 
651  //first node is layer id or name
652  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
654  QVariant value = node->eval( parent, context );
656  QgsVectorLayer* vl = getVectorLayer( value, parent );
657  if ( !vl )
658  {
659  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
660  return QVariant();
661  }
662 
663  // second node is aggregate type
664  node = getNode( values.at( 1 ), parent );
666  value = node->eval( parent, context );
668  bool ok = false;
670  if ( !ok )
671  {
672  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
673  return QVariant();
674  }
675 
676  // third node is subexpression (or field name)
677  node = getNode( values.at( 2 ), parent );
679  QString subExpression = node->dump();
680 
682  //optional forth node is filter
683  if ( values.count() > 3 )
684  {
685  node = getNode( values.at( 3 ), parent );
687  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
688  if ( !nl || nl->value().isValid() )
689  parameters.filter = node->dump();
690  }
691 
692  //optional fifth node is concatenator
693  if ( values.count() > 4 )
694  {
695  node = getNode( values.at( 4 ), parent );
697  value = node->eval( parent, context );
699  parameters.delimiter = value.toString();
700  }
701 
702  QVariant result;
703  if ( context )
704  {
705  QString cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter );
706 
707  QgsExpression subExp( subExpression );
708  QgsExpression filterExp( parameters.filter );
709  if ( filterExp.referencedVariables().contains( "parent" )
710  || filterExp.referencedVariables().contains( QString() )
711  || subExp.referencedVariables().contains( "parent" )
712  || subExp.referencedVariables().contains( QString() ) )
713  {
714  cacheKey += ':' + qHash( context->feature() );
715  }
716 
717  if ( context && context->hasCachedValue( cacheKey ) )
718  return context->cachedValue( cacheKey );
719 
720  QgsExpressionContext subContext( *context );
722  subScope->setVariable( "parent", context->feature() );
723  subContext.appendScope( subScope );
724  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
725 
726  context->setCachedValue( cacheKey, result );
727  }
728  else
729  {
730  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
731  }
732  if ( !ok )
733  {
734  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
735  return QVariant();
736  }
737 
738  return result;
739 }
740 
741 static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
742 {
743  if ( !context )
744  {
745  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
746  return QVariant();
747  }
748 
749  // first step - find current layer
750  QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
751  if ( !vl )
752  {
753  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
754  return QVariant();
755  }
756 
757  //lazy eval, so we need to evaluate nodes now
758 
759  //first node is relation name
760  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
762  QVariant value = node->eval( parent, context );
764  QString relationId = value.toString();
765  // check relation exists
766  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
767  if ( !relation.isValid() || relation.referencedLayer() != vl )
768  {
769  // check for relations by name
770  QList< QgsRelation > relations = QgsProject::instance()->relationManager()->relationsByName( relationId );
771  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
772  {
773  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
774  return QVariant();
775  }
776  else
777  {
778  relation = relations.at( 0 );
779  }
780  }
781 
782  QgsVectorLayer* childLayer = relation.referencingLayer();
783 
784  // second node is aggregate type
785  node = getNode( values.at( 1 ), parent );
787  value = node->eval( parent, context );
789  bool ok = false;
791  if ( !ok )
792  {
793  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
794  return QVariant();
795  }
796 
797  //third node is subexpression (or field name)
798  node = getNode( values.at( 2 ), parent );
800  QString subExpression = node->dump();
801 
802  //optional fourth node is concatenator
804  if ( values.count() > 3 )
805  {
806  node = getNode( values.at( 3 ), parent );
808  value = node->eval( parent, context );
810  parameters.delimiter = value.toString();
811  }
812 
813  FEAT_FROM_CONTEXT( context, f );
814  parameters.filter = relation.getRelatedFeaturesFilter( f );
815 
816  QString cacheKey = QStringLiteral( "relagg:%1:%2:%3:%4" ).arg( vl->id(),
817  QString::number( static_cast< int >( aggregate ) ),
818  subExpression,
819  parameters.filter );
820  if ( context && context->hasCachedValue( cacheKey ) )
821  return context->cachedValue( cacheKey );
822 
823  QVariant result;
824  ok = false;
825 
826 
827  QgsExpressionContext subContext( *context );
828  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
829 
830  if ( !ok )
831  {
832  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
833  return QVariant();
834  }
835 
836  // cache value
837  if ( context )
838  context->setCachedValue( cacheKey, result );
839  return result;
840 }
841 
842 
843 static QVariant fcnAggregateGeneric( QgsAggregateCalculator::Aggregate aggregate, const QVariantList& values, QgsAggregateCalculator::AggregateParameters parameters, const QgsExpressionContext* context, QgsExpression *parent )
844 {
845  if ( !context )
846  {
847  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
848  return QVariant();
849  }
850 
851  // first step - find current layer
852  QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
853  if ( !vl )
854  {
855  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
856  return QVariant();
857  }
858 
859  //lazy eval, so we need to evaluate nodes now
860 
861  //first node is subexpression (or field name)
862  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
864  QString subExpression = node->dump();
865 
866  //optional second node is group by
867  QString groupBy;
868  if ( values.count() > 1 )
869  {
870  node = getNode( values.at( 1 ), parent );
872  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
873  if ( !nl || nl->value().isValid() )
874  groupBy = node->dump();
875  }
876 
877  //optional third node is filter
878  if ( values.count() > 2 )
879  {
880  node = getNode( values.at( 2 ), parent );
882  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
883  if ( !nl || nl->value().isValid() )
884  parameters.filter = node->dump();
885  }
886 
887  // build up filter with group by
888 
889  // find current group by value
890  if ( !groupBy.isEmpty() )
891  {
892  QgsExpression groupByExp( groupBy );
893  QVariant groupByValue = groupByExp.evaluate( context );
894  if ( !parameters.filter.isEmpty() )
895  parameters.filter = QStringLiteral( "(%1) AND (%2=%3)" ).arg( parameters.filter, groupBy, QgsExpression::quotedValue( groupByValue ) );
896  else
897  parameters.filter = QStringLiteral( "(%2 = %3)" ).arg( groupBy, QgsExpression::quotedValue( groupByValue ) );
898  }
899 
900  QString cacheKey = QStringLiteral( "agg:%1:%2:%3:%4" ).arg( vl->id(),
901  QString::number( static_cast< int >( aggregate ) ),
902  subExpression,
903  parameters.filter );
904  if ( context && context->hasCachedValue( cacheKey ) )
905  return context->cachedValue( cacheKey );
906 
907  QVariant result;
908  bool ok = false;
909 
910  QgsExpressionContext subContext( *context );
911  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
912 
913  if ( !ok )
914  {
915  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
916  return QVariant();
917  }
918 
919  // cache value
920  if ( context )
921  context->setCachedValue( cacheKey, result );
922  return result;
923 }
924 
925 
926 static QVariant fcnAggregateCount( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
927 {
929 }
930 
931 static QVariant fcnAggregateCountDistinct( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
932 {
934 }
935 
936 static QVariant fcnAggregateCountMissing( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
937 {
939 }
940 
941 static QVariant fcnAggregateMin( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
942 {
944 }
945 
946 static QVariant fcnAggregateMax( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
947 {
949 }
950 
951 static QVariant fcnAggregateSum( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
952 {
954 }
955 
956 static QVariant fcnAggregateMean( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
957 {
959 }
960 
961 static QVariant fcnAggregateMedian( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
962 {
964 }
965 
966 static QVariant fcnAggregateStdev( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
967 {
969 }
970 
971 static QVariant fcnAggregateRange( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
972 {
974 }
975 
976 static QVariant fcnAggregateMinority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
977 {
979 }
980 
981 static QVariant fcnAggregateMajority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
982 {
984 }
985 
986 static QVariant fcnAggregateQ1( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
987 {
989 }
990 
991 static QVariant fcnAggregateQ3( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
992 {
994 }
995 
996 static QVariant fcnAggregateIQR( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
997 {
999 }
1000 
1001 static QVariant fcnAggregateMinLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1002 {
1004 }
1005 
1006 static QVariant fcnAggregateMaxLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1007 {
1009 }
1010 
1011 static QVariant fcnAggregateCollectGeometry( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1012 {
1014 }
1015 
1016 static QVariant fcnAggregateStringConcat( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
1017 {
1019 
1020  //fourth node is concatenator
1021  if ( values.count() > 3 )
1022  {
1023  QgsExpression::Node* node = getNode( values.at( 3 ), parent );
1025  QVariant value = node->eval( parent, context );
1027  parameters.delimiter = value.toString();
1028  }
1029 
1030  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent );
1031 }
1032 
1033 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1034 {
1035  double minValue = getDoubleValue( values.at( 0 ), parent );
1036  double testValue = getDoubleValue( values.at( 1 ), parent );
1037  double maxValue = getDoubleValue( values.at( 2 ), parent );
1038 
1039  // force testValue to sit inside the range specified by the min and max value
1040  if ( testValue <= minValue )
1041  {
1042  return QVariant( minValue );
1043  }
1044  else if ( testValue >= maxValue )
1045  {
1046  return QVariant( maxValue );
1047  }
1048  else
1049  {
1050  return QVariant( testValue );
1051  }
1052 }
1053 
1054 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1055 {
1056  double x = getDoubleValue( values.at( 0 ), parent );
1057  return QVariant( floor( x ) );
1058 }
1059 
1060 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1061 {
1062  double x = getDoubleValue( values.at( 0 ), parent );
1063  return QVariant( ceil( x ) );
1064 }
1065 
1066 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1067 {
1068  return QVariant( getIntValue( values.at( 0 ), parent ) );
1069 }
1070 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1071 {
1072  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
1073 }
1074 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1075 {
1076  return QVariant( getStringValue( values.at( 0 ), parent ) );
1077 }
1078 
1079 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1080 {
1081  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
1082 }
1083 
1084 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
1085 {
1086  Q_FOREACH ( const QVariant &value, values )
1087  {
1088  if ( value.isNull() )
1089  continue;
1090  return value;
1091  }
1092  return QVariant();
1093 }
1094 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1095 {
1096  QString str = getStringValue( values.at( 0 ), parent );
1097  return QVariant( str.toLower() );
1098 }
1099 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1100 {
1101  QString str = getStringValue( values.at( 0 ), parent );
1102  return QVariant( str.toUpper() );
1103 }
1104 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1105 {
1106  QString str = getStringValue( values.at( 0 ), parent );
1107  QStringList elems = str.split( ' ' );
1108  for ( int i = 0; i < elems.size(); i++ )
1109  {
1110  if ( elems[i].size() > 1 )
1111  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1112  }
1113  return QVariant( elems.join( QStringLiteral( " " ) ) );
1114 }
1115 
1116 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1117 {
1118  QString str = getStringValue( values.at( 0 ), parent );
1119  return QVariant( str.trimmed() );
1120 }
1121 
1122 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1123 {
1124  QString string1 = getStringValue( values.at( 0 ), parent );
1125  QString string2 = getStringValue( values.at( 1 ), parent );
1126  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1127 }
1128 
1129 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1130 {
1131  QString string1 = getStringValue( values.at( 0 ), parent );
1132  QString string2 = getStringValue( values.at( 1 ), parent );
1133  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1134 }
1135 
1136 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1137 {
1138  QString string1 = getStringValue( values.at( 0 ), parent );
1139  QString string2 = getStringValue( values.at( 1 ), parent );
1140  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1141  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1142 }
1143 
1144 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1145 {
1146  QString string = getStringValue( values.at( 0 ), parent );
1147  return QVariant( QgsStringUtils::soundex( string ) );
1148 }
1149 
1150 static QVariant fcnChar( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1151 {
1152  QChar character = QChar( getIntValue( values.at( 0 ), parent ) );
1153  return QVariant( QString( character ) );
1154 }
1155 
1156 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1157 {
1158  if ( values.length() == 2 || values.length() == 3 )
1159  {
1160  QString str = getStringValue( values.at( 0 ), parent );
1161  int wrap = getIntValue( values.at( 1 ), parent );
1162 
1163  if ( !str.isEmpty() && wrap != 0 )
1164  {
1165  QString newstr;
1166  QRegExp rx;
1167  QString customdelimiter = getStringValue( values.at( 2 ), parent );
1168  int delimiterlength;
1169 
1170  if ( customdelimiter.length() > 0 )
1171  {
1172  rx.setPatternSyntax( QRegExp::FixedString );
1173  rx.setPattern( customdelimiter );
1174  delimiterlength = customdelimiter.length();
1175  }
1176  else
1177  {
1178  // \x200B is a ZERO-WIDTH SPACE, needed for worwrap to support a number of complex scripts (Indic, Arabic, etc.)
1179  rx.setPattern( QStringLiteral( "[\\s\\x200B]" ) );
1180  delimiterlength = 1;
1181  }
1182 
1183 
1184  QStringList lines = str.split( '\n' );
1185  int strlength, strcurrent, strhit, lasthit;
1186 
1187  for ( int i = 0; i < lines.size(); i++ )
1188  {
1189  strlength = lines[i].length();
1190  strcurrent = 0;
1191  strhit = 0;
1192  lasthit = 0;
1193 
1194  while ( strcurrent < strlength )
1195  {
1196  // positive wrap value = desired maximum line width to wrap
1197  // negative wrap value = desired minimum line width before wrap
1198  if ( wrap > 0 )
1199  {
1200  //first try to locate delimiter backwards
1201  strhit = lines[i].lastIndexOf( rx, strcurrent + wrap );
1202  if ( strhit == lasthit || strhit == -1 )
1203  {
1204  //if no new backward delimiter found, try to locate forward
1205  strhit = lines[i].indexOf( rx, strcurrent + qAbs( wrap ) );
1206  }
1207  lasthit = strhit;
1208  }
1209  else
1210  {
1211  strhit = lines[i].indexOf( rx, strcurrent + qAbs( wrap ) );
1212  }
1213  if ( strhit > -1 )
1214  {
1215  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
1216  newstr.append( '\n' );
1217  strcurrent = strhit + delimiterlength;
1218  }
1219  else
1220  {
1221  newstr.append( lines[i].midRef( strcurrent ) );
1222  strcurrent = strlength;
1223  }
1224  }
1225  if ( i < lines.size() - 1 ) newstr.append( '\n' );
1226  }
1227 
1228  return QVariant( newstr );
1229  }
1230  }
1231 
1232  return QVariant();
1233 }
1234 
1235 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1236 {
1237  // two variants, one for geometry, one for string
1238  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1239  {
1240  //geometry variant
1241  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1242  if ( geom.type() != QgsWkbTypes::LineGeometry )
1243  return QVariant();
1244 
1245  return QVariant( geom.length() );
1246  }
1247 
1248  //otherwise fall back to string variant
1249  QString str = getStringValue( values.at( 0 ), parent );
1250  return QVariant( str.length() );
1251 }
1252 
1253 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1254 {
1255  if ( values.count() == 2 && values.at( 1 ).type() == QVariant::Map )
1256  {
1257  QString str = getStringValue( values.at( 0 ), parent );
1258  QVariantMap map = getMapValue( values.at( 1 ), parent );
1259 
1260  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1261  {
1262  str = str.replace( it.key(), it.value().toString() );
1263  }
1264 
1265  return QVariant( str );
1266  }
1267  else if ( values.count() == 3 )
1268  {
1269  QString str = getStringValue( values.at( 0 ), parent );
1270  QVariantList before;
1271  QVariantList after;
1272  bool isSingleReplacement = false;
1273 
1274  if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1275  {
1276  before = QVariantList() << getStringValue( values.at( 1 ), parent );
1277  }
1278  else
1279  {
1280  before = getListValue( values.at( 1 ), parent );
1281  }
1282 
1283  if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1284  {
1285  after = QVariantList() << getStringValue( values.at( 2 ), parent );
1286  isSingleReplacement = true;
1287  }
1288  else
1289  {
1290  after = getListValue( values.at( 2 ), parent );
1291  }
1292 
1293  if ( !isSingleReplacement && before.length() != after.length() )
1294  {
1295  parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
1296  return QVariant();
1297  }
1298 
1299  for ( int i = 0; i < before.length(); i++ )
1300  {
1301  str = str.replace( before.at( i ).toString(), after.at( isSingleReplacement ? 0 : i ).toString() );
1302  }
1303 
1304  return QVariant( str );
1305  }
1306  else
1307  {
1308  parent->setEvalErrorString( QObject::tr( "Function replace requires 2 or 3 arguments" ) );
1309  return QVariant();
1310  }
1311 }
1312 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1313 {
1314  QString str = getStringValue( values.at( 0 ), parent );
1315  QString regexp = getStringValue( values.at( 1 ), parent );
1316  QString after = getStringValue( values.at( 2 ), parent );
1317 
1318  QRegularExpression re( regexp );
1319  if ( !re.isValid() )
1320  {
1321  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1322  return QVariant();
1323  }
1324  return QVariant( str.replace( re, after ) );
1325 }
1326 
1327 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1328 {
1329  QString str = getStringValue( values.at( 0 ), parent );
1330  QString regexp = getStringValue( values.at( 1 ), parent );
1331 
1332  QRegularExpression re( regexp );
1333  if ( !re.isValid() )
1334  {
1335  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1336  return QVariant();
1337  }
1338  return QVariant(( str.indexOf( re ) + 1 ) );
1339 }
1340 
1341 static QVariant fcnRegexpMatches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1342 {
1343  QString str = getStringValue( values.at( 0 ), parent );
1344  QString regexp = getStringValue( values.at( 1 ), parent );
1345  QString empty = getStringValue( values.at( 2 ), parent );
1346 
1347  QRegularExpression re( regexp );
1348  if ( !re.isValid() )
1349  {
1350  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1351  return QVariant();
1352  }
1353 
1354  QRegularExpressionMatch matches = re.match( str );
1355  if ( matches.hasMatch() )
1356  {
1357  QVariantList array;
1358  QStringList list = matches.capturedTexts();
1359 
1360  // Skip the first string to only return captured groups
1361  for ( QStringList::const_iterator it = ++list.constBegin(); it != list.constEnd(); ++it )
1362  {
1363  array += ( *it ).isEmpty() == false ? *it : empty;
1364  }
1365 
1366  return QVariant( array );
1367  }
1368  else
1369  {
1370  return QVariant();
1371  }
1372 }
1373 
1374 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1375 {
1376  QString str = getStringValue( values.at( 0 ), parent );
1377  QString regexp = getStringValue( values.at( 1 ), parent );
1378 
1379  QRegularExpression re( regexp );
1380  if ( !re.isValid() )
1381  {
1382  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1383  return QVariant();
1384  }
1385 
1386  // extract substring
1387  QRegularExpressionMatch match = re.match( str );
1388  if ( match.hasMatch() )
1389  {
1390  // return first capture
1391  return QVariant( match.captured( 0 ) );
1392  }
1393  else
1394  {
1395  return QVariant( "" );
1396  }
1397 }
1398 
1399 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
1400 {
1401  return QUuid::createUuid().toString();
1402 }
1403 
1404 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1405 {
1406  if ( !values.at( 0 ).isValid() || !values.at( 1 ).isValid() )
1407  return QVariant();
1408 
1409  QString str = getStringValue( values.at( 0 ), parent );
1410  int from = getIntValue( values.at( 1 ), parent );
1411 
1412  int len = 0;
1413  if ( values.at( 2 ).isValid() )
1414  len = getIntValue( values.at( 2 ), parent );
1415  else
1416  len = str.size();
1417 
1418  if ( from < 0 )
1419  {
1420  from = str.size() + from;
1421  if ( from < 0 )
1422  {
1423  from = 0;
1424  }
1425  }
1426  else if ( from > 0 )
1427  {
1428  //account for the fact that substr() starts at 1
1429  from -= 1;
1430  }
1431 
1432  if ( len < 0 )
1433  {
1434  len = str.size() + len - from;
1435  if ( len < 0 )
1436  {
1437  len = 0;
1438  }
1439  }
1440 
1441  return QVariant( str.mid( from, len ) );
1442 }
1443 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1444 {
1445  FEAT_FROM_CONTEXT( context, f );
1446  // TODO: handling of 64-bit feature ids?
1447  return QVariant( static_cast< int >( f.id() ) );
1448 }
1449 
1450 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1451 {
1452  if ( !context )
1453  return QVariant();
1454 
1455  return context->feature();
1456 }
1457 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1458 {
1459  QgsFeature feat = getFeature( values.at( 0 ), parent );
1460  QString attr = getStringValue( values.at( 1 ), parent );
1461 
1462  return feat.attribute( attr );
1463 }
1464 
1465 static QVariant fcnIsSelected( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
1466 {
1467  QgsVectorLayer* layer = nullptr;
1468  QgsFeature feature;
1469 
1470  if ( values.isEmpty() )
1471  {
1472  feature = context->feature();
1473  layer = getVectorLayer( context->variable( "layer" ), parent );
1474  }
1475  else if ( values.size() == 1 )
1476  {
1477  layer = getVectorLayer( context->variable( "layer" ), parent );
1478  feature = getFeature( values.at( 0 ), parent );
1479  }
1480  else if ( values.size() == 2 )
1481  {
1482  layer = getVectorLayer( values.at( 0 ), parent );
1483  feature = getFeature( values.at( 1 ), parent );
1484  }
1485  else
1486  {
1487  parent->setEvalErrorString( QObject::tr( "Function `is_selected` requires no more than two parameters. %1 given." ).arg( values.length() ) );
1488  return QVariant();
1489  }
1490 
1491  if ( !layer || !feature.isValid() )
1492  {
1493  return QVariant( QVariant::Bool );
1494  }
1495 
1496  return layer->selectedFeaturesIds().contains( feature.id() );
1497 }
1498 
1499 static QVariant fcnNumSelected( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
1500 {
1501  QgsVectorLayer* layer = nullptr;
1502 
1503  if ( values.isEmpty() )
1504  layer = getVectorLayer( context->variable( "layer" ), parent );
1505  else if ( values.count() == 1 )
1506  layer = getVectorLayer( values.at( 0 ), parent );
1507  else
1508  {
1509  parent->setEvalErrorString( QObject::tr( "Function `num_selected` requires no more than one parameter. %1 given." ).arg( values.length() ) );
1510  return QVariant();
1511  }
1512 
1513  if ( !layer )
1514  {
1515  return QVariant( QVariant::LongLong );
1516  }
1517 
1518  return layer->selectedFeatureCount();
1519 }
1520 
1521 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1522 {
1523  QString concat;
1524  Q_FOREACH ( const QVariant &value, values )
1525  {
1526  concat += getStringValue( value, parent );
1527  }
1528  return concat;
1529 }
1530 
1531 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1532 {
1533  QString string = getStringValue( values.at( 0 ), parent );
1534  return string.indexOf( getStringValue( values.at( 1 ), parent ) ) + 1;
1535 }
1536 
1537 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1538 {
1539  QString string = getStringValue( values.at( 0 ), parent );
1540  int pos = getIntValue( values.at( 1 ), parent );
1541  return string.right( pos );
1542 }
1543 
1544 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1545 {
1546  QString string = getStringValue( values.at( 0 ), parent );
1547  int pos = getIntValue( values.at( 1 ), parent );
1548  return string.left( pos );
1549 }
1550 
1551 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1552 {
1553  QString string = getStringValue( values.at( 0 ), parent );
1554  int length = getIntValue( values.at( 1 ), parent );
1555  QString fill = getStringValue( values.at( 2 ), parent );
1556  return string.leftJustified( length, fill.at( 0 ), true );
1557 }
1558 
1559 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1560 {
1561  QString string = getStringValue( values.at( 0 ), parent );
1562  int length = getIntValue( values.at( 1 ), parent );
1563  QString fill = getStringValue( values.at( 2 ), parent );
1564  return string.rightJustified( length, fill.at( 0 ), true );
1565 }
1566 
1567 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1568 {
1569  QString string = getStringValue( values.at( 0 ), parent );
1570  for ( int n = 1; n < values.length(); n++ )
1571  {
1572  string = string.arg( getStringValue( values.at( n ), parent ) );
1573  }
1574  return string;
1575 }
1576 
1577 
1578 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1579 {
1580  return QVariant( QDateTime::currentDateTime() );
1581 }
1582 
1583 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1584 {
1585  return QVariant( getDateValue( values.at( 0 ), parent ) );
1586 }
1587 
1588 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1589 {
1590  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1591 }
1592 
1593 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1594 {
1595  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1596 }
1597 
1598 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1599 {
1600  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1601  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1602  int seconds = d2.secsTo( d1 );
1603  return QVariant::fromValue( QgsInterval( seconds ) );
1604 }
1605 
1606 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1607 {
1608  if ( !values.at( 0 ).canConvert<QDate>() )
1609  return QVariant();
1610 
1611  QDate date = getDateValue( values.at( 0 ), parent );
1612  if ( !date.isValid() )
1613  return QVariant();
1614 
1615  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1616  // (to match PostgreSQL behaviour)
1617  return date.dayOfWeek() % 7;
1618 }
1619 
1620 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1621 {
1622  QVariant value = values.at( 0 );
1623  QgsInterval inter = getInterval( value, parent, false );
1624  if ( inter.isValid() )
1625  {
1626  return QVariant( inter.days() );
1627  }
1628  else
1629  {
1630  QDateTime d1 = getDateTimeValue( value, parent );
1631  return QVariant( d1.date().day() );
1632  }
1633 }
1634 
1635 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1636 {
1637  QVariant value = values.at( 0 );
1638  QgsInterval inter = getInterval( value, parent, false );
1639  if ( inter.isValid() )
1640  {
1641  return QVariant( inter.years() );
1642  }
1643  else
1644  {
1645  QDateTime d1 = getDateTimeValue( value, parent );
1646  return QVariant( d1.date().year() );
1647  }
1648 }
1649 
1650 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1651 {
1652  QVariant value = values.at( 0 );
1653  QgsInterval inter = getInterval( value, parent, false );
1654  if ( inter.isValid() )
1655  {
1656  return QVariant( inter.months() );
1657  }
1658  else
1659  {
1660  QDateTime d1 = getDateTimeValue( value, parent );
1661  return QVariant( d1.date().month() );
1662  }
1663 }
1664 
1665 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1666 {
1667  QVariant value = values.at( 0 );
1668  QgsInterval inter = getInterval( value, parent, false );
1669  if ( inter.isValid() )
1670  {
1671  return QVariant( inter.weeks() );
1672  }
1673  else
1674  {
1675  QDateTime d1 = getDateTimeValue( value, parent );
1676  return QVariant( d1.date().weekNumber() );
1677  }
1678 }
1679 
1680 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1681 {
1682  QVariant value = values.at( 0 );
1683  QgsInterval inter = getInterval( value, parent, false );
1684  if ( inter.isValid() )
1685  {
1686  return QVariant( inter.hours() );
1687  }
1688  else
1689  {
1690  QTime t1 = getTimeValue( value, parent );
1691  return QVariant( t1.hour() );
1692  }
1693 }
1694 
1695 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1696 {
1697  QVariant value = values.at( 0 );
1698  QgsInterval inter = getInterval( value, parent, false );
1699  if ( inter.isValid() )
1700  {
1701  return QVariant( inter.minutes() );
1702  }
1703  else
1704  {
1705  QTime t1 = getTimeValue( value, parent );
1706  return QVariant( t1.minute() );
1707  }
1708 }
1709 
1710 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1711 {
1712  QVariant value = values.at( 0 );
1713  QgsInterval inter = getInterval( value, parent, false );
1714  if ( inter.isValid() )
1715  {
1716  return QVariant( inter.seconds() );
1717  }
1718  else
1719  {
1720  QTime t1 = getTimeValue( value, parent );
1721  return QVariant( t1.second() );
1722  }
1723 }
1724 
1725 
1726 #define ENSURE_GEOM_TYPE(f, g, geomtype) \
1727  if ( !f.hasGeometry() ) \
1728  return QVariant(); \
1729  QgsGeometry g = f.geometry(); \
1730  if ( g.type() != geomtype ) \
1731  return QVariant();
1732 
1733 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1734 {
1735  FEAT_FROM_CONTEXT( context, f );
1737  if ( g.isMultipart() )
1738  {
1739  return g.asMultiPoint().at( 0 ).x();
1740  }
1741  else
1742  {
1743  return g.asPoint().x();
1744  }
1745 }
1746 
1747 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1748 {
1749  FEAT_FROM_CONTEXT( context, f );
1751  if ( g.isMultipart() )
1752  {
1753  return g.asMultiPoint().at( 0 ).y();
1754  }
1755  else
1756  {
1757  return g.asPoint().y();
1758  }
1759 }
1760 
1761 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1762 {
1763  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1764  if ( geom.isEmpty() )
1765  return QVariant();
1766 
1767  //if single point, return the point's x coordinate
1768  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1769  {
1770  return geom.asPoint().x();
1771  }
1772 
1773  //otherwise return centroid x
1774  QgsGeometry centroid = geom.centroid();
1775  QVariant result( centroid.asPoint().x() );
1776  return result;
1777 }
1778 
1779 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1780 {
1781  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1782  if ( geom.isEmpty() )
1783  return QVariant();
1784 
1785  //if single point, return the point's y coordinate
1786  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1787  {
1788  return geom.asPoint().y();
1789  }
1790 
1791  //otherwise return centroid y
1792  QgsGeometry centroid = geom.centroid();
1793  QVariant result( centroid.asPoint().y() );
1794  return result;
1795 }
1796 
1797 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1798 {
1799  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1800  if ( geom.isEmpty() )
1801  return QVariant(); //or 0?
1802 
1803  //if single point, return the point's z coordinate
1804  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1805  {
1806  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1807  if ( point )
1808  return point->z();
1809  }
1810 
1811  return QVariant();
1812 }
1813 
1814 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1815 {
1816  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1817  if ( geom.isEmpty() )
1818  return QVariant(); //or 0?
1819 
1820  //if single point, return the point's m value
1821  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
1822  {
1823  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1824  if ( point )
1825  return point->m();
1826  }
1827 
1828  return QVariant();
1829 }
1830 
1831 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1832 {
1833  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1834 
1835  if ( geom.isEmpty() )
1836  return QVariant();
1837 
1838  //idx is 1 based
1839  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1840 
1841  QgsVertexId vId;
1842  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1843  {
1844  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1845  return QVariant();
1846  }
1847 
1848  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1849  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1850 }
1851 
1852 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1853 {
1854  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1855 
1856  if ( geom.isEmpty() )
1857  return QVariant();
1858 
1859  QgsVertexId vId;
1860  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1861  {
1862  return QVariant();
1863  }
1864 
1865  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1866  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1867 }
1868 
1869 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1870 {
1871  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1872 
1873  if ( geom.isEmpty() )
1874  return QVariant();
1875 
1876  QgsVertexId vId;
1877  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1878  {
1879  return QVariant();
1880  }
1881 
1882  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1883  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1884 }
1885 
1886 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1887 {
1888  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1889 
1890  if ( geom.isEmpty() )
1891  return QVariant();
1892 
1893  bool ignoreClosing = false;
1894  if ( values.length() > 1 )
1895  {
1896  ignoreClosing = getIntValue( values.at( 1 ), parent );
1897  }
1898 
1899  QgsMultiPointV2* mp = new QgsMultiPointV2();
1900 
1901  Q_FOREACH ( const QgsRingSequence &part, geom.geometry()->coordinateSequence() )
1902  {
1903  Q_FOREACH ( const QgsPointSequence &ring, part )
1904  {
1905  bool skipLast = false;
1906  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1907  {
1908  skipLast = true;
1909  }
1910 
1911  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1912  {
1913  mp->addGeometry( ring.at( i ).clone() );
1914  }
1915  }
1916  }
1917 
1918  return QVariant::fromValue( QgsGeometry( mp ) );
1919 }
1920 
1921 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1922 {
1923  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1924 
1925  if ( geom.isEmpty() )
1926  return QVariant();
1927 
1928  QList< QgsLineString* > linesToProcess = QgsGeometryUtils::extractLineStrings( geom.geometry() );
1929 
1930  //ok, now we have a complete list of segmentized lines from the geometry
1932  Q_FOREACH ( QgsLineString* line, linesToProcess )
1933  {
1934  for ( int i = 0; i < line->numPoints() - 1; ++i )
1935  {
1936  QgsLineString* segment = new QgsLineString();
1937  segment->setPoints( QgsPointSequence()
1938  << line->pointN( i )
1939  << line->pointN( i + 1 ) );
1940  ml->addGeometry( segment );
1941  }
1942  delete line;
1943  }
1944 
1945  return QVariant::fromValue( QgsGeometry( ml ) );
1946 }
1947 
1948 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1949 {
1950  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1951 
1952  if ( geom.isEmpty() )
1953  return QVariant();
1954 
1955  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( geom.geometry() );
1956  if ( !curvePolygon )
1957  return QVariant();
1958 
1959  //idx is 1 based
1960  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1961 
1962  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1963  return QVariant();
1964 
1965  QgsCurve* curve = static_cast< QgsCurve* >( curvePolygon->interiorRing( idx )->clone() );
1966  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1967  return result;
1968 }
1969 
1970 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1971 {
1972  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1973 
1974  if ( geom.isEmpty() )
1975  return QVariant();
1976 
1977  QgsGeometryCollection* collection = dynamic_cast< QgsGeometryCollection* >( geom.geometry() );
1978  if ( !collection )
1979  return QVariant();
1980 
1981  //idx is 1 based
1982  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1983 
1984  if ( idx < 0 || idx >= collection->numGeometries() )
1985  return QVariant();
1986 
1987  QgsAbstractGeometry* part = collection->geometryN( idx )->clone();
1988  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
1989  return result;
1990 }
1991 
1992 static QVariant fcnBoundary( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1993 {
1994  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1995 
1996  if ( geom.isEmpty() )
1997  return QVariant();
1998 
1999  QgsAbstractGeometry* boundary = geom.geometry()->boundary();
2000  if ( !boundary )
2001  return QVariant();
2002 
2003  return QVariant::fromValue( QgsGeometry( boundary ) );
2004 }
2005 
2006 static QVariant fcnLineMerge( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2007 {
2008  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2009 
2010  if ( geom.isEmpty() )
2011  return QVariant();
2012 
2013  QgsGeometry merged = geom.mergeLines();
2014  if ( merged.isEmpty() )
2015  return QVariant();
2016 
2017  return QVariant::fromValue( merged );
2018 }
2019 
2020 static QVariant fcnSimplify( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2021 {
2022  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2023 
2024  if ( geom.isEmpty() )
2025  return QVariant();
2026 
2027  double tolerance = getDoubleValue( values.at( 1 ), parent );
2028 
2029  QgsGeometry simplified = geom.simplify( tolerance );
2030  if ( simplified.isEmpty() )
2031  return QVariant();
2032 
2033  return simplified;
2034 }
2035 
2036 static QVariant fcnSimplifyVW( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2037 {
2038  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2039 
2040  if ( geom.isEmpty() )
2041  return QVariant();
2042 
2043  double tolerance = getDoubleValue( values.at( 1 ), parent );
2044 
2046 
2047  QgsGeometry simplified = simplifier.simplify( geom );
2048  if ( simplified.isEmpty() )
2049  return QVariant();
2050 
2051  return simplified;
2052 }
2053 
2054 static QVariant fcnSmooth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2055 {
2056  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2057 
2058  if ( geom.isEmpty() )
2059  return QVariant();
2060 
2061  int iterations = qMin( getIntValue( values.at( 1 ), parent ), 10 );
2062  double offset = qBound( 0.0, getDoubleValue( values.at( 2 ), parent ), 0.5 );
2063  double minLength = getDoubleValue( values.at( 3 ), parent );
2064  double maxAngle = qBound( 0.0, getDoubleValue( values.at( 4 ), parent ), 180.0 );
2065 
2066  QgsGeometry smoothed = geom.smooth( iterations, offset, minLength, maxAngle );
2067  if ( smoothed.isEmpty() )
2068  return QVariant();
2069 
2070  return smoothed;
2071 }
2072 
2073 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2074 {
2075  if ( values.count() < 2 || values.count() > 4 )
2076  {
2077  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
2078  return QVariant();
2079  }
2080 
2081  double x = getDoubleValue( values.at( 0 ), parent );
2082  double y = getDoubleValue( values.at( 1 ), parent );
2083  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
2084  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
2085  switch ( values.count() )
2086  {
2087  case 2:
2088  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
2089  case 3:
2090  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWkbTypes::PointZ, x, y, z ) ) );
2091  case 4:
2092  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWkbTypes::PointZM, x, y, z, m ) ) );
2093  }
2094  return QVariant(); //avoid warning
2095 }
2096 
2097 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2098 {
2099  double x = getDoubleValue( values.at( 0 ), parent );
2100  double y = getDoubleValue( values.at( 1 ), parent );
2101  double m = getDoubleValue( values.at( 2 ), parent );
2102  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWkbTypes::PointM, x, y, 0.0, m ) ) );
2103 }
2104 
2105 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2106 {
2107  if ( values.count() < 2 )
2108  {
2109  return QVariant();
2110  }
2111 
2112  QgsLineString* lineString = new QgsLineString();
2113  lineString->clear();
2114 
2115  Q_FOREACH ( const QVariant& value, values )
2116  {
2117  QgsGeometry geom = getGeometry( value, parent );
2118  if ( geom.isEmpty() )
2119  continue;
2120 
2121  if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2122  continue;
2123 
2124  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
2125  if ( !point )
2126  continue;
2127 
2128  lineString->addVertex( *point );
2129  }
2130 
2131  return QVariant::fromValue( QgsGeometry( lineString ) );
2132 }
2133 
2134 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2135 {
2136  if ( values.count() < 1 )
2137  {
2138  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
2139  return QVariant();
2140  }
2141 
2142  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
2143  if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isMultipart() || outerRing.isEmpty() )
2144  return QVariant();
2145 
2146  QgsPolygonV2* polygon = new QgsPolygonV2();
2147  polygon->setExteriorRing( dynamic_cast< QgsCurve* >( outerRing.geometry()->clone() ) );
2148 
2149  for ( int i = 1; i < values.count(); ++i )
2150  {
2151  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
2152  if ( ringGeom.isEmpty() )
2153  continue;
2154 
2155  if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isMultipart() || ringGeom.isEmpty() )
2156  continue;
2157 
2158  polygon->addInteriorRing( dynamic_cast< QgsCurve* >( ringGeom.geometry()->clone() ) );
2159  }
2160 
2161  return QVariant::fromValue( QgsGeometry( polygon ) );
2162 }
2163 
2164 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
2165 {
2166  FEAT_FROM_CONTEXT( context, f );
2167  int idx = getIntValue( values.at( 0 ), parent );
2168  QgsGeometry g = f.geometry();
2169  if ( g.isEmpty() )
2170  return QVariant();
2171 
2172  if ( idx < 0 )
2173  {
2174  idx += g.geometry()->nCoordinates();
2175  }
2176  if ( idx < 0 || idx >= g.geometry()->nCoordinates() )
2177  {
2178  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
2179  return QVariant();
2180  }
2181 
2182  QgsPoint p = g.vertexAt( idx );
2183  return QVariant( QPointF( p.x(), p.y() ) );
2184 }
2185 
2186 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
2187 {
2188  QVariant v = pointAt( values, f, parent );
2189  if ( v.type() == QVariant::PointF )
2190  return QVariant( v.toPointF().x() );
2191  else
2192  return QVariant();
2193 }
2194 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
2195 {
2196  QVariant v = pointAt( values, f, parent );
2197  if ( v.type() == QVariant::PointF )
2198  return QVariant( v.toPointF().y() );
2199  else
2200  return QVariant();
2201 }
2202 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
2203 {
2204  FEAT_FROM_CONTEXT( context, f );
2205  QgsGeometry geom = f.geometry();
2206  if ( !geom.isEmpty() )
2207  return QVariant::fromValue( geom );
2208  else
2209  return QVariant();
2210 }
2211 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2212 {
2213  QString wkt = getStringValue( values.at( 0 ), parent );
2214  QgsGeometry geom = QgsGeometry::fromWkt( wkt );
2215  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2216  return result;
2217 }
2218 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2219 {
2220  QString gml = getStringValue( values.at( 0 ), parent );
2222  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2223  return result;
2224 }
2225 
2226 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2227 {
2228  FEAT_FROM_CONTEXT( context, f );
2230  QgsDistanceArea* calc = parent->geomCalculator();
2231  if ( calc )
2232  {
2233  double area = calc->measureArea( f.geometry() );
2234  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
2235  return QVariant( area );
2236  }
2237  else
2238  {
2239  return QVariant( f.geometry().area() );
2240  }
2241 }
2242 
2243 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2244 {
2245  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2246 
2247  if ( geom.type() != QgsWkbTypes::PolygonGeometry )
2248  return QVariant();
2249 
2250  return QVariant( geom.area() );
2251 }
2252 
2253 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2254 {
2255  FEAT_FROM_CONTEXT( context, f );
2257  QgsDistanceArea* calc = parent->geomCalculator();
2258  if ( calc )
2259  {
2260  double len = calc->measureLength( f.geometry() );
2261  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2262  return QVariant( len );
2263  }
2264  else
2265  {
2266  return QVariant( f.geometry().length() );
2267  }
2268 }
2269 
2270 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2271 {
2272  FEAT_FROM_CONTEXT( context, f );
2274  QgsDistanceArea* calc = parent->geomCalculator();
2275  if ( calc )
2276  {
2277  double len = calc->measurePerimeter( f.geometry() );
2278  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2279  return QVariant( len );
2280  }
2281  else
2282  {
2283  return f.geometry().isEmpty() ? QVariant( 0 ) : QVariant( f.geometry().geometry()->perimeter() );
2284  }
2285 }
2286 
2287 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2288 {
2289  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2290 
2291  if ( geom.type() != QgsWkbTypes::PolygonGeometry )
2292  return QVariant();
2293 
2294  //length for polygons = perimeter
2295  return QVariant( geom.length() );
2296 }
2297 
2298 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2299 {
2300  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2301  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
2302 }
2303 
2304 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2305 {
2306  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2307  if ( geom.isEmpty() )
2308  return QVariant();
2309 
2310  return QVariant( geom.geometry()->partCount() );
2311 }
2312 
2313 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2314 {
2315  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2316 
2317  if ( geom.isEmpty() )
2318  return QVariant();
2319 
2320  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( geom.geometry() );
2321  if ( curvePolygon )
2322  return QVariant( curvePolygon->numInteriorRings() );
2323 
2324  QgsGeometryCollection* collection = dynamic_cast< QgsGeometryCollection* >( geom.geometry() );
2325  if ( collection )
2326  {
2327  //find first CurvePolygon in collection
2328  for ( int i = 0; i < collection->numGeometries(); ++i )
2329  {
2330  curvePolygon = dynamic_cast< QgsCurvePolygon*>( collection->geometryN( i ) );
2331  if ( !curvePolygon )
2332  continue;
2333 
2334  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
2335  }
2336  }
2337 
2338  return QVariant();
2339 }
2340 
2341 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2342 {
2343  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2344 
2345  if ( geom.isEmpty() )
2346  return QVariant();
2347 
2348  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( geom.geometry() );
2349  if ( curvePolygon )
2350  return QVariant( curvePolygon->ringCount() );
2351 
2352  bool foundPoly = false;
2353  int ringCount = 0;
2354  QgsGeometryCollection* collection = dynamic_cast< QgsGeometryCollection* >( geom.geometry() );
2355  if ( collection )
2356  {
2357  //find CurvePolygons in collection
2358  for ( int i = 0; i < collection->numGeometries(); ++i )
2359  {
2360  curvePolygon = dynamic_cast< QgsCurvePolygon*>( collection->geometryN( i ) );
2361  if ( !curvePolygon )
2362  continue;
2363 
2364  foundPoly = true;
2365  ringCount += curvePolygon->ringCount();
2366  }
2367  }
2368 
2369  if ( !foundPoly )
2370  return QVariant();
2371 
2372  return QVariant( ringCount );
2373 }
2374 
2375 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2376 {
2377  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2378  QgsGeometry geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
2379  QVariant result = !geomBounds.isEmpty() ? QVariant::fromValue( geomBounds ) : QVariant();
2380  return result;
2381 }
2382 
2383 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2384 {
2385  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2386  return QVariant::fromValue( geom.boundingBox().width() );
2387 }
2388 
2389 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2390 {
2391  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2392  return QVariant::fromValue( geom.boundingBox().height() );
2393 }
2394 
2395 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2396 {
2397  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2398  return QVariant::fromValue( geom.boundingBox().xMinimum() );
2399 }
2400 
2401 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2402 {
2403  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2404  return QVariant::fromValue( geom.boundingBox().xMaximum() );
2405 }
2406 
2407 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2408 {
2409  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2410  return QVariant::fromValue( geom.boundingBox().yMinimum() );
2411 }
2412 
2413 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2414 {
2415  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2416  return QVariant::fromValue( geom.boundingBox().yMaximum() );
2417 }
2418 
2419 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2420 {
2421  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2422  if ( fGeom.isEmpty() )
2423  return QVariant();
2424 
2425  QgsCurve* curve = dynamic_cast< QgsCurve* >( fGeom.geometry() );
2426  if ( !curve )
2427  return QVariant();
2428 
2429  return QVariant::fromValue( curve->isClosed() );
2430 }
2431 
2432 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2433 {
2434  if ( values.length() < 2 || values.length() > 3 )
2435  return QVariant();
2436 
2437  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2438  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2439 
2440  if ( fGeom.isEmpty() || sGeom.isEmpty() )
2441  return QVariant();
2442 
2443  QScopedPointer<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( fGeom.geometry() ) );
2444 
2445  if ( values.length() == 2 )
2446  {
2447  //two geometry arguments, return relation
2448  QString result = engine->relate( *sGeom.geometry() );
2449  return QVariant::fromValue( result );
2450  }
2451  else
2452  {
2453  //three arguments, test pattern
2454  QString pattern = getStringValue( values.at( 2 ), parent );
2455  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
2456  return QVariant::fromValue( result );
2457  }
2458 }
2459 
2460 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2461 {
2462  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2463  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2464  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
2465 }
2466 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2467 {
2468  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2469  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2470  return fGeom.disjoint( sGeom ) ? TVL_True : TVL_False;
2471 }
2472 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2473 {
2474  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2475  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2476  return fGeom.intersects( sGeom ) ? TVL_True : TVL_False;
2477 }
2478 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2479 {
2480  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2481  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2482  return fGeom.touches( sGeom ) ? TVL_True : TVL_False;
2483 }
2484 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2485 {
2486  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2487  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2488  return fGeom.crosses( sGeom ) ? TVL_True : TVL_False;
2489 }
2490 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2491 {
2492  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2493  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2494  return fGeom.contains( sGeom ) ? TVL_True : TVL_False;
2495 }
2496 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2497 {
2498  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2499  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2500  return fGeom.overlaps( sGeom ) ? TVL_True : TVL_False;
2501 }
2502 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2503 {
2504  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2505  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2506  return fGeom.within( sGeom ) ? TVL_True : TVL_False;
2507 }
2508 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2509 {
2510  if ( values.length() < 2 || values.length() > 3 )
2511  return QVariant();
2512 
2513  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2514  double dist = getDoubleValue( values.at( 1 ), parent );
2515  int seg = 8;
2516  if ( values.length() == 3 )
2517  seg = getIntValue( values.at( 2 ), parent );
2518 
2519  QgsGeometry geom = fGeom.buffer( dist, seg );
2520  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2521  return result;
2522 }
2523 
2524 static QVariant fcnOffsetCurve( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2525 {
2526  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2527  double dist = getDoubleValue( values.at( 1 ), parent );
2528  int segments = getIntValue( values.at( 2 ), parent );
2529  QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( getIntValue( values.at( 3 ), parent ) );
2530  if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
2531  return QVariant();
2532  double mitreLimit = getDoubleValue( values.at( 3 ), parent );
2533 
2534  QgsGeometry geom = fGeom.offsetCurve( dist, segments, join, mitreLimit );
2535  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2536  return result;
2537 }
2538 
2539 static QVariant fcnSingleSidedBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2540 {
2541  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2542  double dist = getDoubleValue( values.at( 1 ), parent );
2543  int segments = getIntValue( values.at( 2 ), parent );
2544  QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( getIntValue( values.at( 3 ), parent ) );
2545  if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
2546  return QVariant();
2547  double mitreLimit = getDoubleValue( values.at( 3 ), parent );
2548 
2549  QgsGeometry geom = fGeom.singleSidedBuffer( dist, segments, QgsGeometry::SideLeft, join, mitreLimit );
2550  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2551  return result;
2552 }
2553 
2554 static QVariant fcnExtend( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2555 {
2556  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2557  double distStart = getDoubleValue( values.at( 1 ), parent );
2558  double distEnd = getDoubleValue( values.at( 2 ), parent );
2559 
2560  QgsGeometry geom = fGeom.extendLine( distStart, distEnd );
2561  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2562  return result;
2563 }
2564 
2565 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2566 {
2567  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2568  double dx = getDoubleValue( values.at( 1 ), parent );
2569  double dy = getDoubleValue( values.at( 2 ), parent );
2570  fGeom.translate( dx, dy );
2571  return QVariant::fromValue( fGeom );
2572 }
2573 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2574 {
2575  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2576  QgsGeometry geom = fGeom.centroid();
2577  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2578  return result;
2579 }
2580 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2581 {
2582  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2583  QgsGeometry geom = fGeom.pointOnSurface();
2584  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2585  return result;
2586 }
2587 
2588 static QVariant fcnPoleOfInaccessibility( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2589 {
2590  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2591  double tolerance = getDoubleValue( values.at( 1 ), parent );
2592  QgsGeometry geom = fGeom.poleOfInaccessibility( tolerance );
2593  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2594  return result;
2595 }
2596 
2597 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2598 {
2599  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2600  QgsGeometry geom = fGeom.convexHull();
2601  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2602  return result;
2603 }
2604 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2605 {
2606  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2607  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2608  QgsGeometry geom = fGeom.difference( sGeom );
2609  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2610  return result;
2611 }
2612 
2613 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2614 {
2615  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2616  if ( fGeom.isEmpty() )
2617  return QVariant();
2618 
2619  QgsCurve* curve = dynamic_cast< QgsCurve* >( fGeom.geometry() );
2620  if ( !curve )
2621  return QVariant();
2622 
2623  QgsCurve* reversed = curve->reversed();
2624  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2625  return result;
2626 }
2627 
2628 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2629 {
2630  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2631  if ( fGeom.isEmpty() )
2632  return QVariant();
2633 
2634  QgsCurvePolygon* curvePolygon = dynamic_cast< QgsCurvePolygon* >( fGeom.geometry() );
2635  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2636  return QVariant();
2637 
2638  QgsCurve* exterior = static_cast< QgsCurve* >( curvePolygon->exteriorRing()->clone() );
2639  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2640  return result;
2641 }
2642 
2643 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2644 {
2645  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2646  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2647  return QVariant( fGeom.distance( sGeom ) );
2648 }
2649 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2650 {
2651  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2652  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2653  QgsGeometry geom = fGeom.intersection( sGeom );
2654  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2655  return result;
2656 }
2657 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2658 {
2659  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2660  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2661  QgsGeometry geom = fGeom.symDifference( sGeom );
2662  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2663  return result;
2664 }
2665 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2666 {
2667  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2668  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2669  QgsGeometry geom = fGeom.combine( sGeom );
2670  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2671  return result;
2672 }
2673 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2674 {
2675  if ( values.length() < 1 || values.length() > 2 )
2676  return QVariant();
2677 
2678  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2679  int prec = 8;
2680  if ( values.length() == 2 )
2681  prec = getIntValue( values.at( 1 ), parent );
2682  QString wkt = fGeom.exportToWkt( prec );
2683  return QVariant( wkt );
2684 }
2685 
2686 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2687 {
2688  if ( values.length() != 2 )
2689  {
2690  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2691  return QVariant();
2692  }
2693 
2694  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2695  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2696 
2697  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2698  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2699 
2700  if ( !pt1 || !pt2 )
2701  {
2702  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2703  return QVariant();
2704  }
2705 
2706  // Code from postgis
2707  if ( pt1->x() == pt2->x() )
2708  {
2709  if ( pt1->y() < pt2->y() )
2710  return 0.0;
2711  else if ( pt1->y() > pt2->y() )
2712  return M_PI;
2713  else
2714  return 0;
2715  }
2716 
2717  if ( pt1->y() == pt2->y() )
2718  {
2719  if ( pt1->x() < pt2->x() )
2720  return M_PI / 2;
2721  else if ( pt1->x() > pt2->x() )
2722  return M_PI + ( M_PI / 2 );
2723  else
2724  return 0;
2725  }
2726 
2727  if ( pt1->x() < pt2->x() )
2728  {
2729  if ( pt1->y() < pt2->y() )
2730  {
2731  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2732  }
2733  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2734  {
2735  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2736  + ( M_PI / 2 );
2737  }
2738  }
2739 
2740  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2741  {
2742  if ( pt1->y() > pt2->y() )
2743  {
2744  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2745  + M_PI;
2746  }
2747  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2748  {
2749  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2750  + ( M_PI + ( M_PI / 2 ) );
2751  }
2752  }
2753 }
2754 
2755 static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2756 {
2757  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2758 
2759  if ( geom.type() != QgsWkbTypes::PointGeometry )
2760  {
2761  parent->setEvalErrorString( QStringLiteral( "'project' requires a point geometry" ) );
2762  return QVariant();
2763  }
2764 
2765  double distance = getDoubleValue( values.at( 1 ), parent );
2766  double bearing = getDoubleValue( values.at( 2 ), parent );
2767 
2768  QgsPoint p = geom.asPoint();
2769  QgsPoint newPoint = p.project( distance, ( 180 * bearing ) / M_PI );
2770 
2771  return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint.x(), newPoint.y() ) ) );
2772 }
2773 
2774 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2775 {
2776  if ( values.length() != 3 )
2777  return QVariant();
2778 
2779  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2780  double x = getDoubleValue( values.at( 1 ), parent );
2781  double y = getDoubleValue( values.at( 2 ), parent );
2782 
2783  QgsGeometry geom = fGeom.extrude( x, y );
2784 
2785  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2786  return result;
2787 }
2788 
2789 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2790 {
2791  if ( values.length() < 2 )
2792  return QVariant();
2793 
2794  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2795 
2796  if ( !fGeom.isMultipart() )
2797  return values.at( 0 );
2798 
2799  QString expString = getStringValue( values.at( 1 ), parent );
2800  bool asc = values.value( 2 ).toBool();
2801 
2802  QgsExpressionContext* unconstedContext;
2803  QgsFeature f;
2804  if ( ctx )
2805  {
2806  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2807  // so no reason to worry
2808  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2809  f = ctx->feature();
2810  }
2811  else
2812  {
2813  // If there's no context provided, create a fake one
2814  unconstedContext = new QgsExpressionContext();
2815  }
2816 
2817  QgsGeometryCollection* collection = dynamic_cast<QgsGeometryCollection*>( fGeom.geometry() );
2818  Q_ASSERT( collection ); // Should have failed the multipart check above
2819 
2821  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2822  QgsExpressionSorter sorter( orderBy );
2823 
2824  QList<QgsFeature> partFeatures;
2825  partFeatures.reserve( collection->partCount() );
2826  for ( int i = 0; i < collection->partCount(); ++i )
2827  {
2828  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2829  partFeatures << f;
2830  }
2831 
2832  sorter.sortFeatures( partFeatures, unconstedContext );
2833 
2834  QgsGeometryCollection* orderedGeom = dynamic_cast<QgsGeometryCollection*>( fGeom.geometry()->clone() );
2835 
2836  Q_ASSERT( orderedGeom );
2837 
2838  while ( orderedGeom->partCount() )
2839  orderedGeom->removeGeometry( 0 );
2840 
2841  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2842  {
2843  orderedGeom->addGeometry( feature.geometry().geometry()->clone() );
2844  }
2845 
2846  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2847 
2848  if ( !ctx )
2849  delete unconstedContext;
2850 
2851  return result;
2852 }
2853 
2854 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2855 {
2856  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2857  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2858 
2859  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2860 
2861  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2862  return result;
2863 }
2864 
2865 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2866 {
2867  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2868  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2869 
2870  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2871 
2872  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2873  return result;
2874 }
2875 
2876 static QVariant fcnLineInterpolatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2877 {
2878  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2879  double distance = getDoubleValue( values.at( 1 ), parent );
2880 
2881  QgsGeometry geom = lineGeom.interpolate( distance );
2882 
2883  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2884  return result;
2885 }
2886 
2887 static QVariant fcnLineInterpolateAngle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2888 {
2889  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2890  double distance = getDoubleValue( values.at( 1 ), parent );
2891 
2892  return lineGeom.interpolateAngle( distance ) * 180.0 / M_PI;
2893 }
2894 
2895 static QVariant fcnAngleAtVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2896 {
2897  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2898  int vertex = getIntValue( values.at( 1 ), parent );
2899 
2900  return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
2901 }
2902 
2903 static QVariant fcnDistanceToVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2904 {
2905  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2906  int vertex = getIntValue( values.at( 1 ), parent );
2907 
2908  return geom.distanceToVertex( vertex );
2909 }
2910 
2911 static QVariant fcnLineLocatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2912 {
2913  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2914  QgsGeometry pointGeom = getGeometry( values.at( 1 ), parent );
2915 
2916  double distance = lineGeom.lineLocatePoint( pointGeom );
2917 
2918  return distance >= 0 ? distance : QVariant();
2919 }
2920 
2921 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2922 {
2923  if ( values.length() == 2 && values.at( 1 ).toInt() != 0 )
2924  {
2925  double number = getDoubleValue( values.at( 0 ), parent );
2926  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2927  return QVariant( qRound( number * scaler ) / scaler );
2928  }
2929 
2930  if ( values.length() >= 1 )
2931  {
2932  double number = getIntValue( values.at( 0 ), parent );
2933  return QVariant( qRound( number ) );
2934  }
2935 
2936  return QVariant();
2937 }
2938 
2939 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2940 {
2941  Q_UNUSED( values );
2942  Q_UNUSED( parent );
2943  return M_PI;
2944 }
2945 
2946 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2947 {
2948  double value = getDoubleValue( values.at( 0 ), parent );
2949  int places = getIntValue( values.at( 1 ), parent );
2950  if ( places < 0 )
2951  {
2952  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2953  return QVariant();
2954  }
2955  return QStringLiteral( "%L1" ).arg( value, 0, 'f', places );
2956 }
2957 
2958 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2959 {
2960  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2961  QString format = getStringValue( values.at( 1 ), parent );
2962  return dt.toString( format );
2963 }
2964 
2965 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2966 {
2967  int red = getIntValue( values.at( 0 ), parent );
2968  int green = getIntValue( values.at( 1 ), parent );
2969  int blue = getIntValue( values.at( 2 ), parent );
2970  QColor color = QColor( red, green, blue );
2971  if ( ! color.isValid() )
2972  {
2973  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
2974  color = QColor( 0, 0, 0 );
2975  }
2976 
2977  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2978 }
2979 
2980 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
2981 {
2982  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
2984  QVariant value = node->eval( parent, context );
2986  if ( value.toBool() )
2987  {
2988  node = getNode( values.at( 1 ), parent );
2990  value = node->eval( parent, context );
2992  }
2993  else
2994  {
2995  node = getNode( values.at( 2 ), parent );
2997  value = node->eval( parent, context );
2999  }
3000  return value;
3001 }
3002 
3003 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3004 {
3005  int red = getIntValue( values.at( 0 ), parent );
3006  int green = getIntValue( values.at( 1 ), parent );
3007  int blue = getIntValue( values.at( 2 ), parent );
3008  int alpha = getIntValue( values.at( 3 ), parent );
3009  QColor color = QColor( red, green, blue, alpha );
3010  if ( ! color.isValid() )
3011  {
3012  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
3013  color = QColor( 0, 0, 0 );
3014  }
3015  return QgsSymbolLayerUtils::encodeColor( color );
3016 }
3017 
3018 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3019 {
3020  QString rampName = getStringValue( values.at( 0 ), parent );
3021  const QgsColorRamp *mRamp = QgsStyle::defaultStyle()->colorRampRef( rampName );
3022  if ( ! mRamp )
3023  {
3024  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
3025  return QColor( 0, 0, 0 ).name();
3026  }
3027  double value = getDoubleValue( values.at( 1 ), parent );
3028  QColor color = mRamp->color( value );
3029  return QgsSymbolLayerUtils::encodeColor( color );
3030 }
3031 
3032 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
3033 {
3034  // Hue ranges from 0 - 360
3035  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3036  // Saturation ranges from 0 - 100
3037  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3038  // Lightness ranges from 0 - 100
3039  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
3040 
3041  QColor color = QColor::fromHslF( hue, saturation, lightness );
3042 
3043  if ( ! color.isValid() )
3044  {
3045  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
3046  color = QColor( 0, 0, 0 );
3047  }
3048 
3049  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3050 }
3051 
3052 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3053 {
3054  // Hue ranges from 0 - 360
3055  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3056  // Saturation ranges from 0 - 100
3057  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3058  // Lightness ranges from 0 - 100
3059  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
3060  // Alpha ranges from 0 - 255
3061  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
3062 
3063  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
3064  if ( ! color.isValid() )
3065  {
3066  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
3067  color = QColor( 0, 0, 0 );
3068  }
3069  return QgsSymbolLayerUtils::encodeColor( color );
3070 }
3071 
3072 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3073 {
3074  // Hue ranges from 0 - 360
3075  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3076  // Saturation ranges from 0 - 100
3077  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3078  // Value ranges from 0 - 100
3079  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
3080 
3081  QColor color = QColor::fromHsvF( hue, saturation, value );
3082 
3083  if ( ! color.isValid() )
3084  {
3085  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
3086  color = QColor( 0, 0, 0 );
3087  }
3088 
3089  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3090 }
3091 
3092 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3093 {
3094  // Hue ranges from 0 - 360
3095  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
3096  // Saturation ranges from 0 - 100
3097  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
3098  // Value ranges from 0 - 100
3099  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
3100  // Alpha ranges from 0 - 255
3101  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
3102 
3103  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
3104  if ( ! color.isValid() )
3105  {
3106  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
3107  color = QColor( 0, 0, 0 );
3108  }
3109  return QgsSymbolLayerUtils::encodeColor( color );
3110 }
3111 
3112 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3113 {
3114  // Cyan ranges from 0 - 100
3115  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
3116  // Magenta ranges from 0 - 100
3117  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
3118  // Yellow ranges from 0 - 100
3119  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
3120  // Black ranges from 0 - 100
3121  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
3122 
3123  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
3124 
3125  if ( ! color.isValid() )
3126  {
3127  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
3128  color = QColor( 0, 0, 0 );
3129  }
3130 
3131  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
3132 }
3133 
3134 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3135 {
3136  // Cyan ranges from 0 - 100
3137  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
3138  // Magenta ranges from 0 - 100
3139  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
3140  // Yellow ranges from 0 - 100
3141  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
3142  // Black ranges from 0 - 100
3143  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
3144  // Alpha ranges from 0 - 255
3145  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
3146 
3147  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
3148  if ( ! color.isValid() )
3149  {
3150  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
3151  color = QColor( 0, 0, 0 );
3152  }
3153  return QgsSymbolLayerUtils::encodeColor( color );
3154 }
3155 
3156 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3157 {
3158  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3159  if ( ! color.isValid() )
3160  {
3161  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3162  return QVariant();
3163  }
3164 
3165  QString part = getStringValue( values.at( 1 ), parent );
3166  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
3167  return color.red();
3168  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
3169  return color.green();
3170  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
3171  return color.blue();
3172  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
3173  return color.alpha();
3174  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
3175  return color.hsvHueF() * 360;
3176  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
3177  return color.hsvSaturationF() * 100;
3178  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
3179  return color.valueF() * 100;
3180  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
3181  return color.hslHueF() * 360;
3182  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
3183  return color.hslSaturationF() * 100;
3184  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
3185  return color.lightnessF() * 100;
3186  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
3187  return color.cyanF() * 100;
3188  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
3189  return color.magentaF() * 100;
3190  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
3191  return color.yellowF() * 100;
3192  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
3193  return color.blackF() * 100;
3194 
3195  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
3196  return QVariant();
3197 }
3198 
3199 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3200 {
3201  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3202  if ( ! color.isValid() )
3203  {
3204  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3205  return QVariant();
3206  }
3207 
3208  QString part = getStringValue( values.at( 1 ), parent );
3209  int value = getIntValue( values.at( 2 ), parent );
3210  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
3211  color.setRed( value );
3212  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
3213  color.setGreen( value );
3214  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
3215  color.setBlue( value );
3216  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
3217  color.setAlpha( value );
3218  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
3219  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
3220  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
3221  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
3222  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
3223  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
3224  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
3225  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
3226  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
3227  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
3228  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
3229  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
3230  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
3231  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
3232  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
3233  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
3234  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
3235  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
3236  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
3237  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
3238  else
3239  {
3240  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
3241  return QVariant();
3242  }
3243  return QgsSymbolLayerUtils::encodeColor( color );
3244 }
3245 
3246 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3247 {
3248  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3249  if ( ! color.isValid() )
3250  {
3251  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3252  return QVariant();
3253  }
3254 
3255  color = color.darker( getIntValue( values.at( 1 ), parent ) );
3256 
3257  return QgsSymbolLayerUtils::encodeColor( color );
3258 }
3259 
3260 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3261 {
3262  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
3263  if ( ! color.isValid() )
3264  {
3265  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3266  return QVariant();
3267  }
3268 
3269  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
3270 
3271  return QgsSymbolLayerUtils::encodeColor( color );
3272 }
3273 
3274 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3275 {
3276  QgsFeature feat = getFeature( values.at( 0 ), parent );
3277  QgsGeometry geom = feat.geometry();
3278  if ( !geom.isEmpty() )
3279  return QVariant::fromValue( geom );
3280  return QVariant();
3281 }
3282 
3283 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3284 {
3285  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
3286  QString sAuthId = getStringValue( values.at( 1 ), parent );
3287  QString dAuthId = getStringValue( values.at( 2 ), parent );
3288 
3290  if ( ! s.isValid() )
3291  return QVariant::fromValue( fGeom );
3293  if ( ! d.isValid() )
3294  return QVariant::fromValue( fGeom );
3295 
3296  QgsCoordinateTransform t( s, d );
3297  try
3298  {
3299  if ( fGeom.transform( t ) == 0 )
3300  return QVariant::fromValue( fGeom );
3301  }
3302  catch ( QgsCsException &cse )
3303  {
3304  QgsMessageLog::logMessage( QStringLiteral( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
3305  return QVariant();
3306  }
3307  return QVariant();
3308 }
3309 
3310 
3311 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3312 {
3313  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
3314  QgsVectorLayer* vl = getVectorLayer( values.at( 0 ), parent );
3315 
3316  //no layer found
3317  if ( !vl )
3318  {
3319  return QVariant();
3320  }
3321 
3322  QString attribute = getStringValue( values.at( 1 ), parent );
3323  int attributeId = vl->fields().lookupField( attribute );
3324  if ( attributeId == -1 )
3325  {
3326  return QVariant();
3327  }
3328 
3329  const QVariant& attVal = values.at( 2 );
3330  QgsFeatureRequest req;
3331  req.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
3332  QgsExpression::quotedString( attVal.toString() ) ) );
3333  req.setLimit( 1 );
3334  if ( !parent->needsGeometry() )
3335  {
3337  }
3338  QgsFeatureIterator fIt = vl->getFeatures( req );
3339 
3340  QgsFeature fet;
3341  if ( fIt.nextFeature( fet ) )
3342  return QVariant::fromValue( fet );
3343 
3344  return QVariant();
3345 }
3346 
3347 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3348 {
3349  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3350 
3351  //try to find a matching layer by name
3352  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
3353  if ( !layer )
3354  {
3355  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
3356  if ( !layersByName.isEmpty() )
3357  {
3358  layer = layersByName.at( 0 );
3359  }
3360  }
3361 
3362  if ( !layer )
3363  return QVariant();
3364 
3365  QString layerProperty = getStringValue( values.at( 1 ), parent );
3366  if ( QString::compare( layerProperty, QStringLiteral( "name" ), Qt::CaseInsensitive ) == 0 )
3367  return layer->name();
3368  else if ( QString::compare( layerProperty, QStringLiteral( "id" ), Qt::CaseInsensitive ) == 0 )
3369  return layer->id();
3370  else if ( QString::compare( layerProperty, QStringLiteral( "title" ), Qt::CaseInsensitive ) == 0 )
3371  return layer->title();
3372  else if ( QString::compare( layerProperty, QStringLiteral( "abstract" ), Qt::CaseInsensitive ) == 0 )
3373  return layer->abstract();
3374  else if ( QString::compare( layerProperty, QStringLiteral( "keywords" ), Qt::CaseInsensitive ) == 0 )
3375  return layer->keywordList();
3376  else if ( QString::compare( layerProperty, QStringLiteral( "data_url" ), Qt::CaseInsensitive ) == 0 )
3377  return layer->dataUrl();
3378  else if ( QString::compare( layerProperty, QStringLiteral( "attribution" ), Qt::CaseInsensitive ) == 0 )
3379  return layer->attribution();
3380  else if ( QString::compare( layerProperty, QStringLiteral( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
3381  return layer->attributionUrl();
3382  else if ( QString::compare( layerProperty, QStringLiteral( "source" ), Qt::CaseInsensitive ) == 0 )
3383  return layer->publicSource();
3384  else if ( QString::compare( layerProperty, QStringLiteral( "min_scale" ), Qt::CaseInsensitive ) == 0 )
3385  return layer->minimumScale();
3386  else if ( QString::compare( layerProperty, QStringLiteral( "max_scale" ), Qt::CaseInsensitive ) == 0 )
3387  return layer->maximumScale();
3388  else if ( QString::compare( layerProperty, QStringLiteral( "crs" ), Qt::CaseInsensitive ) == 0 )
3389  return layer->crs().authid();
3390  else if ( QString::compare( layerProperty, QStringLiteral( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
3391  return layer->crs().toProj4();
3392  else if ( QString::compare( layerProperty, QStringLiteral( "extent" ), Qt::CaseInsensitive ) == 0 )
3393  {
3394  QgsGeometry extentGeom = QgsGeometry::fromRect( layer->extent() );
3395  QVariant result = QVariant::fromValue( extentGeom );
3396  return result;
3397  }
3398  else if ( QString::compare( layerProperty, QStringLiteral( "type" ), Qt::CaseInsensitive ) == 0 )
3399  {
3400  switch ( layer->type() )
3401  {
3403  return QCoreApplication::translate( "expressions", "Vector" );
3405  return QCoreApplication::translate( "expressions", "Raster" );
3407  return QCoreApplication::translate( "expressions", "Plugin" );
3408  }
3409  }
3410  else
3411  {
3412  //vector layer methods
3413  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
3414  if ( vLayer )
3415  {
3416  if ( QString::compare( layerProperty, QStringLiteral( "storage_type" ), Qt::CaseInsensitive ) == 0 )
3417  return vLayer->storageType();
3418  else if ( QString::compare( layerProperty, QStringLiteral( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
3420  else if ( QString::compare( layerProperty, QStringLiteral( "feature_count" ), Qt::CaseInsensitive ) == 0 )
3421  return QVariant::fromValue( vLayer->featureCount() );
3422  }
3423  }
3424 
3425  return QVariant();
3426 }
3427 
3428 static QVariant fcnGetRasterBandStat( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3429 {
3430  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3431 
3432  //try to find a matching layer by name
3433  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
3434  if ( !layer )
3435  {
3436  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
3437  if ( !layersByName.isEmpty() )
3438  {
3439  layer = layersByName.at( 0 );
3440  }
3441  }
3442 
3443  if ( !layer )
3444  return QVariant();
3445 
3446  QgsRasterLayer* rl = qobject_cast< QgsRasterLayer* >( layer );
3447  if ( !rl )
3448  return QVariant();
3449 
3450  int band = getIntValue( values.at( 1 ), parent );
3451  if ( band < 1 || band > rl->bandCount() )
3452  {
3453  parent->setEvalErrorString( QObject::tr( "Invalid band number %1 for layer %2" ).arg( band ).arg( layerIdOrName ) );
3454  return QVariant();
3455  }
3456 
3457  QString layerProperty = getStringValue( values.at( 2 ), parent );
3458  int stat = 0;
3459 
3460  if ( QString::compare( layerProperty, QStringLiteral( "avg" ), Qt::CaseInsensitive ) == 0 )
3461  stat = QgsRasterBandStats::Mean;
3462  else if ( QString::compare( layerProperty, QStringLiteral( "stdev" ), Qt::CaseInsensitive ) == 0 )
3464  else if ( QString::compare( layerProperty, QStringLiteral( "min" ), Qt::CaseInsensitive ) == 0 )
3465  stat = QgsRasterBandStats::Min;
3466  else if ( QString::compare( layerProperty, QStringLiteral( "max" ), Qt::CaseInsensitive ) == 0 )
3467  stat = QgsRasterBandStats::Max;
3468  else if ( QString::compare( layerProperty, QStringLiteral( "range" ), Qt::CaseInsensitive ) == 0 )
3470  else if ( QString::compare( layerProperty, QStringLiteral( "sum" ), Qt::CaseInsensitive ) == 0 )
3471  stat = QgsRasterBandStats::Sum;
3472  else
3473  {
3474  parent->setEvalErrorString( QObject::tr( "Invalid raster statistic: '%1'" ).arg( layerProperty ) );
3475  return QVariant();
3476  }
3477 
3478  QgsRasterBandStats stats = rl->dataProvider()->bandStatistics( band, stat );
3479  switch ( stat )
3480  {
3482  return stats.mean;
3484  return stats.stdDev;
3486  return stats.minimumValue;
3488  return stats.maximumValue;
3490  return stats.range;
3492  return stats.sum;
3493  }
3494  return QVariant();
3495 }
3496 
3497 static QVariant fcnArray( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
3498 {
3499  return values;
3500 }
3501 
3502 static QVariant fcnArrayLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3503 {
3504  return getListValue( values.at( 0 ), parent ).length();
3505 }
3506 
3507 static QVariant fcnArrayContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3508 {
3509  return QVariant( getListValue( values.at( 0 ), parent ).contains( values.at( 1 ) ) );
3510 }
3511 
3512 static QVariant fcnArrayFind( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3513 {
3514  return getListValue( values.at( 0 ), parent ).indexOf( values.at( 1 ) );
3515 }
3516 
3517 static QVariant fcnArrayGet( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3518 {
3519  const QVariantList list = getListValue( values.at( 0 ), parent );
3520  const int pos = getIntValue( values.at( 1 ), parent );
3521  if ( pos < 0 || pos >= list.length() ) return QVariant();
3522  return list.at( pos );
3523 }
3524 
3525 static QVariant convertToSameType( const QVariant& value, QVariant::Type type )
3526 {
3527  QVariant result = value;
3528  result.convert( type );
3529  return result;
3530 }
3531 
3532 static QVariant fcnArrayAppend( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3533 {
3534  QVariantList list = getListValue( values.at( 0 ), parent );
3535  list.append( values.at( 1 ) );
3536  return convertToSameType( list , values.at( 0 ).type() );
3537 }
3538 
3539 static QVariant fcnArrayPrepend( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3540 {
3541  QVariantList list = getListValue( values.at( 0 ), parent );
3542  list.prepend( values.at( 1 ) );
3543  return convertToSameType( list , values.at( 0 ).type() );
3544 }
3545 
3546 static QVariant fcnArrayInsert( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3547 {
3548  QVariantList list = getListValue( values.at( 0 ), parent );
3549  list.insert( getIntValue( values.at( 1 ), parent ), values.at( 2 ) );
3550  return convertToSameType( list , values.at( 0 ).type() );
3551 }
3552 
3553 static QVariant fcnArrayRemoveAt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3554 {
3555  QVariantList list = getListValue( values.at( 0 ), parent );
3556  list.removeAt( getIntValue( values.at( 1 ), parent ) );
3557  return convertToSameType( list , values.at( 0 ).type() );
3558 }
3559 
3560 static QVariant fcnArrayRemoveAll( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3561 {
3562  QVariantList list = getListValue( values.at( 0 ), parent );
3563  list.removeAll( values.at( 1 ) );
3564  return convertToSameType( list , values.at( 0 ).type() );
3565 }
3566 
3567 static QVariant fcnArrayCat( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3568 {
3569  QVariantList list;
3570  Q_FOREACH ( const QVariant& cur, values )
3571  {
3572  list += getListValue( cur, parent );
3573  }
3574  return convertToSameType( list , values.at( 0 ).type() );
3575 }
3576 
3577 static QVariant fcnArrayIntersect( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3578 {
3579  const QVariantList array1 = getListValue( values.at( 0 ), parent );
3580  Q_FOREACH ( const QVariant& cur, getListValue( values.at( 1 ), parent ) )
3581  {
3582  if ( array1.contains( cur ) )
3583  return QVariant( true );
3584  }
3585  return QVariant( false );
3586 }
3587 
3588 
3589 static QVariant fcnArrayDistinct( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3590 {
3591  QVariantList array = getListValue( values.at( 0 ), parent );
3592 
3593  QVariantList distinct;
3594 
3595  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
3596  {
3597  if ( !distinct.contains( *it ) )
3598  {
3599  distinct += ( *it );
3600  }
3601  }
3602 
3603  return distinct;
3604 }
3605 
3606 static QVariant fcnArrayToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3607 {
3608  QVariantList array = getListValue( values.at( 0 ), parent );
3609  QString delimiter = getStringValue( values.at( 1 ), parent );
3610  QString empty = getStringValue( values.at( 2 ), parent );
3611 
3612  QString str;
3613 
3614  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
3615  {
3616  str += ( *it ).toString().isEmpty() == false ? ( *it ).toString() : empty;
3617  if ( it != ( array.constEnd() - 1 ) )
3618  {
3619  str += delimiter;
3620  }
3621  }
3622 
3623  return QVariant( str );
3624 }
3625 
3626 static QVariant fcnStringToArray( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3627 {
3628  QString str = getStringValue( values.at( 0 ), parent );
3629  QString delimiter = getStringValue( values.at( 1 ), parent );
3630  QString empty = getStringValue( values.at( 2 ), parent );
3631 
3632  QStringList list = str.split( delimiter );
3633  QVariantList array;
3634 
3635  for ( QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
3636  {
3637  array += ( *it ).isEmpty() == false ? *it : empty;
3638  }
3639 
3640  return array;
3641 }
3642 
3643 static QVariant fcnMap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3644 {
3645  QVariantMap result;
3646  for ( int i = 0; i + 1 < values.length(); i += 2 )
3647  {
3648  result.insert( getStringValue( values.at( i ), parent ), values.at( i + 1 ) );
3649  }
3650  return result;
3651 }
3652 
3653 static QVariant fcnMapGet( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3654 {
3655  return getMapValue( values.at( 0 ), parent ).value( values.at( 1 ).toString() );
3656 }
3657 
3658 static QVariant fcnMapExist( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3659 {
3660  return getMapValue( values.at( 0 ), parent ).contains( values.at( 1 ).toString() );
3661 }
3662 
3663 static QVariant fcnMapDelete( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3664 {
3665  QVariantMap map = getMapValue( values.at( 0 ), parent );
3666  map.remove( values.at( 1 ).toString() );
3667  return map;
3668 }
3669 
3670 static QVariant fcnMapInsert( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3671 {
3672  QVariantMap map = getMapValue( values.at( 0 ), parent );
3673  map.insert( values.at( 1 ).toString(), values.at( 2 ) );
3674  return map;
3675 }
3676 
3677 static QVariant fcnMapConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3678 {
3679  QVariantMap result;
3680  Q_FOREACH ( const QVariant& cur, values )
3681  {
3682  const QVariantMap curMap = getMapValue( cur, parent );
3683  for ( QVariantMap::const_iterator it = curMap.constBegin(); it != curMap.constEnd(); ++it )
3684  result.insert( it.key(), it.value() );
3685  }
3686  return result;
3687 }
3688 
3689 static QVariant fcnMapAKeys( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3690 {
3691  return QStringList( getMapValue( values.at( 0 ), parent ).keys() );
3692 }
3693 
3694 static QVariant fcnMapAVals( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3695 {
3696  return getMapValue( values.at( 0 ), parent ).values();
3697 }
3698 
3699 
3700 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
3701 {
3702  int fnIdx = functionIndex( function->name() );
3703  if ( fnIdx != -1 )
3704  {
3705  return false;
3706  }
3707  QgsExpression::gmFunctions.append( function );
3708  if ( transferOwnership )
3709  QgsExpression::gmOwnedFunctions.append( function );
3710  return true;
3711 }
3712 
3713 bool QgsExpression::unregisterFunction( const QString& name )
3714 {
3715  // You can never override the built in functions.
3716  if ( QgsExpression::BuiltinFunctions().contains( name ) )
3717  {
3718  return false;
3719  }
3720  int fnIdx = functionIndex( name );
3721  if ( fnIdx != -1 )
3722  {
3723  QgsExpression::gmFunctions.removeAt( fnIdx );
3724  return true;
3725  }
3726  return false;
3727 }
3728 
3730 {
3731  qDeleteAll( QgsExpression::gmOwnedFunctions );
3733 }
3734 
3736 
3738 {
3739  if ( gmBuiltinFunctions.isEmpty() )
3740  {
3741  Functions(); // this method builds the gmBuiltinFunctions as well
3742  }
3743  return gmBuiltinFunctions;
3744 }
3745 
3746 QList<QgsExpression::Function*> QgsExpression::gmFunctions;
3747 QList<QgsExpression::Function*> QgsExpression::gmOwnedFunctions;
3748 
3749 const QList<QgsExpression::Function*>& QgsExpression::Functions()
3750 {
3751  // The construction of the list isn't thread-safe, and without the mutex,
3752  // crashes in the WFS provider may occur, since it can parse expressions
3753  // in parallel.
3754  // The mutex needs to be recursive.
3755  static QMutex sFunctionsMutex( QMutex::Recursive );
3756  QMutexLocker locker( &sFunctionsMutex );
3757 
3758  if ( gmFunctions.isEmpty() )
3759  {
3760  ParameterList aggParams = ParameterList() << Parameter( QStringLiteral( "expression" ) )
3761  << Parameter( QStringLiteral( "group_by" ), true )
3762  << Parameter( QStringLiteral( "filter" ), true );
3763 
3764  gmFunctions
3765  << new StaticFunction( QStringLiteral( "sqrt" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnSqrt, QStringLiteral( "Math" ) )
3766  << new StaticFunction( QStringLiteral( "radians" ), ParameterList() << Parameter( QStringLiteral( "degrees" ) ), fcnRadians, QStringLiteral( "Math" ) )
3767  << new StaticFunction( QStringLiteral( "degrees" ), ParameterList() << Parameter( QStringLiteral( "radians" ) ), fcnDegrees, QStringLiteral( "Math" ) )
3768  << new StaticFunction( QStringLiteral( "azimuth" ), ParameterList() << Parameter( QStringLiteral( "point_a" ) ) << Parameter( QStringLiteral( "point_b" ) ), fcnAzimuth, QStringList() << QStringLiteral( "Math" ) << QStringLiteral( "GeometryGroup" ) )
3769  << new StaticFunction( QStringLiteral( "project" ), ParameterList() << Parameter( QStringLiteral( "point" ) ) << Parameter( QStringLiteral( "distance" ) ) << Parameter( QStringLiteral( "bearing" ) ), fcnProject, QStringLiteral( "GeometryGroup" ) )
3770  << new StaticFunction( QStringLiteral( "abs" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAbs, QStringLiteral( "Math" ) )
3771  << new StaticFunction( QStringLiteral( "cos" ), ParameterList() << Parameter( QStringLiteral( "angle" ) ), fcnCos, QStringLiteral( "Math" ) )
3772  << new StaticFunction( QStringLiteral( "sin" ), ParameterList() << Parameter( QStringLiteral( "angle" ) ), fcnSin, QStringLiteral( "Math" ) )
3773  << new StaticFunction( QStringLiteral( "tan" ), ParameterList() << Parameter( QStringLiteral( "angle" ) ), fcnTan, QStringLiteral( "Math" ) )
3774  << new StaticFunction( QStringLiteral( "asin" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAsin, QStringLiteral( "Math" ) )
3775  << new StaticFunction( QStringLiteral( "acos" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAcos, QStringLiteral( "Math" ) )
3776  << new StaticFunction( QStringLiteral( "atan" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnAtan, QStringLiteral( "Math" ) )
3777  << new StaticFunction( QStringLiteral( "atan2" ), ParameterList() << Parameter( QStringLiteral( "dx" ) ) << Parameter( QStringLiteral( "dy" ) ), fcnAtan2, QStringLiteral( "Math" ) )
3778  << new StaticFunction( QStringLiteral( "exp" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnExp, QStringLiteral( "Math" ) )
3779  << new StaticFunction( QStringLiteral( "ln" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnLn, QStringLiteral( "Math" ) )
3780  << new StaticFunction( QStringLiteral( "log10" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnLog10, QStringLiteral( "Math" ) )
3781  << new StaticFunction( QStringLiteral( "log" ), ParameterList() << Parameter( QStringLiteral( "base" ) ) << Parameter( QStringLiteral( "value" ) ), fcnLog, QStringLiteral( "Math" ) )
3782  << new StaticFunction( QStringLiteral( "round" ), ParameterList() << Parameter( QStringLiteral( "value" ) ) << Parameter( QStringLiteral( "places" ), true, 0 ), fcnRound, QStringLiteral( "Math" ) )
3783  << new StaticFunction( QStringLiteral( "rand" ), ParameterList() << Parameter( QStringLiteral( "min" ) ) << Parameter( QStringLiteral( "max" ) ), fcnRnd, QStringLiteral( "Math" ) )
3784  << new StaticFunction( QStringLiteral( "randf" ), ParameterList() << Parameter( QStringLiteral( "min" ), true, 0.0 ) << Parameter( QStringLiteral( "max" ), true, 1.0 ), fcnRndF, QStringLiteral( "Math" ) )
3785  << new StaticFunction( QStringLiteral( "max" ), -1, fcnMax, QStringLiteral( "Math" ) )
3786  << new StaticFunction( QStringLiteral( "min" ), -1, fcnMin, QStringLiteral( "Math" ) )
3787  << new StaticFunction( QStringLiteral( "clamp" ), ParameterList() << Parameter( QStringLiteral( "min" ) ) << Parameter( QStringLiteral( "value" ) ) << Parameter( QStringLiteral( "max" ) ), fcnClamp, QStringLiteral( "Math" ) )
3788  << new StaticFunction( QStringLiteral( "scale_linear" ), 5, fcnLinearScale, QStringLiteral( "Math" ) )
3789  << new StaticFunction( QStringLiteral( "scale_exp" ), 6, fcnExpScale, QStringLiteral( "Math" ) )
3790  << new StaticFunction( QStringLiteral( "floor" ), 1, fcnFloor, QStringLiteral( "Math" ) )
3791  << new StaticFunction( QStringLiteral( "ceil" ), 1, fcnCeil, QStringLiteral( "Math" ) )
3792  << new StaticFunction( QStringLiteral( "pi" ), 0, fcnPi, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$pi" ) )
3793  << new StaticFunction( QStringLiteral( "to_int" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToInt, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toint" ) )
3794  << new StaticFunction( QStringLiteral( "to_real" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToReal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toreal" ) )
3795  << new StaticFunction( QStringLiteral( "to_string" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToString, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tostring" ) )
3796  << new StaticFunction( QStringLiteral( "to_datetime" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToDateTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todatetime" ) )
3797  << new StaticFunction( QStringLiteral( "to_date" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToDate, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todate" ) )
3798  << new StaticFunction( QStringLiteral( "to_time" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "totime" ) )
3799  << new StaticFunction( QStringLiteral( "to_interval" ), ParameterList() << Parameter( QStringLiteral( "value" ) ), fcnToInterval, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tointerval" ) )
3800  << new StaticFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
3801  << new StaticFunction( QStringLiteral( "if" ), 3, fcnIf, QStringLiteral( "Conditionals" ), QString(), False, QSet<QString>(), true )
3802 
3803  << new StaticFunction( QStringLiteral( "aggregate" ),
3804  ParameterList()
3805  << Parameter( QStringLiteral( "layer" ) )
3806  << Parameter( QStringLiteral( "aggregate" ) )
3807  << Parameter( QStringLiteral( "expression" ) )
3808  << Parameter( QStringLiteral( "filter" ), true )
3809  << Parameter( QStringLiteral( "concatenator" ), true ),
3810  fcnAggregate,
3811  QStringLiteral( "Aggregates" ),
3812  QString(),
3813  []( const QgsExpression::NodeFunction* node )
3814  {
3815  // usesGeometry callback: return true if @parent variable is referenced
3816 
3817  if ( !node )
3818  return true;
3819 
3820  if ( !node->args() )
3821  return false;
3822 
3823  QSet<QString> referencedVars;
3824  if ( node->args()->count() > 2 )
3825  {
3826  QgsExpression::Node* subExpressionNode = node->args()->at( 2 );
3827  referencedVars = subExpressionNode->referencedVariables();
3828  }
3829 
3830  if ( node->args()->count() > 3 )
3831  {
3832  QgsExpression::Node* filterNode = node->args()->at( 3 );
3833  referencedVars.unite( filterNode->referencedVariables() );
3834  }
3835  return referencedVars.contains( "parent" ) || referencedVars.contains( QString() );
3836  },
3837  []( const QgsExpression::NodeFunction* node )
3838  {
3839  // referencedColumns callback: return AllAttributes if @parent variable is referenced
3840 
3841  if ( !node )
3842  return QSet<QString>() << QgsFeatureRequest::AllAttributes;
3843 
3844  if ( !node->args() )
3845  return QSet<QString>();
3846 
3847  QSet<QString> referencedCols;
3848  QSet<QString> referencedVars;
3849 
3850  if ( node->args()->count() > 2 )
3851  {
3852  QgsExpression::Node* subExpressionNode = node->args()->at( 2 );
3853  referencedVars = subExpressionNode->referencedVariables();
3854  referencedCols = subExpressionNode->referencedColumns();
3855  }
3856  if ( node->args()->count() > 3 )
3857  {
3858  QgsExpression::Node* filterNode = node->args()->at( 3 );
3859  referencedVars = filterNode->referencedVariables();
3860  referencedCols.unite( filterNode->referencedColumns() );
3861  }
3862 
3863  if ( referencedVars.contains( "parent" ) || referencedVars.contains( QString() ) )
3864  return QSet<QString>() << QgsFeatureRequest::AllAttributes;
3865  else
3866  return referencedCols;
3867  },
3868  true
3869  )
3870 
3871  << new StaticFunction( QStringLiteral( "relation_aggregate" ), ParameterList() << Parameter( QStringLiteral( "relation" ) ) << Parameter( QStringLiteral( "aggregate" ) ) << Parameter( QStringLiteral( "expression" ) ) << Parameter( QStringLiteral( "concatenator" ), true ),
3872  fcnAggregateRelation, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>() << QgsFeatureRequest::AllAttributes, true )
3873 
3874  << new StaticFunction( QStringLiteral( "count" ), aggParams, fcnAggregateCount, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3875  << new StaticFunction( QStringLiteral( "count_distinct" ), aggParams, fcnAggregateCountDistinct, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3876  << new StaticFunction( QStringLiteral( "count_missing" ), aggParams, fcnAggregateCountMissing, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3877  << new StaticFunction( QStringLiteral( "minimum" ), aggParams, fcnAggregateMin, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3878  << new StaticFunction( QStringLiteral( "maximum" ), aggParams, fcnAggregateMax, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3879  << new StaticFunction( QStringLiteral( "sum" ), aggParams, fcnAggregateSum, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3880  << new StaticFunction( QStringLiteral( "mean" ), aggParams, fcnAggregateMean, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3881  << new StaticFunction( QStringLiteral( "median" ), aggParams, fcnAggregateMedian, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3882  << new StaticFunction( QStringLiteral( "stdev" ), aggParams, fcnAggregateStdev, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3883  << new StaticFunction( QStringLiteral( "range" ), aggParams, fcnAggregateRange, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3884  << new StaticFunction( QStringLiteral( "minority" ), aggParams, fcnAggregateMinority, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3885  << new StaticFunction( QStringLiteral( "majority" ), aggParams, fcnAggregateMajority, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3886  << new StaticFunction( QStringLiteral( "q1" ), aggParams, fcnAggregateQ1, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3887  << new StaticFunction( QStringLiteral( "q3" ), aggParams, fcnAggregateQ3, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3888  << new StaticFunction( QStringLiteral( "iqr" ), aggParams, fcnAggregateIQR, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3889  << new StaticFunction( QStringLiteral( "min_length" ), aggParams, fcnAggregateMinLength, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3890  << new StaticFunction( QStringLiteral( "max_length" ), aggParams, fcnAggregateMaxLength, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3891  << new StaticFunction( QStringLiteral( "collect" ), aggParams, fcnAggregateCollectGeometry, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3892  << new StaticFunction( QStringLiteral( "concatenate" ), aggParams << Parameter( QStringLiteral( "concatenator" ), true ), fcnAggregateStringConcat, QStringLiteral( "Aggregates" ), QString(), False, QSet<QString>(), true )
3893 
3894  << new StaticFunction( QStringLiteral( "regexp_match" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "regex" ) ), fcnRegexpMatch, QStringList() << QStringLiteral( "Conditionals" ) << QStringLiteral( "String" ) )
3895  << new StaticFunction( QStringLiteral( "regexp_matches" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "regex" ) ) << Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnRegexpMatches, QStringLiteral( "Arrays" ) )
3896 
3897  << new StaticFunction( QStringLiteral( "now" ), 0, fcnNow, QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$now" ) )
3898  << new StaticFunction( QStringLiteral( "age" ), 2, fcnAge, QStringLiteral( "Date and Time" ) )
3899  << new StaticFunction( QStringLiteral( "year" ), 1, fcnYear, QStringLiteral( "Date and Time" ) )
3900  << new StaticFunction( QStringLiteral( "month" ), 1, fcnMonth, QStringLiteral( "Date and Time" ) )
3901  << new StaticFunction( QStringLiteral( "week" ), 1, fcnWeek, QStringLiteral( "Date and Time" ) )
3902  << new StaticFunction( QStringLiteral( "day" ), 1, fcnDay, QStringLiteral( "Date and Time" ) )
3903  << new StaticFunction( QStringLiteral( "hour" ), 1, fcnHour, QStringLiteral( "Date and Time" ) )
3904  << new StaticFunction( QStringLiteral( "minute" ), 1, fcnMinute, QStringLiteral( "Date and Time" ) )
3905  << new StaticFunction( QStringLiteral( "second" ), 1, fcnSeconds, QStringLiteral( "Date and Time" ) )
3906  << new StaticFunction( QStringLiteral( "day_of_week" ), 1, fcnDayOfWeek, QStringLiteral( "Date and Time" ) )
3907  << new StaticFunction( QStringLiteral( "lower" ), 1, fcnLower, QStringLiteral( "String" ) )
3908  << new StaticFunction( QStringLiteral( "upper" ), 1, fcnUpper, QStringLiteral( "String" ) )
3909  << new StaticFunction( QStringLiteral( "title" ), 1, fcnTitle, QStringLiteral( "String" ) )
3910  << new StaticFunction( QStringLiteral( "trim" ), 1, fcnTrim, QStringLiteral( "String" ) )
3911  << new StaticFunction( QStringLiteral( "levenshtein" ), 2, fcnLevenshtein, QStringLiteral( "Fuzzy Matching" ) )
3912  << new StaticFunction( QStringLiteral( "longest_common_substring" ), 2, fcnLCS, QStringLiteral( "Fuzzy Matching" ) )
3913  << new StaticFunction( QStringLiteral( "hamming_distance" ), 2, fcnHamming, QStringLiteral( "Fuzzy Matching" ) )
3914  << new StaticFunction( QStringLiteral( "soundex" ), 1, fcnSoundex, QStringLiteral( "Fuzzy Matching" ) )
3915  << new StaticFunction( QStringLiteral( "char" ), 1, fcnChar, QStringLiteral( "String" ) )
3916  << new StaticFunction( QStringLiteral( "wordwrap" ), ParameterList() << Parameter( QStringLiteral( "text" ) ) << Parameter( QStringLiteral( "length" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "" ), fcnWordwrap, QStringLiteral( "String" ) )
3917  << new StaticFunction( QStringLiteral( "length" ), ParameterList() << Parameter( QStringLiteral( "text" ), true, "" ), fcnLength, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "GeometryGroup" ) )
3918  << new StaticFunction( QStringLiteral( "replace" ), -1, fcnReplace, QStringLiteral( "String" ) )
3919  << new StaticFunction( QStringLiteral( "regexp_replace" ), 3, fcnRegexpReplace, QStringLiteral( "String" ) )
3920  << new StaticFunction( QStringLiteral( "regexp_substr" ), 2, fcnRegexpSubstr, QStringLiteral( "String" ) )
3921  << new StaticFunction( QStringLiteral( "substr" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "start " ) ) << Parameter( QStringLiteral( "length" ), true ), fcnSubstr, QStringLiteral( "String" ), QString(),
3922  false, QSet< QString >(), false, QStringList(), true )
3923  << new StaticFunction( QStringLiteral( "concat" ), -1, fcnConcat, QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList(), true )
3924  << new StaticFunction( QStringLiteral( "strpos" ), 2, fcnStrpos, QStringLiteral( "String" ) )
3925  << new StaticFunction( QStringLiteral( "left" ), 2, fcnLeft, QStringLiteral( "String" ) )
3926  << new StaticFunction( QStringLiteral( "right" ), 2, fcnRight, QStringLiteral( "String" ) )
3927  << new StaticFunction( QStringLiteral( "rpad" ), 3, fcnRPad, QStringLiteral( "String" ) )
3928  << new StaticFunction( QStringLiteral( "lpad" ), 3, fcnLPad, QStringLiteral( "String" ) )
3929  << new StaticFunction( QStringLiteral( "format" ), -1, fcnFormatString, QStringLiteral( "String" ) )
3930  << new StaticFunction( QStringLiteral( "format_number" ), 2, fcnFormatNumber, QStringLiteral( "String" ) )
3931  << new StaticFunction( QStringLiteral( "format_date" ), ParameterList() << Parameter( QStringLiteral( "date" ) ) << Parameter( QStringLiteral( "format" ) ), fcnFormatDate, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "Date and Time" ) )
3932  << new StaticFunction( QStringLiteral( "color_rgb" ), 3, fcnColorRgb, QStringLiteral( "Color" ) )
3933  << new StaticFunction( QStringLiteral( "color_rgba" ), 4, fncColorRgba, QStringLiteral( "Color" ) )
3934  << new StaticFunction( QStringLiteral( "ramp_color" ), 2, fcnRampColor, QStringLiteral( "Color" ) )
3935  << new StaticFunction( QStringLiteral( "color_hsl" ), 3, fcnColorHsl, QStringLiteral( "Color" ) )
3936  << new StaticFunction( QStringLiteral( "color_hsla" ), 4, fncColorHsla, QStringLiteral( "Color" ) )
3937  << new StaticFunction( QStringLiteral( "color_hsv" ), 3, fcnColorHsv, QStringLiteral( "Color" ) )
3938  << new StaticFunction( QStringLiteral( "color_hsva" ), 4, fncColorHsva, QStringLiteral( "Color" ) )
3939  << new StaticFunction( QStringLiteral( "color_cmyk" ), 4, fcnColorCmyk, QStringLiteral( "Color" ) )
3940  << new StaticFunction( QStringLiteral( "color_cmyka" ), 5, fncColorCmyka, QStringLiteral( "Color" ) )
3941  << new StaticFunction( QStringLiteral( "color_part" ), 2, fncColorPart, QStringLiteral( "Color" ) )
3942  << new StaticFunction( QStringLiteral( "darker" ), 2, fncDarker, QStringLiteral( "Color" ) )
3943  << new StaticFunction( QStringLiteral( "lighter" ), 2, fncLighter, QStringLiteral( "Color" ) )
3944  << new StaticFunction( QStringLiteral( "set_color_part" ), 3, fncSetColorPart, QStringLiteral( "Color" ) )
3945  << new StaticFunction( QStringLiteral( "$geometry" ), 0, fcnGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
3946  << new StaticFunction( QStringLiteral( "$area" ), 0, fcnGeomArea, QStringLiteral( "GeometryGroup" ), QString(), true )
3947  << new StaticFunction( QStringLiteral( "area" ), 1, fcnArea, QStringLiteral( "GeometryGroup" ) )
3948  << new StaticFunction( QStringLiteral( "$length" ), 0, fcnGeomLength, QStringLiteral( "GeometryGroup" ), QString(), true )
3949  << new StaticFunction( QStringLiteral( "$perimeter" ), 0, fcnGeomPerimeter, QStringLiteral( "GeometryGroup" ), QString(), true )
3950  << new StaticFunction( QStringLiteral( "perimeter" ), 1, fcnPerimeter, QStringLiteral( "GeometryGroup" ) )
3951  << new StaticFunction( QStringLiteral( "$x" ), 0, fcnX, QStringLiteral( "GeometryGroup" ), QString(), true )
3952  << new StaticFunction( QStringLiteral( "$y" ), 0, fcnY, QStringLiteral( "GeometryGroup" ), QString(), true )
3953  << new StaticFunction( QStringLiteral( "x" ), 1, fcnGeomX, QStringLiteral( "GeometryGroup" ) )
3954  << new StaticFunction( QStringLiteral( "y" ), 1, fcnGeomY, QStringLiteral( "GeometryGroup" ) )
3955  << new StaticFunction( QStringLiteral( "z" ), 1, fcnGeomZ, QStringLiteral( "GeometryGroup" ) )
3956  << new StaticFunction( QStringLiteral( "m" ), 1, fcnGeomM, QStringLiteral( "GeometryGroup" ) )
3957  << new StaticFunction( QStringLiteral( "point_n" ), 2, fcnPointN, QStringLiteral( "GeometryGroup" ) )
3958  << new StaticFunction( QStringLiteral( "start_point" ), 1, fcnStartPoint, QStringLiteral( "GeometryGroup" ) )
3959  << new StaticFunction( QStringLiteral( "end_point" ), 1, fcnEndPoint, QStringLiteral( "GeometryGroup" ) )
3960  << new StaticFunction( QStringLiteral( "nodes_to_points" ), -1, fcnNodesToPoints, QStringLiteral( "GeometryGroup" ) )
3961  << new StaticFunction( QStringLiteral( "segments_to_lines" ), 1, fcnSegmentsToLines, QStringLiteral( "GeometryGroup" ) )
3962  << new StaticFunction( QStringLiteral( "make_point" ), -1, fcnMakePoint, QStringLiteral( "GeometryGroup" ) )
3963  << new StaticFunction( QStringLiteral( "make_point_m" ), 3, fcnMakePointM, QStringLiteral( "GeometryGroup" ) )
3964  << new StaticFunction( QStringLiteral( "make_line" ), -1, fcnMakeLine, QStringLiteral( "GeometryGroup" ) )
3965  << new StaticFunction( QStringLiteral( "make_polygon" ), -1, fcnMakePolygon, QStringLiteral( "GeometryGroup" ) )
3966  << new StaticFunction( QStringLiteral( "$x_at" ), 1, fcnXat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "xat" ) << QStringLiteral( "x_at" ) )
3967  << new StaticFunction( QStringLiteral( "$y_at" ), 1, fcnYat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "yat" ) << QStringLiteral( "y_at" ) )
3968  << new StaticFunction( QStringLiteral( "x_min" ), 1, fcnXMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmin" ) )
3969  << new StaticFunction( QStringLiteral( "x_max" ), 1, fcnXMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmax" ) )
3970  << new StaticFunction( QStringLiteral( "y_min" ), 1, fcnYMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymin" ) )
3971  << new StaticFunction( QStringLiteral( "y_max" ), 1, fcnYMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymax" ) )
3972  << new StaticFunction( QStringLiteral( "geom_from_wkt" ), 1, fcnGeomFromWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromWKT" ) )
3973  << new StaticFunction( QStringLiteral( "geom_from_gml" ), 1, fcnGeomFromGML, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromGML" ) )
3974  << new StaticFunction( QStringLiteral( "relate" ), -1, fcnRelate, QStringLiteral( "GeometryGroup" ) )
3975  << new StaticFunction( QStringLiteral( "intersects_bbox" ), 2, fcnBbox, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "bbox" ) )
3976  << new StaticFunction( QStringLiteral( "disjoint" ), 2, fcnDisjoint, QStringLiteral( "GeometryGroup" ) )
3977  << new StaticFunction( QStringLiteral( "intersects" ), 2, fcnIntersects, QStringLiteral( "GeometryGroup" ) )
3978  << new StaticFunction( QStringLiteral( "touches" ), 2, fcnTouches, QStringLiteral( "GeometryGroup" ) )
3979  << new StaticFunction( QStringLiteral( "crosses" ), 2, fcnCrosses, QStringLiteral( "GeometryGroup" ) )
3980  << new StaticFunction( QStringLiteral( "contains" ), 2, fcnContains, QStringLiteral( "GeometryGroup" ) )
3981  << new StaticFunction( QStringLiteral( "overlaps" ), 2, fcnOverlaps, QStringLiteral( "GeometryGroup" ) )
3982  << new StaticFunction( QStringLiteral( "within" ), 2, fcnWithin, QStringLiteral( "GeometryGroup" ) )
3983  << new StaticFunction( QStringLiteral( "translate" ), 3, fcnTranslate, QStringLiteral( "GeometryGroup" ) )
3984  << new StaticFunction( QStringLiteral( "buffer" ), -1, fcnBuffer, QStringLiteral( "GeometryGroup" ) )
3985  << new StaticFunction( QStringLiteral( "offset_curve" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
3986  << Parameter( QStringLiteral( "distance" ) )
3987  << Parameter( QStringLiteral( "segments" ), true, 8.0 )
3988  << Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
3989  << Parameter( QStringLiteral( "mitre_limit" ), true, 2.0 ),
3990  fcnOffsetCurve, QStringLiteral( "GeometryGroup" ) )
3991  << new StaticFunction( QStringLiteral( "single_sided_buffer" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
3992  << Parameter( QStringLiteral( "distance" ) )
3993  << Parameter( QStringLiteral( "segments" ), true, 8.0 )
3994  << Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
3995  << Parameter( QStringLiteral( "mitre_limit" ), true, 2.0 ),
3996  fcnSingleSidedBuffer, QStringLiteral( "GeometryGroup" ) )
3997  << new StaticFunction( QStringLiteral( "extend" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
3998  << Parameter( QStringLiteral( "start_distance" ) )
3999  << Parameter( QStringLiteral( "end_distance" ) ),
4000  fcnExtend, QStringLiteral( "GeometryGroup" ) )
4001  << new StaticFunction( QStringLiteral( "centroid" ), 1, fcnCentroid, QStringLiteral( "GeometryGroup" ) )
4002  << new StaticFunction( QStringLiteral( "point_on_surface" ), 1, fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
4003  << new StaticFunction( QStringLiteral( "pole_of_inaccessibility" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4004  << Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
4005  << new StaticFunction( QStringLiteral( "reverse" ), 1, fcnReverse, QStringLiteral( "GeometryGroup" ) )
4006  << new StaticFunction( QStringLiteral( "exterior_ring" ), 1, fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
4007  << new StaticFunction( QStringLiteral( "interior_ring_n" ), 2, fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )
4008  << new StaticFunction( QStringLiteral( "geometry_n" ), 2, fcnGeometryN, QStringLiteral( "GeometryGroup" ) )
4009  << new StaticFunction( QStringLiteral( "boundary" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ), fcnBoundary, QStringLiteral( "GeometryGroup" ) )
4010  << new StaticFunction( QStringLiteral( "line_merge" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ), fcnLineMerge, QStringLiteral( "GeometryGroup" ) )
4011  << new StaticFunction( QStringLiteral( "bounds" ), 1, fcnBounds, QStringLiteral( "GeometryGroup" ) )
4012  << new StaticFunction( QStringLiteral( "simplify" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ) << Parameter( QStringLiteral( "tolerance" ) ), fcnSimplify, QStringLiteral( "GeometryGroup" ) )
4013  << new StaticFunction( QStringLiteral( "simplify_vw" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ) << Parameter( QStringLiteral( "tolerance" ) ), fcnSimplifyVW, QStringLiteral( "GeometryGroup" ) )
4014  << new StaticFunction( QStringLiteral( "smooth" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) ) << Parameter( QStringLiteral( "iterations" ), true, 1 )
4015  << Parameter( QStringLiteral( "offset" ), true, 0.25 )
4016  << Parameter( QStringLiteral( "min_length" ), true, -1 )
4017  << Parameter( QStringLiteral( "max_angle" ), true, 180 ), fcnSmooth, QStringLiteral( "GeometryGroup" ) )
4018  << new StaticFunction( QStringLiteral( "num_points" ), 1, fcnGeomNumPoints, QStringLiteral( "GeometryGroup" ) )
4019  << new StaticFunction( QStringLiteral( "num_interior_rings" ), 1, fcnGeomNumInteriorRings, QStringLiteral( "GeometryGroup" ) )
4020  << new StaticFunction( QStringLiteral( "num_rings" ), 1, fcnGeomNumRings, QStringLiteral( "GeometryGroup" ) )
4021  << new StaticFunction( QStringLiteral( "num_geometries" ), 1, fcnGeomNumGeometries, QStringLiteral( "GeometryGroup" ) )
4022  << new StaticFunction( QStringLiteral( "bounds_width" ), 1, fcnBoundsWidth, QStringLiteral( "GeometryGroup" ) )
4023  << new StaticFunction( QStringLiteral( "bounds_height" ), 1, fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) )
4024  << new StaticFunction( QStringLiteral( "is_closed" ), 1, fcnIsClosed, QStringLiteral( "GeometryGroup" ) )
4025  << new StaticFunction( QStringLiteral( "convex_hull" ), 1, fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "convexHull" ) )
4026  << new StaticFunction( QStringLiteral( "difference" ), 2, fcnDifference, QStringLiteral( "GeometryGroup" ) )
4027  << new StaticFunction( QStringLiteral( "distance" ), 2, fcnDistance, QStringLiteral( "GeometryGroup" ) )
4028  << new StaticFunction( QStringLiteral( "intersection" ), 2, fcnIntersection, QStringLiteral( "GeometryGroup" ) )
4029  << new StaticFunction( QStringLiteral( "sym_difference" ), 2, fcnSymDifference, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "symDifference" ) )
4030  << new StaticFunction( QStringLiteral( "combine" ), 2, fcnCombine, QStringLiteral( "GeometryGroup" ) )
4031  << new StaticFunction( QStringLiteral( "union" ), 2, fcnCombine, QStringLiteral( "GeometryGroup" ) )
4032  << new StaticFunction( QStringLiteral( "geom_to_wkt" ), -1, fcnGeomToWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomToWKT" ) )
4033  << new StaticFunction( QStringLiteral( "geometry" ), 1, fcnGetGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
4034  << new StaticFunction( QStringLiteral( "transform" ), 3, fcnTransformGeometry, QStringLiteral( "GeometryGroup" ) )
4035  << new StaticFunction( QStringLiteral( "extrude" ), 3, fcnExtrude, QStringLiteral( "GeometryGroup" ), QString() )
4036  << new StaticFunction( QStringLiteral( "order_parts" ), 3, fcnOrderParts, QStringLiteral( "GeometryGroup" ), QString() )
4037  << new StaticFunction( QStringLiteral( "closest_point" ), 2, fcnClosestPoint, QStringLiteral( "GeometryGroup" ) )
4038  << new StaticFunction( QStringLiteral( "shortest_line" ), 2, fcnShortestLine, QStringLiteral( "GeometryGroup" ) )
4039  << new StaticFunction( QStringLiteral( "line_interpolate_point" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4040  << Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolatePoint, QStringLiteral( "GeometryGroup" ) )
4041  << new StaticFunction( QStringLiteral( "line_interpolate_angle" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4042  << Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolateAngle, QStringLiteral( "GeometryGroup" ) )
4043  << new StaticFunction( QStringLiteral( "line_locate_point" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4044  << Parameter( QStringLiteral( "point" ) ), fcnLineLocatePoint, QStringLiteral( "GeometryGroup" ) )
4045  << new StaticFunction( QStringLiteral( "angle_at_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4046  << Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
4047  << new StaticFunction( QStringLiteral( "distance_to_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
4048  << Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
4049 
4050 
4051  // **Record** functions
4052 
4053  << new StaticFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record" ) )
4054  << new StaticFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record" ) )
4055  << new StaticFunction( QStringLiteral( "uuid" ), 0, fcnUuid, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) )
4056  << new StaticFunction( QStringLiteral( "get_feature" ), 3, fcnGetFeature, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "getFeature" ) )
4057 
4058  << new StaticFunction(
4059  QStringLiteral( "is_selected" ),
4060  -1,
4061  fcnIsSelected,
4062  QStringLiteral( "Record" ),
4063  QString(),
4064  false,
4065  QSet<QString>()
4066  )
4067 
4068  << new StaticFunction(
4069  QStringLiteral( "num_selected" ),
4070  -1,
4072  QStringLiteral( "Record" ),
4073  QString(),
4074  false,
4075  QSet<QString>()
4076  )
4077 
4078  // **General** functions
4079 
4080  << new StaticFunction( QStringLiteral( "layer_property" ), 2, fcnGetLayerProperty, QStringLiteral( "General" ) )
4081  << new StaticFunction( QStringLiteral( "raster_statistic" ), ParameterList() << Parameter( QStringLiteral( "layer" ) )
4082  << Parameter( QStringLiteral( "band" ) )
4083  << Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "General" ) )
4084  << new StaticFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) )
4085 
4086  //return all attributes string for referencedColumns - this is caught by
4087  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
4088  // feature request
4089  << new StaticFunction( QStringLiteral( "eval" ), 1, fcnEval, QStringLiteral( "General" ), QString(), true, QSet<QString>() << QgsFeatureRequest::AllAttributes )
4090  << new StaticFunction( QStringLiteral( "attribute" ), 2, fcnAttribute, QStringLiteral( "Record" ), QString(), false, QSet<QString>() << QgsFeatureRequest::AllAttributes )
4091 
4092  // functions for arrays
4093  << new StaticFunction( QStringLiteral( "array" ), -1, fcnArray, QStringLiteral( "Arrays" ) )
4094  << new StaticFunction( QStringLiteral( "array_length" ), 1, fcnArrayLength, QStringLiteral( "Arrays" ) )
4095  << new StaticFunction( QStringLiteral( "array_contains" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayContains, QStringLiteral( "Arrays" ) )
4096  << new StaticFunction( QStringLiteral( "array_find" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayFind, QStringLiteral( "Arrays" ) )
4097  << new StaticFunction( QStringLiteral( "array_get" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "pos" ) ), fcnArrayGet, QStringLiteral( "Arrays" ) )
4098  << new StaticFunction( QStringLiteral( "array_append" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayAppend, QStringLiteral( "Arrays" ) )
4099  << new StaticFunction( QStringLiteral( "array_prepend" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayPrepend, QStringLiteral( "Arrays" ) )
4100  << new StaticFunction( QStringLiteral( "array_insert" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "pos" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayInsert, QStringLiteral( "Arrays" ) )
4101  << new StaticFunction( QStringLiteral( "array_remove_at" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "pos" ) ), fcnArrayRemoveAt, QStringLiteral( "Arrays" ) )
4102  << new StaticFunction( QStringLiteral( "array_remove_all" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "value" ) ), fcnArrayRemoveAll, QStringLiteral( "Arrays" ) )
4103  << new StaticFunction( QStringLiteral( "array_cat" ), -1, fcnArrayCat, QStringLiteral( "Arrays" ) )
4104  << new StaticFunction( QStringLiteral( "array_intersect" ), ParameterList() << Parameter( QStringLiteral( "array1" ) ) << Parameter( QStringLiteral( "array2" ) ), fcnArrayIntersect, QStringLiteral( "Arrays" ) )
4105  << new StaticFunction( QStringLiteral( "array_distinct" ), 1, fcnArrayDistinct, QStringLiteral( "Arrays" ) )
4106  << new StaticFunction( QStringLiteral( "array_to_string" ), ParameterList() << Parameter( QStringLiteral( "array" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "," ) << Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnArrayToString, QStringLiteral( "Arrays" ) )
4107  << new StaticFunction( QStringLiteral( "string_to_array" ), ParameterList() << Parameter( QStringLiteral( "string" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "," ) << Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnStringToArray, QStringLiteral( "Arrays" ) )
4108 
4109  //functions for maps
4110  << new StaticFunction( QStringLiteral( "map" ), -1, fcnMap, QStringLiteral( "Maps" ) )
4111  << new StaticFunction( QStringLiteral( "map_get" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ), fcnMapGet, QStringLiteral( "Maps" ) )
4112  << new StaticFunction( QStringLiteral( "map_exist" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ), fcnMapExist, QStringLiteral( "Maps" ) )
4113  << new StaticFunction( QStringLiteral( "map_delete" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ), fcnMapDelete, QStringLiteral( "Maps" ) )
4114  << new StaticFunction( QStringLiteral( "map_insert" ), ParameterList() << Parameter( QStringLiteral( "map" ) ) << Parameter( QStringLiteral( "key" ) ) << Parameter( QStringLiteral( "value" ) ), fcnMapInsert, QStringLiteral( "Maps" ) )
4115  << new StaticFunction( QStringLiteral( "map_concat" ), -1, fcnMapConcat, QStringLiteral( "Maps" ) )
4116  << new StaticFunction( QStringLiteral( "map_akeys" ), ParameterList() << Parameter( QStringLiteral( "map" ) ), fcnMapAKeys, QStringLiteral( "Maps" ) )
4117  << new StaticFunction( QStringLiteral( "map_avals" ), ParameterList() << Parameter( QStringLiteral( "map" ) ), fcnMapAVals, QStringLiteral( "Maps" ) )
4118  ;
4119 
4121 
4122  //QgsExpression has ownership of all built-in functions
4123  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
4124  {
4125  gmOwnedFunctions << func;
4126  gmBuiltinFunctions << func->name();
4127  gmBuiltinFunctions.append( func->aliases() );
4128  }
4129  }
4130  return gmFunctions;
4131 }
4132 
4133 bool QgsExpression::checkExpression( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
4134 {
4135  QgsExpression exp( text );
4136  exp.prepare( context );
4137  errorMessage = exp.parserErrorString();
4138  return !exp.hasParserError();
4139 }
4140 
4142 {
4143  detach();
4144  d->mRootNode = ::parseExpression( expression, d->mParserErrorString );
4145  d->mEvalErrorString = QString();
4146  d->mExp = expression;
4147 }
4148 
4150 {
4151  if ( !d->mExp.isNull() )
4152  return d->mExp;
4153  else
4154  return dump();
4155 }
4156 
4157 QString QgsExpression::quotedColumnRef( QString name )
4158 {
4159  return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
4160 }
4161 
4162 QString QgsExpression::quotedString( QString text )
4163 {
4164  text.replace( '\'', QLatin1String( "''" ) );
4165  text.replace( '\\', QLatin1String( "\\\\" ) );
4166  text.replace( '\n', QLatin1String( "\\n" ) );
4167  text.replace( '\t', QLatin1String( "\\t" ) );
4168  return QStringLiteral( "'%1'" ).arg( text );
4169 }
4170 
4171 QString QgsExpression::quotedValue( const QVariant &value )
4172 {
4173  return quotedValue( value, value.type() );
4174 }
4175 
4176 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
4177 {
4178  if ( value.isNull() )
4179  return QStringLiteral( "NULL" );
4180 
4181  switch ( type )
4182  {
4183  case QVariant::Int:
4184  case QVariant::LongLong:
4185  case QVariant::Double:
4186  return value.toString();
4187 
4188  case QVariant::Bool:
4189  return value.toBool() ? "TRUE" : "FALSE";
4190 
4191  default:
4192  case QVariant::String:
4193  return quotedString( value.toString() );
4194  }
4195 
4196 }
4197 
4198 bool QgsExpression::isFunctionName( const QString &name )
4199 {
4200  return functionIndex( name ) != -1;
4201 }
4202 
4203 int QgsExpression::functionIndex( const QString &name )
4204 {
4205  int count = functionCount();
4206  for ( int i = 0; i < count; i++ )
4207  {
4208  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
4209  return i;
4210  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
4211  {
4212  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
4213  return i;
4214  }
4215  }
4216  return -1;
4217 }
4218 
4220 {
4221  return Functions().size();
4222 }
4223 
4224 
4225 QgsExpression::QgsExpression( const QString& expr )
4226  : d( new QgsExpressionPrivate )
4227 {
4228  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
4229  d->mExp = expr;
4230  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
4231 }
4232 
4234  : d( other.d )
4235 {
4236  d->ref.ref();
4237 }
4238 
4240 {
4241  d = other.d;
4242  d->ref.ref();
4243  return *this;
4244 }
4245 
4247  : d( new QgsExpressionPrivate )
4248 {
4249 }
4250 
4252 {
4253  Q_ASSERT( d );
4254  if ( !d->ref.deref() )
4255  delete d;
4256 }
4257 
4258 bool QgsExpression::operator==( const QgsExpression& other ) const
4259 {
4260  if ( d == other.d || d->mExp == other.d->mExp )
4261  return true;
4262  return false;
4263 }
4264 
4266 {
4267  return d->mRootNode;
4268 }
4269 
4270 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
4271 
4272 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
4273 
4275 {
4276  if ( !d->mRootNode )
4277  return QSet<QString>();
4278 
4279  return d->mRootNode->referencedColumns();
4280 }
4281 
4283 {
4284  if ( !d->mRootNode )
4285  return QSet<QString>();
4286 
4287  return d->mRootNode->referencedVariables();
4288 }
4289 
4291 {
4292  bool needs = false;
4293  Q_FOREACH ( Node* n, mList->list() )
4294  needs |= n->needsGeometry();
4295  return needs;
4296 }
4297 
4299 {
4300  if ( !d->mRootNode )
4301  return QSet<int>();
4302 
4303  const QSet<QString> referencedFields = d->mRootNode->referencedColumns();
4304  QSet<int> referencedIndexes;
4305 
4306 for ( const QString& fieldName : referencedFields )
4307  {
4308  if ( fieldName == QgsFeatureRequest::AllAttributes )
4309  {
4310  referencedIndexes = fields.allAttributesList().toSet();
4311  break;
4312  }
4313  referencedIndexes << fields.lookupField( fieldName );
4314  }
4315 
4316  return referencedIndexes;
4317 }
4318 
4320 {
4321  if ( !d->mRootNode )
4322  return false;
4323  return d->mRootNode->needsGeometry();
4324 }
4325 
4327 {
4328  if ( d->mCalc.data() )
4329  return;
4330 
4331  // Use planimetric as default
4332  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea() );
4333  d->mCalc->setEllipsoidalMode( false );
4334 }
4335 
4337 {
4338  Q_ASSERT( d );
4339 
4340  if ( d->ref > 1 )
4341  {
4342  ( void )d->ref.deref();
4343 
4344  d = new QgsExpressionPrivate( *d );
4345  }
4346 }
4347 
4349 {
4350  detach();
4351  if ( calc )
4352  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea( *calc ) );
4353  else
4354  d->mCalc.clear();
4355 }
4356 
4358 {
4359  detach();
4360  d->mEvalErrorString = QString();
4361  if ( !d->mRootNode )
4362  {
4363  //re-parse expression. Creation of QgsExpressionContexts may have added extra
4364  //known functions since this expression was created, so we have another try
4365  //at re-parsing it now that the context must have been created
4366  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
4367  }
4368 
4369  if ( !d->mRootNode )
4370  {
4371  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
4372  return false;
4373  }
4374 
4375  return d->mRootNode->prepare( this, context );
4376 }
4377 
4379 {
4380  d->mEvalErrorString = QString();
4381  if ( !d->mRootNode )
4382  {
4383  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
4384  return QVariant();
4385  }
4386 
4387  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
4388 }
4389 
4391 {
4392  d->mEvalErrorString = QString();
4393  if ( !d->mRootNode )
4394  {
4395  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
4396  return QVariant();
4397  }
4398 
4399  return d->mRootNode->eval( this, context );
4400 }
4401 
4403 {
4404  return !d->mEvalErrorString.isNull();
4405 }
4406 
4408 {
4409  return d->mEvalErrorString;
4410 }
4411 
4412 void QgsExpression::setEvalErrorString( const QString& str )
4413 {
4414  d->mEvalErrorString = str;
4415 }
4416 
4417 QString QgsExpression::dump() const
4418 {
4419  if ( !d->mRootNode )
4420  return QString();
4421 
4422  return d->mRootNode->dump();
4423 }
4424 
4426 {
4427  return d->mCalc.data();
4428 }
4429 
4431 {
4432  return d->mDistanceUnit;
4433 }
4434 
4436 {
4437  d->mDistanceUnit = unit;
4438 }
4439 
4441 {
4442  return d->mAreaUnit;
4443 }
4444 
4446 {
4447  d->mAreaUnit = unit;
4448 }
4449 
4450 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea )
4451 {
4452  QString expr_action;
4453 
4454  int index = 0;
4455  while ( index < action.size() )
4456  {
4457  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
4458 
4459  int pos = rx.indexIn( action, index );
4460  if ( pos < 0 )
4461  break;
4462 
4463  int start = index;
4464  index = pos + rx.matchedLength();
4465  QString to_replace = rx.cap( 1 ).trimmed();
4466  QgsDebugMsg( "Found expression: " + to_replace );
4467 
4468  QgsExpression exp( to_replace );
4469  if ( exp.hasParserError() )
4470  {
4471  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
4472  expr_action += action.midRef( start, index - start );
4473  continue;
4474  }
4475 
4476  if ( distanceArea )
4477  {
4478  //if QgsDistanceArea specified for area/distance conversion, use it
4479  exp.setGeomCalculator( distanceArea );
4480  }
4481 
4482  QVariant result = exp.evaluate( context );
4483 
4484  if ( exp.hasEvalError() )
4485  {
4486  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
4487  expr_action += action.midRef( start, index - start );
4488  continue;
4489  }
4490 
4491  QgsDebugMsg( "Expression result is: " + result.toString() );
4492  expr_action += action.mid( start, pos - start ) + result.toString();
4493  }
4494 
4495  expr_action += action.midRef( index );
4496 
4497  return expr_action;
4498 }
4499 
4500 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
4501 {
4502  bool ok;
4503  //first test if text is directly convertible to double
4504  double convertedValue = text.toDouble( &ok );
4505  if ( ok )
4506  {
4507  return convertedValue;
4508  }
4509 
4510  //otherwise try to evalute as expression
4511  QgsExpression expr( text );
4512 
4513  QgsExpressionContext context;
4516 
4517  QVariant result = expr.evaluate( &context );
4518  convertedValue = result.toDouble( &ok );
4519  if ( expr.hasEvalError() || !ok )
4520  {
4521  return fallbackValue;
4522  }
4523  return convertedValue;
4524 }
4525 
4526 
4528 // nodes
4529 
4531 {
4532  mList.append( node->node );
4533  mNameList.append( node->name.toLower() );
4534  mHasNamedNodes = true;
4535 }
4536 
4538 {
4539  NodeList* nl = new NodeList;
4540  Q_FOREACH ( Node* node, mList )
4541  {
4542  nl->mList.append( node->clone() );
4543  }
4544  nl->mNameList = mNameList;
4545 
4546  return nl;
4547 }
4548 
4550 {
4551  QString msg;
4552  bool first = true;
4553  Q_FOREACH ( Node* n, mList )
4554  {
4555  if ( !first ) msg += QLatin1String( ", " );
4556  else first = false;
4557  msg += n->dump();
4558  }
4559  return msg;
4560 }
4561 
4562 
4563 //
4564 
4566 {
4567  QVariant val = mOperand->eval( parent, context );
4569 
4570  switch ( mOp )
4571  {
4572  case uoNot:
4573  {
4574  TVL tvl = getTVLValue( val, parent );
4576  return tvl2variant( NOT[tvl] );
4577  }
4578 
4579  case uoMinus:
4580  if ( isIntSafe( val ) )
4581  return QVariant( - getIntValue( val, parent ) );
4582  else if ( isDoubleSafe( val ) )
4583  return QVariant( - getDoubleValue( val, parent ) );
4584  else
4585  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
4586  default:
4587  Q_ASSERT( 0 && "unknown unary operation" );
4588  }
4589  return QVariant();
4590 }
4591 
4593 {
4594  return mOperand->prepare( parent, context );
4595 }
4596 
4598 {
4599  return QStringLiteral( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
4600 }
4601 
4603 {
4604  return mOperand->referencedColumns();
4605 }
4606 
4608 {
4609  return mOperand->referencedVariables();
4610 }
4611 
4613 {
4614  return new NodeUnaryOperator( mOp, mOperand->clone() );
4615 }
4616 
4617 //
4618 
4620 {
4621  QVariant vL = mOpLeft->eval( parent, context );
4623  QVariant vR = mOpRight->eval( parent, context );
4625 
4626  switch ( mOp )
4627  {
4628  case boPlus:
4629  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
4630  {
4631  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
4633  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
4635  return QVariant( sL + sR );
4636  }
4637  //intentional fall-through
4638  FALLTHROUGH;
4639  case boMinus:
4640  case boMul:
4641  case boDiv:
4642  case boMod:
4643  {
4644  if ( isNull( vL ) || isNull( vR ) )
4645  return QVariant();
4646  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
4647  {
4648  // both are integers - let's use integer arithmetics
4649  int iL = getIntValue( vL, parent );
4651  int iR = getIntValue( vR, parent );
4653 
4654  if ( mOp == boMod && iR == 0 )
4655  return QVariant();
4656 
4657  return QVariant( computeInt( iL, iR ) );
4658  }
4659  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
4660  {
4661  QDateTime dL = getDateTimeValue( vL, parent );
4663  QgsInterval iL = getInterval( vR, parent );
4665  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
4666  {
4667  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
4668  return QVariant();
4669  }
4670  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
4671  }
4672  else if ( mOp == boPlus && (( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
4673  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
4674  {
4675  QDate date = getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
4677  QTime time = getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
4679  QDateTime dt = QDateTime( date, time );
4680  return QVariant( dt );
4681  }
4682  else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
4683  {
4684  QDate date1 = getDateValue( vL, parent );
4686  QDate date2 = getDateValue( vR, parent );
4688  return date1 - date2;
4689  }
4690  else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
4691  {
4692  QTime time1 = getTimeValue( vL, parent );
4694  QTime time2 = getTimeValue( vR, parent );
4696  return time1 - time2;
4697  }
4698  else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
4699  {
4700  QDateTime datetime1 = getDateTimeValue( vL, parent );
4702  QDateTime datetime2 = getDateTimeValue( vR, parent );
4704  return datetime1 - datetime2;
4705  }
4706  else
4707  {
4708  // general floating point arithmetic
4709  double fL = getDoubleValue( vL, parent );
4711  double fR = getDoubleValue( vR, parent );
4713  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
4714  return QVariant(); // silently handle division by zero and return NULL
4715  return QVariant( computeDouble( fL, fR ) );
4716  }
4717  }
4718  case boIntDiv:
4719  {
4720  //integer division
4721  double fL = getDoubleValue( vL, parent );
4723  double fR = getDoubleValue( vR, parent );
4725  if ( fR == 0. )
4726  return QVariant(); // silently handle division by zero and return NULL
4727  return QVariant( qFloor( fL / fR ) );
4728  }
4729  case boPow:
4730  if ( isNull( vL ) || isNull( vR ) )
4731  return QVariant();
4732  else
4733  {
4734  double fL = getDoubleValue( vL, parent );
4736  double fR = getDoubleValue( vR, parent );
4738  return QVariant( pow( fL, fR ) );
4739  }
4740 
4741  case boAnd:
4742  {
4743  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4745  return tvl2variant( AND[tvlL][tvlR] );
4746  }
4747 
4748  case boOr:
4749  {
4750  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4752  return tvl2variant( OR[tvlL][tvlR] );
4753  }
4754 
4755  case boEQ:
4756  case boNE:
4757  case boLT:
4758  case boGT:
4759  case boLE:
4760  case boGE:
4761  if ( isNull( vL ) || isNull( vR ) )
4762  {
4763  return TVL_Unknown;
4764  }
4765  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4766  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4767  {
4768  // do numeric comparison if both operators can be converted to numbers,
4769  // and they aren't both string
4770  double fL = getDoubleValue( vL, parent );
4772  double fR = getDoubleValue( vR, parent );
4774  return compare( fL - fR ) ? TVL_True : TVL_False;
4775  }
4776  else
4777  {
4778  // do string comparison otherwise
4779  QString sL = getStringValue( vL, parent );
4781  QString sR = getStringValue( vR, parent );
4783  int diff = QString::compare( sL, sR );
4784  return compare( diff ) ? TVL_True : TVL_False;
4785  }
4786 
4787  case boIs:
4788  case boIsNot:
4789  if ( isNull( vL ) && isNull( vR ) ) // both operators null
4790  return ( mOp == boIs ? TVL_True : TVL_False );
4791  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
4792  return ( mOp == boIs ? TVL_False : TVL_True );
4793  else // both operators non-null
4794  {
4795  bool equal = false;
4796  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4797  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4798  {
4799  double fL = getDoubleValue( vL, parent );
4801  double fR = getDoubleValue( vR, parent );
4803  equal = qgsDoubleNear( fL, fR );
4804  }
4805  else
4806  {
4807  QString sL = getStringValue( vL, parent );
4809  QString sR = getStringValue( vR, parent );
4811  equal = QString::compare( sL, sR ) == 0;
4812  }
4813  if ( equal )
4814  return mOp == boIs ? TVL_True : TVL_False;
4815  else
4816  return mOp == boIs ? TVL_False : TVL_True;
4817  }
4818 
4819  case boRegexp:
4820  case boLike:
4821  case boNotLike:
4822  case boILike:
4823  case boNotILike:
4824  if ( isNull( vL ) || isNull( vR ) )
4825  return TVL_Unknown;
4826  else
4827  {
4828  QString str = getStringValue( vL, parent );
4830  QString regexp = getStringValue( vR, parent );
4832  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
4833  bool matches;
4834  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
4835  {
4836  QString esc_regexp = QRegExp::escape( regexp );
4837  // manage escape % and _
4838  if ( esc_regexp.startsWith( '%' ) )
4839  {
4840  esc_regexp.replace( 0, 1, QStringLiteral( ".*" ) );
4841  }
4842  QRegExp rx( "[^\\\\](%)" );
4843  int pos = 0;
4844  while (( pos = rx.indexIn( esc_regexp, pos ) ) != -1 )
4845  {
4846  esc_regexp.replace( pos + 1, 1, QStringLiteral( ".*" ) );
4847  pos += 1;
4848  }
4849  rx.setPattern( QStringLiteral( "\\\\%" ) );
4850  esc_regexp.replace( rx, QStringLiteral( "%" ) );
4851  if ( esc_regexp.startsWith( '_' ) )
4852  {
4853  esc_regexp.replace( 0, 1, QStringLiteral( "." ) );
4854  }
4855  rx.setPattern( QStringLiteral( "[^\\\\](_)" ) );
4856  pos = 0;
4857  while (( pos = rx.indexIn( esc_regexp, pos ) ) != -1 )
4858  {
4859  esc_regexp.replace( pos + 1, 1, '.' );
4860  pos += 1;
4861  }
4862  rx.setPattern( QStringLiteral( "\\\\_" ) );
4863  esc_regexp.replace( rx, QStringLiteral( "_" ) );
4864  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
4865  }
4866  else
4867  {
4868  matches = QRegExp( regexp ).indexIn( str ) != -1;
4869  }
4870 
4871  if ( mOp == boNotLike || mOp == boNotILike )
4872  {
4873  matches = !matches;
4874  }
4875 
4876  return matches ? TVL_True : TVL_False;
4877  }
4878 
4879  case boConcat:
4880  if ( isNull( vL ) || isNull( vR ) )
4881  return QVariant();
4882  else
4883  {
4884  QString sL = getStringValue( vL, parent );
4886  QString sR = getStringValue( vR, parent );
4888  return QVariant( sL + sR );
4889  }
4890 
4891  default:
4892  break;
4893  }
4894  Q_ASSERT( false );
4895  return QVariant();
4896 }
4897 
4899 {
4900  switch ( mOp )
4901  {
4902  case boEQ:
4903  return qgsDoubleNear( diff, 0.0 );
4904  case boNE:
4905  return !qgsDoubleNear( diff, 0.0 );
4906  case boLT:
4907  return diff < 0;
4908  case boGT:
4909  return diff > 0;
4910  case boLE:
4911  return diff <= 0;
4912  case boGE:
4913  return diff >= 0;
4914  default:
4915  Q_ASSERT( false );
4916  return false;
4917  }
4918 }
4919 
4921 {
4922  switch ( mOp )
4923  {
4924  case boPlus:
4925  return x + y;
4926  case boMinus:
4927  return x -y;
4928  case boMul:
4929  return x*y;
4930  case boDiv:
4931  return x / y;
4932  case boMod:
4933  return x % y;
4934  default:
4935  Q_ASSERT( false );
4936  return 0;
4937  }
4938 }
4939 
4941 {
4942  switch ( mOp )
4943  {
4944  case boPlus:
4945  return d.addSecs( i->seconds() );
4946  case boMinus:
4947  return d.addSecs( -i->seconds() );
4948  default:
4949  Q_ASSERT( false );
4950  return QDateTime();
4951  }
4952 }
4953 
4955 {
4956  switch ( mOp )
4957  {
4958  case boPlus:
4959  return x + y;
4960  case boMinus:
4961  return x -y;
4962  case boMul:
4963  return x*y;
4964  case boDiv:
4965  return x / y;
4966  case boMod:
4967  return fmod( x, y );
4968  default:
4969  Q_ASSERT( false );
4970  return 0;
4971  }
4972 }
4973 
4975 {
4976  bool resL = mOpLeft->prepare( parent, context );
4977  bool resR = mOpRight->prepare( parent, context );
4978  return resL && resR;
4979 }
4980 
4982 {
4983  // see left/right in qgsexpressionparser.yy
4984  switch ( mOp )
4985  {
4986  case boOr:
4987  return 1;
4988 
4989  case boAnd:
4990  return 2;
4991 
4992  case boEQ:
4993  case boNE:
4994  case boLE:
4995  case boGE:
4996  case boLT:
4997  case boGT:
4998  case boRegexp:
4999  case boLike:
5000  case boILike:
5001  case boNotLike:
5002  case boNotILike:
5003  case boIs:
5004  case boIsNot:
5005  return 3;
5006 
5007  case boPlus:
5008  case boMinus:
5009  return 4;
5010 
5011  case boMul:
5012  case boDiv:
5013  case boIntDiv:
5014  case boMod:
5015  return 5;
5016 
5017  case boPow:
5018  return 6;
5019 
5020  case boConcat:
5021  return 7;
5022  }
5023  Q_ASSERT( 0 && "unexpected binary operator" );
5024  return -1;
5025 }
5026 
5028 {
5029  // see left/right in qgsexpressionparser.yy
5030  switch ( mOp )
5031  {
5032  case boOr:
5033  case boAnd:
5034  case boEQ:
5035  case boNE:
5036  case boLE:
5037  case boGE:
5038  case boLT:
5039  case boGT:
5040  case boRegexp:
5041  case boLike:
5042  case boILike:
5043  case boNotLike:
5044  case boNotILike:
5045  case boIs:
5046  case boIsNot:
5047  case boPlus:
5048  case boMinus:
5049  case boMul:
5050  case boDiv:
5051  case boIntDiv:
5052  case boMod:
5053  case boConcat:
5054  return true;
5055 
5056  case boPow:
5057  return false;
5058  }
5059  Q_ASSERT( 0 && "unexpected binary operator" );
5060  return false;
5061 }
5062 
5064 {
5065  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
5066  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
5067  QgsExpression::NodeUnaryOperator *ruOp = dynamic_cast<QgsExpression::NodeUnaryOperator *>( mOpRight );
5068 
5069  QString rdump( mOpRight->dump() );
5070 
5071  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
5072  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
5073  {
5074  rdump.prepend( '(' ).append( ')' );
5075  }
5076 
5077  QString fmt;
5078  if ( leftAssociative() )
5079  {
5080  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
5081  fmt += QLatin1String( " %2 " );
5082  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
5083  }
5084  else
5085  {
5086  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
5087  fmt += QLatin1String( " %2 " );
5088  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
5089  }
5090 
5091  return fmt.arg( mOpLeft->dump(), BinaryOperatorText[mOp], rdump );
5092 }
5093 
5095 {
5096  return mOpLeft->referencedColumns() + mOpRight->referencedColumns();
5097 }
5098 
5100 {
5101  return mOpLeft->referencedVariables() + mOpRight->referencedVariables();
5102 }
5103