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