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