QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 )
165  : QgsExpressionFunction( fnname, params, group, helpText, lazyEval, handlesNull, false )
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 );
1679  subContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
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 
4219  QgsGeometryCollection *orderedGeom = qgsgeometry_cast<QgsGeometryCollection *>( fGeom.constGet()->clone() );
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 
5803  << new QgsStaticExpressionFunction( QStringLiteral( "count" ), aggParams, fcnAggregateCount, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5804  << new QgsStaticExpressionFunction( QStringLiteral( "count_distinct" ), aggParams, fcnAggregateCountDistinct, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5805  << new QgsStaticExpressionFunction( QStringLiteral( "count_missing" ), aggParams, fcnAggregateCountMissing, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5806  << new QgsStaticExpressionFunction( QStringLiteral( "minimum" ), aggParams, fcnAggregateMin, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5807  << new QgsStaticExpressionFunction( QStringLiteral( "maximum" ), aggParams, fcnAggregateMax, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5808  << new QgsStaticExpressionFunction( QStringLiteral( "sum" ), aggParams, fcnAggregateSum, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5809  << new QgsStaticExpressionFunction( QStringLiteral( "mean" ), aggParams, fcnAggregateMean, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5810  << new QgsStaticExpressionFunction( QStringLiteral( "median" ), aggParams, fcnAggregateMedian, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5811  << new QgsStaticExpressionFunction( QStringLiteral( "stdev" ), aggParams, fcnAggregateStdev, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5812  << new QgsStaticExpressionFunction( QStringLiteral( "range" ), aggParams, fcnAggregateRange, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5813  << new QgsStaticExpressionFunction( QStringLiteral( "minority" ), aggParams, fcnAggregateMinority, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5814  << new QgsStaticExpressionFunction( QStringLiteral( "majority" ), aggParams, fcnAggregateMajority, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5815  << new QgsStaticExpressionFunction( QStringLiteral( "q1" ), aggParams, fcnAggregateQ1, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5816  << new QgsStaticExpressionFunction( QStringLiteral( "q3" ), aggParams, fcnAggregateQ3, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5817  << new QgsStaticExpressionFunction( QStringLiteral( "iqr" ), aggParams, fcnAggregateIQR, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5818  << new QgsStaticExpressionFunction( QStringLiteral( "min_length" ), aggParams, fcnAggregateMinLength, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5819  << new QgsStaticExpressionFunction( QStringLiteral( "max_length" ), aggParams, fcnAggregateMaxLength, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5820  << new QgsStaticExpressionFunction( QStringLiteral( "collect" ), aggParams, fcnAggregateCollectGeometry, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5821  << new QgsStaticExpressionFunction( QStringLiteral( "concatenate" ), aggParamsConcat, fcnAggregateStringConcat, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5822  << new QgsStaticExpressionFunction( QStringLiteral( "concatenate_unique" ), aggParamsConcat, fcnAggregateStringConcatUnique, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5823  << new QgsStaticExpressionFunction( QStringLiteral( "array_agg" ), aggParamsArray, fcnAggregateArray, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
5824 
5825  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_match" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ), fcnRegexpMatch, QStringList() << QStringLiteral( "Conditionals" ) << QStringLiteral( "String" ) )
5826  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_matches" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnRegexpMatches, QStringLiteral( "Arrays" ) )
5827 
5828  << new QgsStaticExpressionFunction( QStringLiteral( "now" ), 0, fcnNow, QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$now" ) )
5829  << new QgsStaticExpressionFunction( QStringLiteral( "age" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime1" ) )
5830  << QgsExpressionFunction::Parameter( QStringLiteral( "datetime2" ) ),
5831  fcnAge, QStringLiteral( "Date and Time" ) )
5832  << new QgsStaticExpressionFunction( QStringLiteral( "year" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnYear, QStringLiteral( "Date and Time" ) )
5833  << new QgsStaticExpressionFunction( QStringLiteral( "month" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnMonth, QStringLiteral( "Date and Time" ) )
5834  << new QgsStaticExpressionFunction( QStringLiteral( "week" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnWeek, QStringLiteral( "Date and Time" ) )
5835  << new QgsStaticExpressionFunction( QStringLiteral( "day" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnDay, QStringLiteral( "Date and Time" ) )
5836  << new QgsStaticExpressionFunction( QStringLiteral( "hour" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnHour, QStringLiteral( "Date and Time" ) )
5837  << new QgsStaticExpressionFunction( QStringLiteral( "minute" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnMinute, QStringLiteral( "Date and Time" ) )
5838  << new QgsStaticExpressionFunction( QStringLiteral( "second" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnSeconds, QStringLiteral( "Date and Time" ) )
5839  << new QgsStaticExpressionFunction( QStringLiteral( "epoch" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnEpoch, QStringLiteral( "Date and Time" ) )
5840  << new QgsStaticExpressionFunction( QStringLiteral( "datetime_from_epoch" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "long" ) ), fcnDateTimeFromEpoch, QStringLiteral( "Date and Time" ) )
5841  << new QgsStaticExpressionFunction( QStringLiteral( "day_of_week" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnDayOfWeek, QStringLiteral( "Date and Time" ) )
5842  << new QgsStaticExpressionFunction( QStringLiteral( "make_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "year" ) )
5843  << QgsExpressionFunction::Parameter( QStringLiteral( "month" ) )
5844  << QgsExpressionFunction::Parameter( QStringLiteral( "day" ) ),
5845  fcnMakeDate, QStringLiteral( "Date and Time" ) )
5846  << new QgsStaticExpressionFunction( QStringLiteral( "make_time" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hour" ) )
5847  << QgsExpressionFunction::Parameter( QStringLiteral( "minute" ) )
5848  << QgsExpressionFunction::Parameter( QStringLiteral( "second" ) ),
5849  fcnMakeTime, QStringLiteral( "Date and Time" ) )
5850  << new QgsStaticExpressionFunction( QStringLiteral( "make_datetime" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "year" ) )
5851  << QgsExpressionFunction::Parameter( QStringLiteral( "month" ) )
5852  << QgsExpressionFunction::Parameter( QStringLiteral( "day" ) )
5853  << QgsExpressionFunction::Parameter( QStringLiteral( "hour" ) )
5854  << QgsExpressionFunction::Parameter( QStringLiteral( "minute" ) )
5855  << QgsExpressionFunction::Parameter( QStringLiteral( "second" ) ),
5856  fcnMakeDateTime, QStringLiteral( "Date and Time" ) )
5857  << new QgsStaticExpressionFunction( QStringLiteral( "make_interval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "years" ), true, 0 )
5858  << QgsExpressionFunction::Parameter( QStringLiteral( "months" ), true, 0 )
5859  << QgsExpressionFunction::Parameter( QStringLiteral( "weeks" ), true, 0 )
5860  << QgsExpressionFunction::Parameter( QStringLiteral( "days" ), true, 0 )
5861  << QgsExpressionFunction::Parameter( QStringLiteral( "hours" ), true, 0 )
5862  << QgsExpressionFunction::Parameter( QStringLiteral( "minutes" ), true, 0 )
5863  << QgsExpressionFunction::Parameter( QStringLiteral( "seconds" ), true, 0 ),
5864  fcnMakeInterval, QStringLiteral( "Date and Time" ) )
5865  << new QgsStaticExpressionFunction( QStringLiteral( "lower" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnLower, QStringLiteral( "String" ) )
5866  << new QgsStaticExpressionFunction( QStringLiteral( "upper" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnUpper, QStringLiteral( "String" ) )
5867  << new QgsStaticExpressionFunction( QStringLiteral( "title" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTitle, QStringLiteral( "String" ) )
5868  << new QgsStaticExpressionFunction( QStringLiteral( "trim" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTrim, QStringLiteral( "String" ) )
5869  << new QgsStaticExpressionFunction( QStringLiteral( "levenshtein" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnLevenshtein, QStringLiteral( "Fuzzy Matching" ) )
5870  << new QgsStaticExpressionFunction( QStringLiteral( "longest_common_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnLCS, QStringLiteral( "Fuzzy Matching" ) )
5871  << new QgsStaticExpressionFunction( QStringLiteral( "hamming_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnHamming, QStringLiteral( "Fuzzy Matching" ) )
5872  << new QgsStaticExpressionFunction( QStringLiteral( "soundex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnSoundex, QStringLiteral( "Fuzzy Matching" ) )
5873  << new QgsStaticExpressionFunction( QStringLiteral( "char" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "code" ) ), fcnChar, QStringLiteral( "String" ) )
5874  << new QgsStaticExpressionFunction( QStringLiteral( "ascii" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnAscii, QStringLiteral( "String" ) )
5875  << new QgsStaticExpressionFunction( QStringLiteral( "wordwrap" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "" ), fcnWordwrap, QStringLiteral( "String" ) )
5876  << new QgsStaticExpressionFunction( QStringLiteral( "length" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ), true, "" ), fcnLength, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "GeometryGroup" ) )
5877  << new QgsStaticExpressionFunction( QStringLiteral( "replace" ), -1, fcnReplace, QStringLiteral( "String" ) )
5878  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_replace" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "input_string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) )
5879  << QgsExpressionFunction::Parameter( QStringLiteral( "replacement" ) ), fcnRegexpReplace, QStringLiteral( "String" ) )
5880  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_substr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "input_string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ), fcnRegexpSubstr, QStringLiteral( "String" ) )
5881  << new QgsStaticExpressionFunction( QStringLiteral( "substr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "start " ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ), true ), fcnSubstr, QStringLiteral( "String" ), QString(),
5882  false, QSet< QString >(), false, QStringList(), true )
5883  << new QgsStaticExpressionFunction( QStringLiteral( "concat" ), -1, fcnConcat, QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList(), true )
5884  << new QgsStaticExpressionFunction( QStringLiteral( "strpos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "haystack" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "needle" ) ), fcnStrpos, QStringLiteral( "String" ) )
5885  << new QgsStaticExpressionFunction( QStringLiteral( "left" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ), fcnLeft, QStringLiteral( "String" ) )
5886  << new QgsStaticExpressionFunction( QStringLiteral( "right" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ), fcnRight, QStringLiteral( "String" ) )
5887  << new QgsStaticExpressionFunction( QStringLiteral( "rpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnRPad, QStringLiteral( "String" ) )
5888  << new QgsStaticExpressionFunction( QStringLiteral( "lpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnLPad, QStringLiteral( "String" ) )
5889  << new QgsStaticExpressionFunction( QStringLiteral( "format" ), -1, fcnFormatString, QStringLiteral( "String" ) )
5890  << new QgsStaticExpressionFunction( QStringLiteral( "format_number" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "number" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "places" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatNumber, QStringLiteral( "String" ) )
5891  << new QgsStaticExpressionFunction( QStringLiteral( "format_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "format" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatDate, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "Date and Time" ) )
5892  << new QgsStaticExpressionFunction( QStringLiteral( "color_grayscale_average" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ), fcnColorGrayscaleAverage, QStringLiteral( "Color" ) )
5893  << new QgsStaticExpressionFunction( QStringLiteral( "color_mix_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color1" ) )
5894  << QgsExpressionFunction::Parameter( QStringLiteral( "color2" ) )
5895  << QgsExpressionFunction::Parameter( QStringLiteral( "ratio" ) ),
5896  fcnColorMixRgb, QStringLiteral( "Color" ) )
5897  << new QgsStaticExpressionFunction( QStringLiteral( "color_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "red" ) )
5898  << QgsExpressionFunction::Parameter( QStringLiteral( "green" ) )
5899  << QgsExpressionFunction::Parameter( QStringLiteral( "blue" ) ),
5900  fcnColorRgb, QStringLiteral( "Color" ) )
5901  << new QgsStaticExpressionFunction( QStringLiteral( "color_rgba" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "red" ) )
5902  << QgsExpressionFunction::Parameter( QStringLiteral( "green" ) )
5903  << QgsExpressionFunction::Parameter( QStringLiteral( "blue" ) )
5904  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
5905  fncColorRgba, QStringLiteral( "Color" ) )
5906  << new QgsStaticExpressionFunction( QStringLiteral( "ramp_color" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "ramp_name" ) )
5907  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
5908  fcnRampColor, QStringLiteral( "Color" ) )
5909  << new QgsStaticExpressionFunction( QStringLiteral( "create_ramp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) )
5910  << QgsExpressionFunction::Parameter( QStringLiteral( "discrete" ), true, false ),
5911  fcnCreateRamp, QStringLiteral( "Color" ) )
5912  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsl" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
5913  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
5914  << QgsExpressionFunction::Parameter( QStringLiteral( "lightness" ) ),
5915  fcnColorHsl, QStringLiteral( "Color" ) )
5916  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsla" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
5917  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
5918  << QgsExpressionFunction::Parameter( QStringLiteral( "lightness" ) )
5919  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
5920  fncColorHsla, QStringLiteral( "Color" ) )
5921  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsv" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
5922  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
5923  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
5924  fcnColorHsv, QStringLiteral( "Color" ) )
5925  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsva" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
5926  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
5927  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) )
5928  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
5929  fncColorHsva, QStringLiteral( "Color" ) )
5930  << new QgsStaticExpressionFunction( QStringLiteral( "color_cmyk" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "cyan" ) )
5931  << QgsExpressionFunction::Parameter( QStringLiteral( "magenta" ) )
5932  << QgsExpressionFunction::Parameter( QStringLiteral( "yellow" ) )
5933  << QgsExpressionFunction::Parameter( QStringLiteral( "black" ) ),
5934  fcnColorCmyk, QStringLiteral( "Color" ) )
5935  << new QgsStaticExpressionFunction( QStringLiteral( "color_cmyka" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "cyan" ) )
5936  << QgsExpressionFunction::Parameter( QStringLiteral( "magenta" ) )
5937  << QgsExpressionFunction::Parameter( QStringLiteral( "yellow" ) )
5938  << QgsExpressionFunction::Parameter( QStringLiteral( "black" ) )
5939  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
5940  fncColorCmyka, QStringLiteral( "Color" ) )
5941  << new QgsStaticExpressionFunction( QStringLiteral( "color_part" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
5942  << QgsExpressionFunction::Parameter( QStringLiteral( "component" ) ),
5943  fncColorPart, QStringLiteral( "Color" ) )
5944  << new QgsStaticExpressionFunction( QStringLiteral( "darker" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
5945  << QgsExpressionFunction::Parameter( QStringLiteral( "factor" ) ),
5946  fncDarker, QStringLiteral( "Color" ) )
5947  << new QgsStaticExpressionFunction( QStringLiteral( "lighter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
5948  << QgsExpressionFunction::Parameter( QStringLiteral( "factor" ) ),
5949  fncLighter, QStringLiteral( "Color" ) )
5950  << new QgsStaticExpressionFunction( QStringLiteral( "set_color_part" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "component" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fncSetColorPart, QStringLiteral( "Color" ) )
5951 
5952  // file info
5953  << new QgsStaticExpressionFunction( QStringLiteral( "base_file_name" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5954  fcnBaseFileName, QStringLiteral( "Files and Paths" ) )
5955  << new QgsStaticExpressionFunction( QStringLiteral( "file_suffix" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5956  fcnFileSuffix, QStringLiteral( "Files and Paths" ) )
5957  << new QgsStaticExpressionFunction( QStringLiteral( "file_exists" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5958  fcnFileExists, QStringLiteral( "Files and Paths" ) )
5959  << new QgsStaticExpressionFunction( QStringLiteral( "file_name" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5960  fcnFileName, QStringLiteral( "Files and Paths" ) )
5961  << new QgsStaticExpressionFunction( QStringLiteral( "is_file" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5962  fcnPathIsFile, QStringLiteral( "Files and Paths" ) )
5963  << new QgsStaticExpressionFunction( QStringLiteral( "is_directory" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5964  fcnPathIsDir, QStringLiteral( "Files and Paths" ) )
5965  << new QgsStaticExpressionFunction( QStringLiteral( "file_path" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5966  fcnFilePath, QStringLiteral( "Files and Paths" ) )
5967  << new QgsStaticExpressionFunction( QStringLiteral( "file_size" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
5968  fcnFileSize, QStringLiteral( "Files and Paths" ) )
5969 
5970  // hash
5971  << new QgsStaticExpressionFunction( QStringLiteral( "hash" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "method" ) ),
5972  fcnGenericHash, QStringLiteral( "Conversions" ) )
5973  << new QgsStaticExpressionFunction( QStringLiteral( "md5" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
5974  fcnHashMd5, QStringLiteral( "Conversions" ) )
5975  << new QgsStaticExpressionFunction( QStringLiteral( "sha256" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
5976  fcnHashSha256, QStringLiteral( "Conversions" ) )
5977 
5978  //base64
5979  << new QgsStaticExpressionFunction( QStringLiteral( "to_base64" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
5980  fcnToBase64, QStringLiteral( "Conversions" ) )
5981  << new QgsStaticExpressionFunction( QStringLiteral( "from_base64" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
5982  fcnFromBase64, QStringLiteral( "Conversions" ) )
5983 
5984  // deprecated stuff - hidden from users
5985  << new QgsStaticExpressionFunction( QStringLiteral( "$scale" ), QgsExpressionFunction::ParameterList(), fcnMapScale, QStringLiteral( "deprecated" ) );
5986 
5987  QgsStaticExpressionFunction *geomFunc = new QgsStaticExpressionFunction( QStringLiteral( "$geometry" ), 0, fcnGeometry, QStringLiteral( "GeometryGroup" ), QString(), true );
5988  geomFunc->setIsStatic( false );
5989  functions << geomFunc;
5990 
5991  QgsStaticExpressionFunction *areaFunc = new QgsStaticExpressionFunction( QStringLiteral( "$area" ), 0, fcnGeomArea, QStringLiteral( "GeometryGroup" ), QString(), true );
5992  areaFunc->setIsStatic( false );
5993  functions << areaFunc;
5994 
5995  functions << new QgsStaticExpressionFunction( QStringLiteral( "area" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnArea, QStringLiteral( "GeometryGroup" ) );
5996 
5997  QgsStaticExpressionFunction *lengthFunc = new QgsStaticExpressionFunction( QStringLiteral( "$length" ), 0, fcnGeomLength, QStringLiteral( "GeometryGroup" ), QString(), true );
5998  lengthFunc->setIsStatic( false );
5999  functions << lengthFunc;
6000 
6001  QgsStaticExpressionFunction *perimeterFunc = new QgsStaticExpressionFunction( QStringLiteral( "$perimeter" ), 0, fcnGeomPerimeter, QStringLiteral( "GeometryGroup" ), QString(), true );
6002  perimeterFunc->setIsStatic( false );
6003  functions << perimeterFunc;
6004 
6005  functions << new QgsStaticExpressionFunction( QStringLiteral( "perimeter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnPerimeter, QStringLiteral( "GeometryGroup" ) );
6006 
6007  QgsStaticExpressionFunction *xFunc = new QgsStaticExpressionFunction( QStringLiteral( "$x" ), 0, fcnX, QStringLiteral( "GeometryGroup" ), QString(), true );
6008  xFunc->setIsStatic( false );
6009  functions << xFunc;
6010 
6011  QgsStaticExpressionFunction *yFunc = new QgsStaticExpressionFunction( QStringLiteral( "$y" ), 0, fcnY, QStringLiteral( "GeometryGroup" ), QString(), true );
6012  yFunc->setIsStatic( false );
6013  functions << yFunc;
6014 
6015  functions
6016  << new QgsStaticExpressionFunction( QStringLiteral( "is_valid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnGeomIsValid, QStringLiteral( "GeometryGroup" ) )
6017  << new QgsStaticExpressionFunction( QStringLiteral( "x" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnGeomX, QStringLiteral( "GeometryGroup" ) )
6018  << new QgsStaticExpressionFunction( QStringLiteral( "y" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnGeomY, QStringLiteral( "GeometryGroup" ) )
6019  << new QgsStaticExpressionFunction( QStringLiteral( "z" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnGeomZ, QStringLiteral( "GeometryGroup" ) )
6020  << new QgsStaticExpressionFunction( QStringLiteral( "m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnGeomM, QStringLiteral( "GeometryGroup" ) )
6021  << new QgsStaticExpressionFunction( QStringLiteral( "point_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ), fcnPointN, QStringLiteral( "GeometryGroup" ) )
6022  << new QgsStaticExpressionFunction( QStringLiteral( "start_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnStartPoint, QStringLiteral( "GeometryGroup" ) )
6023  << new QgsStaticExpressionFunction( QStringLiteral( "end_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnEndPoint, QStringLiteral( "GeometryGroup" ) )
6024  << new QgsStaticExpressionFunction( QStringLiteral( "nodes_to_points" ), -1, fcnNodesToPoints, QStringLiteral( "GeometryGroup" ) )
6025  << new QgsStaticExpressionFunction( QStringLiteral( "segments_to_lines" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnSegmentsToLines, QStringLiteral( "GeometryGroup" ) )
6026  << new QgsStaticExpressionFunction( QStringLiteral( "collect_geometries" ), -1, fcnCollectGeometries, QStringLiteral( "GeometryGroup" ) )
6027  << new QgsStaticExpressionFunction( QStringLiteral( "make_point" ), -1, fcnMakePoint, QStringLiteral( "GeometryGroup" ) )
6028  << new QgsStaticExpressionFunction( QStringLiteral( "make_point_m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "x" ) )
6029  << QgsExpressionFunction::Parameter( QStringLiteral( "y" ) )
6030  << QgsExpressionFunction::Parameter( QStringLiteral( "m" ) ),
6031  fcnMakePointM, QStringLiteral( "GeometryGroup" ) )
6032  << new QgsStaticExpressionFunction( QStringLiteral( "make_line" ), -1, fcnMakeLine, QStringLiteral( "GeometryGroup" ) )
6033  << new QgsStaticExpressionFunction( QStringLiteral( "make_polygon" ), -1, fcnMakePolygon, QStringLiteral( "GeometryGroup" ) )
6034  << new QgsStaticExpressionFunction( QStringLiteral( "make_triangle" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6035  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6036  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6037  fcnMakeTriangle, QStringLiteral( "GeometryGroup" ) )
6038  << new QgsStaticExpressionFunction( QStringLiteral( "make_circle" ), QgsExpressionFunction::ParameterList()
6039  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6040  << QgsExpressionFunction::Parameter( QStringLiteral( "radius" ) )
6041  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6042  fcnMakeCircle, QStringLiteral( "GeometryGroup" ) )
6043  << new QgsStaticExpressionFunction( QStringLiteral( "make_ellipse" ), QgsExpressionFunction::ParameterList()
6044  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6045  << QgsExpressionFunction::Parameter( QStringLiteral( "semi_major_axis" ) )
6046  << QgsExpressionFunction::Parameter( QStringLiteral( "semi_minor_axis" ) )
6047  << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
6048  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6049  fcnMakeEllipse, QStringLiteral( "GeometryGroup" ) )
6050  << new QgsStaticExpressionFunction( QStringLiteral( "make_regular_polygon" ), QgsExpressionFunction::ParameterList()
6051  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6052  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6053  << QgsExpressionFunction::Parameter( QStringLiteral( "number_sides" ) )
6054  << QgsExpressionFunction::Parameter( QStringLiteral( "circle" ), true, 0 ),
6055  fcnMakeRegularPolygon, QStringLiteral( "GeometryGroup" ) )
6056  << new QgsStaticExpressionFunction( QStringLiteral( "make_square" ), QgsExpressionFunction::ParameterList()
6057  << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6058  << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) ),
6059  fcnMakeSquare, QStringLiteral( "GeometryGroup" ) )
6060  << new QgsStaticExpressionFunction( QStringLiteral( "make_rectangle_3points" ), QgsExpressionFunction::ParameterList()
6061  << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6062  << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) )
6063  << QgsExpressionFunction::Parameter( QStringLiteral( "point3" ) )
6064  << QgsExpressionFunction::Parameter( QStringLiteral( "option" ), true, 0 ),
6065  fcnMakeRectangleFrom3Points, QStringLiteral( "GeometryGroup" ) );
6066  QgsStaticExpressionFunction *xAtFunc = new QgsStaticExpressionFunction( QStringLiteral( "$x_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "i" ) ), fcnXat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "xat" ) << QStringLiteral( "x_at" ) );
6067  xAtFunc->setIsStatic( false );
6068  functions << xAtFunc;
6069 
6070  QgsStaticExpressionFunction *yAtFunc = new QgsStaticExpressionFunction( QStringLiteral( "$y_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "i" ) ), fcnYat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "yat" ) << QStringLiteral( "y_at" ) );
6071  yAtFunc->setIsStatic( false );
6072  functions << yAtFunc;
6073 
6074  functions
6075  << new QgsStaticExpressionFunction( QStringLiteral( "x_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnXMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmin" ) )
6076  << new QgsStaticExpressionFunction( QStringLiteral( "x_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnXMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmax" ) )
6077  << new QgsStaticExpressionFunction( QStringLiteral( "y_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnYMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymin" ) )
6078  << new QgsStaticExpressionFunction( QStringLiteral( "y_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnYMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymax" ) )
6079  << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_wkt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ) ), fcnGeomFromWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromWKT" ) )
6080  << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_wkb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "binary" ) ), fcnGeomFromWKB, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false )
6081  << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_gml" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "gml" ) ), fcnGeomFromGML, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromGML" ) )
6082  << new QgsStaticExpressionFunction( QStringLiteral( "flip_coordinates" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnFlipCoordinates, QStringLiteral( "GeometryGroup" ) )
6083  << new QgsStaticExpressionFunction( QStringLiteral( "relate" ), -1, fcnRelate, QStringLiteral( "GeometryGroup" ) )
6084  << new QgsStaticExpressionFunction( QStringLiteral( "intersects_bbox" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBbox, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "bbox" ) )
6085  << new QgsStaticExpressionFunction( QStringLiteral( "disjoint" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6086  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6087  fcnDisjoint, QStringLiteral( "GeometryGroup" ) )
6088  << new QgsStaticExpressionFunction( QStringLiteral( "intersects" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6089  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6090  fcnIntersects, QStringLiteral( "GeometryGroup" ) )
6091  << new QgsStaticExpressionFunction( QStringLiteral( "touches" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6092  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6093  fcnTouches, QStringLiteral( "GeometryGroup" ) )
6094  << new QgsStaticExpressionFunction( QStringLiteral( "crosses" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6095  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6096  fcnCrosses, QStringLiteral( "GeometryGroup" ) )
6097  << new QgsStaticExpressionFunction( QStringLiteral( "contains" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6098  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6099  fcnContains, QStringLiteral( "GeometryGroup" ) )
6100  << new QgsStaticExpressionFunction( QStringLiteral( "overlaps" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6101  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6102  fcnOverlaps, QStringLiteral( "GeometryGroup" ) )
6103  << new QgsStaticExpressionFunction( QStringLiteral( "within" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6104  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6105  fcnWithin, QStringLiteral( "GeometryGroup" ) )
6106  << new QgsStaticExpressionFunction( QStringLiteral( "translate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
6107  << QgsExpressionFunction::Parameter( QStringLiteral( "dx" ) )
6108  << QgsExpressionFunction::Parameter( QStringLiteral( "dy" ) ),
6109  fcnTranslate, QStringLiteral( "GeometryGroup" ) )
6110  << new QgsStaticExpressionFunction( QStringLiteral( "rotate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
6111  << QgsExpressionFunction::Parameter( QStringLiteral( "rotation" ) )
6112  << QgsExpressionFunction::Parameter( QStringLiteral( "center" ), true ),
6113  fcnRotate, QStringLiteral( "GeometryGroup" ) )
6114  << new QgsStaticExpressionFunction( QStringLiteral( "buffer" ), -1, fcnBuffer, QStringLiteral( "GeometryGroup" ) )
6115  << new QgsStaticExpressionFunction( QStringLiteral( "force_rhr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6116  fcnForceRHR, QStringLiteral( "GeometryGroup" ) )
6117  << new QgsStaticExpressionFunction( QStringLiteral( "wedge_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6118  << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
6119  << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) )
6120  << QgsExpressionFunction::Parameter( QStringLiteral( "outer_radius" ) )
6121  << QgsExpressionFunction::Parameter( QStringLiteral( "inner_radius" ), true, 0.0 ), fcnWedgeBuffer, QStringLiteral( "GeometryGroup" ) )
6122  << new QgsStaticExpressionFunction( QStringLiteral( "tapered_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6123  << QgsExpressionFunction::Parameter( QStringLiteral( "start_width" ) )
6124  << QgsExpressionFunction::Parameter( QStringLiteral( "end_width" ) )
6125  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6126  , fcnTaperedBuffer, QStringLiteral( "GeometryGroup" ) )
6127  << new QgsStaticExpressionFunction( QStringLiteral( "buffer_by_m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6128  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6129  , fcnBufferByM, QStringLiteral( "GeometryGroup" ) )
6130  << new QgsStaticExpressionFunction( QStringLiteral( "offset_curve" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6131  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6132  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6133  << QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
6134  << QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2.0 ),
6135  fcnOffsetCurve, QStringLiteral( "GeometryGroup" ) )
6136  << new QgsStaticExpressionFunction( QStringLiteral( "single_sided_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6137  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6138  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6139  << QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
6140  << QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2.0 ),
6141  fcnSingleSidedBuffer, QStringLiteral( "GeometryGroup" ) )
6142  << new QgsStaticExpressionFunction( QStringLiteral( "extend" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6143  << QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) )
6144  << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ),
6145  fcnExtend, QStringLiteral( "GeometryGroup" ) )
6146  << new QgsStaticExpressionFunction( QStringLiteral( "centroid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnCentroid, QStringLiteral( "GeometryGroup" ) )
6147  << new QgsStaticExpressionFunction( QStringLiteral( "point_on_surface" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
6148  << new QgsStaticExpressionFunction( QStringLiteral( "pole_of_inaccessibility" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6149  << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
6150  << new QgsStaticExpressionFunction( QStringLiteral( "reverse" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnReverse, QStringLiteral( "GeometryGroup" ) )
6151  << new QgsStaticExpressionFunction( QStringLiteral( "exterior_ring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
6152  << new QgsStaticExpressionFunction( QStringLiteral( "interior_ring_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6153  << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ),
6154  fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )
6155  << new QgsStaticExpressionFunction( QStringLiteral( "geometry_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6156  << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ),
6157  fcnGeometryN, QStringLiteral( "GeometryGroup" ) )
6158  << new QgsStaticExpressionFunction( QStringLiteral( "boundary" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundary, QStringLiteral( "GeometryGroup" ) )
6159  << new QgsStaticExpressionFunction( QStringLiteral( "line_merge" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnLineMerge, QStringLiteral( "GeometryGroup" ) )
6160  << new QgsStaticExpressionFunction( QStringLiteral( "bounds" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnBounds, QStringLiteral( "GeometryGroup" ) )
6161  << new QgsStaticExpressionFunction( QStringLiteral( "simplify" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnSimplify, QStringLiteral( "GeometryGroup" ) )
6162  << new QgsStaticExpressionFunction( QStringLiteral( "simplify_vw" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnSimplifyVW, QStringLiteral( "GeometryGroup" ) )
6163  << new QgsStaticExpressionFunction( QStringLiteral( "smooth" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "iterations" ), true, 1 )
6164  << QgsExpressionFunction::Parameter( QStringLiteral( "offset" ), true, 0.25 )
6165  << QgsExpressionFunction::Parameter( QStringLiteral( "min_length" ), true, -1 )
6166  << QgsExpressionFunction::Parameter( QStringLiteral( "max_angle" ), true, 180 ), fcnSmooth, QStringLiteral( "GeometryGroup" ) )
6167  << new QgsStaticExpressionFunction( QStringLiteral( "num_points" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnGeomNumPoints, QStringLiteral( "GeometryGroup" ) )
6168  << new QgsStaticExpressionFunction( QStringLiteral( "num_interior_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumInteriorRings, QStringLiteral( "GeometryGroup" ) )
6169  << new QgsStaticExpressionFunction( QStringLiteral( "num_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumRings, QStringLiteral( "GeometryGroup" ) )
6170  << new QgsStaticExpressionFunction( QStringLiteral( "num_geometries" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumGeometries, QStringLiteral( "GeometryGroup" ) )
6171  << new QgsStaticExpressionFunction( QStringLiteral( "bounds_width" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnBoundsWidth, QStringLiteral( "GeometryGroup" ) )
6172  << new QgsStaticExpressionFunction( QStringLiteral( "bounds_height" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) )
6173  << new QgsStaticExpressionFunction( QStringLiteral( "is_closed" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnIsClosed, QStringLiteral( "GeometryGroup" ) )
6174  << new QgsStaticExpressionFunction( QStringLiteral( "close_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnCloseLine, QStringLiteral( "GeometryGroup" ) )
6175  << new QgsStaticExpressionFunction( QStringLiteral( "is_empty" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnIsEmpty, QStringLiteral( "GeometryGroup" ) )
6176  << new QgsStaticExpressionFunction( QStringLiteral( "is_empty_or_null" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) ), fcnIsEmptyOrNull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6177  << new QgsStaticExpressionFunction( QStringLiteral( "convex_hull" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "convexHull" ) )
6178  << new QgsStaticExpressionFunction( QStringLiteral( "oriented_bbox" ), QgsExpressionFunction::ParameterList()
6179  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6180  fcnOrientedBBox, QStringLiteral( "GeometryGroup" ) )
6181  << new QgsStaticExpressionFunction( QStringLiteral( "minimal_circle" ), QgsExpressionFunction::ParameterList()
6182  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6183  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6184  fcnMinimalCircle, QStringLiteral( "GeometryGroup" ) )
6185  << new QgsStaticExpressionFunction( QStringLiteral( "difference" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry_a" ) )
6186  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry_b" ) ),
6187  fcnDifference, QStringLiteral( "GeometryGroup" ) )
6188  << new QgsStaticExpressionFunction( QStringLiteral( "distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry a" ) )
6189  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry b" ) ),
6190  fcnDistance, QStringLiteral( "GeometryGroup" ) )
6191  << new QgsStaticExpressionFunction( QStringLiteral( "hausdorff_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) )
6192  << QgsExpressionFunction::Parameter( QStringLiteral( "densify_fraction" ), true ),
6193  fcnHausdorffDistance, QStringLiteral( "GeometryGroup" ) )
6194  << new QgsStaticExpressionFunction( QStringLiteral( "intersection" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry_a" ) )
6195  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry_b" ) ),
6196  fcnIntersection, QStringLiteral( "GeometryGroup" ) )
6197  << new QgsStaticExpressionFunction( QStringLiteral( "sym_difference" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6198  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6199  fcnSymDifference, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "symDifference" ) )
6200  << new QgsStaticExpressionFunction( QStringLiteral( "combine" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6201  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6202  fcnCombine, QStringLiteral( "GeometryGroup" ) )
6203  << new QgsStaticExpressionFunction( QStringLiteral( "union" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6204  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6205  fcnCombine, QStringLiteral( "GeometryGroup" ) )
6206  << new QgsStaticExpressionFunction( QStringLiteral( "geom_to_wkt" ), -1, fcnGeomToWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomToWKT" ) )
6207  << new QgsStaticExpressionFunction( QStringLiteral( "geom_to_wkb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomToWKB, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false )
6208  << new QgsStaticExpressionFunction( QStringLiteral( "geometry" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ) ), fcnGetGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
6209  << new QgsStaticExpressionFunction( QStringLiteral( "transform" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
6210  << QgsExpressionFunction::Parameter( QStringLiteral( "source_auth_id" ) )
6211  << QgsExpressionFunction::Parameter( QStringLiteral( "dest_auth_id" ) ),
6212  fcnTransformGeometry, QStringLiteral( "GeometryGroup" ) )
6213  << new QgsStaticExpressionFunction( QStringLiteral( "extrude" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
6214  << QgsExpressionFunction::Parameter( QStringLiteral( "x" ) )
6215  << QgsExpressionFunction::Parameter( QStringLiteral( "y" ) ),
6216  fcnExtrude, QStringLiteral( "GeometryGroup" ), QString() )
6217  << new QgsStaticExpressionFunction( QStringLiteral( "is_multipart" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6218  fcnGeomIsMultipart, QStringLiteral( "GeometryGroup" ) )
6219  << new QgsStaticExpressionFunction( QStringLiteral( "z_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6220  fcnZMax, QStringLiteral( "GeometryGroup" ) )
6221  << new QgsStaticExpressionFunction( QStringLiteral( "z_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6222  fcnZMin, QStringLiteral( "GeometryGroup" ) )
6223  << new QgsStaticExpressionFunction( QStringLiteral( "m_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6224  fcnMMax, QStringLiteral( "GeometryGroup" ) )
6225  << new QgsStaticExpressionFunction( QStringLiteral( "m_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6226  fcnMMin, QStringLiteral( "GeometryGroup" ) );
6227 
6228 
6229  QgsStaticExpressionFunction *orderPartsFunc = new QgsStaticExpressionFunction( QStringLiteral( "order_parts" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geom" ) )
6230  << QgsExpressionFunction::Parameter( QStringLiteral( "orderby" ) )
6231  << QgsExpressionFunction::Parameter( QStringLiteral( "ascending" ) ),
6232  fcnOrderParts, QStringLiteral( "GeometryGroup" ), QString() );
6233 
6234  orderPartsFunc->setIsStaticFunction(
6235  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6236  {
6237  const QList< QgsExpressionNode *> argList = node->args()->list();
6238  for ( QgsExpressionNode *argNode : argList )
6239  {
6240  if ( !argNode->isStatic( parent, context ) )
6241  return false;
6242  }
6243 
6244  if ( node->args()->count() > 1 )
6245  {
6246  QgsExpressionNode *argNode = node->args()->at( 1 );
6247 
6248  QString expString = argNode->eval( parent, context ).toString();
6249 
6250  QgsExpression e( expString );
6251 
6252  if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) )
6253  return true;
6254  }
6255 
6256  return true;
6257  } );
6258 
6259  orderPartsFunc->setPrepareFunction( []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6260  {
6261  if ( node->args()->count() > 1 )
6262  {
6263  QgsExpressionNode *argNode = node->args()->at( 1 );
6264  QString expression = argNode->eval( parent, context ).toString();
6265  QgsExpression e( expression );
6266  e.prepare( context );
6267  context->setCachedValue( expression, QVariant::fromValue( e ) );
6268  }
6269  return true;
6270  }
6271  );
6272  functions << orderPartsFunc;
6273 
6274  functions
6275  << new QgsStaticExpressionFunction( QStringLiteral( "closest_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6276  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6277  fcnClosestPoint, QStringLiteral( "GeometryGroup" ) )
6278  << new QgsStaticExpressionFunction( QStringLiteral( "shortest_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6279  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6280  fcnShortestLine, QStringLiteral( "GeometryGroup" ) )
6281  << new QgsStaticExpressionFunction( QStringLiteral( "line_interpolate_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6282  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolatePoint, QStringLiteral( "GeometryGroup" ) )
6283  << new QgsStaticExpressionFunction( QStringLiteral( "line_interpolate_angle" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6284  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolateAngle, QStringLiteral( "GeometryGroup" ) )
6285  << new QgsStaticExpressionFunction( QStringLiteral( "line_locate_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6286  << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnLineLocatePoint, QStringLiteral( "GeometryGroup" ) )
6287  << new QgsStaticExpressionFunction( QStringLiteral( "angle_at_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6288  << QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
6289  << new QgsStaticExpressionFunction( QStringLiteral( "distance_to_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6290  << QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
6291  << new QgsStaticExpressionFunction( QStringLiteral( "line_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6292  << QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ), fcnLineSubset, QStringLiteral( "GeometryGroup" ) );
6293 
6294 
6295  // **Record** functions
6296 
6297  QgsStaticExpressionFunction *idFunc = new QgsStaticExpressionFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record and Attributes" ) );
6298  idFunc->setIsStatic( false );
6299  functions << idFunc;
6300 
6301  QgsStaticExpressionFunction *currentFeatureFunc = new QgsStaticExpressionFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record and Attributes" ) );
6302  currentFeatureFunc->setIsStatic( false );
6303  functions << currentFeatureFunc;
6304 
6305  QgsStaticExpressionFunction *uuidFunc = new QgsStaticExpressionFunction( QStringLiteral( "uuid" ), 0, fcnUuid, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) );
6306  uuidFunc->setIsStatic( false );
6307  functions << uuidFunc;
6308 
6309  functions
6310  << new QgsStaticExpressionFunction( QStringLiteral( "get_feature" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6311  << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) )
6312  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6313  fcnGetFeature, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "QgsExpressionUtils::getFeature" ) )
6314  << new QgsStaticExpressionFunction( QStringLiteral( "get_feature_by_id" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6315  << QgsExpressionFunction::Parameter( QStringLiteral( "feature_id" ) ),
6316  fcnGetFeatureById, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false );
6317 
6318  QgsStaticExpressionFunction *attributesFunc = new QgsStaticExpressionFunction( QStringLiteral( "attributes" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ), true ),
6319  fcnAttributes, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
6320  attributesFunc->setIsStatic( false );
6321  functions << attributesFunc;
6322 
6324  QStringLiteral( "maptip" ),
6325  -1,
6326  fcnFeatureMaptip,
6327  QStringLiteral( "Record and Attributes" ),
6328  QString(),
6329  false,
6330  QSet<QString>()
6331  );
6332  maptipFunc->setIsStatic( false );
6333  functions << maptipFunc;
6334 
6336  QStringLiteral( "display_expression" ),
6337  -1,
6338  fcnFeatureDisplayExpression,
6339  QStringLiteral( "Record and Attributes" ),
6340  QString(),
6341  false,
6342  QSet<QString>()
6343  );
6344  displayFunc->setIsStatic( false );
6345  functions << displayFunc;
6346 
6348  QStringLiteral( "is_selected" ),
6349  -1,
6350  fcnIsSelected,
6351  QStringLiteral( "Record and Attributes" ),
6352  QString(),
6353  false,
6354  QSet<QString>()
6355  );
6356  isSelectedFunc->setIsStatic( false );
6357  functions << isSelectedFunc;
6358 
6359  functions
6361  QStringLiteral( "num_selected" ),
6362  -1,
6363  fcnNumSelected,
6364  QStringLiteral( "Record and Attributes" ),
6365  QString(),
6366  false,
6367  QSet<QString>()
6368  );
6369 
6370  functions
6372  QStringLiteral( "sqlite_fetch_and_increment" ),
6374  << QgsExpressionFunction::Parameter( QStringLiteral( "database" ) )
6375  << QgsExpressionFunction::Parameter( QStringLiteral( "table" ) )
6376  << QgsExpressionFunction::Parameter( QStringLiteral( "id_field" ) )
6377  << QgsExpressionFunction::Parameter( QStringLiteral( "filter_attribute" ) )
6378  << QgsExpressionFunction::Parameter( QStringLiteral( "filter_value" ) )
6379  << QgsExpressionFunction::Parameter( QStringLiteral( "default_values" ), true ),
6380  fcnSqliteFetchAndIncrement,
6381  QStringLiteral( "Record and Attributes" )
6382  );
6383 
6384  // **Fields and Values** functions
6385  QgsStaticExpressionFunction *representValueFunc = new QgsStaticExpressionFunction( QStringLiteral( "represent_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "field_name" ), true ), fcnRepresentValue, QStringLiteral( "Record and Attributes" ) );
6386 
6387  representValueFunc->setPrepareFunction( []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6388  {
6389  Q_UNUSED( context )
6390  if ( node->args()->count() == 1 )
6391  {
6392  QgsExpressionNodeColumnRef *colRef = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
6393  if ( colRef )
6394  {
6395  return true;
6396  }
6397  else
6398  {
6399  parent->setEvalErrorString( tr( "If represent_value is called with 1 parameter, it must be an attribute." ) );
6400  return false;
6401  }
6402  }
6403  else if ( node->args()->count() == 2 )
6404  {
6405  return true;
6406  }
6407  else
6408  {
6409  parent->setEvalErrorString( tr( "represent_value must be called with exactly 1 or 2 parameters." ) );
6410  return false;
6411  }
6412  }
6413  );
6414 
6415  functions << representValueFunc;
6416 
6417  // **General** functions
6418  functions
6419  << new QgsStaticExpressionFunction( QStringLiteral( "layer_property" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6420  << QgsExpressionFunction::Parameter( QStringLiteral( "property" ) ),
6421  fcnGetLayerProperty, QStringLiteral( "General" ) )
6422  << new QgsStaticExpressionFunction( QStringLiteral( "decode_uri" ),
6424  << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6425  << QgsExpressionFunction::Parameter( QStringLiteral( "part" ), true ),
6426  fcnDecodeUri, QStringLiteral( "Map Layers" ) )
6427  << new QgsStaticExpressionFunction( QStringLiteral( "raster_statistic" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6428  << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) )
6429  << QgsExpressionFunction::Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "Rasters" ) );
6430 
6431  // **var** function
6432  QgsStaticExpressionFunction *varFunction = new QgsStaticExpressionFunction( QStringLiteral( "var" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnGetVariable, QStringLiteral( "General" ) );
6433  varFunction->setIsStaticFunction(
6434  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6435  {
6436  /* A variable node is static if it has a static name and the name can be found at prepare
6437  * time and is tagged with isStatic.
6438  * It is not static if a variable is set during iteration or not tagged isStatic.
6439  * (e.g. geom_part variable)
6440  */
6441  if ( node->args()->count() > 0 )
6442  {
6443  QgsExpressionNode *argNode = node->args()->at( 0 );
6444 
6445  if ( !argNode->isStatic( parent, context ) )
6446  return false;
6447 
6448  QString varName = argNode->eval( parent, context ).toString();
6449 
6450  const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
6451  return scope ? scope->isStatic( varName ) : false;
6452  }
6453  return false;
6454  }
6455  );
6456 
6457  functions
6458  << varFunction;
6459 
6460  functions << new QgsStaticExpressionFunction( QStringLiteral( "eval_template" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "template" ) ), fcnEvalTemplate, QStringLiteral( "General" ), QString(), true );
6461 
6462  QgsStaticExpressionFunction *evalFunc = new QgsStaticExpressionFunction( QStringLiteral( "eval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ), fcnEval, QStringLiteral( "General" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
6463  evalFunc->setIsStaticFunction(
6464  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6465  {
6466  if ( node->args()->count() > 0 )
6467  {
6468  QgsExpressionNode *argNode = node->args()->at( 0 );
6469 
6470  if ( argNode->isStatic( parent, context ) )
6471  {
6472  QString expString = argNode->eval( parent, context ).toString();
6473 
6474  QgsExpression e( expString );
6475 
6476  if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) )
6477  return true;
6478  }
6479  }
6480 
6481  return false;
6482  } );
6483 
6484  functions << evalFunc;
6485 
6486  QgsStaticExpressionFunction *attributeFunc = new QgsStaticExpressionFunction( QStringLiteral( "attribute" ), -1, fcnAttribute, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
6487  attributeFunc->setIsStaticFunction(
6488  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6489  {
6490  const QList< QgsExpressionNode *> argList = node->args()->list();
6491  for ( QgsExpressionNode *argNode : argList )
6492  {
6493  if ( !argNode->isStatic( parent, context ) )
6494  return false;
6495  }
6496 
6497  if ( node->args()->count() == 1 )
6498  {
6499  // not static -- this is the variant which uses the current feature taken direct from the expression context
6500  return false;
6501  }
6502 
6503  return true;
6504  } );
6505  functions << attributeFunc;
6506 
6507  functions
6508  << new QgsStaticExpressionFunction( QStringLiteral( "env" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnEnvVar, QStringLiteral( "General" ), QString() )
6510  << new QgsStaticExpressionFunction( QStringLiteral( "raster_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterValue, QStringLiteral( "Rasters" ) )
6511 
6512  // functions for arrays
6515  << new QgsStaticExpressionFunction( QStringLiteral( "array" ), -1, fcnArray, QStringLiteral( "Arrays" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6516  << new QgsStaticExpressionFunction( QStringLiteral( "array_sort" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "ascending" ), true, true ), fcnArraySort, QStringLiteral( "Arrays" ) )
6517  << new QgsStaticExpressionFunction( QStringLiteral( "array_length" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayLength, QStringLiteral( "Arrays" ) )
6518  << new QgsStaticExpressionFunction( QStringLiteral( "array_contains" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayContains, QStringLiteral( "Arrays" ) )
6519  << new QgsStaticExpressionFunction( QStringLiteral( "array_all" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array_b" ) ), fcnArrayAll, QStringLiteral( "Arrays" ) )
6520  << new QgsStaticExpressionFunction( QStringLiteral( "array_find" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayFind, QStringLiteral( "Arrays" ) )
6521  << new QgsStaticExpressionFunction( QStringLiteral( "array_get" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ), fcnArrayGet, QStringLiteral( "Arrays" ) )
6522  << new QgsStaticExpressionFunction( QStringLiteral( "array_first" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayFirst, QStringLiteral( "Arrays" ) )
6523  << new QgsStaticExpressionFunction( QStringLiteral( "array_last" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayLast, QStringLiteral( "Arrays" ) )
6524  << new QgsStaticExpressionFunction( QStringLiteral( "array_append" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayAppend, QStringLiteral( "Arrays" ) )
6525  << new QgsStaticExpressionFunction( QStringLiteral( "array_prepend" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayPrepend, QStringLiteral( "Arrays" ) )
6526  << new QgsStaticExpressionFunction( QStringLiteral( "array_insert" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayInsert, QStringLiteral( "Arrays" ) )
6527  << new QgsStaticExpressionFunction( QStringLiteral( "array_remove_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ), fcnArrayRemoveAt, QStringLiteral( "Arrays" ) )
6528  << new QgsStaticExpressionFunction( QStringLiteral( "array_remove_all" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayRemoveAll, QStringLiteral( "Arrays" ) )
6529  << new QgsStaticExpressionFunction( QStringLiteral( "array_cat" ), -1, fcnArrayCat, QStringLiteral( "Arrays" ) )
6530  << new QgsStaticExpressionFunction( QStringLiteral( "array_slice" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "start_pos" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_pos" ) ), fcnArraySlice, QStringLiteral( "Arrays" ) )
6531  << new QgsStaticExpressionFunction( QStringLiteral( "array_reverse" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayReverse, QStringLiteral( "Arrays" ) )
6532  << new QgsStaticExpressionFunction( QStringLiteral( "array_intersect" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array2" ) ), fcnArrayIntersect, QStringLiteral( "Arrays" ) )
6533  << new QgsStaticExpressionFunction( QStringLiteral( "array_distinct" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayDistinct, QStringLiteral( "Arrays" ) )
6534  << new QgsStaticExpressionFunction( QStringLiteral( "array_to_string" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "," ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnArrayToString, QStringLiteral( "Arrays" ) )
6535  << new QgsStaticExpressionFunction( QStringLiteral( "string_to_array" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "," ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnStringToArray, QStringLiteral( "Arrays" ) )
6536  << new QgsStaticExpressionFunction( QStringLiteral( "generate_series" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "start" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "stop" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "step" ), true, 1.0 ), fcnGenerateSeries, QStringLiteral( "Arrays" ) )
6537 
6538  //functions for maps
6539  << new QgsStaticExpressionFunction( QStringLiteral( "json_to_map" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnLoadJson, QStringLiteral( "Maps" ) )
6540  << new QgsStaticExpressionFunction( QStringLiteral( "from_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLoadJson, QStringLiteral( "Maps" ) )
6541  << new QgsStaticExpressionFunction( QStringLiteral( "map_to_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnWriteJson, QStringLiteral( "Maps" ) )
6542  << new QgsStaticExpressionFunction( QStringLiteral( "to_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "json_string" ) ), fcnWriteJson, QStringLiteral( "Maps" ) )
6543  << new QgsStaticExpressionFunction( QStringLiteral( "hstore_to_map" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnHstoreToMap, QStringLiteral( "Maps" ) )
6544  << new QgsStaticExpressionFunction( QStringLiteral( "map_to_hstore" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapToHstore, QStringLiteral( "Maps" ) )
6545  << new QgsStaticExpressionFunction( QStringLiteral( "map" ), -1, fcnMap, QStringLiteral( "Maps" ) )
6546  << new QgsStaticExpressionFunction( QStringLiteral( "map_get" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapGet, QStringLiteral( "Maps" ) )
6547  << new QgsStaticExpressionFunction( QStringLiteral( "map_exist" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapExist, QStringLiteral( "Maps" ) )
6548  << new QgsStaticExpressionFunction( QStringLiteral( "map_delete" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapDelete, QStringLiteral( "Maps" ) )
6549  << new QgsStaticExpressionFunction( QStringLiteral( "map_insert" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnMapInsert, QStringLiteral( "Maps" ) )
6550  << new QgsStaticExpressionFunction( QStringLiteral( "map_concat" ), -1, fcnMapConcat, QStringLiteral( "Maps" ) )
6551  << new QgsStaticExpressionFunction( QStringLiteral( "map_akeys" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapAKeys, QStringLiteral( "Maps" ) )
6552  << new QgsStaticExpressionFunction( QStringLiteral( "map_avals" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapAVals, QStringLiteral( "Maps" ) )
6553  ;
6554 
6556 
6557  //QgsExpression has ownership of all built-in functions
6558  for ( QgsExpressionFunction *func : qgis::as_const( functions ) )
6559  {
6560  *sOwnedFunctions() << func;
6561  *sBuiltinFunctions() << func->name();
6562  sBuiltinFunctions()->append( func->aliases() );
6563  }
6564  }
6565  return functions;
6566 }
6567 
6568 bool QgsExpression::registerFunction( QgsExpressionFunction *function, bool transferOwnership )
6569 {
6570  int fnIdx = functionIndex( function->name() );
6571  if ( fnIdx != -1 )
6572  {
6573  return false;
6574  }
6575  sFunctions()->append( function );
6576  if ( transferOwnership )
6577  sOwnedFunctions()->append( function );
6578  return true;
6579 }
6580 
6581 bool QgsExpression::unregisterFunction( const QString &name )
6582 {
6583  // You can never override the built in functions.
6584  if ( QgsExpression::BuiltinFunctions().contains( name ) )
6585  {
6586  return false;
6587  }
6588  int fnIdx = functionIndex( name );
6589  if ( fnIdx != -1 )
6590  {
6591  sFunctions()->removeAt( fnIdx );
6592  return true;
6593  }
6594  return false;
6595 }
6596 
6598 {
6599  qDeleteAll( *sOwnedFunctions() );
6600  sOwnedFunctions()->clear();
6601 }
6602 
6604 {
6605  if ( sBuiltinFunctions()->isEmpty() )
6606  {
6607  Functions(); // this method builds the gmBuiltinFunctions as well
6608  }
6609  return *sBuiltinFunctions();
6610 }
6611 
6612 
6614  : QgsExpressionFunction( QStringLiteral( "array_foreach" ), QgsExpressionFunction::ParameterList()
6615  << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) )
6616  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
6617  QStringLiteral( "Arrays" ) )
6618 {
6619 
6620 }
6621 
6623 {
6624  bool isStatic = false;
6625 
6626  QgsExpressionNode::NodeList *args = node->args();
6627 
6628  if ( args->count() < 2 )
6629  return false;
6630 
6631  if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
6632  {
6633  isStatic = true;
6634  }
6635  return isStatic;
6636 }
6637 
6639 {
6640  Q_UNUSED( node )
6641  QVariantList result;
6642 
6643  if ( args->count() < 2 )
6644  // error
6645  return result;
6646 
6647  QVariantList array = args->at( 0 )->eval( parent, context ).toList();
6648 
6649  QgsExpressionContext *subContext = const_cast<QgsExpressionContext *>( context );
6650  std::unique_ptr< QgsExpressionContext > tempContext;
6651  if ( !subContext )
6652  {
6653  tempContext = qgis::make_unique< QgsExpressionContext >();
6654  subContext = tempContext.get();
6655  }
6656 
6658  subContext->appendScope( subScope );
6659 
6660  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
6661  {
6662  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), *it, true ) );
6663  result << args->at( 1 )->eval( parent, subContext );
6664  }
6665 
6666  if ( context )
6667  delete subContext->popScope();
6668 
6669  return result;
6670 }
6671 
6672 QVariant QgsArrayForeachExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
6673 {
6674  // This is a dummy function, all the real handling is in run
6675  Q_UNUSED( values )
6676  Q_UNUSED( context )
6677  Q_UNUSED( parent )
6678  Q_UNUSED( node )
6679 
6680  Q_ASSERT( false );
6681  return QVariant();
6682 }
6683 
6685 {
6686  QgsExpressionNode::NodeList *args = node->args();
6687 
6688  if ( args->count() < 2 )
6689  // error
6690  return false;
6691 
6692  args->at( 0 )->prepare( parent, context );
6693 
6694  QgsExpressionContext subContext;
6695  if ( context )
6696  subContext = *context;
6697 
6699  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), QVariant(), true ) );
6700  subContext.appendScope( subScope );
6701 
6702  args->at( 1 )->prepare( parent, &subContext );
6703 
6704  return true;
6705 }
6706 
6708  : QgsExpressionFunction( QStringLiteral( "array_filter" ), QgsExpressionFunction::ParameterList()
6709  << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) )
6710  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
6711  QStringLiteral( "Arrays" ) )
6712 {
6713 
6714 }
6715 
6717 {
6718  bool isStatic = false;
6719 
6720  QgsExpressionNode::NodeList *args = node->args();
6721 
6722  if ( args->count() < 2 )
6723  return false;
6724 
6725  if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
6726  {
6727  isStatic = true;
6728  }
6729  return isStatic;
6730 }
6731 
6733 {
6734  Q_UNUSED( node )
6735  QVariantList result;
6736 
6737  if ( args->count() < 2 )
6738  // error
6739  return result;
6740 
6741  const QVariantList array = args->at( 0 )->eval( parent, context ).toList();
6742 
6743  QgsExpressionContext *subContext = const_cast<QgsExpressionContext *>( context );
6744  std::unique_ptr< QgsExpressionContext > tempContext;
6745  if ( !subContext )
6746  {
6747  tempContext = qgis::make_unique< QgsExpressionContext >();
6748  subContext = tempContext.get();
6749  }
6750 
6752  subContext->appendScope( subScope );
6753 
6754  for ( const QVariant &value : array )
6755  {
6756  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), value, true ) );
6757  if ( args->at( 1 )->eval( parent, subContext ).toBool() )
6758  result << value;
6759  }
6760 
6761  if ( context )
6762  delete subContext->popScope();
6763 
6764  return result;
6765 }
6766 
6767 QVariant QgsArrayFilterExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
6768 {
6769  // This is a dummy function, all the real handling is in run
6770  Q_UNUSED( values )
6771  Q_UNUSED( context )
6772  Q_UNUSED( parent )
6773  Q_UNUSED( node )
6774 
6775  Q_ASSERT( false );
6776  return QVariant();
6777 }
6778 
6780 {
6781  QgsExpressionNode::NodeList *args = node->args();
6782 
6783  if ( args->count() < 2 )
6784  // error
6785  return false;
6786 
6787  args->at( 0 )->prepare( parent, context );
6788 
6789  QgsExpressionContext subContext;
6790  if ( context )
6791  subContext = *context;
6792 
6794  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), QVariant(), true ) );
6795  subContext.appendScope( subScope );
6796 
6797  args->at( 1 )->prepare( parent, &subContext );
6798 
6799  return true;
6800 }
6802  : QgsExpressionFunction( QStringLiteral( "with_variable" ), QgsExpressionFunction::ParameterList() <<
6803  QgsExpressionFunction::Parameter( QStringLiteral( "name" ) )
6804  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) )
6805  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
6806  QStringLiteral( "General" ) )
6807 {
6808 
6809 }
6810 
6812 {
6813  bool isStatic = false;
6814 
6815  QgsExpressionNode::NodeList *args = node->args();
6816 
6817  if ( args->count() < 3 )
6818  return false;
6819 
6820  // We only need to check if the node evaluation is static, if both - name and value - are static.
6821  if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
6822  {
6823  QVariant name = args->at( 0 )->eval( parent, context );
6824  QVariant value = args->at( 1 )->eval( parent, context );
6825 
6826  // Temporarily append a new scope to provide the variable
6827  appendTemporaryVariable( context, name.toString(), value );
6828  if ( args->at( 2 )->isStatic( parent, context ) )
6829  isStatic = true;
6830  popTemporaryVariable( context );
6831  }
6832 
6833  return isStatic;
6834 }
6835 
6837 {
6838  Q_UNUSED( node )
6839  QVariant result;
6840 
6841  if ( args->count() < 3 )
6842  // error
6843  return result;
6844 
6845  QVariant name = args->at( 0 )->eval( parent, context );
6846  QVariant value = args->at( 1 )->eval( parent, context );
6847 
6848  const QgsExpressionContext *updatedContext = context;
6849  std::unique_ptr< QgsExpressionContext > tempContext;
6850  if ( !updatedContext )
6851  {
6852  tempContext = qgis::make_unique< QgsExpressionContext >();
6853  updatedContext = tempContext.get();
6854  }
6855 
6856  appendTemporaryVariable( updatedContext, name.toString(), value );
6857  result = args->at( 2 )->eval( parent, updatedContext );
6858 
6859  if ( context )
6860  popTemporaryVariable( updatedContext );
6861 
6862  return result;
6863 }
6864 
6865 QVariant QgsWithVariableExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
6866 {
6867  // This is a dummy function, all the real handling is in run
6868  Q_UNUSED( values )
6869  Q_UNUSED( context )
6870  Q_UNUSED( parent )
6871  Q_UNUSED( node )
6872 
6873  Q_ASSERT( false );
6874  return QVariant();
6875 }
6876 
6878 {
6879  QgsExpressionNode::NodeList *args = node->args();
6880 
6881  if ( args->count() < 3 )
6882  // error
6883  return false;
6884 
6885  QVariant name = args->at( 0 )->prepare( parent, context );
6886  QVariant value = args->at( 1 )->prepare( parent, context );
6887 
6888  const QgsExpressionContext *updatedContext = context;
6889  std::unique_ptr< QgsExpressionContext > tempContext;
6890  if ( !updatedContext )
6891  {
6892  tempContext = qgis::make_unique< QgsExpressionContext >();
6893  updatedContext = tempContext.get();
6894  }
6895 
6896  appendTemporaryVariable( updatedContext, name.toString(), value );
6897  args->at( 2 )->prepare( parent, updatedContext );
6898 
6899  if ( context )
6900  popTemporaryVariable( updatedContext );
6901 
6902  return true;
6903 }
6904 
6905 void QgsWithVariableExpressionFunction::popTemporaryVariable( const QgsExpressionContext *context ) const
6906 {
6907  QgsExpressionContext *updatedContext = const_cast<QgsExpressionContext *>( context );
6908  delete updatedContext->popScope();
6909 }
6910 
6911 void QgsWithVariableExpressionFunction::appendTemporaryVariable( const QgsExpressionContext *context, const QString &name, const QVariant &value ) const
6912 {
6915 
6916  QgsExpressionContext *updatedContext = const_cast<QgsExpressionContext *>( context );
6917  updatedContext->appendScope( scope );
6918 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QgsGeometry::combine
QgsGeometry combine(const QgsGeometry &geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
Definition: qgsgeometry.cpp:2417
qgspolygon.h
QgsFeatureRequest::NoGeometry
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition: qgsfeaturerequest.h:107
QgsPoint::project
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which correspond to this point projected by a specified distance with specified a...
Definition: qgspoint.cpp:685
QgsAbstractGeometry::coordinateSequence
virtual QgsCoordinateSequence coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:993
QgsExpressionNode::dump
virtual QString dump() const =0
Dump this node into a serialized (part) of an expression.
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:369
QgsGeometry::hausdorffDistanceDensify
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeometry.cpp:1839
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:49
QgsProject::relationManager
QgsRelationManager relationManager
Definition: qgsproject.h:103
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:88
formatter
Definition: qgsbasicnumericformat.cpp:24
QgsColorRamp
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
QgsFeatureRequest::OrderByClause
Definition: qgsfeaturerequest.h:142
qgsexpressioncontextutils.h
qgsrasterbandstats.h
QgsEllipse
Ellipse geometry type.
Definition: qgsellipse.h:39
QgsAggregateCalculator::AggregateParameters::delimiter
QString delimiter
Delimiter to use for joining values with the StringConcatenate aggregate.
Definition: qgsaggregatecalculator.h:107
QgsAggregateCalculator::Range
@ Range
Range of values (max - min) (numeric and datetime fields only)
Definition: qgsaggregatecalculator.h:76
QgsRasterLayer::bandCount
int bandCount() const
Returns the number of bands in this layer.
Definition: qgsrasterlayer.cpp:216
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:52
QgsExpression::quotedString
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
Definition: qgsexpression.cpp:70
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsStaticExpressionFunction::aliases
QStringList aliases() const override
Returns a list of possible aliases for the function.
Definition: qgsexpressionfunction.cpp:175
QgsDistanceArea::measureLength
double measureLength(const QgsGeometry &geometry) const
Measures the length of a geometry.
Definition: qgsdistancearea.cpp:192
QgsInterval::seconds
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:168
QgsHstoreUtils::build
CORE_EXPORT QString build(const QVariantMap &map)
Build a hstore-formatted string from a QVariantMap.
Definition: qgshstoreutils.cpp:88
QgsGeometry::transform
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:2836
QgsGeometry::distance
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry.
Definition: qgsgeometry.cpp:1809
QgsMapLayer::attributionUrl
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:394
QgsCoordinateReferenceSystem::description
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
Definition: qgscoordinatereferencesystem.cpp:1304
QgsCoordinateTransformContext
Definition: qgscoordinatetransformcontext.h:57
qgsrasterlayer.h
qgsfeaturerequest.h
QgsGeometry::within
bool within(const QgsGeometry &geometry) const
Returns true if the geometry is completely within another geometry.
Definition: qgsgeometry.cpp:1279
QgsGradientColorRamp
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
QgsCircle
Circle geometry type.
Definition: qgscircle.h:43
QgsExpressionNodeLiteral
An expression node for literal values.
Definition: qgsexpressionnodeimpl.h:364
QgsLineString::setPoints
void setPoints(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
Definition: qgslinestring.cpp:756
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
QgsExpressionContextScope::setVariable
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
Definition: qgsexpressioncontext.cpp:78
QgsWithVariableExpressionFunction
Handles the with_variable(name, value, node) expression function.
Definition: qgsexpressionfunction.h:557
QgsExpressionContext::popScope
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
Definition: qgsexpressioncontext.cpp:500
QgsGeometry::angleAtVertex
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
Definition: qgsgeometry.cpp:430
QgsMapLayerType::MeshLayer
@ MeshLayer
Added in 3.2.
QgsRasterInterface::bandStatistics
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
Definition: qgsrasterinterface.cpp:116
qgslinestring.h
QgsEditorWidgetSetup
Definition: qgseditorwidgetsetup.h:28
QgsQuadrilateral
Quadrilateral geometry type. A quadrilateral is a polygon with four edges (or sides) and four vertice...
Definition: qgsquadrilateral.h:35
QgsMapLayerType::VectorLayer
@ VectorLayer
QgsStaticExpressionFunction::setPrepareFunction
void setPrepareFunction(const std::function< bool(const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext *)> &prepareFunc)
Set a function that will be called in the prepare step to determine if the function is static or not.
Definition: qgsexpressionfunction.cpp:223
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:93
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsGeometryCollection::numGeometries
int numGeometries() const
Returns the number of geometries within the collection.
Definition: qgsgeometrycollection.h:51
QgsProject::mapLayersByName
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
Definition: qgsproject.cpp:3129
sqlite3_database_unique_ptr::prepare
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
Definition: qgssqliteutils.cpp:99
QgsAggregateCalculator::Minority
@ Minority
Minority of values.
Definition: qgsaggregatecalculator.h:77
algorithm
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
QgsRasterBandStats
Definition: qgsrasterbandstats.h:34
QgsAggregateCalculator::AggregateParameters
A bundle of parameters controlling aggregate calculation.
Definition: qgsaggregatecalculator.h:91
QgsCurve::reversed
virtual QgsCurve * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsGeometry::isMultipart
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
Definition: qgsgeometry.cpp:377
QgsAggregateCalculator::CountDistinct
@ CountDistinct
Number of distinct values.
Definition: qgsaggregatecalculator.h:67
QgsExpression::geomCalculator
QgsDistanceArea * geomCalculator()
Returns calculator used for distance and area calculations (used by $length, $area and $perimeter fun...
Definition: qgsexpression.cpp:397
QgsExpressionFunction::func
virtual QVariant func(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node)=0
Returns result of evaluating the function.
qgsstringutils.h
QgsExpressionContext::hasCachedValue
bool hasCachedValue(const QString &key) const
Returns true if the expression context contains a cached value with a matching key.
Definition: qgsexpressioncontext.cpp:580
QgsCoordinateReferenceSystem::fromOgcWmsCrs
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Definition: qgscoordinatereferencesystem.cpp:200
QgsAggregateCalculator::Min
@ Min
Min of values.
Definition: qgsaggregatecalculator.h:69
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsGeometry::interpolate
QgsGeometry interpolate(double distance) const
Returns an interpolated point on the geometry at the specified distance.
Definition: qgsgeometry.cpp:2272
QgsQuadrilateral::rectangleFrom3Points
static QgsQuadrilateral rectangleFrom3Points(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, ConstructionOption mode)
Construct a QgsQuadrilateral as a Rectangle from 3 points.
Definition: qgsquadrilateral.cpp:33
QgsExpressionNodeColumnRef
An expression node which takes it value from a feature's field.
Definition: qgsexpressionnodeimpl.h:400
QgsMultiPoint::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultipoint.cpp:138
QgsRectangle::xMaximum
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsQuadrilateral::ConstructionOption
ConstructionOption
A quadrilateral can be constructed from 3 points where the second distance can be determined by the t...
Definition: qgsquadrilateral.h:65
QgsStyle::colorRampRef
const QgsColorRamp * colorRampRef(const QString &name) const
Returns a const pointer to a symbol (doesn't create new instance)
Definition: qgsstyle.cpp:402
QgsExpressionContextUtils::registerContextFunctions
static void registerContextFunctions()
Registers all known core functions provided by QgsExpressionContextScope objects.
Definition: qgsexpressioncontextutils.cpp:815
qgssymbollayerutils.h
QgsRegularPolygon::CircumscribedCircle
@ CircumscribedCircle
Definition: qgsregularpolygon.h:52
QgsFields::count
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsFields
Definition: qgsfields.h:44
QgsGeometry::fromWkb
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
Definition: qgsgeometry.cpp:332
QgsEditorWidgetSetup::config
QVariantMap config() const
Definition: qgseditorwidgetsetup.h:64
QgsArrayFilterExpressionFunction
Handles the array_filter(array, expression) expression function.
Definition: qgsexpressionfunction.h:533
QgsAggregateCalculator::StringConcatenateUnique
@ StringConcatenateUnique
Concatenate unique values with a joining string (string fields only). Specify the delimiter using set...
Definition: qgsaggregatecalculator.h:87
QgsArrayFilterExpressionFunction::prepare
bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
This will be called during the prepare step() of an expression if it is not static.
Definition: qgsexpressionfunction.cpp:6779
QgsMultiLineString
Multi line string geometry collection.
Definition: qgsmultilinestring.h:29
QgsRasterBandStats::mean
double mean
The mean cell value for the band. NO_DATA values are excluded.
Definition: qgsrasterbandstats.h:107
QgsGeometry::centroid
QgsGeometry centroid() const
Returns the center of mass of a geometry.
Definition: qgsgeometry.cpp:2153
QgsAggregateCalculator::CountMissing
@ CountMissing
Number of missing (null) values.
Definition: qgsaggregatecalculator.h:68
qgsmultipoint.h
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
qgsfieldformatterregistry.h
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:86
QgsPoint::z
double z
Definition: qgspoint.h:60
QgsVectorLayer::aggregate
QVariant aggregate(QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression, const QgsAggregateCalculator::AggregateParameters &parameters=QgsAggregateCalculator::AggregateParameters(), QgsExpressionContext *context=nullptr, bool *ok=nullptr, QgsFeatureIds *fids=nullptr) const
Calculates an aggregated value from the layer's features.
Definition: qgsvectorlayer.cpp:4268
QgsHstoreUtils::parse
CORE_EXPORT QVariantMap parse(const QString &string)
Returns a QVariantMap object containing the key and values from a hstore-formatted string.
Definition: qgshstoreutils.cpp:20
qgis.h
QgsDistanceArea::measureArea
double measureArea(const QgsGeometry &geometry) const
Measures the area of a geometry.
Definition: qgsdistancearea.cpp:183
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsRelationManager::relation
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Definition: qgsrelationmanager.cpp:96
QgsPoint::inclination
double inclination(const QgsPoint &other) const
Calculates Cartesian inclination between this point and other one (starting from zenith = 0 to nadir ...
Definition: qgspoint.cpp:673
QgsRegularPolygon::InscribedCircle
@ InscribedCircle
Definition: qgsregularpolygon.h:51
QgsQuadrilateral::Projected
@ Projected
Definition: qgsquadrilateral.h:68
QgsRasterBandStats::range
double range
The range is the distance between min & max.
Definition: qgsrasterbandstats.h:110
QgsAggregateCalculator::ArrayAggregate
@ ArrayAggregate
Create an array of values.
Definition: qgsaggregatecalculator.h:86
QgsTransaction::executeSql
virtual bool executeSql(const QString &sql, QString &error, bool isDirty=false, const QString &name=QString())=0
Execute the sql string.
qgsunittypes.h
QgsVectorDataProvider::transaction
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
Definition: qgsvectordataprovider.cpp:621
QgsMapLayer::abstract
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:302
QgsAggregateCalculator::Count
@ Count
Count.
Definition: qgsaggregatecalculator.h:66
QgsGeometry::rotate
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Definition: qgsgeometry.cpp:803
QgsStringUtils::hammingDistance
static int hammingDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Hamming distance between two strings.
Definition: qgsstringutils.cpp:277
QgsWithVariableExpressionFunction::func
QVariant func(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node) override
Returns result of evaluating the function.
Definition: qgsexpressionfunction.cpp:6865
QgsGeometry::minimalEnclosingCircle
QgsGeometry minimalEnclosingCircle(QgsPointXY &center, double &radius, unsigned int segments=36) const
Returns the minimal enclosing circle for the geometry.
Definition: qgsgeometry.cpp:1084
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:306
QgsExpression::BuiltinFunctions
static const QStringList & BuiltinFunctions()
Definition: qgsexpressionfunction.cpp:6603
QgsAbstractMetadataBase::title
QString title() const
Returns the human readable name of the resource, typically displayed in search results.
Definition: qgsabstractmetadatabase.cpp:51
QgsExpressionNode::NodeList::at
QgsExpressionNode * at(int i)
Gets the node at position i in the list.
Definition: qgsexpressionnode.h:151
QgsTransaction
Definition: qgstransaction.h:56
QgsInterval::months
double months() const
Returns the interval duration in months (based on a 30 day month).
Definition: qgsinterval.h:103
sqlite3_statement_unique_ptr::columnAsInt64
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).
Definition: qgssqliteutils.cpp:73
QgsAbstractGeometry::partCount
virtual int partCount() const =0
Returns count of parts contained in the geometry.
fcnRampColor
QVariant fcnRampColor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction *)
Definition: qgsexpressionfunction.cpp:4504
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:43
QgsProject::mapLayer
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Definition: qgsproject.cpp:3124
QgsDataProvider::dataSourceUri
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
Definition: qgsdataprovider.h:142
QgsGeometry::overlaps
bool overlaps(const QgsGeometry &geometry) const
Returns true if the geometry overlaps another geometry.
Definition: qgsgeometry.cpp:1267
QgsAggregateCalculator::AggregateParameters::orderBy
QgsFeatureRequest::OrderBy orderBy
Optional order by clauses.
Definition: qgsaggregatecalculator.h:113
QgsVectorLayer::featureCount
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
Definition: qgsvectorlayer.cpp:751
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:57
QgsGeometry::buffer
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
Definition: qgsgeometry.cpp:1919
QgsExpressionContext::variable
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
Definition: qgsexpressioncontext.cpp:296
sqlite3_database_unique_ptr::errorMessage
QString errorMessage() const
Returns the most recent error message encountered by the database.
Definition: qgssqliteutils.cpp:94
QgsField::name
QString name
Definition: qgsfield.h:59
Q_GLOBAL_STATIC
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
QgsExpressionContext::setCachedValue
void setCachedValue(const QString &key, const QVariant &value) const
Sets a value to cache within the expression context.
Definition: qgsexpressioncontext.cpp:575
QgsMultiPointXY
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:80
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:143
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:99
qgsogcutils.h
QgsMapLayer::dataUrl
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:338
QgsExpressionContext::fields
QgsFields fields() const
Convenience function for retrieving the fields for the context, if set.
Definition: qgsexpressioncontext.cpp:561
QgsGeometryUtils::extractLineStrings
static QVector< QgsLineString * > extractLineStrings(const QgsAbstractGeometry *geom)
Returns list of linestrings extracted from the passed geometry.
Definition: qgsgeometryutils.cpp:31
QgsGeometry::mergeLines
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
Definition: qgsgeometry.cpp:2436
QgsArrayForeachExpressionFunction::prepare
bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
This will be called during the prepare step() of an expression if it is not static.
Definition: qgsexpressionfunction.cpp:6684
QgsRasterBandStats::Range
@ Range
Definition: qgsrasterbandstats.h:68
QgsGeometry::distanceToVertex
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
Definition: qgsgeometry.cpp:414
QgsGeometry::intersection
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
Definition: qgsgeometry.cpp:2395
QgsExpressionFunction::handlesNull
virtual bool handlesNull() const
Returns true if the function handles NULL values in arguments by itself, and the default NULL value h...
Definition: qgsexpressionfunction.cpp:149
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:229
sqlite3_statement_unique_ptr::step
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
Definition: qgssqliteutils.cpp:41
QgsFeatureRequest::setFilterFid
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
Definition: qgsfeaturerequest.cpp:103
QgsOgcUtils::Context::transformContext
QgsCoordinateTransformContext transformContext
Definition: qgsogcutils.h:70
QgsMapToPixelSimplifier::Visvalingam
@ Visvalingam
The simplification gives each point in a line an importance weighting, so that least important points...
Definition: qgsmaptopixelgeometrysimplifier.h:46
QgsMapLayer::providerType
QString providerType() const
Returns the provider type (provider key) for this layer.
Definition: qgsmaplayer.cpp:1614
QgsRelation::referencingLayer
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:129
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:111
QgsExpressionFunction::aliases
virtual QStringList aliases() const
Returns a list of possible aliases for the function.
Definition: qgsexpressionfunction.cpp:112
QgsGeometry::nearestPoint
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest point on this geometry to another geometry.
Definition: qgsgeometry.cpp:610
QgsQuadrilateral::Distance
@ Distance
Definition: qgsquadrilateral.h:67
QgsAbstractGeometry::vertexAt
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
QgsExpressionFunction::referencedColumns
virtual QSet< QString > referencedColumns(const QgsExpressionNodeFunction *node) const
Returns a set of field names which are required for this function.
Definition: qgsexpressionfunction.cpp:133
QgsRelationManager::relationsByName
QList< QgsRelation > relationsByName(const QString &name) const
Returns a list of relations with matching names.
Definition: qgsrelationmanager.cpp:101
QgsDistanceArea::convertAreaMeasurement
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
Definition: qgsdistancearea.cpp:1156
qgsapplication.h
QgsExpression::quotedValue
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
Definition: qgsexpression.cpp:79
QgsRasterBandStats::maximumValue
double maximumValue
The maximum cell value in the raster band.
Definition: qgsrasterbandstats.h:99
QgsFeatureRequest::ALL_ATTRIBUTES
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
Definition: qgsfeaturerequest.h:295
QgsWkbTypes::PointM
@ PointM
Definition: qgswkbtypes.h:98
QgsArrayForeachExpressionFunction::isStatic
bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
Will be called during prepare to determine if the function is static.
Definition: qgsexpressionfunction.cpp:6622
QgsAggregateCalculator::InterQuartileRange
@ InterQuartileRange
Inter quartile range (IQR) (numeric fields only)
Definition: qgsaggregatecalculator.h:81
QgsGeometryCollection::createEmptyWithSameType
QgsGeometryCollection * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Definition: qgsgeometrycollection.cpp:111
QgsExpressionContext::cachedValue
QVariant cachedValue(const QString &key) const
Returns the matching cached value, if set.
Definition: qgsexpressioncontext.cpp:585
QgsGradientStopsList
QList< QgsGradientStop > QgsGradientStopsList
List of gradient stops.
Definition: qgscolorramp.h:127
QgsCoordinateFormatter::FormatDegreesMinutes
@ FormatDegreesMinutes
Degrees and decimal minutes, eg 30degrees 45.55'.
Definition: qgscoordinateformatter.h:51
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsEditorWidgetSetup::type
QString type() const
Definition: qgseditorwidgetsetup.h:59
QgsPoint::y
double y
Definition: qgspoint.h:59
QgsPoint::isValid
bool isValid(QString &error, int flags=0) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Definition: qgspoint.cpp:389
QgsExpression::setEvalErrorString
void setEvalErrorString(const QString &str)
Sets evaluation error (used internally by evaluation functions)
Definition: qgsexpression.cpp:384
QgsArrayFilterExpressionFunction::isStatic
bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
Will be called during prepare to determine if the function is static.
Definition: qgsexpressionfunction.cpp:6716
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsGeometryCollection
Geometry collection.
Definition: qgsgeometrycollection.h:35
QgsGeometry::poleOfInaccessibility
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
Definition: qgsgeometry.cpp:2192
QgsMapLayer::metadata
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:87
QgsAggregateCalculator::StDevSample
@ StDevSample
Sample standard deviation of values (numeric fields only)
Definition: qgsaggregatecalculator.h:75
qgsgeometryengine.h
QgsExpression::hasEvalError
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Definition: qgsexpression.cpp:374
QgsGeometry::intersects
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
Definition: qgsgeometry.cpp:1144
QgsCsException
Definition: qgsexception.h:65
QgsWkbTypes::PointZM
@ PointZM
Definition: qgswkbtypes.h:111
QgsLineString::clone
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgslinestring.cpp:293
QgsExpression::unregisterFunction
static bool unregisterFunction(const QString &name)
Unregisters a function from the expression engine.
Definition: qgsexpressionfunction.cpp:6581
QgsStaticExpressionFunction::isStatic
bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
Will be called during prepare to determine if the function is static.
Definition: qgsexpressionfunction.cpp:196
QgsWithVariableExpressionFunction::run
QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node) override
Evaluates the function, first evaluating all required arguments before passing them to the function's...
Definition: qgsexpressionfunction.cpp:6836
QgsGeometryCollection::partCount
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgsgeometrycollection.cpp:823
QgsArrayForeachExpressionFunction::func
QVariant func(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node) override
Returns result of evaluating the function.
Definition: qgsexpressionfunction.cpp:6672
QgsWkbTypes::geometryDisplayString
static QString geometryDisplayString(GeometryType type)
Returns a display string for a geometry type.
Definition: qgswkbtypes.cpp:155
qgshstoreutils.h
QgsExpressionFunction::Parameter
Definition: qgsexpressionfunction.h:54
qgsexpressionsorter.h
QgsExpressionFunction::ParameterList
QList< QgsExpressionFunction::Parameter > ParameterList
List of parameters, used for function definition.
Definition: qgsexpressionfunction.h:104
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsMapLayer::dataProvider
virtual QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Definition: qgsmaplayer.cpp:169
QgsMapLayer::keywordList
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:318
qgsmultipolygon.h
QgsExpressionNode::eval
QVariant eval(QgsExpression *parent, const QgsExpressionContext *context)
Evaluate this node with the given context and parent.
Definition: qgsexpressionnode.cpp:20
QgsFeature::setGeometry
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:137
qgsproviderregistry.h
QgsAbstractMetadataBase::abstract
QString abstract() const
Returns a free-form description of the resource.
Definition: qgsabstractmetadatabase.cpp:61
QgsStaticExpressionFunction::setIsStaticFunction
void setIsStaticFunction(const std::function< bool(const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext *) > &isStatic)
Set a function that will be called in the prepare step to determine if the function is static or not.
Definition: qgsexpressionfunction.cpp:212
QgsStaticExpressionFunction::referencedColumns
QSet< QString > referencedColumns(const QgsExpressionNodeFunction *node) const override
Returns a set of field names which are required for this function.
Definition: qgsexpressionfunction.cpp:188
QgsGeometry::extendLine
QgsGeometry extendLine(double startDistance, double endDistance) const
Extends a (multi)line geometry by extrapolating out the start or end of the line by a specified dista...
Definition: qgsgeometry.cpp:2073
QgsExpressionNodeFunction::args
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
Definition: qgsexpressionnodeimpl.h:336
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
QgsGeometry::offsetCurve
QgsGeometry offsetCurve(double distance, int segments, JoinStyle joinStyle, double miterLimit) const
Returns an offset line at a given distance and side from an input line.
Definition: qgsgeometry.cpp:1957
QgsGeometry::smooth
QgsGeometry smooth(unsigned int iterations=1, double offset=0.25, double minimumDistance=-1.0, double maxAngle=180.0) const
Smooths a geometry by rounding off corners using the Chaikin algorithm.
Definition: qgsgeometry.cpp:3171
qgscolorramp.h
qHash
uint qHash(const QVariant &variant)
Hash for QVariant.
Definition: qgis.cpp:219
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsExpressionNode::referencedColumns
virtual QSet< QString > referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node.
QgsRasterDataProvider::sample
virtual double sample(const QgsPointXY &point, int band, bool *ok=nullptr, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Samples a raster value from the specified band found at the point position.
Definition: qgsrasterdataprovider.cpp:316
QgsMapLayer::extent
virtual QgsRectangle extent() const
Returns the extent of the layer.
Definition: qgsmaplayer.cpp:197
QgsGeometryCollection::addGeometry
virtual bool addGeometry(QgsAbstractGeometry *g)
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsgeometrycollection.cpp:226
QgsGeometry::variableWidthBufferByM
QgsGeometry variableWidthBufferByM(int segments) const
Calculates a variable width buffer for a (multi)linestring geometry, where the width at each node is ...
Definition: qgsgeometry.cpp:2066
qgsRound
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition: qgis.h:363
QgsRelation::referencedLayer
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:47
QgsException::what
QString what() const
Definition: qgsexception.h:48
QgsGeometry::taperedBuffer
QgsGeometry taperedBuffer(double startWidth, double endWidth, int segments) const
Calculates a variable width buffer ("tapered buffer") for a (multi)curve geometry.
Definition: qgsgeometry.cpp:2059
QgsExpressionFunction::operator==
bool operator==(const QgsExpressionFunction &other) const
Definition: qgsexpressionfunction.cpp:144
QgsCurve::curveSubstring
virtual QgsCurve * curveSubstring(double startDistance, double endDistance) const =0
Returns a new curve representing a substring of this curve.
QgsMapLayerType::RasterLayer
@ RasterLayer
QgsSqliteUtils::quotedValue
static QString quotedValue(const QVariant &value)
Returns a properly quoted and escaped version of value for use in SQL strings.
Definition: qgssqliteutils.cpp:223
QgsVectorLayer::selectedFeatureIds
const Q_INVOKABLE QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Definition: qgsvectorlayer.cpp:3433
QgsAggregateCalculator::StringMinimumLength
@ StringMinimumLength
Minimum length of string (string fields only)
Definition: qgsaggregatecalculator.h:82
QgsCoordinateReferenceSystem::authid
QString authid() const
Returns the authority identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1299
QgsAbstractGeometry::clone
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QgsRasterBandStats::StdDev
@ StdDev
Definition: qgsrasterbandstats.h:71
QgsExpressionNode::referencedVariables
virtual QSet< QString > referencedVariables() const =0
Returns a set of all variables which are used in this expression.
qgstriangle.h
qgsexpressionutils.h
QgsGeometry::convexHull
QgsGeometry convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry.
Definition: qgsgeometry.cpp:2199
ENSURE_NO_EVAL_ERROR
#define ENSURE_NO_EVAL_ERROR
Definition: qgsexpressionutils.h:31
QgsLayerMetadata::rights
QStringList rights() const
Returns a list of attribution or copyright strings associated with the resource.
Definition: qgslayermetadata.cpp:51
qgsexpressionfunction.h
QgsWkbTypes::PointZ
@ PointZ
Definition: qgswkbtypes.h:85
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:902
QgsWithVariableExpressionFunction::QgsWithVariableExpressionFunction
QgsWithVariableExpressionFunction()
Definition: qgsexpressionfunction.cpp:6801
QgsProviderRegistry::decodeUri
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
Definition: qgsproviderregistry.cpp:431
QgsPoint::m
double m
Definition: qgspoint.h:61
QgsGeometry::length
double length() const
Returns the planar, 2-dimensional length of geometry.
Definition: qgsgeometry.cpp:1798
QgsRasterBandStats::Min
@ Min
Definition: qgsrasterbandstats.h:66
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QgsMapLayer::isEditable
virtual bool isEditable() const
Returns true if the layer can be edited.
Definition: qgsmaplayer.cpp:1735
qgsquadrilateral.h
QgsQuadrilateral::squareFromDiagonal
static QgsQuadrilateral squareFromDiagonal(const QgsPoint &p1, const QgsPoint &p2)
Construct a QgsQuadrilateral as a square from a diagonal.
Definition: qgsquadrilateral.cpp:159
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:148
QgsAbstractGeometry::is3D
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:202
QgsMapToPixelSimplifier::SimplifyGeometry
@ SimplifyGeometry
The geometries can be simplified using the current map2pixel context state.
Definition: qgsmaptopixelgeometrysimplifier.h:57
QgsCoordinateFormatter::formatY
static QString formatY(double y, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats a y coordinate value according to the specified parameters.
Definition: qgscoordinateformatter.cpp:42
QgsGeometry::isEmpty
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Definition: qgsgeometry.cpp:367
QgsGeometry::extrude
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
Definition: qgsgeometry.cpp:2496
QgsMapLayer::title
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:286
qgsvectorlayerfeatureiterator.h
qgsregularpolygon.h
QgsArrayForeachExpressionFunction
Handles the array_foreach(array, expression) expression function.
Definition: qgsexpressionfunction.h:510
QgsGeometry::crosses
bool crosses(const QgsGeometry &geometry) const
Returns true if the geometry crosses another geometry.
Definition: qgsgeometry.cpp:1291
QgsAbstractGeometry::nCoordinates
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
Definition: qgsabstractgeometry.cpp:116
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:125
QgsWeakMapLayerPointer
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1670
QgsStaticExpressionFunction
Definition: qgsexpressionfunction.h:349
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:128
QgsAggregateCalculator::Median
@ Median
Median of values (numeric fields only)
Definition: qgsaggregatecalculator.h:73
QgsRegularPolygon::ConstructionOption
ConstructionOption
A regular polygon can be constructed inscribed in a circle or circumscribed about a circle.
Definition: qgsregularpolygon.h:49
QgsRasterLayer
Definition: qgsrasterlayer.h:72
QgsAggregateCalculator::Max
@ Max
Max of values.
Definition: qgsaggregatecalculator.h:70
QgsRasterBandStats::Mean
@ Mean
Definition: qgsrasterbandstats.h:70
QgsGeometry::SideLeft
@ SideLeft
Buffer to left of line.
Definition: qgsgeometry.h:1110
QgsCoordinateReferenceSystem::toProj
QString toProj() const
Returns a Proj string representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1398
QgsExpressionNodeFunction
An expression node for expression functions.
Definition: qgsexpressionnodeimpl.h:316
QgsFeatureRequest::setTimeout
QgsFeatureRequest & setTimeout(int timeout)
Sets the timeout (in milliseconds) for the maximum time we should wait during feature requests before...
Definition: qgsfeaturerequest.cpp:325
QgsExpressionFunction::isDeprecated
virtual bool isDeprecated() const
Returns true if the function is deprecated and should not be presented as a valid option to users in ...
Definition: qgsexpressionfunction.cpp:139
QgsInterval::minutes
double minutes() const
Returns the interval duration in minutes.
Definition: qgsinterval.h:155
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:48
QgsGeometry::pointOnSurface
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
Definition: qgsgeometry.cpp:2177
qgscurvepolygon.h
QgsMapLayer::minimumScale
double minimumScale() const
Returns the minimum map scale (i.e.
Definition: qgsmaplayer.cpp:741
QgsGeometry::touches
bool touches(const QgsGeometry &geometry) const
Returns true if the geometry touches another geometry.
Definition: qgsgeometry.cpp:1255
QgsCurvePolygon::isEmpty
bool isEmpty() const override
Returns true if the geometry is empty.
Definition: qgscurvepolygon.cpp:893
QgsGeometry::fromWkt
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
Definition: qgsgeometry.cpp:154
QgsMultiPoint
Multi point geometry collection.
Definition: qgsmultipoint.h:29
QgsMapLayer::maximumScale
double maximumScale() const
Returns the maximum map scale (i.e.
Definition: qgsmaplayer.cpp:725
sqlite3_database_unique_ptr::open_v2
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
Definition: qgssqliteutils.cpp:86
QgsAggregateCalculator::StringConcatenate
@ StringConcatenate
Concatenate values with a joining string (string fields only). Specify the delimiter using setDelimit...
Definition: qgsaggregatecalculator.h:84
QgsRasterBandStats::Sum
@ Sum
Definition: qgsrasterbandstats.h:69
QgsExpression::Functions
static const QList< QgsExpressionFunction * > & Functions()
Definition: qgsexpressionfunction.cpp:5649
QgsCoordinateReferenceSystem
Definition: qgscoordinatereferencesystem.h:206
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:71
QgsRectangle::yMaximum
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsExpressionFunction::prepare
virtual bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const
This will be called during the prepare step() of an expression if it is not static.
Definition: qgsexpressionfunction.cpp:125
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsGeometry::simplify
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
Definition: qgsgeometry.cpp:2113
QgsApplication::fieldFormatterRegistry
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
Definition: qgsapplication.cpp:2219
qgsstyle.h
qgsgeometryutils.h
QgsGeometry::vertexAt
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Definition: qgsgeometry.cpp:588
QgsMapToPixelSimplifier
Definition: qgsmaptopixelgeometrysimplifier.h:38
QgsExpressionNode::NodeList::list
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
Definition: qgsexpressionnode.h:144
QgsStaticExpressionFunction::usesGeometry
bool usesGeometry(const QgsExpressionNodeFunction *node) const override
Does this function use a geometry object.
Definition: qgsexpressionfunction.cpp:180
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:490
qgsvectorlayer.h
QgsPointXY
Definition: qgspointxy.h:43
QgsOgcUtils::geometryFromGML
static QgsGeometry geometryFromGML(const QString &xmlString, const QgsOgcUtils::Context &context=QgsOgcUtils::Context())
Static method that creates geometry from GML.
Definition: qgsogcutils.cpp:167
QgsRasterBandStats::sum
double sum
The sum of all cells in the band. NO_DATA values are excluded.
Definition: qgsrasterbandstats.h:119
QgsRasterBandStats::minimumValue
double minimumValue
The minimum cell value in the raster band.
Definition: qgsrasterbandstats.h:104
QgsExpressionNode
Definition: qgsexpressionnode.h:34
QgsAggregateCalculator::Mean
@ Mean
Mean of values (numeric fields only)
Definition: qgsaggregatecalculator.h:72
QgsExpression::functionIndex
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
Definition: qgsexpression.cpp:123
QgsGeometry::hausdorffDistance
double hausdorffDistance(const QgsGeometry &geom) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeometry.cpp:1827
QgsCurve::clone
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
QgsInterval::weeks
double weeks() const
Returns the interval duration in weeks.
Definition: qgsinterval.h:116
QgsOgcUtils::Context::layer
const QgsMapLayer * layer
Definition: qgsogcutils.h:69
QgsGeometry::asPoint
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Definition: qgsgeometry.cpp:1559
QgsExpression::areaUnits
QgsUnitTypes::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), e.g.,...
Definition: qgsexpression.cpp:420
QgsExpression::distanceUnits
QgsUnitTypes::DistanceUnit distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), e....
Definition: qgsexpression.cpp:410
QgsRasterBandStats::Max
@ Max
Definition: qgsrasterbandstats.h:67
qgstransaction.h
QgsStringUtils::soundex
static QString soundex(const QString &string)
Returns the Soundex representation of a string.
Definition: qgsstringutils.cpp:316
QgsMapLayer::publicSource
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
Definition: qgsmaplayer.cpp:184
QgsExpressionNode::isStatic
virtual bool isStatic(QgsExpression *parent, const QgsExpressionContext *context) const =0
Returns true if this node can be evaluated for a static value.
QgsCoordinateFormatter::FormatDegreesMinutesSeconds
@ FormatDegreesMinutesSeconds
Degrees, minutes and seconds, eg 30 degrees 45'30".
Definition: qgscoordinateformatter.h:50
QgsGeometry::createGeometryEngine
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
Definition: qgsgeometry.cpp:3659
QgsAggregateCalculator::ThirdQuartile
@ ThirdQuartile
Third quartile (numeric fields only)
Definition: qgsaggregatecalculator.h:80
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:142
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:76
QgsCoordinateFormatter::FlagDegreesUseStringSuffix
@ FlagDegreesUseStringSuffix
Include a direction suffix (eg 'N', 'E', 'S' or 'W'), otherwise a "-" prefix is used for west and sou...
Definition: qgscoordinateformatter.h:60
QgsGeometry::asWkt
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Definition: qgsgeometry.cpp:1303
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
QgsGeometry::interpolateAngle
double interpolateAngle(double distance) const
Returns the angle parallel to the linestring or polygon boundary at the specified distance along the ...
Definition: qgsgeometry.cpp:2341
QgsExpressionFunction::usesGeometry
virtual bool usesGeometry(const QgsExpressionNodeFunction *node) const
Does this function use a geometry object.
Definition: qgsexpressionfunction.cpp:106
QgsCoordinateReferenceSystem::mapUnits
QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:210
QgsFeatureRequest::setRequestMayBeNested
QgsFeatureRequest & setRequestMayBeNested(bool requestMayBeNested)
In case this request may be run nested within another already running iteration on the same connectio...
Definition: qgsfeaturerequest.cpp:336
QgsCurve::isClosed
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsGeometryCollection::geometryN
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Definition: qgsgeometrycollection.h:79
QgsVectorLayer::mapTipTemplate
QString mapTipTemplate
Definition: qgsvectorlayer.h:391
QgsExpressionFunction::lazyEval
bool lazyEval() const
true if this function should use lazy evaluation.
Definition: qgsexpressionfunction.h:232
QgsRectangle::center
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
ExpressionFunctionList
QList< QgsExpressionFunction * > ExpressionFunctionList
Definition: qgsexpressionfunction.cpp:62
QgsAggregateCalculator::Aggregate
Aggregate
Available aggregates to calculate.
Definition: qgsaggregatecalculator.h:64
qgsthreadingutils.h
qgsexpressionnodeimpl.h
QgsFeatureRequest::OrderBy
Definition: qgsfeaturerequest.h:242
QgsExpressionNodeColumnRef::name
QString name() const
The name of the column.
Definition: qgsexpressionnodeimpl.h:414
QgsGeometry::shortestLine
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Definition: qgsgeometry.cpp:619
QgsExpressionFunction::run
virtual QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node)
Evaluates the function, first evaluating all required arguments before passing them to the function's...
Definition: qgsexpressionfunction.cpp:73
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsDistanceArea::measurePerimeter
double measurePerimeter(const QgsGeometry &geometry) const
Measures the perimeter of a polygon geometry.
Definition: qgsdistancearea.cpp:201
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:44
qgscurve.h
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsGeometry
Definition: qgsgeometry.h:122
QgsExpressionFunction
Definition: qgsexpressionfunction.h:40
QgsThreadingUtils::runOnMainThread
static bool runOnMainThread(const Func &func, QgsFeedback *feedback=nullptr)
Guarantees that func is executed on the main thread.
Definition: qgsthreadingutils.h:56
QgsAggregateCalculator::Majority
@ Majority
Majority of values.
Definition: qgsaggregatecalculator.h:78
QgsStaticExpressionFunction::prepare
bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
This will be called during the prepare step() of an expression if it is not static.
Definition: qgsexpressionfunction.cpp:204
QgsRegularPolygon
Regular Polygon geometry type.
Definition: qgsregularpolygon.h:41
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsGeometry::JoinStyleRound
@ JoinStyleRound
Use rounded joins.
Definition: qgsgeometry.h:1127
QgsDistanceArea::convertLengthMeasurement
double convertLengthMeasurement(double length, QgsUnitTypes::DistanceUnit toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
Definition: qgsdistancearea.cpp:1142
QgsFeatureRequest::setLimit
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
Definition: qgsfeaturerequest.cpp:178
QgsArrayForeachExpressionFunction::run
QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node) override
Evaluates the function, first evaluating all required arguments before passing them to the function's...
Definition: qgsexpressionfunction.cpp:6638
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsCoordinateFormatter::Format
Format
Available formats for displaying coordinates.
Definition: qgscoordinateformatter.h:47
QgsGeometry::singleSidedBuffer
QgsGeometry singleSidedBuffer(double distance, int segments, BufferSide side, JoinStyle joinStyle=JoinStyleRound, double miterLimit=2.0) const
Returns a single sided buffer for a (multi)line geometry.
Definition: qgsgeometry.cpp:2015
sqlite3_database_unique_ptr::exec
int exec(const QString &sql, QString &errorMessage) const
Executes the sql command in the database.
Definition: qgssqliteutils.cpp:109
QgsCurvePolygon::ringCount
int ringCount(int part=0) const override
Returns the number of rings of which this geometry is built.
Definition: qgscurvepolygon.cpp:1134
QgsRelation::isValid
bool isValid
Definition: qgsrelation.h:49
QgsPointXY::x
double x
Definition: qgspointxy.h:47
QgsExpressionContext::feature
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
Definition: qgsexpressioncontext.cpp:540
QgsInterval
A representation of the interval between two datetime values.
Definition: qgsinterval.h:40
QgsGeometry::translate
OperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
Definition: qgsgeometry.cpp:790
QgsExpressionFunction::name
QString name() const
The name of the function.
Definition: qgsexpressionfunction.h:190
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1033
QgsInterval::years
double years() const
Returns the interval duration in years (based on an average year length)
Definition: qgsinterval.h:90
QgsFieldFormatterRegistry::fieldFormatter
QgsFieldFormatter * fieldFormatter(const QString &id) const
Gets a field formatter by its id.
Definition: qgsfieldformatterregistry.cpp:72
qgsmaptopixelgeometrysimplifier.h
QgsExpression::helpText
static QString helpText(QString name)
Returns the help text for a specified function.
Definition: qgsexpression.cpp:531
QgsGeometry::forceRHR
QgsGeometry forceRHR() const
Forces geometries to respect the Right-Hand-Rule, in which the area that is bounded by a polygon is t...
Definition: qgsgeometry.cpp:2651
QgsRectangle::height
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QgsColorRamp::color
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Added in 3.14.
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
QgsRectangle::yMinimum
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
QgsStringUtils::wordWrap
static QString wordWrap(const QString &string, int length, bool useMaxLineLength=true, const QString &customDelimiter=QString())
Automatically wraps a string by inserting new line characters at appropriate locations in the string.
Definition: qgsstringutils.cpp:580
QgsAbstractGeometry::isMeasure
bool isMeasure() const
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:211
QgsAggregateCalculator::stringToAggregate
static Aggregate stringToAggregate(const QString &string, bool *ok=nullptr)
Converts a string to a aggregate type.
Definition: qgsaggregatecalculator.cpp:130
QgsRelation
Definition: qgsrelation.h:41
QgsGeometry::asMultiPoint
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
Definition: qgsgeometry.cpp:1655
QgsRasterBandStats::stdDev
double stdDev
The standard deviation of the cell values.
Definition: qgsrasterbandstats.h:113
QgsExpression::needsGeometry
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
Definition: qgsexpression.cpp:266
QgsAbstractGeometry::boundary
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
QgsVectorLayer::storageType
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
Definition: qgsvectorlayer.cpp:340
QgsInterval::days
double days() const
Returns the interval duration in days.
Definition: qgsinterval.h:129
QgsGeometry::createWedgeBuffer
static QgsGeometry createWedgeBuffer(const QgsPoint &center, double azimuth, double angularWidth, double outerRadius, double innerRadius=0)
Creates a wedge shaped buffer from a center point.
Definition: qgsgeometry.cpp:276
QgsExpressionFunction::allParamsStatic
static bool allParamsStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context)
This will return true if all the params for the provided function node are static within the constrai...
Definition: qgsexpressionfunction.cpp:228
QgsAbstractMetadataBase::KeywordMap
QMap< QString, QStringList > KeywordMap
Map of vocabulary string to keyword list.
Definition: qgsabstractmetadatabase.h:78
QgsAggregateCalculator::FirstQuartile
@ FirstQuartile
First quartile (numeric fields only)
Definition: qgsaggregatecalculator.h:79
FEAT_FROM_CONTEXT
#define FEAT_FROM_CONTEXT(c, f)
Definition: qgsexpressionutils.h:34
QgsArrayFilterExpressionFunction::run
QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node) override
Evaluates the function, first evaluating all required arguments before passing them to the function's...
Definition: qgsexpressionfunction.cpp:6732
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:962
QgsExpression::registerFunction
static bool registerFunction(QgsExpressionFunction *function, bool transferOwnership=false)
Registers a function to the expression engine.
Definition: qgsexpressionfunction.cpp:6568
QgsMultiLineString::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultilinestring.cpp:121
QgsDistanceArea
Definition: qgsdistancearea.h:49
QgsFeature::fields
QgsFields fields
Definition: qgsfeature.h:70
QgsInterval::hours
double hours() const
Returns the interval duration in hours.
Definition: qgsinterval.h:142
QgsGeometry::vertexIdFromVertexNr
bool vertexIdFromVertexNr(int number, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
Definition: qgsgeometry.cpp:2973
qgsexception.h
QgsAggregateCalculator::Sum
@ Sum
Sum of values.
Definition: qgsaggregatecalculator.h:71
qgsdistancearea.h
QgsArrayForeachExpressionFunction::QgsArrayForeachExpressionFunction
QgsArrayForeachExpressionFunction()
Definition: qgsexpressionfunction.cpp:6613
QgsAggregateCalculator::AggregateParameters::filter
QString filter
Optional filter for calculating aggregate over a subset of features, or an empty string to use all fe...
Definition: qgsaggregatecalculator.h:100
QgsAggregateCalculator::GeometryCollect
@ GeometryCollect
Create a multipart geometry from aggregated geometries.
Definition: qgsaggregatecalculator.h:85
QgsGeometry::JoinStyle
JoinStyle
Join styles for buffers.
Definition: qgsgeometry.h:1125
QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds
@ FlagDegreesPadMinutesSeconds
Pad minute and second values with leading zeros, eg '05' instead of '5'.
Definition: qgscoordinateformatter.h:61
QgsFeature
Definition: qgsfeature.h:55
QgsExpressionFunction::isStatic
virtual bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const
Will be called during prepare to determine if the function is static.
Definition: qgsexpressionfunction.cpp:117
QgsArrayFilterExpressionFunction::func
QVariant func(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node) override
Returns result of evaluating the function.
Definition: qgsexpressionfunction.cpp:6767
QgsStringUtils::levenshteinDistance
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings.
Definition: qgsstringutils.cpp:132
QgsGeometry::symDifference
QgsGeometry symDifference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other.
Definition: qgsgeometry.cpp:2476
QgsGeometry::contains
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
Definition: qgsgeometry.cpp:1199
ENSURE_GEOM_TYPE
#define ENSURE_GEOM_TYPE(f, g, geomtype)
Definition: qgsexpressionfunction.cpp:2256
QgsGeometry::vertices_end
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Definition: qgsgeometry.cpp:1858
QgsRelation::getRelatedFeaturesFilter
QString getRelatedFeaturesFilter(const QgsFeature &feature) const
Returns a filter expression which returns all the features on the referencing (child) layer which hav...
Definition: qgsrelation.cpp:215
QgsVectorLayer::selectedFeatureCount
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
Definition: qgsvectorlayer.cpp:3428
QgsGeometry::isGeosValid
bool isGeosValid(QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Checks validity of the geometry using GEOS.
Definition: qgsgeometry.cpp:2734
QgsCurve::segmentize
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:159
QgsGeometry::vertices_begin
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsgeometry.cpp:1851
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:324
QgsCoordinateFormatter::formatX
static QString formatX(double x, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats an x coordinate value according to the specified parameters.
Definition: qgscoordinateformatter.cpp:23
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:118
QgsField::editorWidgetSetup
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:496
QgsFields::at
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
QgsGeometry::orientedMinimumBoundingBox
QgsGeometry orientedMinimumBoundingBox(double &area, double &angle, double &width, double &height) const
Returns the oriented minimum bounding box for the geometry, which is the smallest (by area) rotated r...
Definition: qgsgeometry.cpp:971
QgsExpression::cleanRegisteredFunctions
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine.
Definition: qgsexpressionfunction.cpp:6597
QgsExpression
Definition: qgsexpression.h:113
qgscoordinateformatter.h
QgsVectorLayer::displayExpression
QString displayExpression
Definition: qgsvectorlayer.h:390
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
QgsArrayFilterExpressionFunction::QgsArrayFilterExpressionFunction
QgsArrayFilterExpressionFunction()
Definition: qgsexpressionfunction.cpp:6707
sqlite3_database_unique_ptr
Definition: qgssqliteutils.h:118
QgsGeometry::type
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:126
QgsExpressionNode::prepare
bool prepare(QgsExpression *parent, const QgsExpressionContext *context)
Prepare this node for evaluation.
Definition: qgsexpressionnode.cpp:33
QgsWithVariableExpressionFunction::prepare
bool prepare(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
This will be called during the prepare step() of an expression if it is not static.
Definition: qgsexpressionfunction.cpp:6877
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:659
QgsProviderRegistry::instance
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Definition: qgsproviderregistry.cpp:48
QgsGeometry::area
double area() const
Returns the planar, 2-dimensional area of the geometry.
Definition: qgsgeometry.cpp:1775
QgsAbstractMetadataBase::keywords
QgsAbstractMetadataBase::KeywordMap keywords() const
Returns the keywords map, which is a set of descriptive keywords associated with the resource.
Definition: qgsabstractmetadatabase.cpp:86
QgsExpression::replaceExpressionText
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
Definition: qgsexpression.cpp:430
QgsGeometryCollection::removeGeometry
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
Definition: qgsgeometrycollection.cpp:252
QgsExpressionNode::NodeList::count
int count() const
Returns the number of nodes in the list.
Definition: qgsexpressionnode.h:133
QgsRegularPolygon::toPolygon
QgsPolygon * toPolygon() const
Returns as a polygon.
Definition: qgsregularpolygon.cpp:183
QgsFieldFormatter
Definition: qgsfieldformatter.h:72
QgsFeatureRequest::setFlags
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Definition: qgsfeaturerequest.cpp:184
QgsSqliteUtils::quotedIdentifier
static QString quotedIdentifier(const QString &identifier)
Returns a properly quoted version of identifier.
Definition: qgssqliteutils.cpp:216
QgsAggregateCalculator::StringMaximumLength
@ StringMaximumLength
Maximum length of string (string fields only)
Definition: qgsaggregatecalculator.h:83
QgsStaticExpressionFunction::setIsStatic
void setIsStatic(bool isStatic)
Tag this function as either static or not static.
Definition: qgsexpressionfunction.cpp:217
QgsStaticExpressionFunction::QgsStaticExpressionFunction
QgsStaticExpressionFunction(const QString &fnname, int params, FcnEval fcn, const QString &group, const QString &helpText=QString(), bool usesGeometry=false, const QSet< QString > &referencedColumns=QSet< QString >(), bool lazyEval=false, const QStringList &aliases=QStringList(), bool handlesNull=false)
Static function for evaluation against a QgsExpressionContext, using an unnamed list of parameter val...
Definition: qgsexpressionfunction.h:356
QgsMapLayer::type
QgsMapLayerType type() const
Returns the type of the layer.
Definition: qgsmaplayer.cpp:129
QgsInterval::isValid
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:181
QgsPoint::x
double x
Definition: qgspoint.h:58
QgsGradientStop
Represents a color stop within a QgsGradientColorRamp color ramp.
Definition: qgscolorramp.h:101
QgsRectangle::width
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsGeometry::difference
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other.
Definition: qgsgeometry.cpp:2456
QgsMapLayerType::PluginLayer
@ PluginLayer
sqlite3_statement_unique_ptr
Definition: qgssqliteutils.h:69
QgsGeometry::JoinStyleBevel
@ JoinStyleBevel
Use beveled joins.
Definition: qgsgeometry.h:1129
QgsRasterLayer::dataProvider
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Definition: qgsrasterlayer.cpp:233
QgsRectangle::xMinimum
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
qgsmultilinestring.h
qgsfieldformatter.h
QgsOgcUtils::Context
The Context struct stores the current layer and coordinate transform context.
Definition: qgsogcutils.h:58
QgsTriangle
Triangle geometry type.
Definition: qgstriangle.h:33
QgsExpressionNode::NodeList
A list of expression nodes.
Definition: qgsexpressionnode.h:117
QgsGeometry::collectGeometry
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
Definition: qgsgeometry.cpp:247
QgsExpressionContext::hasFeature
bool hasFeature() const
Returns true if the context has a feature associated with it.
Definition: qgsexpressioncontext.cpp:529
QgsFeatureId
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
qgsmessagelog.h
QgsQuadrilateral::toPolygon
QgsPolygon * toPolygon(bool force2D=false) const
Returns the quadrilateral as a new polygon.
Definition: qgsquadrilateral.cpp:369
QgsStringUtils::longestCommonSubstring
static QString longestCommonSubstring(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the longest common substring between two strings.
Definition: qgsstringutils.cpp:214
QgsWithVariableExpressionFunction::isStatic
bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const override
Will be called during prepare to determine if the function is static.
Definition: qgsexpressionfunction.cpp:6811
QgsGeometry::lineLocatePoint
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
Definition: qgsgeometry.cpp:2322
QgsGeometry::disjoint
bool disjoint(const QgsGeometry &geometry) const
Returns true if the geometry is disjoint of another geometry.
Definition: qgsgeometry.cpp:1224