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