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