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