QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 "qgscoordinateutils.h"
21 #include "qgsexpressionfunction.h"
22 #include "qgsexpressionutils.h"
23 #include "qgsexpressionnodeimpl.h"
24 #include "qgsfeaturerequest.h"
25 #include "qgsstringutils.h"
26 #include "qgsmultipoint.h"
27 #include "qgsgeometryutils.h"
28 #include "qgshstoreutils.h"
29 #include "qgsmultilinestring.h"
30 #include "qgslinestring.h"
31 #include "qgscurvepolygon.h"
33 #include "qgspolygon.h"
34 #include "qgstriangle.h"
35 #include "qgscurve.h"
36 #include "qgsregularpolygon.h"
37 #include "qgsquadrilateral.h"
38 #include "qgsmultipolygon.h"
39 #include "qgsogcutils.h"
40 #include "qgsdistancearea.h"
41 #include "qgsgeometryengine.h"
42 #include "qgsexpressionsorter.h"
43 #include "qgssymbollayerutils.h"
44 #include "qgsstyle.h"
45 #include "qgsexception.h"
46 #include "qgsmessagelog.h"
47 #include "qgsrasterlayer.h"
48 #include "qgsvectorlayer.h"
49 #include "qgsrasterbandstats.h"
50 #include "qgscolorramp.h"
52 #include "qgsfieldformatter.h"
54 #include "qgsproviderregistry.h"
55 #include "sqlite3.h"
56 #include "qgstransaction.h"
57 #include "qgsthreadingutils.h"
58 #include "qgsapplication.h"
59 #include "qgis.h"
61 #include "qgsunittypes.h"
62 #include "qgsspatialindex.h"
63 
64 typedef QList<QgsExpressionFunction *> ExpressionFunctionList;
65 
66 Q_GLOBAL_STATIC( ExpressionFunctionList, sOwnedFunctions )
67 Q_GLOBAL_STATIC( QStringList, sBuiltinFunctions )
69 
72 Q_DECLARE_METATYPE( std::shared_ptr<QgsVectorLayer> )
73 
74 const QString QgsExpressionFunction::helpText() const
75 {
76  return mHelpText.isEmpty() ? QgsExpression::helpText( mName ) : mHelpText;
77 }
78 
80 {
81  Q_UNUSED( node )
82  // evaluate arguments
83  QVariantList argValues;
84  if ( args )
85  {
86  int arg = 0;
87  const QList< QgsExpressionNode * > argList = args->list();
88  for ( QgsExpressionNode *n : argList )
89  {
90  QVariant v;
91  if ( lazyEval() )
92  {
93  // Pass in the node for the function to eval as it needs.
94  v = QVariant::fromValue( n );
95  }
96  else
97  {
98  v = n->eval( parent, context );
100  bool defaultParamIsNull = mParameterList.count() > arg && mParameterList.at( arg ).optional() && !mParameterList.at( arg ).defaultValue().isValid();
101  if ( QgsExpressionUtils::isNull( v ) && !defaultParamIsNull && !handlesNull() )
102  return QVariant(); // all "normal" functions return NULL, when any QgsExpressionFunction::Parameter is NULL (so coalesce is abnormal)
103  }
104  argValues.append( v );
105  arg++;
106  }
107  }
108 
109  return func( argValues, context, parent, node );
110 }
111 
113 {
114  Q_UNUSED( node )
115  return true;
116 }
117 
119 {
120  return QStringList();
121 }
122 
124 {
125  Q_UNUSED( parent )
126  Q_UNUSED( context )
127  Q_UNUSED( node )
128  return false;
129 }
130 
132 {
133  Q_UNUSED( parent )
134  Q_UNUSED( context )
135  Q_UNUSED( node )
136  return true;
137 }
138 
140 {
141  Q_UNUSED( node )
142  return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
143 }
144 
146 {
147  return mGroups.isEmpty() ? false : mGroups.contains( QStringLiteral( "deprecated" ) );
148 }
149 
151 {
152  return ( QString::compare( mName, other.mName, Qt::CaseInsensitive ) == 0 );
153 }
154 
156 {
157  return mHandlesNull;
158 }
159 
160 // doxygen doesn't like this constructor for some reason (maybe the function arguments?)
163  FcnEval fcn,
164  const QString &group,
165  const QString &helpText,
166  const std::function < bool ( const QgsExpressionNodeFunction *node ) > &usesGeometry,
167  const std::function < QSet<QString>( const QgsExpressionNodeFunction *node ) > &referencedColumns,
168  bool lazyEval,
169  const QStringList &aliases,
170  bool handlesNull )
171  : QgsExpressionFunction( fnname, params, group, helpText, lazyEval, handlesNull, false )
172  , mFnc( fcn )
173  , mAliases( aliases )
174  , mUsesGeometry( false )
175  , mUsesGeometryFunc( usesGeometry )
176  , mReferencedColumnsFunc( referencedColumns )
177 {
178 }
180 
182 {
183  return mAliases;
184 }
185 
187 {
188  if ( mUsesGeometryFunc )
189  return mUsesGeometryFunc( node );
190  else
191  return mUsesGeometry;
192 }
193 
195 {
196  if ( mReferencedColumnsFunc )
197  return mReferencedColumnsFunc( node );
198  else
199  return mReferencedColumns;
200 }
201 
203 {
204  if ( mIsStaticFunc )
205  return mIsStaticFunc( node, parent, context );
206  else
207  return mIsStatic;
208 }
209 
211 {
212  if ( mPrepareFunc )
213  return mPrepareFunc( node, parent, context );
214 
215  return true;
216 }
217 
219 {
220  mIsStaticFunc = isStatic;
221 }
222 
224 {
225  mIsStaticFunc = nullptr;
226  mIsStatic = isStatic;
227 }
228 
229 void QgsStaticExpressionFunction::setPrepareFunction( const std::function<bool ( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * )> &prepareFunc )
230 {
231  mPrepareFunc = prepareFunc;
232 }
233 
235 {
236  if ( node && node->args() )
237  {
238  const QList< QgsExpressionNode * > argList = node->args()->list();
239  for ( QgsExpressionNode *argNode : argList )
240  {
241  if ( !argNode->isStatic( parent, context ) )
242  return false;
243  }
244  }
245 
246  return true;
247 }
248 
249 static QVariant fcnGenerateSeries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
250 {
251  double start = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
252  double stop = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
253  double step = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
254 
255  if ( step == 0.0 || ( step > 0.0 && start > stop ) || ( step < 0.0 && start < stop ) )
256  return QVariant();
257 
258  QVariantList array;
259  int length = 1;
260 
261  array << start;
262  double current = start + step;
263  while ( ( ( step > 0.0 && current <= stop ) || ( step < 0.0 && current >= stop ) ) && length <= 1000000 )
264  {
265  array << current;
266  current += step;
267  length++;
268  }
269 
270  return array;
271 }
272 
273 static QVariant fcnGetVariable( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
274 {
275  if ( !context )
276  return QVariant();
277 
278  QString name = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
279  return context->variable( name );
280 }
281 
282 static QVariant fcnEvalTemplate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
283 {
284  QString templateString = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
285  return QgsExpression::replaceExpressionText( templateString, context );
286 }
287 
288 static QVariant fcnEval( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
289 {
290  if ( !context )
291  return QVariant();
292 
293  QString expString = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
294  QgsExpression expression( expString );
295  return expression.evaluate( context );
296 }
297 
298 static QVariant fcnSqrt( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
299 {
300  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
301  return QVariant( std::sqrt( x ) );
302 }
303 
304 static QVariant fcnAbs( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
305 {
306  double val = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
307  return QVariant( std::fabs( val ) );
308 }
309 
310 static QVariant fcnRadians( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
311 {
312  double deg = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
313  return ( deg * M_PI ) / 180;
314 }
315 static QVariant fcnDegrees( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
316 {
317  double rad = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
318  return ( 180 * rad ) / M_PI;
319 }
320 static QVariant fcnSin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
321 {
322  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
323  return QVariant( std::sin( x ) );
324 }
325 static QVariant fcnCos( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
326 {
327  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
328  return QVariant( std::cos( x ) );
329 }
330 static QVariant fcnTan( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
331 {
332  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
333  return QVariant( std::tan( x ) );
334 }
335 static QVariant fcnAsin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
336 {
337  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
338  return QVariant( std::asin( x ) );
339 }
340 static QVariant fcnAcos( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
341 {
342  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
343  return QVariant( std::acos( x ) );
344 }
345 static QVariant fcnAtan( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
346 {
347  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
348  return QVariant( std::atan( x ) );
349 }
350 static QVariant fcnAtan2( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
351 {
352  double y = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
353  double x = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
354  return QVariant( std::atan2( y, x ) );
355 }
356 static QVariant fcnExp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
357 {
358  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
359  return QVariant( std::exp( x ) );
360 }
361 static QVariant fcnLn( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
362 {
363  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
364  if ( x <= 0 )
365  return QVariant();
366  return QVariant( std::log( x ) );
367 }
368 static QVariant fcnLog10( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
369 {
370  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
371  if ( x <= 0 )
372  return QVariant();
373  return QVariant( log10( x ) );
374 }
375 static QVariant fcnLog( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
376 {
377  double b = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
378  double x = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
379  if ( x <= 0 || b <= 0 )
380  return QVariant();
381  return QVariant( std::log( x ) / std::log( b ) );
382 }
383 static QVariant fcnRndF( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
384 {
385  double min = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
386  double max = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
387  if ( max < min )
388  return QVariant();
389 
390  std::random_device rd;
391  std::mt19937_64 generator( rd() );
392 
393  if ( !QgsExpressionUtils::isNull( values.at( 2 ) ) )
394  {
395  quint32 seed;
396  if ( QgsExpressionUtils::isIntSafe( values.at( 2 ) ) )
397  {
398  // if seed can be converted to int, we use as is
399  seed = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
400  }
401  else
402  {
403  // if not, we hash string representation to int
404  QString seedStr = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
405  std::hash<std::string> hasher;
406  seed = hasher( seedStr.toStdString() );
407  }
408  generator.seed( seed );
409  }
410 
411  // Return a random double in the range [min, max] (inclusive)
412  double f = static_cast< double >( generator() ) / static_cast< double >( generator.max() );
413  return QVariant( min + f * ( max - min ) );
414 }
415 static QVariant fcnRnd( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
416 {
417  qlonglong min = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
418  qlonglong max = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
419  if ( max < min )
420  return QVariant();
421 
422  std::random_device rd;
423  std::mt19937_64 generator( rd() );
424 
425  if ( !QgsExpressionUtils::isNull( values.at( 2 ) ) )
426  {
427  quint32 seed;
428  if ( QgsExpressionUtils::isIntSafe( values.at( 2 ) ) )
429  {
430  // if seed can be converted to int, we use as is
431  seed = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
432  }
433  else
434  {
435  // if not, we hash string representation to int
436  QString seedStr = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
437  std::hash<std::string> hasher;
438  seed = hasher( seedStr.toStdString() );
439  }
440  generator.seed( seed );
441  }
442 
443  qint64 randomInteger = min + ( generator() % ( max - min + 1 ) );
444  if ( randomInteger > std::numeric_limits<int>::max() || randomInteger < -std::numeric_limits<int>::max() )
445  return QVariant( randomInteger );
446 
447  // Prevent wrong conversion of QVariant. See #36412
448  return QVariant( int( randomInteger ) );
449 }
450 
451 static QVariant fcnLinearScale( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
452 {
453  double val = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
454  double domainMin = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
455  double domainMax = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
456  double rangeMin = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
457  double rangeMax = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
458 
459  if ( domainMin >= domainMax )
460  {
461  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
462  return QVariant();
463  }
464 
465  // outside of domain?
466  if ( val >= domainMax )
467  {
468  return rangeMax;
469  }
470  else if ( val <= domainMin )
471  {
472  return rangeMin;
473  }
474 
475  // calculate linear scale
476  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
477  double c = rangeMin - ( domainMin * m );
478 
479  // Return linearly scaled value
480  return QVariant( m * val + c );
481 }
482 
483 static QVariant fcnExpScale( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
484 {
485  double val = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
486  double domainMin = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
487  double domainMax = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
488  double rangeMin = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
489  double rangeMax = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
490  double exponent = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
491 
492  if ( domainMin >= domainMax )
493  {
494  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
495  return QVariant();
496  }
497  if ( exponent <= 0 )
498  {
499  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
500  return QVariant();
501  }
502 
503  // outside of domain?
504  if ( val >= domainMax )
505  {
506  return rangeMax;
507  }
508  else if ( val <= domainMin )
509  {
510  return rangeMin;
511  }
512 
513  // Return exponentially scaled value
514  return QVariant( ( ( rangeMax - rangeMin ) / std::pow( domainMax - domainMin, exponent ) ) * std::pow( val - domainMin, exponent ) + rangeMin );
515 }
516 
517 static QVariant fcnMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
518 {
519  QVariant result( QVariant::Double );
520  double maxVal = std::numeric_limits<double>::quiet_NaN();
521  for ( const QVariant &val : values )
522  {
523  double testVal = val.isNull() ? std::numeric_limits<double>::quiet_NaN() : QgsExpressionUtils::getDoubleValue( val, parent );
524  if ( std::isnan( maxVal ) )
525  {
526  maxVal = testVal;
527  }
528  else if ( !std::isnan( testVal ) )
529  {
530  maxVal = std::max( maxVal, testVal );
531  }
532  }
533 
534  if ( !std::isnan( maxVal ) )
535  {
536  result = QVariant( maxVal );
537  }
538  return result;
539 }
540 
541 static QVariant fcnMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
542 {
543  QVariant result( QVariant::Double );
544  double minVal = std::numeric_limits<double>::quiet_NaN();
545  for ( const QVariant &val : values )
546  {
547  double testVal = val.isNull() ? std::numeric_limits<double>::quiet_NaN() : QgsExpressionUtils::getDoubleValue( val, parent );
548  if ( std::isnan( minVal ) )
549  {
550  minVal = testVal;
551  }
552  else if ( !std::isnan( testVal ) )
553  {
554  minVal = std::min( minVal, testVal );
555  }
556  }
557 
558  if ( !std::isnan( minVal ) )
559  {
560  result = QVariant( minVal );
561  }
562  return result;
563 }
564 
565 static QVariant fcnAggregate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
566 {
567  //lazy eval, so we need to evaluate nodes now
568 
569  //first node is layer id or name
570  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
572  QVariant value = node->eval( parent, context );
574  QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( value, parent );
575  if ( !vl )
576  {
577  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
578  return QVariant();
579  }
580 
581  // second node is aggregate type
582  node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
584  value = node->eval( parent, context );
586  bool ok = false;
587  QgsAggregateCalculator::Aggregate aggregate = QgsAggregateCalculator::stringToAggregate( QgsExpressionUtils::getStringValue( value, parent ), &ok );
588  if ( !ok )
589  {
590  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
591  return QVariant();
592  }
593 
594  // third node is subexpression (or field name)
595  node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
597  QString subExpression = node->dump();
598 
600  //optional forth node is filter
601  if ( values.count() > 3 )
602  {
603  node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
605  QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
606  if ( !nl || nl->value().isValid() )
607  parameters.filter = node->dump();
608  }
609 
610  //optional fifth node is concatenator
611  if ( values.count() > 4 )
612  {
613  node = QgsExpressionUtils::getNode( values.at( 4 ), parent );
615  value = node->eval( parent, context );
617  parameters.delimiter = value.toString();
618  }
619 
620  //optional sixth node is order by
621  QString orderBy;
622  if ( values.count() > 5 )
623  {
624  node = QgsExpressionUtils::getNode( values.at( 5 ), parent );
626  QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
627  if ( !nl || nl->value().isValid() )
628  {
629  orderBy = node->dump();
630  parameters.orderBy << QgsFeatureRequest::OrderByClause( orderBy );
631  }
632  }
633 
634  QVariant result;
635  if ( context )
636  {
637  QString cacheKey;
638  QgsExpression subExp( subExpression );
639  QgsExpression filterExp( parameters.filter );
640 
641  bool isStatic = true;
642  if ( filterExp.referencedVariables().contains( QStringLiteral( "parent" ) )
643  || filterExp.referencedVariables().contains( QString() )
644  || subExp.referencedVariables().contains( QStringLiteral( "parent" ) )
645  || subExp.referencedVariables().contains( QString() ) )
646  {
647  isStatic = false;
648  }
649  else
650  {
651  const QSet<QString> refVars = filterExp.referencedVariables() + subExp.referencedVariables();
652  for ( const QString &varName : refVars )
653  {
654  const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
655  if ( scope && !scope->isStatic( varName ) )
656  {
657  isStatic = false;
658  break;
659  }
660  }
661  }
662 
663  if ( !isStatic )
664  {
665  cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4:%5%6:%7" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter,
666  QString::number( context->feature().id() ), QString( qHash( context->feature() ) ), orderBy );
667  }
668  else
669  {
670  cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4:%5" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter, orderBy );
671  }
672 
673  if ( context && context->hasCachedValue( cacheKey ) )
674  {
675  return context->cachedValue( cacheKey );
676  }
677 
678  QgsExpressionContext subContext( *context );
680  subScope->setVariable( QStringLiteral( "parent" ), context->feature() );
681  subContext.appendScope( subScope );
682  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
683 
684  context->setCachedValue( cacheKey, result );
685  }
686  else
687  {
688  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
689  }
690  if ( !ok )
691  {
692  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
693  return QVariant();
694  }
695 
696  return result;
697 }
698 
699 static QVariant fcnAggregateRelation( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
700 {
701  if ( !context )
702  {
703  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
704  return QVariant();
705  }
706 
707  // first step - find current layer
708  QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
709  if ( !vl )
710  {
711  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
712  return QVariant();
713  }
714 
715  //lazy eval, so we need to evaluate nodes now
716 
717  //first node is relation name
718  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
720  QVariant value = node->eval( parent, context );
722  QString relationId = value.toString();
723  // check relation exists
724  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
725  if ( !relation.isValid() || relation.referencedLayer() != vl )
726  {
727  // check for relations by name
728  QList< QgsRelation > relations = QgsProject::instance()->relationManager()->relationsByName( relationId );
729  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
730  {
731  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
732  return QVariant();
733  }
734  else
735  {
736  relation = relations.at( 0 );
737  }
738  }
739 
740  QgsVectorLayer *childLayer = relation.referencingLayer();
741 
742  // second node is aggregate type
743  node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
745  value = node->eval( parent, context );
747  bool ok = false;
748  QgsAggregateCalculator::Aggregate aggregate = QgsAggregateCalculator::stringToAggregate( QgsExpressionUtils::getStringValue( value, parent ), &ok );
749  if ( !ok )
750  {
751  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
752  return QVariant();
753  }
754 
755  //third node is subexpression (or field name)
756  node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
758  QString subExpression = node->dump();
759 
760  //optional fourth node is concatenator
762  if ( values.count() > 3 )
763  {
764  node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
766  value = node->eval( parent, context );
768  parameters.delimiter = value.toString();
769  }
770 
771  //optional fifth node is order by
772  QString orderBy;
773  if ( values.count() > 4 )
774  {
775  node = QgsExpressionUtils::getNode( values.at( 4 ), parent );
777  QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
778  if ( !nl || nl->value().isValid() )
779  {
780  orderBy = node->dump();
781  parameters.orderBy << QgsFeatureRequest::OrderByClause( orderBy );
782  }
783  }
784 
785  if ( !context->hasFeature() )
786  return QVariant();
787  QgsFeature f = context->feature();
788 
789  parameters.filter = relation.getRelatedFeaturesFilter( f );
790 
791  QString cacheKey = QStringLiteral( "relagg:%1:%2:%3:%4:%5" ).arg( vl->id(),
792  QString::number( static_cast< int >( aggregate ) ),
793  subExpression,
794  parameters.filter,
795  orderBy );
796  if ( context->hasCachedValue( cacheKey ) )
797  return context->cachedValue( cacheKey );
798 
799  QVariant result;
800  ok = false;
801 
802 
803  QgsExpressionContext subContext( *context );
804  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
805 
806  if ( !ok )
807  {
808  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
809  return QVariant();
810  }
811 
812  // cache value
813  context->setCachedValue( cacheKey, result );
814  return result;
815 }
816 
817 
818 static QVariant fcnAggregateGeneric( QgsAggregateCalculator::Aggregate aggregate, const QVariantList &values, QgsAggregateCalculator::AggregateParameters parameters, const QgsExpressionContext *context, QgsExpression *parent, int orderByPos = -1 )
819 {
820  if ( !context )
821  {
822  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
823  return QVariant();
824  }
825 
826  // first step - find current layer
827  QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
828  if ( !vl )
829  {
830  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
831  return QVariant();
832  }
833 
834  //lazy eval, so we need to evaluate nodes now
835 
836  //first node is subexpression (or field name)
837  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
839  QString subExpression = node->dump();
840 
841  //optional second node is group by
842  QString groupBy;
843  if ( values.count() > 1 )
844  {
845  node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
847  QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
848  if ( !nl || nl->value().isValid() )
849  groupBy = node->dump();
850  }
851 
852  //optional third node is filter
853  if ( values.count() > 2 )
854  {
855  node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
857  QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
858  if ( !nl || nl->value().isValid() )
859  parameters.filter = node->dump();
860  }
861 
862  //optional order by node, if supported
863  QString orderBy;
864  if ( orderByPos >= 0 && values.count() > orderByPos )
865  {
866  node = QgsExpressionUtils::getNode( values.at( orderByPos ), parent );
868  QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
869  if ( !nl || nl->value().isValid() )
870  {
871  orderBy = node->dump();
872  parameters.orderBy << QgsFeatureRequest::OrderByClause( orderBy );
873  }
874  }
875 
876  // build up filter with group by
877 
878  // find current group by value
879  if ( !groupBy.isEmpty() )
880  {
881  QgsExpression groupByExp( groupBy );
882  QVariant groupByValue = groupByExp.evaluate( context );
883  QString groupByClause = QStringLiteral( "%1 %2 %3" ).arg( groupBy,
884  groupByValue.isNull() ? QStringLiteral( "is" ) : QStringLiteral( "=" ),
885  QgsExpression::quotedValue( groupByValue ) );
886  if ( !parameters.filter.isEmpty() )
887  parameters.filter = QStringLiteral( "(%1) AND (%2)" ).arg( parameters.filter, groupByClause );
888  else
889  parameters.filter = groupByClause;
890  }
891 
892  QgsExpression subExp( subExpression );
893  QgsExpression filterExp( parameters.filter );
894 
895  bool isStatic = true;
896  const QSet<QString> refVars = filterExp.referencedVariables() + subExp.referencedVariables();
897  for ( const QString &varName : refVars )
898  {
899  const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
900  if ( scope && !scope->isStatic( varName ) )
901  {
902  isStatic = false;
903  break;
904  }
905  }
906 
907  QString cacheKey;
908  if ( !isStatic )
909  {
910  cacheKey = QStringLiteral( "agg:%1:%2:%3:%4:%5%6:%7" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter,
911  QString::number( context->feature().id() ), QString( qHash( context->feature() ) ), orderBy );
912  }
913  else
914  {
915  cacheKey = QStringLiteral( "agg:%1:%2:%3:%4:%5" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter, orderBy );
916  }
917 
918  if ( context->hasCachedValue( cacheKey ) )
919  return context->cachedValue( cacheKey );
920 
921  QVariant result;
922  bool ok = false;
923 
924  QgsExpressionContext subContext( *context );
926  subScope->setVariable( QStringLiteral( "parent" ), context->feature() );
927  subContext.appendScope( subScope );
928  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
929 
930  if ( !ok )
931  {
932  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
933  return QVariant();
934  }
935 
936  // cache value
937  context->setCachedValue( cacheKey, result );
938  return result;
939 }
940 
941 
942 static QVariant fcnAggregateCount( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
943 {
944  return fcnAggregateGeneric( QgsAggregateCalculator::Count, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
945 }
946 
947 static QVariant fcnAggregateCountDistinct( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
948 {
949  return fcnAggregateGeneric( QgsAggregateCalculator::CountDistinct, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
950 }
951 
952 static QVariant fcnAggregateCountMissing( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
953 {
954  return fcnAggregateGeneric( QgsAggregateCalculator::CountMissing, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
955 }
956 
957 static QVariant fcnAggregateMin( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
958 {
959  return fcnAggregateGeneric( QgsAggregateCalculator::Min, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
960 }
961 
962 static QVariant fcnAggregateMax( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
963 {
964  return fcnAggregateGeneric( QgsAggregateCalculator::Max, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
965 }
966 
967 static QVariant fcnAggregateSum( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
968 {
969  return fcnAggregateGeneric( QgsAggregateCalculator::Sum, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
970 }
971 
972 static QVariant fcnAggregateMean( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
973 {
974  return fcnAggregateGeneric( QgsAggregateCalculator::Mean, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
975 }
976 
977 static QVariant fcnAggregateMedian( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
978 {
979  return fcnAggregateGeneric( QgsAggregateCalculator::Median, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
980 }
981 
982 static QVariant fcnAggregateStdev( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
983 {
984  return fcnAggregateGeneric( QgsAggregateCalculator::StDevSample, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
985 }
986 
987 static QVariant fcnAggregateRange( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
988 {
989  return fcnAggregateGeneric( QgsAggregateCalculator::Range, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
990 }
991 
992 static QVariant fcnAggregateMinority( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
993 {
994  return fcnAggregateGeneric( QgsAggregateCalculator::Minority, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
995 }
996 
997 static QVariant fcnAggregateMajority( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
998 {
999  return fcnAggregateGeneric( QgsAggregateCalculator::Majority, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1000 }
1001 
1002 static QVariant fcnAggregateQ1( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1003 {
1004  return fcnAggregateGeneric( QgsAggregateCalculator::FirstQuartile, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1005 }
1006 
1007 static QVariant fcnAggregateQ3( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1008 {
1009  return fcnAggregateGeneric( QgsAggregateCalculator::ThirdQuartile, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1010 }
1011 
1012 static QVariant fcnAggregateIQR( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1013 {
1014  return fcnAggregateGeneric( QgsAggregateCalculator::InterQuartileRange, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1015 }
1016 
1017 static QVariant fcnAggregateMinLength( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1018 {
1019  return fcnAggregateGeneric( QgsAggregateCalculator::StringMinimumLength, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1020 }
1021 
1022 static QVariant fcnAggregateMaxLength( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1023 {
1024  return fcnAggregateGeneric( QgsAggregateCalculator::StringMaximumLength, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1025 }
1026 
1027 static QVariant fcnAggregateCollectGeometry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1028 {
1029  return fcnAggregateGeneric( QgsAggregateCalculator::GeometryCollect, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1030 }
1031 
1032 static QVariant fcnAggregateStringConcat( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1033 {
1035 
1036  //fourth node is concatenator
1037  if ( values.count() > 3 )
1038  {
1039  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
1041  QVariant value = node->eval( parent, context );
1043  parameters.delimiter = value.toString();
1044  }
1045 
1046  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent, 4 );
1047 }
1048 
1049 static QVariant fcnAggregateStringConcatUnique( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1050 {
1052 
1053  //fourth node is concatenator
1054  if ( values.count() > 3 )
1055  {
1056  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
1058  QVariant value = node->eval( parent, context );
1060  parameters.delimiter = value.toString();
1061  }
1062 
1063  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenateUnique, values, parameters, context, parent, 4 );
1064 }
1065 
1066 static QVariant fcnAggregateArray( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1067 {
1068  return fcnAggregateGeneric( QgsAggregateCalculator::ArrayAggregate, values, QgsAggregateCalculator::AggregateParameters(), context, parent, 3 );
1069 }
1070 
1071 static QVariant fcnMapScale( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
1072 {
1073  if ( !context )
1074  return QVariant();
1075 
1076  QVariant scale = context->variable( QStringLiteral( "map_scale" ) );
1077  bool ok = false;
1078  if ( !scale.isValid() || scale.isNull() )
1079  return QVariant();
1080 
1081  const double v = scale.toDouble( &ok );
1082  if ( ok )
1083  return v;
1084  return QVariant();
1085 }
1086 
1087 static QVariant fcnClamp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1088 {
1089  double minValue = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1090  double testValue = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
1091  double maxValue = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
1092 
1093  // force testValue to sit inside the range specified by the min and max value
1094  if ( testValue <= minValue )
1095  {
1096  return QVariant( minValue );
1097  }
1098  else if ( testValue >= maxValue )
1099  {
1100  return QVariant( maxValue );
1101  }
1102  else
1103  {
1104  return QVariant( testValue );
1105  }
1106 }
1107 
1108 static QVariant fcnFloor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1109 {
1110  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1111  return QVariant( std::floor( x ) );
1112 }
1113 
1114 static QVariant fcnCeil( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1115 {
1116  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1117  return QVariant( std::ceil( x ) );
1118 }
1119 
1120 static QVariant fcnToInt( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1121 {
1122  return QVariant( QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) );
1123 }
1124 static QVariant fcnToReal( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1125 {
1126  return QVariant( QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent ) );
1127 }
1128 static QVariant fcnToString( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1129 {
1130  return QVariant( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ) );
1131 }
1132 
1133 static QVariant fcnToDateTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1134 {
1135  QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1136  QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1137  if ( format.isEmpty() && !language.isEmpty() )
1138  {
1139  parent->setEvalErrorString( QObject::tr( "A format is required to convert to DateTime when the language is specified" ) );
1140  return QVariant( QDateTime() );
1141  }
1142 
1143  if ( format.isEmpty() && language.isEmpty() )
1144  return QVariant( QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent ) );
1145 
1146  QString datetimestring = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1147  QLocale locale = QLocale();
1148  if ( !language.isEmpty() )
1149  {
1150  locale = QLocale( language );
1151  }
1152 
1153  QDateTime datetime = locale.toDateTime( datetimestring, format );
1154  if ( !datetime.isValid() )
1155  {
1156  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( datetimestring ) );
1157  datetime = QDateTime();
1158  }
1159  return QVariant( datetime );
1160 }
1161 
1162 static QVariant fcnMakeDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1163 {
1164  const int year = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
1165  const int month = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1166  const int day = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
1167 
1168  const QDate date( year, month, day );
1169  if ( !date.isValid() )
1170  {
1171  parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid date" ).arg( year ).arg( month ).arg( day ) );
1172  return QVariant();
1173  }
1174  return QVariant( date );
1175 }
1176 
1177 static QVariant fcnMakeTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1178 {
1179  const int hours = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
1180  const int minutes = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1181  const double seconds = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
1182 
1183  const QTime time( hours, minutes, std::floor( seconds ), ( seconds - std::floor( seconds ) ) * 1000 );
1184  if ( !time.isValid() )
1185  {
1186  parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid time" ).arg( hours ).arg( minutes ).arg( seconds ) );
1187  return QVariant();
1188  }
1189  return QVariant( time );
1190 }
1191 
1192 static QVariant fcnMakeDateTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1193 {
1194  const int year = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
1195  const int month = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1196  const int day = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
1197  const int hours = QgsExpressionUtils::getIntValue( values.at( 3 ), parent );
1198  const int minutes = QgsExpressionUtils::getIntValue( values.at( 4 ), parent );
1199  const double seconds = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
1200 
1201  const QDate date( year, month, day );
1202  if ( !date.isValid() )
1203  {
1204  parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid date" ).arg( year ).arg( month ).arg( day ) );
1205  return QVariant();
1206  }
1207  const QTime time( hours, minutes, std::floor( seconds ), ( seconds - std::floor( seconds ) ) * 1000 );
1208  if ( !time.isValid() )
1209  {
1210  parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid time" ).arg( hours ).arg( minutes ).arg( seconds ) );
1211  return QVariant();
1212  }
1213  return QVariant( QDateTime( date, time ) );
1214 }
1215 
1216 static QVariant fcnMakeInterval( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1217 {
1218  const double years = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1219  const double months = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
1220  const double weeks = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
1221  const double days = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
1222  const double hours = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
1223  const double minutes = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
1224  const double seconds = QgsExpressionUtils::getDoubleValue( values.at( 6 ), parent );
1225 
1226  return QVariant::fromValue( QgsInterval( years, months, weeks, days, hours, minutes, seconds ) );
1227 }
1228 
1229 static QVariant fcnCoalesce( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
1230 {
1231  for ( const QVariant &value : values )
1232  {
1233  if ( value.isNull() )
1234  continue;
1235  return value;
1236  }
1237  return QVariant();
1238 }
1239 
1240 static QVariant fcnNullIf( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
1241 {
1242  const QVariant val1 = values.at( 0 );
1243  const QVariant val2 = values.at( 1 );
1244 
1245  if ( val1 == val2 )
1246  return QVariant();
1247  else
1248  return val1;
1249 }
1250 
1251 static QVariant fcnLower( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1252 {
1253  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1254  return QVariant( str.toLower() );
1255 }
1256 static QVariant fcnUpper( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1257 {
1258  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1259  return QVariant( str.toUpper() );
1260 }
1261 static QVariant fcnTitle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1262 {
1263  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1264  QStringList elems = str.split( ' ' );
1265  for ( int i = 0; i < elems.size(); i++ )
1266  {
1267  if ( elems[i].size() > 1 )
1268  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1269  }
1270  return QVariant( elems.join( QLatin1Char( ' ' ) ) );
1271 }
1272 
1273 static QVariant fcnTrim( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1274 {
1275  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1276  return QVariant( str.trimmed() );
1277 }
1278 
1279 static QVariant fcnLevenshtein( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1280 {
1281  QString string1 = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1282  QString string2 = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1283  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1284 }
1285 
1286 static QVariant fcnLCS( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1287 {
1288  QString string1 = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1289  QString string2 = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1290  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1291 }
1292 
1293 static QVariant fcnHamming( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1294 {
1295  QString string1 = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1296  QString string2 = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1297  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1298  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1299 }
1300 
1301 static QVariant fcnSoundex( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1302 {
1303  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1304  return QVariant( QgsStringUtils::soundex( string ) );
1305 }
1306 
1307 static QVariant fcnChar( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1308 {
1309  QChar character = QChar( QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent ) );
1310  return QVariant( QString( character ) );
1311 }
1312 
1313 static QVariant fcnAscii( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1314 {
1315  QString value = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1316 
1317  if ( value.isEmpty() )
1318  {
1319  return QVariant();
1320  }
1321 
1322  int res = value.at( 0 ).unicode();
1323  return QVariant( res );
1324 }
1325 
1326 static QVariant fcnWordwrap( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1327 {
1328  if ( values.length() == 2 || values.length() == 3 )
1329  {
1330  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1331  qlonglong wrap = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1332 
1333  QString customdelimiter = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1334 
1335  return QgsStringUtils::wordWrap( str, static_cast< int >( wrap ), wrap > 0, customdelimiter );
1336  }
1337 
1338  return QVariant();
1339 }
1340 
1341 static QVariant fcnLength( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1342 {
1343  // two variants, one for geometry, one for string
1344  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1345  {
1346  //geometry variant
1347  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
1348  if ( geom.type() != QgsWkbTypes::LineGeometry )
1349  return QVariant();
1350 
1351  return QVariant( geom.length() );
1352  }
1353 
1354  //otherwise fall back to string variant
1355  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1356  return QVariant( str.length() );
1357 }
1358 
1359 static QVariant fcnReplace( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1360 {
1361  if ( values.count() == 2 && values.at( 1 ).type() == QVariant::Map )
1362  {
1363  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1364  QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 1 ), parent );
1365 
1366  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1367  {
1368  str = str.replace( it.key(), it.value().toString() );
1369  }
1370 
1371  return QVariant( str );
1372  }
1373  else if ( values.count() == 3 )
1374  {
1375  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1376  QVariantList before;
1377  QVariantList after;
1378  bool isSingleReplacement = false;
1379 
1380  if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1381  {
1382  before = QVariantList() << QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1383  }
1384  else
1385  {
1386  before = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
1387  }
1388 
1389  if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1390  {
1391  after = QVariantList() << QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1392  isSingleReplacement = true;
1393  }
1394  else
1395  {
1396  after = QgsExpressionUtils::getListValue( values.at( 2 ), parent );
1397  }
1398 
1399  if ( !isSingleReplacement && before.length() != after.length() )
1400  {
1401  parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
1402  return QVariant();
1403  }
1404 
1405  for ( int i = 0; i < before.length(); i++ )
1406  {
1407  str = str.replace( before.at( i ).toString(), after.at( isSingleReplacement ? 0 : i ).toString() );
1408  }
1409 
1410  return QVariant( str );
1411  }
1412  else
1413  {
1414  parent->setEvalErrorString( QObject::tr( "Function replace requires 2 or 3 arguments" ) );
1415  return QVariant();
1416  }
1417 }
1418 static QVariant fcnRegexpReplace( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1419 {
1420  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1421  QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1422  QString after = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1423 
1424  QRegularExpression re( regexp );
1425  if ( !re.isValid() )
1426  {
1427  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1428  return QVariant();
1429  }
1430  return QVariant( str.replace( re, after ) );
1431 }
1432 
1433 static QVariant fcnRegexpMatch( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1434 {
1435  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1436  QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1437 
1438  QRegularExpression re( regexp );
1439  if ( !re.isValid() )
1440  {
1441  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1442  return QVariant();
1443  }
1444  return QVariant( ( str.indexOf( re ) + 1 ) );
1445 }
1446 
1447 static QVariant fcnRegexpMatches( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1448 {
1449  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1450  QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1451  QString empty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1452 
1453  QRegularExpression re( regexp );
1454  if ( !re.isValid() )
1455  {
1456  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1457  return QVariant();
1458  }
1459 
1460  QRegularExpressionMatch matches = re.match( str );
1461  if ( matches.hasMatch() )
1462  {
1463  QVariantList array;
1464  QStringList list = matches.capturedTexts();
1465 
1466  // Skip the first string to only return captured groups
1467  for ( QStringList::const_iterator it = ++list.constBegin(); it != list.constEnd(); ++it )
1468  {
1469  array += ( !( *it ).isEmpty() ) ? *it : empty;
1470  }
1471 
1472  return QVariant( array );
1473  }
1474  else
1475  {
1476  return QVariant();
1477  }
1478 }
1479 
1480 static QVariant fcnRegexpSubstr( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1481 {
1482  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1483  QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1484 
1485  QRegularExpression re( regexp );
1486  if ( !re.isValid() )
1487  {
1488  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1489  return QVariant();
1490  }
1491 
1492  // extract substring
1493  QRegularExpressionMatch match = re.match( str );
1494  if ( match.hasMatch() )
1495  {
1496  // return first capture
1497  if ( match.lastCapturedIndex() > 0 )
1498  {
1499  // a capture group was present, so use that
1500  return QVariant( match.captured( 1 ) );
1501  }
1502  else
1503  {
1504  // no capture group, so using all match
1505  return QVariant( match.captured( 0 ) );
1506  }
1507  }
1508  else
1509  {
1510  return QVariant( "" );
1511  }
1512 }
1513 
1514 static QVariant fcnUuid( const QVariantList &, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
1515 {
1516  return QUuid::createUuid().toString();
1517 }
1518 
1519 static QVariant fcnSubstr( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1520 {
1521  if ( !values.at( 0 ).isValid() || !values.at( 1 ).isValid() )
1522  return QVariant();
1523 
1524  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1525  int from = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
1526 
1527  int len = 0;
1528  if ( values.at( 2 ).isValid() )
1529  len = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
1530  else
1531  len = str.size();
1532 
1533  if ( from < 0 )
1534  {
1535  from = str.size() + from;
1536  if ( from < 0 )
1537  {
1538  from = 0;
1539  }
1540  }
1541  else if ( from > 0 )
1542  {
1543  //account for the fact that substr() starts at 1
1544  from -= 1;
1545  }
1546 
1547  if ( len < 0 )
1548  {
1549  len = str.size() + len - from;
1550  if ( len < 0 )
1551  {
1552  len = 0;
1553  }
1554  }
1555 
1556  return QVariant( str.mid( from, len ) );
1557 }
1558 static QVariant fcnFeatureId( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
1559 {
1560  FEAT_FROM_CONTEXT( context, f )
1561  // TODO: handling of 64-bit feature ids?
1562  return QVariant( static_cast< int >( f.id() ) );
1563 }
1564 
1565 static QVariant fcnRasterValue( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1566 {
1567  QgsRasterLayer *layer = QgsExpressionUtils::getRasterLayer( values.at( 0 ), parent );
1568  if ( !layer || !layer->dataProvider() )
1569  {
1570  parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid raster layer." ) );
1571  return QVariant();
1572  }
1573 
1574  int bandNb = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
1575  if ( bandNb < 1 || bandNb > layer->bandCount() )
1576  {
1577  parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid raster band number." ) );
1578  return QVariant();
1579  }
1580 
1581  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );
1582  if ( geom.isNull() || geom.type() != QgsWkbTypes::PointGeometry )
1583  {
1584  parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid point geometry." ) );
1585  return QVariant();
1586  }
1587 
1588  QgsPointXY point = geom.asPoint();
1589  if ( geom.isMultipart() )
1590  {
1591  QgsMultiPointXY multiPoint = geom.asMultiPoint();
1592  if ( multiPoint.count() == 1 )
1593  {
1594  point = multiPoint[0];
1595  }
1596  else
1597  {
1598  // if the geometry contains more than one part, return an undefined value
1599  return QVariant();
1600  }
1601  }
1602 
1603  double value = layer->dataProvider()->sample( point, bandNb );
1604  return std::isnan( value ) ? QVariant() : value;
1605 }
1606 
1607 static QVariant fcnFeature( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
1608 {
1609  if ( !context )
1610  return QVariant();
1611 
1612  return context->feature();
1613 }
1614 
1615 static QVariant fcnAttribute( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1616 {
1617  QgsFeature feature;
1618  QString attr;
1619  if ( values.size() == 1 )
1620  {
1621  attr = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1622  feature = context->feature();
1623  }
1624  else if ( values.size() == 2 )
1625  {
1626  feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1627  attr = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1628  }
1629  else
1630  {
1631  parent->setEvalErrorString( QObject::tr( "Function `attribute` requires one or two parameters. %1 given." ).arg( values.length() ) );
1632  return QVariant();
1633  }
1634 
1635  return feature.attribute( attr );
1636 }
1637 
1638 static QVariant fcnAttributes( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1639 {
1640  QgsFeature feature;
1641  if ( values.size() == 0 || values.at( 0 ).isNull() )
1642  {
1643  feature = context->feature();
1644  }
1645  else
1646  {
1647  feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1648  }
1649 
1650  const QgsFields fields = feature.fields();
1651  QVariantMap result;
1652  for ( int i = 0; i < fields.count(); ++i )
1653  {
1654  result.insert( fields.at( i ).name(), feature.attribute( i ) );
1655  }
1656  return result;
1657 }
1658 
1659 static QVariant fcnCoreFeatureMaptipDisplay( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const bool isMaptip )
1660 {
1661  QgsVectorLayer *layer = nullptr;
1662  QgsFeature feature;
1663  bool evaluate = true;
1664 
1665  if ( values.isEmpty() )
1666  {
1667  feature = context->feature();
1668  layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1669  }
1670  else if ( values.size() == 1 )
1671  {
1672  layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1673  feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1674  }
1675  else if ( values.size() == 2 )
1676  {
1677  layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1678  feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
1679  }
1680  else if ( values.size() == 3 )
1681  {
1682  layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1683  feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
1684  evaluate = values.value( 2 ).toBool();
1685  }
1686  else
1687  {
1688  if ( isMaptip )
1689  {
1690  parent->setEvalErrorString( QObject::tr( "Function `maptip` requires no more than three parameters. %1 given." ).arg( values.length() ) );
1691  }
1692  else
1693  {
1694  parent->setEvalErrorString( QObject::tr( "Function `display` requires no more than three parameters. %1 given." ).arg( values.length() ) );
1695  }
1696  return QVariant();
1697  }
1698 
1699  if ( !layer )
1700  {
1701  parent->setEvalErrorString( QObject::tr( "The layer is not valid." ) );
1702  return QVariant( );
1703  }
1704 
1705  if ( !feature.isValid() )
1706  {
1707  parent->setEvalErrorString( QObject::tr( "The feature is not valid." ) );
1708  return QVariant( );
1709  }
1710 
1711  if ( ! evaluate )
1712  {
1713  if ( isMaptip )
1714  {
1715  return layer->mapTipTemplate();
1716  }
1717  else
1718  {
1719  return layer->displayExpression();
1720  }
1721  }
1722 
1723  QgsExpressionContext subContext( *context );
1724  subContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
1725  subContext.setFeature( feature );
1726 
1727  if ( isMaptip )
1728  {
1729  return QgsExpression::replaceExpressionText( layer->mapTipTemplate(), &subContext );
1730  }
1731  else
1732  {
1733  QgsExpression exp( layer->displayExpression() );
1734  exp.prepare( &subContext );
1735  return exp.evaluate( &subContext ).toString();
1736  }
1737 }
1738 
1739 static QVariant fcnFeatureDisplayExpression( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1740 {
1741  return fcnCoreFeatureMaptipDisplay( values, context, parent, false );
1742 }
1743 
1744 static QVariant fcnFeatureMaptip( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1745 {
1746  return fcnCoreFeatureMaptipDisplay( values, context, parent, true );
1747 }
1748 
1749 static QVariant fcnIsSelected( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1750 {
1751  QgsVectorLayer *layer = nullptr;
1752  QgsFeature feature;
1753 
1754  if ( values.isEmpty() )
1755  {
1756  feature = context->feature();
1757  layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1758  }
1759  else if ( values.size() == 1 )
1760  {
1761  layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1762  feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1763  }
1764  else if ( values.size() == 2 )
1765  {
1766  layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1767  feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
1768  }
1769  else
1770  {
1771  parent->setEvalErrorString( QObject::tr( "Function `is_selected` requires no more than two parameters. %1 given." ).arg( values.length() ) );
1772  return QVariant();
1773  }
1774 
1775  if ( !layer || !feature.isValid() )
1776  {
1777  return QVariant( QVariant::Bool );
1778  }
1779 
1780  return layer->selectedFeatureIds().contains( feature.id() );
1781 }
1782 
1783 static QVariant fcnNumSelected( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1784 {
1785  QgsVectorLayer *layer = nullptr;
1786 
1787  if ( values.isEmpty() )
1788  layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1789  else if ( values.count() == 1 )
1790  layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1791  else
1792  {
1793  parent->setEvalErrorString( QObject::tr( "Function `num_selected` requires no more than one parameter. %1 given." ).arg( values.length() ) );
1794  return QVariant();
1795  }
1796 
1797  if ( !layer )
1798  {
1799  return QVariant( QVariant::LongLong );
1800  }
1801 
1802  return layer->selectedFeatureCount();
1803 }
1804 
1805 static QVariant fcnSqliteFetchAndIncrement( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1806 {
1807  static QMap<QString, qlonglong> counterCache;
1808  QVariant functionResult;
1809 
1810  std::function<void()> fetchAndIncrementFunc = [ =, &functionResult ]()
1811  {
1812  QString database;
1813  const QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1814 
1815  if ( layer )
1816  {
1817  const QVariantMap decodedUri = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
1818  database = decodedUri.value( QStringLiteral( "path" ) ).toString();
1819  if ( database.isEmpty() )
1820  {
1821  parent->setEvalErrorString( QObject::tr( "Could not extract file path from layer `%1`." ).arg( layer->name() ) );
1822  }
1823  }
1824  else
1825  {
1826  database = values.at( 0 ).toString();
1827  }
1828 
1829  const QString table = values.at( 1 ).toString();
1830  const QString idColumn = values.at( 2 ).toString();
1831  const QString filterAttribute = values.at( 3 ).toString();
1832  const QVariant filterValue = values.at( 4 ).toString();
1833  const QVariantMap defaultValues = values.at( 5 ).toMap();
1834 
1835  // read from database
1836  sqlite3_database_unique_ptr sqliteDb;
1837  sqlite3_statement_unique_ptr sqliteStatement;
1838 
1839  if ( sqliteDb.open_v2( database, SQLITE_OPEN_READWRITE, nullptr ) != SQLITE_OK )
1840  {
1841  parent->setEvalErrorString( QObject::tr( "Could not open sqlite database %1. Error %2. " ).arg( database, sqliteDb.errorMessage() ) );
1842  functionResult = QVariant();
1843  return;
1844  }
1845 
1846  QString errorMessage;
1847  QString currentValSql;
1848 
1849  qlonglong nextId = 0;
1850  bool cachedMode = false;
1851  bool valueRetrieved = false;
1852 
1853  QString cacheString = QStringLiteral( "%1:%2:%3:%4:%5" ).arg( database, table, idColumn, filterAttribute, filterValue.toString() );
1854 
1855  // Running in transaction mode, check for cached value first
1856  if ( layer && layer->dataProvider() && layer->dataProvider()->transaction() )
1857  {
1858  cachedMode = true;
1859 
1860  auto cachedCounter = counterCache.find( cacheString );
1861 
1862  if ( cachedCounter != counterCache.end() )
1863  {
1864  qlonglong &cachedValue = cachedCounter.value();
1865  nextId = cachedValue;
1866  nextId += 1;
1867  cachedValue = nextId;
1868  valueRetrieved = true;
1869  }
1870  }
1871 
1872  // Either not in cached mode or no cached value found, obtain from DB
1873  if ( !cachedMode || !valueRetrieved )
1874  {
1875  int result = SQLITE_ERROR;
1876 
1877  currentValSql = QStringLiteral( "SELECT %1 FROM %2" ).arg( QgsSqliteUtils::quotedIdentifier( idColumn ), QgsSqliteUtils::quotedIdentifier( table ) );
1878  if ( !filterAttribute.isNull() )
1879  {
1880  currentValSql += QStringLiteral( " WHERE %1 = %2" ).arg( QgsSqliteUtils::quotedIdentifier( filterAttribute ), QgsSqliteUtils::quotedValue( filterValue ) );
1881  }
1882 
1883  sqliteStatement = sqliteDb.prepare( currentValSql, result );
1884 
1885  if ( result == SQLITE_OK )
1886  {
1887  nextId = 0;
1888  if ( sqliteStatement.step() == SQLITE_ROW )
1889  {
1890  nextId = sqliteStatement.columnAsInt64( 0 ) + 1;
1891  }
1892 
1893  // If in cached mode: add value to cache and connect to transaction
1894  if ( cachedMode && result == SQLITE_OK )
1895  {
1896  counterCache.insert( cacheString, nextId );
1897 
1898  QObject::connect( layer->dataProvider()->transaction(), &QgsTransaction::destroyed, [cacheString]()
1899  {
1900  counterCache.remove( cacheString );
1901  } );
1902  }
1903  valueRetrieved = true;
1904  }
1905  }
1906 
1907  if ( valueRetrieved )
1908  {
1909  QString upsertSql;
1910  upsertSql = QStringLiteral( "INSERT OR REPLACE INTO %1" ).arg( QgsSqliteUtils::quotedIdentifier( table ) );
1911  QStringList cols;
1912  QStringList vals;
1913  cols << QgsSqliteUtils::quotedIdentifier( idColumn );
1914  vals << QgsSqliteUtils::quotedValue( nextId );
1915 
1916  if ( !filterAttribute.isNull() )
1917  {
1918  cols << QgsSqliteUtils::quotedIdentifier( filterAttribute );
1919  vals << QgsSqliteUtils::quotedValue( filterValue );
1920  }
1921 
1922  for ( QVariantMap::const_iterator iter = defaultValues.constBegin(); iter != defaultValues.constEnd(); ++iter )
1923  {
1924  cols << QgsSqliteUtils::quotedIdentifier( iter.key() );
1925  vals << iter.value().toString();
1926  }
1927 
1928  upsertSql += QLatin1String( " (" ) + cols.join( ',' ) + ')';
1929  upsertSql += QLatin1String( " VALUES " );
1930  upsertSql += '(' + vals.join( ',' ) + ')';
1931 
1932  int result = SQLITE_ERROR;
1933  if ( layer && layer->dataProvider() && layer->dataProvider()->transaction() )
1934  {
1935  QgsTransaction *transaction = layer->dataProvider()->transaction();
1936  if ( transaction->executeSql( upsertSql, errorMessage ) )
1937  {
1938  result = SQLITE_OK;
1939  }
1940  }
1941  else
1942  {
1943  result = sqliteDb.exec( upsertSql, errorMessage );
1944  }
1945  if ( result == SQLITE_OK )
1946  {
1947  functionResult = QVariant( nextId );
1948  return;
1949  }
1950  else
1951  {
1952  parent->setEvalErrorString( QStringLiteral( "Could not increment value: SQLite error: \"%1\" (%2)." ).arg( errorMessage, QString::number( result ) ) );
1953  functionResult = QVariant();
1954  return;
1955  }
1956  }
1957 
1958  functionResult = QVariant();
1959  };
1960 
1961  QgsThreadingUtils::runOnMainThread( fetchAndIncrementFunc );
1962 
1963  return functionResult;
1964 }
1965 
1966 static QVariant fcnConcat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1967 {
1968  QString concat;
1969  for ( const QVariant &value : values )
1970  {
1971  if ( !value.isNull() )
1972  concat += QgsExpressionUtils::getStringValue( value, parent );
1973  }
1974  return concat;
1975 }
1976 
1977 static QVariant fcnStrpos( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1978 {
1979  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1980  return string.indexOf( QgsExpressionUtils::getStringValue( values.at( 1 ), parent ) ) + 1;
1981 }
1982 
1983 static QVariant fcnRight( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1984 {
1985  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1986  int pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
1987  return string.right( pos );
1988 }
1989 
1990 static QVariant fcnLeft( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1991 {
1992  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1993  int pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
1994  return string.left( pos );
1995 }
1996 
1997 static QVariant fcnRPad( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1998 {
1999  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2000  int length = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2001  QString fill = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2002  return string.leftJustified( length, fill.at( 0 ), true );
2003 }
2004 
2005 static QVariant fcnLPad( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2006 {
2007  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2008  int length = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2009  QString fill = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2010  return string.rightJustified( length, fill.at( 0 ), true );
2011 }
2012 
2013 static QVariant fcnFormatString( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2014 {
2015  if ( values.size() < 1 )
2016  {
2017  parent->setEvalErrorString( QObject::tr( "Function format requires at least 1 argument" ) );
2018  return QVariant();
2019  }
2020 
2021  QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2022  for ( int n = 1; n < values.length(); n++ )
2023  {
2024  string = string.arg( QgsExpressionUtils::getStringValue( values.at( n ), parent ) );
2025  }
2026  return string;
2027 }
2028 
2029 
2030 static QVariant fcnNow( const QVariantList &, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
2031 {
2032  return QVariant( QDateTime::currentDateTime() );
2033 }
2034 
2035 static QVariant fcnToDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2036 {
2037  QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
2038  QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2039  if ( format.isEmpty() && !language.isEmpty() )
2040  {
2041  parent->setEvalErrorString( QObject::tr( "A format is required to convert to Date when the language is specified" ) );
2042  return QVariant( QDate() );
2043  }
2044 
2045  if ( format.isEmpty() && language.isEmpty() )
2046  return QVariant( QgsExpressionUtils::getDateValue( values.at( 0 ), parent ) );
2047 
2048  QString datestring = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2049  QLocale locale = QLocale();
2050  if ( !language.isEmpty() )
2051  {
2052  locale = QLocale( language );
2053  }
2054 
2055  QDate date = locale.toDate( datestring, format );
2056  if ( !date.isValid() )
2057  {
2058  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( datestring ) );
2059  date = QDate();
2060  }
2061  return QVariant( date );
2062 }
2063 
2064 static QVariant fcnToTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2065 {
2066  QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
2067  QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2068  if ( format.isEmpty() && !language.isEmpty() )
2069  {
2070  parent->setEvalErrorString( QObject::tr( "A format is required to convert to Time when the language is specified" ) );
2071  return QVariant( QTime() );
2072  }
2073 
2074  if ( format.isEmpty() && language.isEmpty() )
2075  return QVariant( QgsExpressionUtils::getTimeValue( values.at( 0 ), parent ) );
2076 
2077  QString timestring = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2078  QLocale locale = QLocale();
2079  if ( !language.isEmpty() )
2080  {
2081  locale = QLocale( language );
2082  }
2083 
2084  QTime time = locale.toTime( timestring, format );
2085  if ( !time.isValid() )
2086  {
2087  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( timestring ) );
2088  time = QTime();
2089  }
2090  return QVariant( time );
2091 }
2092 
2093 static QVariant fcnToInterval( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2094 {
2095  return QVariant::fromValue( QgsExpressionUtils::getInterval( values.at( 0 ), parent ) );
2096 }
2097 
2098 /*
2099  * DMS functions
2100  */
2101 
2102 static QVariant floatToDegreeFormat( const QgsCoordinateFormatter::Format format, const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2103 {
2104  double value = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
2105  QString axis = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
2106  int precision = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
2107 
2108  QString formatString;
2109  if ( values.count() > 3 )
2110  formatString = QgsExpressionUtils::getStringValue( values.at( 3 ), parent );
2111 
2112  QgsCoordinateFormatter::FormatFlags flags = QgsCoordinateFormatter::FormatFlags();
2113  if ( formatString.compare( QLatin1String( "suffix" ), Qt::CaseInsensitive ) == 0 )
2114  {
2116  }
2117  else if ( formatString.compare( QLatin1String( "aligned" ), Qt::CaseInsensitive ) == 0 )
2118  {
2120  }
2121  else if ( ! formatString.isEmpty() )
2122  {
2123  parent->setEvalErrorString( QObject::tr( "Invalid formatting parameter: '%1'. It must be empty, or 'suffix' or 'aligned'." ).arg( formatString ) );
2124  return QVariant();
2125  }
2126 
2127  if ( axis.compare( QLatin1String( "x" ), Qt::CaseInsensitive ) == 0 )
2128  {
2129  return QVariant::fromValue( QgsCoordinateFormatter::formatX( value, format, precision, flags ) );
2130  }
2131  else if ( axis.compare( QLatin1String( "y" ), Qt::CaseInsensitive ) == 0 )
2132  {
2133  return QVariant::fromValue( QgsCoordinateFormatter::formatY( value, format, precision, flags ) );
2134  }
2135  else
2136  {
2137  parent->setEvalErrorString( QObject::tr( "Invalid axis name: '%1'. It must be either 'x' or 'y'." ).arg( axis ) );
2138  return QVariant();
2139  }
2140 }
2141 
2142 static QVariant fcnToDegreeMinute( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
2143 {
2145  return floatToDegreeFormat( format, values, context, parent, node );
2146 }
2147 
2148 static QVariant fcnToDecimal( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2149 {
2150  double value = 0.0;
2151  bool ok = false;
2152  value = QgsCoordinateUtils::dmsToDecimal( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), &ok );
2153 
2154  return ok ? QVariant( value ) : QVariant();
2155 }
2156 
2157 static QVariant fcnToDegreeMinuteSecond( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
2158 {
2160  return floatToDegreeFormat( format, values, context, parent, node );
2161 }
2162 
2163 static QVariant fcnAge( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2164 {
2165  QDateTime d1 = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
2166  QDateTime d2 = QgsExpressionUtils::getDateTimeValue( values.at( 1 ), parent );
2167  qint64 seconds = d2.secsTo( d1 );
2168  return QVariant::fromValue( QgsInterval( seconds ) );
2169 }
2170 
2171 static QVariant fcnDayOfWeek( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2172 {
2173  if ( !values.at( 0 ).canConvert<QDate>() )
2174  return QVariant();
2175 
2176  QDate date = QgsExpressionUtils::getDateValue( values.at( 0 ), parent );
2177  if ( !date.isValid() )
2178  return QVariant();
2179 
2180  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
2181  // (to match PostgreSQL behavior)
2182  return date.dayOfWeek() % 7;
2183 }
2184 
2185 static QVariant fcnDay( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2186 {
2187  QVariant value = values.at( 0 );
2188  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2189  if ( inter.isValid() )
2190  {
2191  return QVariant( inter.days() );
2192  }
2193  else
2194  {
2195  QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2196  return QVariant( d1.date().day() );
2197  }
2198 }
2199 
2200 static QVariant fcnYear( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2201 {
2202  QVariant value = values.at( 0 );
2203  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2204  if ( inter.isValid() )
2205  {
2206  return QVariant( inter.years() );
2207  }
2208  else
2209  {
2210  QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2211  return QVariant( d1.date().year() );
2212  }
2213 }
2214 
2215 static QVariant fcnMonth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2216 {
2217  QVariant value = values.at( 0 );
2218  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2219  if ( inter.isValid() )
2220  {
2221  return QVariant( inter.months() );
2222  }
2223  else
2224  {
2225  QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2226  return QVariant( d1.date().month() );
2227  }
2228 }
2229 
2230 static QVariant fcnWeek( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2231 {
2232  QVariant value = values.at( 0 );
2233  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2234  if ( inter.isValid() )
2235  {
2236  return QVariant( inter.weeks() );
2237  }
2238  else
2239  {
2240  QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2241  return QVariant( d1.date().weekNumber() );
2242  }
2243 }
2244 
2245 static QVariant fcnHour( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2246 {
2247  QVariant value = values.at( 0 );
2248  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2249  if ( inter.isValid() )
2250  {
2251  return QVariant( inter.hours() );
2252  }
2253  else
2254  {
2255  QTime t1 = QgsExpressionUtils::getTimeValue( value, parent );
2256  return QVariant( t1.hour() );
2257  }
2258 }
2259 
2260 static QVariant fcnMinute( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2261 {
2262  QVariant value = values.at( 0 );
2263  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2264  if ( inter.isValid() )
2265  {
2266  return QVariant( inter.minutes() );
2267  }
2268  else
2269  {
2270  QTime t1 = QgsExpressionUtils::getTimeValue( value, parent );
2271  return QVariant( t1.minute() );
2272  }
2273 }
2274 
2275 static QVariant fcnSeconds( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2276 {
2277  QVariant value = values.at( 0 );
2278  QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2279  if ( inter.isValid() )
2280  {
2281  return QVariant( inter.seconds() );
2282  }
2283  else
2284  {
2285  QTime t1 = QgsExpressionUtils::getTimeValue( value, parent );
2286  return QVariant( t1.second() );
2287  }
2288 }
2289 
2290 static QVariant fcnEpoch( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2291 {
2292  QDateTime dt = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
2293  if ( dt.isValid() )
2294  {
2295  return QVariant( dt.toMSecsSinceEpoch() );
2296  }
2297  else
2298  {
2299  return QVariant();
2300  }
2301 }
2302 
2303 static QVariant fcnDateTimeFromEpoch( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2304 {
2305  long long millisecs_since_epoch = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
2306  // no sense to check for strange values, as Qt behavior is undefined anyway (see docs)
2307  return QVariant( QDateTime::fromMSecsSinceEpoch( millisecs_since_epoch ) );
2308 }
2309 
2310 #define ENSURE_GEOM_TYPE(f, g, geomtype) \
2311  if ( !(f).hasGeometry() ) \
2312  return QVariant(); \
2313  QgsGeometry g = (f).geometry(); \
2314  if ( (g).type() != (geomtype) ) \
2315  return QVariant();
2316 
2317 static QVariant fcnX( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
2318 {
2319  FEAT_FROM_CONTEXT( context, f )
2321  if ( g.isMultipart() )
2322  {
2323  return g.asMultiPoint().at( 0 ).x();
2324  }
2325  else
2326  {
2327  return g.asPoint().x();
2328  }
2329 }
2330 
2331 static QVariant fcnY( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
2332 {
2333  FEAT_FROM_CONTEXT( context, f )
2335  if ( g.isMultipart() )
2336  {
2337  return g.asMultiPoint().at( 0 ).y();
2338  }
2339  else
2340  {
2341  return g.asPoint().y();
2342  }
2343 }
2344 
2345 static QVariant fcnGeomIsValid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2346 {
2347  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2348  if ( geom.isNull() )
2349  return QVariant();
2350 
2351  bool isValid = geom.isGeosValid();
2352 
2353  return QVariant( isValid );
2354 }
2355 
2356 static QVariant fcnGeomX( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2357 {
2358  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2359  if ( geom.isNull() )
2360  return QVariant();
2361 
2362  //if single point, return the point's x coordinate
2363  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2364  {
2365  return geom.asPoint().x();
2366  }
2367 
2368  //otherwise return centroid x
2369  QgsGeometry centroid = geom.centroid();
2370  QVariant result( centroid.asPoint().x() );
2371  return result;
2372 }
2373 
2374 static QVariant fcnGeomY( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2375 {
2376  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2377  if ( geom.isNull() )
2378  return QVariant();
2379 
2380  //if single point, return the point's y coordinate
2381  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2382  {
2383  return geom.asPoint().y();
2384  }
2385 
2386  //otherwise return centroid y
2387  QgsGeometry centroid = geom.centroid();
2388  QVariant result( centroid.asPoint().y() );
2389  return result;
2390 }
2391 
2392 static QVariant fcnGeomZ( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2393 {
2394  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2395  if ( geom.isNull() )
2396  return QVariant(); //or 0?
2397 
2398  if ( !geom.constGet()->is3D() )
2399  return QVariant();
2400 
2401  //if single point, return the point's z coordinate
2402  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2403  {
2404  const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2405  if ( point )
2406  return point->z();
2407  }
2408  else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
2409  {
2410  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2411  {
2412  if ( collection->numGeometries() == 1 )
2413  {
2414  if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
2415  return point->z();
2416  }
2417  }
2418  }
2419 
2420  return QVariant();
2421 }
2422 
2423 static QVariant fcnGeomM( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2424 {
2425  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2426  if ( geom.isNull() )
2427  return QVariant(); //or 0?
2428 
2429  if ( !geom.constGet()->isMeasure() )
2430  return QVariant();
2431 
2432  //if single point, return the point's m value
2433  if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2434  {
2435  const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2436  if ( point )
2437  return point->m();
2438  }
2439  else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
2440  {
2441  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2442  {
2443  if ( collection->numGeometries() == 1 )
2444  {
2445  if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
2446  return point->m();
2447  }
2448  }
2449  }
2450 
2451  return QVariant();
2452 }
2453 
2454 static QVariant fcnPointN( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2455 {
2456  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2457 
2458  if ( geom.isNull() )
2459  return QVariant();
2460 
2461  int idx = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2462 
2463  if ( idx < 0 )
2464  {
2465  //negative idx
2466  int count = geom.constGet()->nCoordinates();
2467  idx = count + idx;
2468  }
2469  else
2470  {
2471  //positive idx is 1 based
2472  idx -= 1;
2473  }
2474 
2475  QgsVertexId vId;
2476  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
2477  {
2478  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
2479  return QVariant();
2480  }
2481 
2482  QgsPoint point = geom.constGet()->vertexAt( vId );
2483  return QVariant::fromValue( QgsGeometry( new QgsPoint( point ) ) );
2484 }
2485 
2486 static QVariant fcnStartPoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2487 {
2488  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2489 
2490  if ( geom.isNull() )
2491  return QVariant();
2492 
2493  QgsVertexId vId;
2494  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
2495  {
2496  return QVariant();
2497  }
2498 
2499  QgsPoint point = geom.constGet()->vertexAt( vId );
2500  return QVariant::fromValue( QgsGeometry( new QgsPoint( point ) ) );
2501 }
2502 
2503 static QVariant fcnEndPoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2504 {
2505  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2506 
2507  if ( geom.isNull() )
2508  return QVariant();
2509 
2510  QgsVertexId vId;
2511  if ( !geom.vertexIdFromVertexNr( geom.constGet()->nCoordinates() - 1, vId ) )
2512  {
2513  return QVariant();
2514  }
2515 
2516  QgsPoint point = geom.constGet()->vertexAt( vId );
2517  return QVariant::fromValue( QgsGeometry( new QgsPoint( point ) ) );
2518 }
2519 
2520 static QVariant fcnNodesToPoints( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2521 {
2522  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2523 
2524  if ( geom.isNull() )
2525  return QVariant();
2526 
2527  bool ignoreClosing = false;
2528  if ( values.length() > 1 )
2529  {
2530  ignoreClosing = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
2531  }
2532 
2533  QgsMultiPoint *mp = new QgsMultiPoint();
2534 
2535  const QgsCoordinateSequence sequence = geom.constGet()->coordinateSequence();
2536  for ( const QgsRingSequence &part : sequence )
2537  {
2538  for ( const QgsPointSequence &ring : part )
2539  {
2540  bool skipLast = false;
2541  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
2542  {
2543  skipLast = true;
2544  }
2545 
2546  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
2547  {
2548  mp->addGeometry( ring.at( i ).clone() );
2549  }
2550  }
2551  }
2552 
2553  return QVariant::fromValue( QgsGeometry( mp ) );
2554 }
2555 
2556 static QVariant fcnSegmentsToLines( 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 QVector< QgsLineString * > linesToProcess = QgsGeometryUtils::extractLineStrings( geom.constGet() );
2564 
2565  //OK, now we have a complete list of segmentized lines from the geometry
2567  for ( QgsLineString *line : linesToProcess )
2568  {
2569  for ( int i = 0; i < line->numPoints() - 1; ++i )
2570  {
2571  QgsLineString *segment = new QgsLineString();
2572  segment->setPoints( QgsPointSequence()
2573  << line->pointN( i )
2574  << line->pointN( i + 1 ) );
2575  ml->addGeometry( segment );
2576  }
2577  delete line;
2578  }
2579 
2580  return QVariant::fromValue( QgsGeometry( ml ) );
2581 }
2582 
2583 static QVariant fcnInteriorRingN( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2584 {
2585  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2586 
2587  if ( geom.isNull() )
2588  return QVariant();
2589 
2590  const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
2591  if ( !curvePolygon && geom.isMultipart() )
2592  {
2593  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2594  {
2595  if ( collection->numGeometries() == 1 )
2596  {
2597  curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
2598  }
2599  }
2600  }
2601 
2602  if ( !curvePolygon )
2603  return QVariant();
2604 
2605  //idx is 1 based
2606  qlonglong idx = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) - 1;
2607 
2608  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
2609  return QVariant();
2610 
2611  QgsCurve *curve = static_cast< QgsCurve * >( curvePolygon->interiorRing( static_cast< int >( idx ) )->clone() );
2612  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
2613  return result;
2614 }
2615 
2616 static QVariant fcnGeometryN( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2617 {
2618  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2619 
2620  if ( geom.isNull() )
2621  return QVariant();
2622 
2623  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() );
2624  if ( !collection )
2625  return QVariant();
2626 
2627  //idx is 1 based
2628  qlonglong idx = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) - 1;
2629 
2630  if ( idx < 0 || idx >= collection->numGeometries() )
2631  return QVariant();
2632 
2633  QgsAbstractGeometry *part = collection->geometryN( static_cast< int >( idx ) )->clone();
2634  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
2635  return result;
2636 }
2637 
2638 static QVariant fcnBoundary( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2639 {
2640  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2641 
2642  if ( geom.isNull() )
2643  return QVariant();
2644 
2645  QgsAbstractGeometry *boundary = geom.constGet()->boundary();
2646  if ( !boundary )
2647  return QVariant();
2648 
2649  return QVariant::fromValue( QgsGeometry( boundary ) );
2650 }
2651 
2652 static QVariant fcnLineMerge( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2653 {
2654  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2655 
2656  if ( geom.isNull() )
2657  return QVariant();
2658 
2659  QgsGeometry merged = geom.mergeLines();
2660  if ( merged.isNull() )
2661  return QVariant();
2662 
2663  return QVariant::fromValue( merged );
2664 }
2665 
2666 static QVariant fcnSimplify( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2667 {
2668  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2669 
2670  if ( geom.isNull() )
2671  return QVariant();
2672 
2673  double tolerance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2674 
2675  QgsGeometry simplified = geom.simplify( tolerance );
2676  if ( simplified.isNull() )
2677  return QVariant();
2678 
2679  return simplified;
2680 }
2681 
2682 static QVariant fcnSimplifyVW( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2683 {
2684  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2685 
2686  if ( geom.isNull() )
2687  return QVariant();
2688 
2689  double tolerance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2690 
2692 
2693  QgsGeometry simplified = simplifier.simplify( geom );
2694  if ( simplified.isNull() )
2695  return QVariant();
2696 
2697  return simplified;
2698 }
2699 
2700 static QVariant fcnSmooth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2701 {
2702  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2703 
2704  if ( geom.isNull() )
2705  return QVariant();
2706 
2707  int iterations = std::min( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ), 10 );
2708  double offset = qBound( 0.0, QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent ), 0.5 );
2709  double minLength = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
2710  double maxAngle = qBound( 0.0, QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent ), 180.0 );
2711 
2712  QgsGeometry smoothed = geom.smooth( static_cast<unsigned int>( iterations ), offset, minLength, maxAngle );
2713  if ( smoothed.isNull() )
2714  return QVariant();
2715 
2716  return smoothed;
2717 }
2718 
2719 static QVariant fcnCollectGeometries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2720 {
2721  QVariantList list;
2722  if ( values.size() == 1 && ( values.at( 0 ).type() == QVariant::List || values.at( 0 ).type() == QVariant::StringList ) )
2723  {
2724  list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
2725  }
2726  else
2727  {
2728  list = values;
2729  }
2730 
2731  QVector< QgsGeometry > parts;
2732  parts.reserve( list.size() );
2733  for ( const QVariant &value : qgis::as_const( list ) )
2734  {
2735  if ( value.canConvert<QgsGeometry>() )
2736  {
2737  parts << value.value<QgsGeometry>();
2738  }
2739  else
2740  {
2741  parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
2742  return QgsGeometry();
2743  }
2744  }
2745 
2746  return QgsGeometry::collectGeometry( parts );
2747 }
2748 
2749 static QVariant fcnMakePoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2750 {
2751  if ( values.count() < 2 || values.count() > 4 )
2752  {
2753  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
2754  return QVariant();
2755  }
2756 
2757  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
2758  double y = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2759  double z = values.count() >= 3 ? QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent ) : 0.0;
2760  double m = values.count() >= 4 ? QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent ) : 0.0;
2761  switch ( values.count() )
2762  {
2763  case 2:
2764  return QVariant::fromValue( QgsGeometry( new QgsPoint( x, y ) ) );
2765  case 3:
2766  return QVariant::fromValue( QgsGeometry( new QgsPoint( QgsWkbTypes::PointZ, x, y, z ) ) );
2767  case 4:
2768  return QVariant::fromValue( QgsGeometry( new QgsPoint( QgsWkbTypes::PointZM, x, y, z, m ) ) );
2769  }
2770  return QVariant(); //avoid warning
2771 }
2772 
2773 static QVariant fcnMakePointM( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2774 {
2775  double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
2776  double y = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2777  double m = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
2778  return QVariant::fromValue( QgsGeometry( new QgsPoint( QgsWkbTypes::PointM, x, y, 0.0, m ) ) );
2779 }
2780 
2781 static QVariant fcnMakeLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2782 {
2783  if ( values.empty() )
2784  {
2785  return QVariant();
2786  }
2787 
2788  QVector<QgsPoint> points;
2789  points.reserve( values.count() );
2790 
2791  auto addPoint = [&points]( const QgsGeometry & geom )
2792  {
2793  if ( geom.isNull() )
2794  return;
2795 
2796  if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2797  return;
2798 
2799  const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2800  if ( !point )
2801  return;
2802 
2803  points << *point;
2804  };
2805 
2806  for ( const QVariant &value : values )
2807  {
2808  if ( value.type() == QVariant::List )
2809  {
2810  const QVariantList list = value.toList();
2811  for ( const QVariant &v : list )
2812  {
2813  addPoint( QgsExpressionUtils::getGeometry( v, parent ) );
2814  }
2815  }
2816  else
2817  {
2818  addPoint( QgsExpressionUtils::getGeometry( value, parent ) );
2819  }
2820  }
2821 
2822  if ( points.count() < 2 )
2823  return QVariant();
2824 
2825  return QgsGeometry( new QgsLineString( points ) );
2826 }
2827 
2828 static QVariant fcnMakePolygon( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2829 {
2830  if ( values.count() < 1 )
2831  {
2832  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
2833  return QVariant();
2834  }
2835 
2836  QgsGeometry outerRing = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2837  if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isNull() )
2838  return QVariant();
2839 
2840  std::unique_ptr< QgsPolygon > polygon = qgis::make_unique< QgsPolygon >();
2841 
2842  const QgsCurve *exteriorRing = qgsgeometry_cast< QgsCurve * >( outerRing.constGet() );
2843  if ( !exteriorRing && outerRing.isMultipart() )
2844  {
2845  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( outerRing.constGet() ) )
2846  {
2847  if ( collection->numGeometries() == 1 )
2848  {
2849  exteriorRing = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2850  }
2851  }
2852  }
2853 
2854  if ( !exteriorRing )
2855  return QVariant();
2856 
2857  polygon->setExteriorRing( exteriorRing->segmentize() );
2858 
2859 
2860  for ( int i = 1; i < values.count(); ++i )
2861  {
2862  QgsGeometry ringGeom = QgsExpressionUtils::getGeometry( values.at( i ), parent );
2863  if ( ringGeom.isNull() )
2864  continue;
2865 
2866  if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isNull() )
2867  continue;
2868 
2869  const QgsCurve *ring = qgsgeometry_cast< QgsCurve * >( ringGeom.constGet() );
2870  if ( !ring && ringGeom.isMultipart() )
2871  {
2872  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( ringGeom.constGet() ) )
2873  {
2874  if ( collection->numGeometries() == 1 )
2875  {
2876  ring = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2877  }
2878  }
2879  }
2880 
2881  if ( !ring )
2882  continue;
2883 
2884  polygon->addInteriorRing( ring->segmentize() );
2885  }
2886 
2887  return QVariant::fromValue( QgsGeometry( std::move( polygon ) ) );
2888 }
2889 
2890 static QVariant fcnMakeTriangle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2891 {
2892  std::unique_ptr<QgsTriangle> tr( new QgsTriangle() );
2893  std::unique_ptr<QgsLineString> lineString( new QgsLineString() );
2894  lineString->clear();
2895 
2896  for ( const QVariant &value : values )
2897  {
2898  QgsGeometry geom = QgsExpressionUtils::getGeometry( value, parent );
2899  if ( geom.isNull() )
2900  return QVariant();
2901 
2902  if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2903  return QVariant();
2904 
2905  const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2906  if ( !point && geom.isMultipart() )
2907  {
2908  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2909  {
2910  if ( collection->numGeometries() == 1 )
2911  {
2912  point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2913  }
2914  }
2915  }
2916 
2917  if ( !point )
2918  return QVariant();
2919 
2920  lineString->addVertex( *point );
2921  }
2922 
2923  tr->setExteriorRing( lineString.release() );
2924 
2925  return QVariant::fromValue( QgsGeometry( tr.release() ) );
2926 }
2927 
2928 static QVariant fcnMakeCircle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2929 {
2930  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2931  if ( geom.isNull() )
2932  return QVariant();
2933 
2934  if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2935  return QVariant();
2936 
2937  double radius = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2938  int segment = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
2939 
2940  if ( segment < 3 )
2941  {
2942  parent->setEvalErrorString( QObject::tr( "Segment must be greater than 2" ) );
2943  return QVariant();
2944  }
2945  const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2946  if ( !point && geom.isMultipart() )
2947  {
2948  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2949  {
2950  if ( collection->numGeometries() == 1 )
2951  {
2952  point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2953  }
2954  }
2955  }
2956  if ( !point )
2957  return QVariant();
2958 
2959  QgsCircle circ( *point, radius );
2960  return QVariant::fromValue( QgsGeometry( circ.toPolygon( static_cast<unsigned int>( segment ) ) ) );
2961 }
2962 
2963 static QVariant fcnMakeEllipse( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2964 {
2965  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2966  if ( geom.isNull() )
2967  return QVariant();
2968 
2969  if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2970  return QVariant();
2971 
2972  double majorAxis = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2973  double minorAxis = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
2974  double azimuth = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
2975  int segment = QgsExpressionUtils::getNativeIntValue( values.at( 4 ), parent );
2976  if ( segment < 3 )
2977  {
2978  parent->setEvalErrorString( QObject::tr( "Segment must be greater than 2" ) );
2979  return QVariant();
2980  }
2981  const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2982  if ( !point && geom.isMultipart() )
2983  {
2984  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2985  {
2986  if ( collection->numGeometries() == 1 )
2987  {
2988  point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2989  }
2990  }
2991  }
2992  if ( !point )
2993  return QVariant();
2994 
2995  QgsEllipse elp( *point, majorAxis, minorAxis, azimuth );
2996  return QVariant::fromValue( QgsGeometry( elp.toPolygon( static_cast<unsigned int>( segment ) ) ) );
2997 }
2998 
2999 static QVariant fcnMakeRegularPolygon( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3000 {
3001 
3002  QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3003  if ( pt1.isNull() )
3004  return QVariant();
3005 
3006  if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
3007  return QVariant();
3008 
3009  QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3010  if ( pt2.isNull() )
3011  return QVariant();
3012 
3013  if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
3014  return QVariant();
3015 
3016  unsigned int nbEdges = static_cast<unsigned int>( QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) );
3017  if ( nbEdges < 3 )
3018  {
3019  parent->setEvalErrorString( QObject::tr( "Number of edges/sides must be greater than 2" ) );
3020  return QVariant();
3021  }
3022 
3023  QgsRegularPolygon::ConstructionOption option = static_cast< QgsRegularPolygon::ConstructionOption >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3025  {
3026  parent->setEvalErrorString( QObject::tr( "Option can be 0 (inscribed) or 1 (circumscribed)" ) );
3027  return QVariant();
3028  }
3029 
3030  const QgsPoint *center = qgsgeometry_cast< const QgsPoint * >( pt1.constGet() );
3031  if ( !center && pt1.isMultipart() )
3032  {
3033  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt1.constGet() ) )
3034  {
3035  if ( collection->numGeometries() == 1 )
3036  {
3037  center = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3038  }
3039  }
3040  }
3041  if ( !center )
3042  return QVariant();
3043 
3044  const QgsPoint *corner = qgsgeometry_cast< const QgsPoint * >( pt2.constGet() );
3045  if ( !corner && pt2.isMultipart() )
3046  {
3047  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt2.constGet() ) )
3048  {
3049  if ( collection->numGeometries() == 1 )
3050  {
3051  corner = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3052  }
3053  }
3054  }
3055  if ( !corner )
3056  return QVariant();
3057 
3058  QgsRegularPolygon rp = QgsRegularPolygon( *center, *corner, nbEdges, option );
3059 
3060  return QVariant::fromValue( QgsGeometry( rp.toPolygon() ) );
3061 
3062 }
3063 
3064 static QVariant fcnMakeSquare( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3065 {
3066  QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3067  if ( pt1.isNull() )
3068  return QVariant();
3069  if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
3070  return QVariant();
3071 
3072  QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3073  if ( pt2.isNull() )
3074  return QVariant();
3075  if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
3076  return QVariant();
3077 
3078  const QgsPoint *point1 = qgsgeometry_cast< const QgsPoint *>( pt1.constGet() );
3079  const QgsPoint *point2 = qgsgeometry_cast< const QgsPoint *>( pt2.constGet() );
3080  QgsQuadrilateral square = QgsQuadrilateral::squareFromDiagonal( *point1, *point2 );
3081 
3082  return QVariant::fromValue( QgsGeometry( square.toPolygon() ) );
3083 }
3084 
3085 static QVariant fcnMakeRectangleFrom3Points( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3086 {
3087  QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3088  if ( pt1.isNull() )
3089  return QVariant();
3090  if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
3091  return QVariant();
3092 
3093  QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3094  if ( pt2.isNull() )
3095  return QVariant();
3096  if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
3097  return QVariant();
3098 
3099  QgsGeometry pt3 = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );
3100  if ( pt3.isNull() )
3101  return QVariant();
3102  if ( pt3.type() != QgsWkbTypes::PointGeometry || pt3.isMultipart() )
3103  return QVariant();
3104 
3105  QgsQuadrilateral::ConstructionOption option = static_cast< QgsQuadrilateral::ConstructionOption >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3106  if ( ( option < QgsQuadrilateral::Distance ) || ( option > QgsQuadrilateral::Projected ) )
3107  {
3108  parent->setEvalErrorString( QObject::tr( "Option can be 0 (distance) or 1 (projected)" ) );
3109  return QVariant();
3110  }
3111  const QgsPoint *point1 = qgsgeometry_cast< const QgsPoint *>( pt1.constGet() );
3112  const QgsPoint *point2 = qgsgeometry_cast< const QgsPoint *>( pt2.constGet() );
3113  const QgsPoint *point3 = qgsgeometry_cast< const QgsPoint *>( pt3.constGet() );
3114  QgsQuadrilateral rect = QgsQuadrilateral::rectangleFrom3Points( *point1, *point2, *point3, option );
3115  return QVariant::fromValue( QgsGeometry( rect.toPolygon() ) );
3116 }
3117 
3118 static QVariant pointAt( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent ) // helper function
3119 {
3120  FEAT_FROM_CONTEXT( context, f )
3121  int idx = QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent );
3122  QgsGeometry g = f.geometry();
3123  if ( g.isNull() )
3124  return QVariant();
3125 
3126  if ( idx < 0 )
3127  {
3128  idx += g.constGet()->nCoordinates();
3129  }
3130  if ( idx < 0 || idx >= g.constGet()->nCoordinates() )
3131  {
3132  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
3133  return QVariant();
3134  }
3135 
3136  QgsPointXY p = g.vertexAt( idx );
3137  return QVariant( QPointF( p.x(), p.y() ) );
3138 }
3139 
3140 static QVariant fcnXat( const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent, const QgsExpressionNodeFunction * )
3141 {
3142  QVariant v = pointAt( values, f, parent );
3143  if ( v.type() == QVariant::PointF )
3144  return QVariant( v.toPointF().x() );
3145  else
3146  return QVariant();
3147 }
3148 static QVariant fcnYat( const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent, const QgsExpressionNodeFunction * )
3149 {
3150  QVariant v = pointAt( values, f, parent );
3151  if ( v.type() == QVariant::PointF )
3152  return QVariant( v.toPointF().y() );
3153  else
3154  return QVariant();
3155 }
3156 static QVariant fcnGeometry( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
3157 {
3158  FEAT_FROM_CONTEXT( context, f )
3159  QgsGeometry geom = f.geometry();
3160  if ( !geom.isNull() )
3161  return QVariant::fromValue( geom );
3162  else
3163  return QVariant( QVariant::UserType );
3164 }
3165 
3166 static QVariant fcnGeomFromWKT( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3167 {
3168  QString wkt = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
3169  QgsGeometry geom = QgsGeometry::fromWkt( wkt );
3170  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3171  return result;
3172 }
3173 
3174 static QVariant fcnGeomFromWKB( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3175 {
3176  const QByteArray wkb = QgsExpressionUtils::getBinaryValue( values.at( 0 ), parent );
3177  if ( wkb.isNull() )
3178  return QVariant();
3179 
3180  QgsGeometry geom;
3181  geom.fromWkb( wkb );
3182  return !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3183 }
3184 
3185 static QVariant fcnGeomFromGML( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3186 {
3187  QString gml = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
3188  QgsOgcUtils::Context ogcContext;
3189  if ( context )
3190  {
3191  QgsWeakMapLayerPointer mapLayerPtr {context->variable( QStringLiteral( "layer" ) ).value<QgsWeakMapLayerPointer>() };
3192  if ( mapLayerPtr )
3193  {
3194  ogcContext.layer = mapLayerPtr.data();
3195  ogcContext.transformContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
3196  }
3197  }
3198  QgsGeometry geom = QgsOgcUtils::geometryFromGML( gml, ogcContext );
3199  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3200  return result;
3201 }
3202 
3203 static QVariant fcnGeomArea( const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3204 {
3205  FEAT_FROM_CONTEXT( context, f )
3207  QgsDistanceArea *calc = parent->geomCalculator();
3208  if ( calc )
3209  {
3210  double area = calc->measureArea( f.geometry() );
3211  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
3212  return QVariant( area );
3213  }
3214  else
3215  {
3216  return QVariant( f.geometry().area() );
3217  }
3218 }
3219 
3220 static QVariant fcnArea( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3221 {
3222  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3223 
3224  if ( geom.type() != QgsWkbTypes::PolygonGeometry )
3225  return QVariant();
3226 
3227  return QVariant( geom.area() );
3228 }
3229 
3230 static QVariant fcnGeomLength( const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3231 {
3232  FEAT_FROM_CONTEXT( context, f )
3234  QgsDistanceArea *calc = parent->geomCalculator();
3235  if ( calc )
3236  {
3237  double len = calc->measureLength( f.geometry() );
3238  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
3239  return QVariant( len );
3240  }
3241  else
3242  {
3243  return QVariant( f.geometry().length() );
3244  }
3245 }
3246 
3247 static QVariant fcnGeomPerimeter( const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3248 {
3249  FEAT_FROM_CONTEXT( context, f )
3251  QgsDistanceArea *calc = parent->geomCalculator();
3252  if ( calc )
3253  {
3254  double len = calc->measurePerimeter( f.geometry() );
3255  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
3256  return QVariant( len );
3257  }
3258  else
3259  {
3260  return f.geometry().isNull() ? QVariant( 0 ) : QVariant( f.geometry().constGet()->perimeter() );
3261  }
3262 }
3263 
3264 static QVariant fcnPerimeter( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3265 {
3266  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3267 
3268  if ( geom.type() != QgsWkbTypes::PolygonGeometry )
3269  return QVariant();
3270 
3271  //length for polygons = perimeter
3272  return QVariant( geom.length() );
3273 }
3274 
3275 static QVariant fcnGeomNumPoints( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3276 {
3277  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3278  return QVariant( geom.isNull() ? 0 : geom.constGet()->nCoordinates() );
3279 }
3280 
3281 static QVariant fcnGeomNumGeometries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3282 {
3283  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3284  if ( geom.isNull() )
3285  return QVariant();
3286 
3287  return QVariant( geom.constGet()->partCount() );
3288 }
3289 
3290 static QVariant fcnGeomIsMultipart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3291 {
3292  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3293  if ( geom.isNull() )
3294  return QVariant();
3295 
3296  return QVariant( geom.isMultipart() );
3297 }
3298 
3299 static QVariant fcnGeomNumInteriorRings( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3300 {
3301  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3302 
3303  if ( geom.isNull() )
3304  return QVariant();
3305 
3306  const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
3307  if ( curvePolygon )
3308  return QVariant( curvePolygon->numInteriorRings() );
3309 
3310  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() );
3311  if ( collection )
3312  {
3313  //find first CurvePolygon in collection
3314  for ( int i = 0; i < collection->numGeometries(); ++i )
3315  {
3316  curvePolygon = qgsgeometry_cast< const QgsCurvePolygon *>( collection->geometryN( i ) );
3317  if ( !curvePolygon )
3318  continue;
3319 
3320  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
3321  }
3322  }
3323 
3324  return QVariant();
3325 }
3326 
3327 static QVariant fcnGeomNumRings( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3328 {
3329  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3330 
3331  if ( geom.isNull() )
3332  return QVariant();
3333 
3334  const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
3335  if ( curvePolygon )
3336  return QVariant( curvePolygon->ringCount() );
3337 
3338  bool foundPoly = false;
3339  int ringCount = 0;
3340  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() );
3341  if ( collection )
3342  {
3343  //find CurvePolygons in collection
3344  for ( int i = 0; i < collection->numGeometries(); ++i )
3345  {
3346  curvePolygon = qgsgeometry_cast< QgsCurvePolygon *>( collection->geometryN( i ) );
3347  if ( !curvePolygon )
3348  continue;
3349 
3350  foundPoly = true;
3351  ringCount += curvePolygon->ringCount();
3352  }
3353  }
3354 
3355  if ( !foundPoly )
3356  return QVariant();
3357 
3358  return QVariant( ringCount );
3359 }
3360 
3361 static QVariant fcnBounds( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3362 {
3363  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3364  QgsGeometry geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
3365  QVariant result = !geomBounds.isNull() ? QVariant::fromValue( geomBounds ) : QVariant();
3366  return result;
3367 }
3368 
3369 static QVariant fcnBoundsWidth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3370 {
3371  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3372  return QVariant::fromValue( geom.boundingBox().width() );
3373 }
3374 
3375 static QVariant fcnBoundsHeight( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3376 {
3377  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3378  return QVariant::fromValue( geom.boundingBox().height() );
3379 }
3380 
3381 static QVariant fcnXMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3382 {
3383  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3384  return QVariant::fromValue( geom.boundingBox().xMinimum() );
3385 }
3386 
3387 static QVariant fcnXMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3388 {
3389  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3390  return QVariant::fromValue( geom.boundingBox().xMaximum() );
3391 }
3392 
3393 static QVariant fcnYMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3394 {
3395  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3396  return QVariant::fromValue( geom.boundingBox().yMinimum() );
3397 }
3398 
3399 static QVariant fcnYMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3400 {
3401  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3402  return QVariant::fromValue( geom.boundingBox().yMaximum() );
3403 }
3404 
3405 static QVariant fcnZMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3406 {
3407  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3408 
3409  if ( geom.isNull() || geom.isEmpty( ) )
3410  return QVariant();
3411 
3412  if ( !geom.constGet()->is3D() )
3413  return QVariant();
3414 
3415  double max = std::numeric_limits< double >::lowest();
3416 
3417  for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3418  {
3419  double z = ( *it ).z();
3420 
3421  if ( max < z )
3422  max = z;
3423  }
3424 
3425  if ( max == std::numeric_limits< double >::lowest() )
3426  return QVariant( QVariant::Double );
3427 
3428  return QVariant( max );
3429 }
3430 
3431 static QVariant fcnZMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3432 {
3433  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3434 
3435  if ( geom.isNull() || geom.isEmpty() )
3436  return QVariant();
3437 
3438  if ( !geom.constGet()->is3D() )
3439  return QVariant();
3440 
3441  double min = std::numeric_limits< double >::max();
3442 
3443  for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3444  {
3445  double z = ( *it ).z();
3446 
3447  if ( z < min )
3448  min = z;
3449  }
3450 
3451  if ( min == std::numeric_limits< double >::max() )
3452  return QVariant( QVariant::Double );
3453 
3454  return QVariant( min );
3455 }
3456 
3457 static QVariant fcnMMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3458 {
3459  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3460 
3461  if ( geom.isNull() || geom.isEmpty() )
3462  return QVariant();
3463 
3464  if ( !geom.constGet()->isMeasure() )
3465  return QVariant();
3466 
3467  double min = std::numeric_limits< double >::max();
3468 
3469  for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3470  {
3471  double m = ( *it ).m();
3472 
3473  if ( m < min )
3474  min = m;
3475  }
3476 
3477  if ( min == std::numeric_limits< double >::max() )
3478  return QVariant( QVariant::Double );
3479 
3480  return QVariant( min );
3481 }
3482 
3483 static QVariant fcnMMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3484 {
3485  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3486 
3487  if ( geom.isNull() || geom.isEmpty() )
3488  return QVariant();
3489 
3490  if ( !geom.constGet()->isMeasure() )
3491  return QVariant();
3492 
3493  double max = std::numeric_limits< double >::lowest();
3494 
3495  for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3496  {
3497  double m = ( *it ).m();
3498 
3499  if ( max < m )
3500  max = m;
3501  }
3502 
3503  if ( max == std::numeric_limits< double >::lowest() )
3504  return QVariant( QVariant::Double );
3505 
3506  return QVariant( max );
3507 }
3508 
3509 static QVariant fcnFlipCoordinates( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3510 {
3511  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3512  if ( geom.isNull() )
3513  return QVariant();
3514 
3515  std::unique_ptr< QgsAbstractGeometry > flipped( geom.constGet()->clone() );
3516  flipped->swapXy();
3517  return QVariant::fromValue( QgsGeometry( std::move( flipped ) ) );
3518 }
3519 
3520 static QVariant fcnIsClosed( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3521 {
3522  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3523  if ( fGeom.isNull() )
3524  return QVariant();
3525 
3526  const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( fGeom.constGet() );
3527  if ( !curve && fGeom.isMultipart() )
3528  {
3529  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
3530  {
3531  if ( collection->numGeometries() == 1 )
3532  {
3533  curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
3534  }
3535  }
3536  }
3537 
3538  if ( !curve )
3539  return QVariant();
3540 
3541  return QVariant::fromValue( curve->isClosed() );
3542 }
3543 
3544 static QVariant fcnCloseLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3545 {
3546  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3547 
3548  if ( geom.isNull() )
3549  return QVariant();
3550 
3551  QVariant result;
3552  if ( !geom.isMultipart() )
3553  {
3554  const QgsLineString *line = qgsgeometry_cast<const QgsLineString * >( geom.constGet() );
3555 
3556  if ( !line )
3557  return QVariant();
3558 
3559  std::unique_ptr< QgsLineString > closedLine( line->clone() );
3560  closedLine->close();
3561 
3562  result = QVariant::fromValue( QgsGeometry( std::move( closedLine ) ) );
3563  }
3564  else
3565  {
3566  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( geom.constGet() );
3567 
3568  std::unique_ptr< QgsGeometryCollection > closed( collection->createEmptyWithSameType() );
3569 
3570  for ( int i = 0; i < collection->numGeometries(); ++i )
3571  {
3572  if ( const QgsLineString *line = qgsgeometry_cast<const QgsLineString * >( collection->geometryN( i ) ) )
3573  {
3574  std::unique_ptr< QgsLineString > closedLine( line->clone() );
3575  closedLine->close();
3576 
3577  closed->addGeometry( closedLine.release() );
3578  }
3579  }
3580  result = QVariant::fromValue( QgsGeometry( std::move( closed ) ) );
3581  }
3582 
3583  return result;
3584 }
3585 
3586 static QVariant fcnIsEmpty( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3587 {
3588  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3589  if ( fGeom.isNull() )
3590  return QVariant();
3591 
3592  return QVariant::fromValue( fGeom.isEmpty() );
3593 }
3594 
3595 static QVariant fcnIsEmptyOrNull( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3596 {
3597  if ( values.at( 0 ).isNull() )
3598  return QVariant::fromValue( true );
3599 
3600  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3601  return QVariant::fromValue( fGeom.isNull() || fGeom.isEmpty() );
3602 }
3603 
3604 static QVariant fcnRelate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3605 {
3606  if ( values.length() < 2 || values.length() > 3 )
3607  return QVariant();
3608 
3609  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3610  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3611 
3612  if ( fGeom.isNull() || sGeom.isNull() )
3613  return QVariant();
3614 
3615  std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( fGeom.constGet() ) );
3616 
3617  if ( values.length() == 2 )
3618  {
3619  //two geometry arguments, return relation
3620  QString result = engine->relate( sGeom.constGet() );
3621  return QVariant::fromValue( result );
3622  }
3623  else
3624  {
3625  //three arguments, test pattern
3626  QString pattern = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
3627  bool result = engine->relatePattern( sGeom.constGet(), pattern );
3628  return QVariant::fromValue( result );
3629  }
3630 }
3631 
3632 static QVariant fcnBbox( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3633 {
3634  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3635  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3636  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
3637 }
3638 static QVariant fcnDisjoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3639 {
3640  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3641  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3642  return fGeom.disjoint( sGeom ) ? TVL_True : TVL_False;
3643 }
3644 static QVariant fcnIntersects( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3645 {
3646  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3647  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3648  return fGeom.intersects( sGeom ) ? TVL_True : TVL_False;
3649 }
3650 static QVariant fcnTouches( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3651 {
3652  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3653  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3654  return fGeom.touches( sGeom ) ? TVL_True : TVL_False;
3655 }
3656 static QVariant fcnCrosses( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3657 {
3658  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3659  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3660  return fGeom.crosses( sGeom ) ? TVL_True : TVL_False;
3661 }
3662 static QVariant fcnContains( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3663 {
3664  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3665  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3666  return fGeom.contains( sGeom ) ? TVL_True : TVL_False;
3667 }
3668 static QVariant fcnOverlaps( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3669 {
3670  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3671  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3672  return fGeom.overlaps( sGeom ) ? TVL_True : TVL_False;
3673 }
3674 static QVariant fcnWithin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3675 {
3676  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3677  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3678  return fGeom.within( sGeom ) ? TVL_True : TVL_False;
3679 }
3680 static QVariant fcnBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3681 {
3682  if ( values.length() < 2 || values.length() > 3 )
3683  return QVariant();
3684 
3685  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3686  double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3687  int seg = 8;
3688  if ( values.length() == 3 )
3689  seg = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
3690 
3691  QgsGeometry geom = fGeom.buffer( dist, seg );
3692  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3693  return result;
3694 }
3695 
3696 static QVariant fcnForceRHR( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3697 {
3698  const QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3699  const QgsGeometry reoriented = fGeom.forceRHR();
3700  return !reoriented.isNull() ? QVariant::fromValue( reoriented ) : QVariant();
3701 }
3702 
3703 static QVariant fcnWedgeBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3704 {
3705  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3706  const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( fGeom.constGet() );
3707  if ( !pt && fGeom.isMultipart() )
3708  {
3709  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
3710  {
3711  if ( collection->numGeometries() == 1 )
3712  {
3713  pt = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3714  }
3715  }
3716  }
3717 
3718  if ( !pt )
3719  {
3720  parent->setEvalErrorString( QObject::tr( "Function `wedge_buffer` requires a point value for the center." ) );
3721  return QVariant();
3722  }
3723 
3724  double azimuth = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3725  double width = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3726  double outerRadius = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3727  double innerRadius = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
3728 
3729  QgsGeometry geom = QgsGeometry::createWedgeBuffer( *pt, azimuth, width, outerRadius, innerRadius );
3730  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3731  return result;
3732 }
3733 
3734 static QVariant fcnTaperedBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3735 {
3736  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3737  if ( fGeom.type() != QgsWkbTypes::LineGeometry )
3738  {
3739  parent->setEvalErrorString( QObject::tr( "Function `tapered_buffer` requires a line geometry." ) );
3740  return QVariant();
3741  }
3742 
3743  double startWidth = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3744  double endWidth = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3745  int segments = static_cast< int >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3746 
3747  QgsGeometry geom = fGeom.taperedBuffer( startWidth, endWidth, segments );
3748  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3749  return result;
3750 }
3751 
3752 static QVariant fcnBufferByM( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3753 {
3754  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3755  if ( fGeom.type() != QgsWkbTypes::LineGeometry )
3756  {
3757  parent->setEvalErrorString( QObject::tr( "Function `buffer_by_m` requires a line geometry." ) );
3758  return QVariant();
3759  }
3760 
3761  int segments = static_cast< int >( QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) );
3762 
3763  QgsGeometry geom = fGeom.variableWidthBufferByM( segments );
3764  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3765  return result;
3766 }
3767 
3768 static QVariant fcnOffsetCurve( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3769 {
3770  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3771  double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3772  int segments = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
3773  QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3774  if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
3775  return QVariant();
3776  double miterLimit = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3777 
3778  QgsGeometry geom = fGeom.offsetCurve( dist, segments, join, miterLimit );
3779  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3780  return result;
3781 }
3782 
3783 static QVariant fcnSingleSidedBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3784 {
3785  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3786  double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3787  int segments = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
3788  QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3789  if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
3790  return QVariant();
3791  double miterLimit = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3792 
3793  QgsGeometry geom = fGeom.singleSidedBuffer( dist, segments, QgsGeometry::SideLeft, join, miterLimit );
3794  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3795  return result;
3796 }
3797 
3798 static QVariant fcnExtend( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3799 {
3800  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3801  double distStart = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3802  double distEnd = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3803 
3804  QgsGeometry geom = fGeom.extendLine( distStart, distEnd );
3805  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3806  return result;
3807 }
3808 
3809 static QVariant fcnTranslate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3810 {
3811  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3812  double dx = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3813  double dy = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3814  fGeom.translate( dx, dy );
3815  return QVariant::fromValue( fGeom );
3816 }
3817 
3818 static QVariant fcnRotate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3819 {
3820  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3821  const double rotation = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3822  const QgsGeometry center = values.at( 2 ).isValid() ? QgsExpressionUtils::getGeometry( values.at( 2 ), parent )
3823  : QgsGeometry();
3824 
3825  QgsPointXY pt;
3826  if ( center.isNull() )
3827  {
3828  // if center wasn't specified, use bounding box centroid
3829  pt = fGeom.boundingBox().center();
3830  }
3831  else if ( center.type() != QgsWkbTypes::PointGeometry )
3832  {
3833  parent->setEvalErrorString( QObject::tr( "Function 'rotate' requires a point value for the center" ) );
3834  return QVariant();
3835  }
3836  else if ( center.isMultipart() )
3837  {
3838  QgsMultiPointXY multiPoint = center.asMultiPoint();
3839  if ( multiPoint.count() == 1 )
3840  {
3841  pt = multiPoint[0];
3842  }
3843  else
3844  {
3845  parent->setEvalErrorString( QObject::tr( "Function 'rotate' requires a point value for the center" ) );
3846  return QVariant();
3847  }
3848  }
3849  else
3850  {
3851  pt = center.asPoint();
3852  }
3853 
3854  fGeom.rotate( rotation, pt );
3855  return QVariant::fromValue( fGeom );
3856 }
3857 
3858 static QVariant fcnCentroid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3859 {
3860  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3861  QgsGeometry geom = fGeom.centroid();
3862  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3863  return result;
3864 }
3865 static QVariant fcnPointOnSurface( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3866 {
3867  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3868  QgsGeometry geom = fGeom.pointOnSurface();
3869  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3870  return result;
3871 }
3872 
3873 static QVariant fcnPoleOfInaccessibility( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3874 {
3875  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3876  double tolerance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3877  QgsGeometry geom = fGeom.poleOfInaccessibility( tolerance );
3878  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3879  return result;
3880 }
3881 
3882 static QVariant fcnConvexHull( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3883 {
3884  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3885  QgsGeometry geom = fGeom.convexHull();
3886  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3887  return result;
3888 }
3889 
3890 
3891 static QVariant fcnMinimalCircle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3892 {
3893  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3894  int segments = 36;
3895  if ( values.length() == 2 )
3896  segments = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
3897  if ( segments < 0 )
3898  {
3899  parent->setEvalErrorString( QObject::tr( "Parameter can not be negative." ) );
3900  return QVariant();
3901  }
3902 
3903  QgsGeometry geom = fGeom.minimalEnclosingCircle( static_cast<unsigned int>( segments ) );
3904  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3905  return result;
3906 }
3907 
3908 static QVariant fcnOrientedBBox( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3909 {
3910  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3911  QgsGeometry geom = fGeom.orientedMinimumBoundingBox( );
3912  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3913  return result;
3914 }
3915 
3916 static QVariant fcnMainAngle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3917 {
3918  const QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3919 
3920  // we use the angle of the oriented minimum bounding box to calculate the polygon main angle.
3921  // While ArcGIS uses a different approach ("the angle of longest collection of segments that have similar orientation"), this
3922  // yields similar results to OMBB approach under the same constraints ("this tool is meant for primarily orthogonal polygons rather than organically shaped ones.")
3923 
3924  double area, angle, width, height;
3925  const QgsGeometry geom = fGeom.orientedMinimumBoundingBox( area, angle, width, height );
3926 
3927  if ( geom.isNull() )
3928  {
3929  parent->setEvalErrorString( QObject::tr( "Error calculating polygon main angle: %1" ).arg( geom.lastError() ) );
3930  return QVariant();
3931  }
3932  return angle;
3933 }
3934 
3935 static QVariant fcnDifference( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3936 {
3937  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3938  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3939  QgsGeometry geom = fGeom.difference( sGeom );
3940  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3941  return result;
3942 }
3943 
3944 static QVariant fcnReverse( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3945 {
3946  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3947  if ( fGeom.isNull() )
3948  return QVariant();
3949 
3950  QVariant result;
3951  if ( !fGeom.isMultipart() )
3952  {
3953  const QgsCurve *curve = qgsgeometry_cast<const QgsCurve * >( fGeom.constGet() );
3954  if ( !curve )
3955  return QVariant();
3956 
3957  QgsCurve *reversed = curve->reversed();
3958  result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
3959  }
3960  else
3961  {
3962  const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( fGeom.constGet() );
3963  std::unique_ptr< QgsGeometryCollection > reversed( collection->createEmptyWithSameType() );
3964  for ( int i = 0; i < collection->numGeometries(); ++i )
3965  {
3966  if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve * >( collection->geometryN( i ) ) )
3967  {
3968  reversed->addGeometry( curve->reversed() );
3969  }
3970  else
3971  {
3972  reversed->addGeometry( collection->geometryN( i )->clone() );
3973  }
3974  }
3975  result = reversed ? QVariant::fromValue( QgsGeometry( std::move( reversed ) ) ) : QVariant();
3976  }
3977  return result;
3978 }
3979 
3980 static QVariant fcnExteriorRing( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3981 {
3982  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3983  if ( fGeom.isNull() )
3984  return QVariant();
3985 
3986  const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( fGeom.constGet() );
3987  if ( !curvePolygon && fGeom.isMultipart() )
3988  {
3989  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
3990  {
3991  if ( collection->numGeometries() == 1 )
3992  {
3993  curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
3994  }
3995  }
3996  }
3997 
3998  if ( !curvePolygon || !curvePolygon->exteriorRing() )
3999  return QVariant();
4000 
4001  QgsCurve *exterior = static_cast< QgsCurve * >( curvePolygon->exteriorRing()->clone() );
4002  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
4003  return result;
4004 }
4005 
4006 static QVariant fcnDistance( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4007 {
4008  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4009  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4010  return QVariant( fGeom.distance( sGeom ) );
4011 }
4012 
4013 static QVariant fcnHausdorffDistance( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4014 {
4015  QgsGeometry g1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4016  QgsGeometry g2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4017 
4018  double res = -1;
4019  if ( values.length() == 3 && values.at( 2 ).isValid() )
4020  {
4021  double densify = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4022  densify = qBound( 0.0, densify, 1.0 );
4023  res = g1.hausdorffDistanceDensify( g2, densify );
4024  }
4025  else
4026  {
4027  res = g1.hausdorffDistance( g2 );
4028  }
4029 
4030  return res > -1 ? QVariant( res ) : QVariant();
4031 }
4032 
4033 static QVariant fcnIntersection( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4034 {
4035  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4036  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4037  QgsGeometry geom = fGeom.intersection( sGeom );
4038  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4039  return result;
4040 }
4041 static QVariant fcnSymDifference( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4042 {
4043  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4044  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4045  QgsGeometry geom = fGeom.symDifference( sGeom );
4046  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4047  return result;
4048 }
4049 static QVariant fcnCombine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4050 {
4051  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4052  QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4053  QgsGeometry geom = fGeom.combine( sGeom );
4054  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4055  return result;
4056 }
4057 
4058 static QVariant fcnGeomToWKT( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4059 {
4060  if ( values.length() < 1 || values.length() > 2 )
4061  return QVariant();
4062 
4063  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4064  int prec = 8;
4065  if ( values.length() == 2 )
4066  prec = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4067  QString wkt = fGeom.asWkt( prec );
4068  return QVariant( wkt );
4069 }
4070 
4071 static QVariant fcnGeomToWKB( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4072 {
4073  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4074  return fGeom.isNull() ? QVariant() : QVariant( fGeom.asWkb() );
4075 }
4076 
4077 static QVariant fcnAzimuth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4078 {
4079  if ( values.length() != 2 )
4080  {
4081  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
4082  return QVariant();
4083  }
4084 
4085  QgsGeometry fGeom1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4086  QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4087 
4088  const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
4089  if ( !pt1 && fGeom1.isMultipart() )
4090  {
4091  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
4092  {
4093  if ( collection->numGeometries() == 1 )
4094  {
4095  pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4096  }
4097  }
4098  }
4099 
4100  const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
4101  if ( !pt2 && fGeom2.isMultipart() )
4102  {
4103  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
4104  {
4105  if ( collection->numGeometries() == 1 )
4106  {
4107  pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4108  }
4109  }
4110  }
4111 
4112  if ( !pt1 || !pt2 )
4113  {
4114  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
4115  return QVariant();
4116  }
4117 
4118  // Code from PostGIS
4119  if ( qgsDoubleNear( pt1->x(), pt2->x() ) )
4120  {
4121  if ( pt1->y() < pt2->y() )
4122  return 0.0;
4123  else if ( pt1->y() > pt2->y() )
4124  return M_PI;
4125  else
4126  return 0;
4127  }
4128 
4129  if ( qgsDoubleNear( pt1->y(), pt2->y() ) )
4130  {
4131  if ( pt1->x() < pt2->x() )
4132  return M_PI_2;
4133  else if ( pt1->x() > pt2->x() )
4134  return M_PI + ( M_PI_2 );
4135  else
4136  return 0;
4137  }
4138 
4139  if ( pt1->x() < pt2->x() )
4140  {
4141  if ( pt1->y() < pt2->y() )
4142  {
4143  return std::atan( std::fabs( pt1->x() - pt2->x() ) / std::fabs( pt1->y() - pt2->y() ) );
4144  }
4145  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
4146  {
4147  return std::atan( std::fabs( pt1->y() - pt2->y() ) / std::fabs( pt1->x() - pt2->x() ) )
4148  + ( M_PI_2 );
4149  }
4150  }
4151 
4152  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
4153  {
4154  if ( pt1->y() > pt2->y() )
4155  {
4156  return std::atan( std::fabs( pt1->x() - pt2->x() ) / std::fabs( pt1->y() - pt2->y() ) )
4157  + M_PI;
4158  }
4159  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
4160  {
4161  return std::atan( std::fabs( pt1->y() - pt2->y() ) / std::fabs( pt1->x() - pt2->x() ) )
4162  + ( M_PI + ( M_PI_2 ) );
4163  }
4164  }
4165 }
4166 
4167 static QVariant fcnProject( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4168 {
4169  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4170 
4171  if ( geom.type() != QgsWkbTypes::PointGeometry )
4172  {
4173  parent->setEvalErrorString( QStringLiteral( "'project' requires a point geometry" ) );
4174  return QVariant();
4175  }
4176 
4177  double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4178  double azimuth = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4179  double inclination = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
4180 
4181  const QgsPoint *p = static_cast<const QgsPoint *>( geom.constGet() );
4182  QgsPoint newPoint = p->project( distance, 180.0 * azimuth / M_PI, 180.0 * inclination / M_PI );
4183 
4184  return QVariant::fromValue( QgsGeometry( new QgsPoint( newPoint ) ) );
4185 }
4186 
4187 static QVariant fcnInclination( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4188 {
4189  QgsGeometry fGeom1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4190  QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4191 
4192  const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
4193  if ( !pt1 && fGeom1.isMultipart() )
4194  {
4195  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
4196  {
4197  if ( collection->numGeometries() == 1 )
4198  {
4199  pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4200  }
4201  }
4202  }
4203  const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
4204  if ( !pt2 && fGeom2.isMultipart() )
4205  {
4206  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
4207  {
4208  if ( collection->numGeometries() == 1 )
4209  {
4210  pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4211  }
4212  }
4213  }
4214 
4215  if ( ( fGeom1.type() != QgsWkbTypes::PointGeometry ) || ( fGeom2.type() != QgsWkbTypes::PointGeometry ) ||
4216  !pt1 || !pt2 )
4217  {
4218  parent->setEvalErrorString( QStringLiteral( "Function 'inclination' requires two points as arguments." ) );
4219  return QVariant();
4220  }
4221 
4222  return pt1->inclination( *pt2 );
4223 
4224 }
4225 
4226 static QVariant fcnExtrude( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4227 {
4228  if ( values.length() != 3 )
4229  return QVariant();
4230 
4231  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4232  double x = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4233  double y = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4234 
4235  QgsGeometry geom = fGeom.extrude( x, y );
4236 
4237  QVariant result = geom.constGet() ? QVariant::fromValue( geom ) : QVariant();
4238  return result;
4239 }
4240 
4241 static QVariant fcnOrderParts( const QVariantList &values, const QgsExpressionContext *ctx, QgsExpression *parent, const QgsExpressionNodeFunction * )
4242 {
4243  if ( values.length() < 2 )
4244  return QVariant();
4245 
4246  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4247 
4248  if ( !fGeom.isMultipart() )
4249  return values.at( 0 );
4250 
4251  QString expString = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4252  QVariant cachedExpression;
4253  if ( ctx )
4254  cachedExpression = ctx->cachedValue( expString );
4255  QgsExpression expression;
4256 
4257  if ( cachedExpression.isValid() )
4258  {
4259  expression = cachedExpression.value<QgsExpression>();
4260  }
4261  else
4262  expression = QgsExpression( expString );
4263 
4264  bool asc = values.value( 2 ).toBool();
4265 
4266  QgsExpressionContext *unconstedContext = nullptr;
4267  QgsFeature f;
4268  if ( ctx )
4269  {
4270  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
4271  // so no reason to worry
4272  unconstedContext = const_cast<QgsExpressionContext *>( ctx );
4273  f = ctx->feature();
4274  }
4275  else
4276  {
4277  // If there's no context provided, create a fake one
4278  unconstedContext = new QgsExpressionContext();
4279  }
4280 
4281  const QgsGeometryCollection *collection = qgsgeometry_cast<const QgsGeometryCollection *>( fGeom.constGet() );
4282  Q_ASSERT( collection ); // Should have failed the multipart check above
4283 
4285  orderBy.append( QgsFeatureRequest::OrderByClause( expression, asc ) );
4286  QgsExpressionSorter sorter( orderBy );
4287 
4288  QList<QgsFeature> partFeatures;
4289  partFeatures.reserve( collection->partCount() );
4290  for ( int i = 0; i < collection->partCount(); ++i )
4291  {
4292  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
4293  partFeatures << f;
4294  }
4295 
4296  sorter.sortFeatures( partFeatures, unconstedContext );
4297 
4298  QgsGeometryCollection *orderedGeom = qgsgeometry_cast<QgsGeometryCollection *>( fGeom.constGet()->clone() );
4299 
4300  Q_ASSERT( orderedGeom );
4301 
4302  while ( orderedGeom->partCount() )
4303  orderedGeom->removeGeometry( 0 );
4304 
4305  for ( const QgsFeature &feature : qgis::as_const( partFeatures ) )
4306  {
4307  orderedGeom->addGeometry( feature.geometry().constGet()->clone() );
4308  }
4309 
4310  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
4311 
4312  if ( !ctx )
4313  delete unconstedContext;
4314 
4315  return result;
4316 }
4317 
4318 static QVariant fcnClosestPoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4319 {
4320  QgsGeometry fromGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4321  QgsGeometry toGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4322 
4323  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
4324 
4325  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4326  return result;
4327 }
4328 
4329 static QVariant fcnShortestLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4330 {
4331  QgsGeometry fromGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4332  QgsGeometry toGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4333 
4334  QgsGeometry geom = fromGeom.shortestLine( toGeom );
4335 
4336  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4337  return result;
4338 }
4339 
4340 static QVariant fcnLineInterpolatePoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4341 {
4342  QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4343  double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4344 
4345  QgsGeometry geom = lineGeom.interpolate( distance );
4346 
4347  QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4348  return result;
4349 }
4350 
4351 static QVariant fcnLineSubset( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4352 {
4353  QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4354  if ( lineGeom.type() != QgsWkbTypes::LineGeometry )
4355  {
4356  parent->setEvalErrorString( QObject::tr( "line_substring requires a curve geometry input" ) );
4357  return QVariant();
4358  }
4359 
4360  const QgsCurve *curve = nullptr;
4361  if ( !lineGeom.isMultipart() )
4362  curve = qgsgeometry_cast< const QgsCurve * >( lineGeom.constGet() );
4363  else
4364  {
4365  if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( lineGeom.constGet() ) )
4366  {
4367  if ( collection->numGeometries() > 0 )
4368  {
4369  curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
4370  }
4371  }
4372  }
4373  if ( !curve )
4374  return QVariant();
4375 
4376  double startDistance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4377  double endDistance = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4378 
4379  std::unique_ptr< QgsCurve > substring( curve->curveSubstring( startDistance, endDistance ) );
4380  QgsGeometry result( std::move( substring ) );
4381  return !result.isNull() ? QVariant::fromValue( result ) : QVariant();
4382 }
4383 
4384 static QVariant fcnLineInterpolateAngle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4385 {
4386  QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4387  double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4388 
4389  return lineGeom.interpolateAngle( distance ) * 180.0 / M_PI;
4390 }
4391 
4392 static QVariant fcnAngleAtVertex( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4393 {
4394  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4395  int vertex = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4396  if ( vertex < 0 )
4397  {
4398  //negative idx
4399  int count = geom.constGet()->nCoordinates();
4400  vertex = count + vertex;
4401  }
4402 
4403  return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
4404 }
4405 
4406 static QVariant fcnDistanceToVertex( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4407 {
4408  QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4409  int vertex = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4410  if ( vertex < 0 )
4411  {
4412  //negative idx
4413  int count = geom.constGet()->nCoordinates();
4414  vertex = count + vertex;
4415  }
4416 
4417  return geom.distanceToVertex( vertex );
4418 }
4419 
4420 static QVariant fcnLineLocatePoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4421 {
4422  QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4423  QgsGeometry pointGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4424 
4425  double distance = lineGeom.lineLocatePoint( pointGeom );
4426 
4427  return distance >= 0 ? distance : QVariant();
4428 }
4429 
4430 static QVariant fcnRound( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4431 {
4432  if ( values.length() == 2 && values.at( 1 ).toInt() != 0 )
4433  {
4434  double number = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
4435  return qgsRound( number, QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
4436  }
4437 
4438  if ( values.length() >= 1 )
4439  {
4440  double number = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
4441  return QVariant( qlonglong( std::round( number ) ) );
4442  }
4443 
4444  return QVariant();
4445 }
4446 
4447 static QVariant fcnPi( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4448 {
4449  Q_UNUSED( values )
4450  Q_UNUSED( parent )
4451  return M_PI;
4452 }
4453 
4454 static QVariant fcnFormatNumber( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4455 {
4456  const double value = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
4457  const int places = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4458  const QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
4459  if ( places < 0 )
4460  {
4461  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
4462  return QVariant();
4463  }
4464 
4465  QLocale locale = !language.isEmpty() ? QLocale( language ) : QLocale();
4466  locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
4467  return locale.toString( value, 'f', places );
4468 }
4469 
4470 static QVariant fcnFormatDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4471 {
4472  const QDateTime datetime = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
4473  const QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4474  const QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
4475 
4476  QLocale locale = !language.isEmpty() ? QLocale( language ) : QLocale();
4477  return locale.toString( datetime, format );
4478 }
4479 
4480 static QVariant fcnColorGrayscaleAverage( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
4481 {
4482  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4483  int avg = ( color.red() + color.green() + color.blue() ) / 3;
4484  int alpha = color.alpha();
4485 
4486  color.setRgb( avg, avg, avg, alpha );
4487 
4488  return QgsSymbolLayerUtils::encodeColor( color );
4489 }
4490 
4491 static QVariant fcnColorMixRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4492 {
4493  QColor color1 = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4494  QColor color2 = QgsSymbolLayerUtils::decodeColor( values.at( 1 ).toString() );
4495  double ratio = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4496  if ( ratio > 1 )
4497  {
4498  ratio = 1;
4499  }
4500  else if ( ratio < 0 )
4501  {
4502  ratio = 0;
4503  }
4504 
4505  int red = static_cast<int>( color1.red() * ( 1 - ratio ) + color2.red() * ratio );
4506  int green = static_cast<int>( color1.green() * ( 1 - ratio ) + color2.green() * ratio );
4507  int blue = static_cast<int>( color1.blue() * ( 1 - ratio ) + color2.blue() * ratio );
4508  int alpha = static_cast<int>( color1.alpha() * ( 1 - ratio ) + color2.alpha() * ratio );
4509 
4510  QColor newColor( red, green, blue, alpha );
4511 
4512  return QgsSymbolLayerUtils::encodeColor( newColor );
4513 }
4514 
4515 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4516 {
4517  int red = QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent );
4518  int green = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4519  int blue = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
4520  QColor color = QColor( red, green, blue );
4521  if ( ! color.isValid() )
4522  {
4523  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
4524  color = QColor( 0, 0, 0 );
4525  }
4526 
4527  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4528 }
4529 
4530 static QVariant fcnTry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4531 {
4532  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
4533  QVariant value = node->eval( parent, context );
4534  if ( parent->hasEvalError() )
4535  {
4536  parent->setEvalErrorString( QString() );
4537  node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
4539  value = node->eval( parent, context );
4541  }
4542  return value;
4543 }
4544 
4545 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4546 {
4547  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
4549  QVariant value = node->eval( parent, context );
4551  if ( value.toBool() )
4552  {
4553  node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
4555  value = node->eval( parent, context );
4557  }
4558  else
4559  {
4560  node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
4562  value = node->eval( parent, context );
4564  }
4565  return value;
4566 }
4567 
4568 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4569 {
4570  int red = QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent );
4571  int green = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4572  int blue = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
4573  int alpha = QgsExpressionUtils::getNativeIntValue( values.at( 3 ), parent );
4574  QColor color = QColor( red, green, blue, alpha );
4575  if ( ! color.isValid() )
4576  {
4577  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
4578  color = QColor( 0, 0, 0 );
4579  }
4580  return QgsSymbolLayerUtils::encodeColor( color );
4581 }
4582 
4583 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4584 {
4585  QgsGradientColorRamp expRamp;
4586  const QgsColorRamp *ramp = nullptr;
4587  if ( values.at( 0 ).canConvert<QgsGradientColorRamp>() )
4588  {
4589  expRamp = QgsExpressionUtils::getRamp( values.at( 0 ), parent );
4590  ramp = &expRamp;
4591  }
4592  else
4593  {
4594  QString rampName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
4595  ramp = QgsStyle::defaultStyle()->colorRampRef( rampName );
4596  if ( ! ramp )
4597  {
4598  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
4599  return QVariant();
4600  }
4601  }
4602 
4603  double value = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4604  QColor color = ramp->color( value );
4605  return QgsSymbolLayerUtils::encodeColor( color );
4606 }
4607 
4608 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4609 {
4610  // Hue ranges from 0 - 360
4611  double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4612  // Saturation ranges from 0 - 100
4613  double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4614  // Lightness ranges from 0 - 100
4615  double lightness = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4616 
4617  QColor color = QColor::fromHslF( hue, saturation, lightness );
4618 
4619  if ( ! color.isValid() )
4620  {
4621  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
4622  color = QColor( 0, 0, 0 );
4623  }
4624 
4625  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4626 }
4627 
4628 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4629 {
4630  // Hue ranges from 0 - 360
4631  double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4632  // Saturation ranges from 0 - 100
4633  double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4634  // Lightness ranges from 0 - 100
4635  double lightness = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4636  // Alpha ranges from 0 - 255
4637  double alpha = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 255.0;
4638 
4639  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
4640  if ( ! color.isValid() )
4641  {
4642  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
4643  color = QColor( 0, 0, 0 );
4644  }
4645  return QgsSymbolLayerUtils::encodeColor( color );
4646 }
4647 
4648 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4649 {
4650  // Hue ranges from 0 - 360
4651  double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4652  // Saturation ranges from 0 - 100
4653  double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4654  // Value ranges from 0 - 100
4655  double value = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4656 
4657  QColor color = QColor::fromHsvF( hue, saturation, value );
4658 
4659  if ( ! color.isValid() )
4660  {
4661  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
4662  color = QColor( 0, 0, 0 );
4663  }
4664 
4665  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4666 }
4667 
4668 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4669 {
4670  // Hue ranges from 0 - 360
4671  double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4672  // Saturation ranges from 0 - 100
4673  double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4674  // Value ranges from 0 - 100
4675  double value = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4676  // Alpha ranges from 0 - 255
4677  double alpha = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 255.0;
4678 
4679  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
4680  if ( ! color.isValid() )
4681  {
4682  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
4683  color = QColor( 0, 0, 0 );
4684  }
4685  return QgsSymbolLayerUtils::encodeColor( color );
4686 }
4687 
4688 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4689 {
4690  // Cyan ranges from 0 - 100
4691  double cyan = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 100.0;
4692  // Magenta ranges from 0 - 100
4693  double magenta = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4694  // Yellow ranges from 0 - 100
4695  double yellow = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4696  // Black ranges from 0 - 100
4697  double black = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 100.0;
4698 
4699  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
4700 
4701  if ( ! color.isValid() )
4702  {
4703  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
4704  color = QColor( 0, 0, 0 );
4705  }
4706 
4707  return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4708 }
4709 
4710 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4711 {
4712  // Cyan ranges from 0 - 100
4713  double cyan = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 100.0;
4714  // Magenta ranges from 0 - 100
4715  double magenta = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4716  // Yellow ranges from 0 - 100
4717  double yellow = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4718  // Black ranges from 0 - 100
4719  double black = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 100.0;
4720  // Alpha ranges from 0 - 255
4721  double alpha = QgsExpressionUtils::getIntValue( values.at( 4 ), parent ) / 255.0;
4722 
4723  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
4724  if ( ! color.isValid() )
4725  {
4726  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
4727  color = QColor( 0, 0, 0 );
4728  }
4729  return QgsSymbolLayerUtils::encodeColor( color );
4730 }
4731 
4732 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4733 {
4734  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4735  if ( ! color.isValid() )
4736  {
4737  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4738  return QVariant();
4739  }
4740 
4741  QString part = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4742  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
4743  return color.red();
4744  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
4745  return color.green();
4746  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
4747  return color.blue();
4748  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
4749  return color.alpha();
4750  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
4751  return color.hsvHueF() * 360;
4752  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
4753  return color.hsvSaturationF() * 100;
4754  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
4755  return color.valueF() * 100;
4756  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
4757  return color.hslHueF() * 360;
4758  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
4759  return color.hslSaturationF() * 100;
4760  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
4761  return color.lightnessF() * 100;
4762  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
4763  return color.cyanF() * 100;
4764  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
4765  return color.magentaF() * 100;
4766  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
4767  return color.yellowF() * 100;
4768  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
4769  return color.blackF() * 100;
4770 
4771  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
4772  return QVariant();
4773 }
4774 
4775 static QVariant fcnCreateRamp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4776 {
4777  const QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
4778  if ( map.count() < 1 )
4779  {
4780  parent->setEvalErrorString( QObject::tr( "A minimum of two colors is required to create a ramp" ) );
4781  return QVariant();
4782  }
4783 
4784  QList< QColor > colors;
4785  QgsGradientStopsList stops;
4786  for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
4787  {
4788  colors << QgsSymbolLayerUtils::decodeColor( it.value().toString() );
4789  if ( !colors.last().isValid() )
4790  {
4791  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( it.value().toString() ) );
4792  return QVariant();
4793  }
4794 
4795  double step = it.key().toDouble();
4796  if ( it == map.constBegin() )
4797  {
4798  if ( step != 0.0 )
4799  stops << QgsGradientStop( step, colors.last() );
4800  }
4801  else if ( it == map.constEnd() )
4802  {
4803  if ( step != 1.0 )
4804  stops << QgsGradientStop( step, colors.last() );
4805  }
4806  else
4807  {
4808  stops << QgsGradientStop( step, colors.last() );
4809  }
4810  }
4811  bool discrete = values.at( 1 ).toBool();
4812 
4813  return QVariant::fromValue( QgsGradientColorRamp( colors.first(), colors.last(), discrete, stops ) );
4814 }
4815 
4816 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4817 {
4818  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4819  if ( ! color.isValid() )
4820  {
4821  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4822  return QVariant();
4823  }
4824 
4825  QString part = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4826  int value = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
4827  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
4828  color.setRed( value );
4829  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
4830  color.setGreen( value );
4831  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
4832  color.setBlue( value );
4833  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
4834  color.setAlpha( value );
4835  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
4836  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
4837  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
4838  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
4839  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
4840  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
4841  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
4842  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
4843  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
4844  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
4845  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
4846  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
4847  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
4848  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
4849  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
4850  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
4851  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
4852  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
4853  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
4854  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
4855  else
4856  {
4857  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
4858  return QVariant();
4859  }
4860  return QgsSymbolLayerUtils::encodeColor( color );
4861 }
4862 
4863 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4864 {
4865  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4866  if ( ! color.isValid() )
4867  {
4868  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4869  return QVariant();
4870  }
4871 
4872  color = color.darker( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
4873 
4874  return QgsSymbolLayerUtils::encodeColor( color );
4875 }
4876 
4877 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4878 {
4879  QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4880  if ( ! color.isValid() )
4881  {
4882  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4883  return QVariant();
4884  }
4885 
4886  color = color.lighter( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
4887 
4888  return QgsSymbolLayerUtils::encodeColor( color );
4889 }
4890 
4891 static QVariant fcnGetGeometry( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4892 {
4893  QgsFeature feat = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
4894  QgsGeometry geom = feat.geometry();
4895  if ( !geom.isNull() )
4896  return QVariant::fromValue( geom );
4897  return QVariant();
4898 }
4899 
4900 static QVariant fcnTransformGeometry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4901 {
4902  QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4903  QString sAuthId = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4904  QString dAuthId = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
4905 
4907  if ( ! s.isValid() )
4908  return QVariant::fromValue( fGeom );
4910  if ( ! d.isValid() )
4911  return QVariant::fromValue( fGeom );
4912 
4914  if ( context )
4915  tContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
4916  QgsCoordinateTransform t( s, d, tContext );
4917  try
4918  {
4919  if ( fGeom.transform( t ) == 0 )
4920  return QVariant::fromValue( fGeom );
4921  }
4922  catch ( QgsCsException &cse )
4923  {
4924  QgsMessageLog::logMessage( QObject::tr( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
4925  return QVariant();
4926  }
4927  return QVariant();
4928 }
4929 
4930 
4931 static QVariant fcnGetFeatureById( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4932 {
4933  QVariant result;
4934  QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
4935  if ( vl )
4936  {
4937  QgsFeatureId fid = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
4938 
4939  QgsFeatureRequest req;
4940  req.setFilterFid( fid );
4941  req.setTimeout( 10000 );
4942  req.setRequestMayBeNested( true );
4943  QgsFeatureIterator fIt = vl->getFeatures( req );
4944 
4945  QgsFeature fet;
4946  if ( fIt.nextFeature( fet ) )
4947  result = QVariant::fromValue( fet );
4948  }
4949 
4950  return result;
4951 }
4952 
4953 static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4954 {
4955  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
4956 
4957  std::unique_ptr<QgsVectorLayerFeatureSource> featureSource = QgsExpressionUtils::getFeatureSource( values.at( 0 ), parent );
4958 
4959  //no layer found
4960  if ( !featureSource )
4961  {
4962  return QVariant();
4963  }
4964 
4965  QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4966  int attributeId = featureSource->fields().lookupField( attribute );
4967  if ( attributeId == -1 )
4968  {
4969  return QVariant();
4970  }
4971 
4972  const QVariant &attVal = values.at( 2 );
4973 
4974  const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( featureSource->id(), QString::number( attributeId ), attVal.toString() );
4975  if ( context && context->hasCachedValue( cacheValueKey ) )
4976  {
4977  return context->cachedValue( cacheValueKey );
4978  }
4979 
4980  QgsFeatureRequest req;
4981  req.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
4982  QgsExpression::quotedString( attVal.toString() ) ) );
4983  req.setLimit( 1 );
4984  req.setTimeout( 10000 );
4985  req.setRequestMayBeNested( true );
4986  if ( !parent->needsGeometry() )
4987  {
4989  }
4990  QgsFeatureIterator fIt = featureSource->getFeatures( req );
4991 
4992  QgsFeature fet;
4993  QVariant res;
4994  if ( fIt.nextFeature( fet ) )
4995  {
4996  res = QVariant::fromValue( fet );
4997  }
4998 
4999  if ( context )
5000  context->setCachedValue( cacheValueKey, res );
5001  return res;
5002 }
5003 
5004 static QVariant fcnRepresentValue( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
5005 {
5006  QVariant result;
5007  QString fieldName;
5008 
5009  if ( context )
5010  {
5011  if ( !values.isEmpty() )
5012  {
5013  QgsExpressionNodeColumnRef *col = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
5014  if ( col && ( values.size() == 1 || !values.at( 1 ).isValid() ) )
5015  fieldName = col->name();
5016  else if ( values.size() == 2 )
5017  fieldName = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5018  }
5019 
5020  QVariant value = values.at( 0 );
5021 
5022  const QgsFields fields = context->fields();
5023  int fieldIndex = fields.lookupField( fieldName );
5024 
5025  if ( fieldIndex == -1 )
5026  {
5027  parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: Field not found %2" ).arg( QStringLiteral( "represent_value" ), fieldName ) );
5028  }
5029  else
5030  {
5031  QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
5032 
5033  const QString cacheValueKey = QStringLiteral( "repvalfcnval:%1:%2:%3" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName, value.toString() );
5034  if ( context->hasCachedValue( cacheValueKey ) )
5035  {
5036  return context->cachedValue( cacheValueKey );
5037  }
5038 
5039  const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
5041 
5042  const QString cacheKey = QStringLiteral( "repvalfcn:%1:%2" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName );
5043 
5044  QVariant cache;
5045  if ( !context->hasCachedValue( cacheKey ) )
5046  {
5047  cache = formatter->createCache( layer, fieldIndex, setup.config() );
5048  context->setCachedValue( cacheKey, cache );
5049  }
5050  else
5051  cache = context->cachedValue( cacheKey );
5052 
5053  result = formatter->representValue( layer, fieldIndex, setup.config(), cache, value );
5054 
5055  context->setCachedValue( cacheValueKey, result );
5056  }
5057  }
5058  else
5059  {
5060  parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: function cannot be evaluated without a context." ).arg( QStringLiteral( "represent_value" ), fieldName ) );
5061  }
5062 
5063  return result;
5064 }
5065 
5066 static QVariant fcnGetLayerProperty( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5067 {
5068  QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
5069 
5070  if ( !layer )
5071  return QVariant();
5072 
5073  // here, we always prefer the layer metadata values over the older server-specific published values
5074  QString layerProperty = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5075  if ( QString::compare( layerProperty, QStringLiteral( "name" ), Qt::CaseInsensitive ) == 0 )
5076  return layer->name();
5077  else if ( QString::compare( layerProperty, QStringLiteral( "id" ), Qt::CaseInsensitive ) == 0 )
5078  return layer->id();
5079  else if ( QString::compare( layerProperty, QStringLiteral( "title" ), Qt::CaseInsensitive ) == 0 )
5080  return !layer->metadata().title().isEmpty() ? layer->metadata().title() : layer->title();
5081  else if ( QString::compare( layerProperty, QStringLiteral( "abstract" ), Qt::CaseInsensitive ) == 0 )
5082  return !layer->metadata().abstract().isEmpty() ? layer->metadata().abstract() : layer->abstract();
5083  else if ( QString::compare( layerProperty, QStringLiteral( "keywords" ), Qt::CaseInsensitive ) == 0 )
5084  {
5085  QStringList keywords;
5086  const QgsAbstractMetadataBase::KeywordMap keywordMap = layer->metadata().keywords();
5087  for ( auto it = keywordMap.constBegin(); it != keywordMap.constEnd(); ++it )
5088  {
5089  keywords.append( it.value() );
5090  }
5091  if ( !keywords.isEmpty() )
5092  return keywords;
5093  return layer->keywordList();
5094  }
5095  else if ( QString::compare( layerProperty, QStringLiteral( "data_url" ), Qt::CaseInsensitive ) == 0 )
5096  return layer->dataUrl();
5097  else if ( QString::compare( layerProperty, QStringLiteral( "attribution" ), Qt::CaseInsensitive ) == 0 )
5098  {
5099  return !layer->metadata().rights().isEmpty() ? QVariant( layer->metadata().rights() ) : QVariant( layer->attribution() );
5100  }
5101  else if ( QString::compare( layerProperty, QStringLiteral( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
5102  return layer->attributionUrl();
5103  else if ( QString::compare( layerProperty, QStringLiteral( "source" ), Qt::CaseInsensitive ) == 0 )
5104  return layer->publicSource();
5105  else if ( QString::compare( layerProperty, QStringLiteral( "min_scale" ), Qt::CaseInsensitive ) == 0 )
5106  return layer->minimumScale();
5107  else if ( QString::compare( layerProperty, QStringLiteral( "max_scale" ), Qt::CaseInsensitive ) == 0 )
5108  return layer->maximumScale();
5109  else if ( QString::compare( layerProperty, QStringLiteral( "is_editable" ), Qt::CaseInsensitive ) == 0 )
5110  return layer->isEditable();
5111  else if ( QString::compare( layerProperty, QStringLiteral( "crs" ), Qt::CaseInsensitive ) == 0 )
5112  return layer->crs().authid();
5113  else if ( QString::compare( layerProperty, QStringLiteral( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
5114  return layer->crs().toProj();
5115  else if ( QString::compare( layerProperty, QStringLiteral( "crs_description" ), Qt::CaseInsensitive ) == 0 )
5116  return layer->crs().description();
5117  else if ( QString::compare( layerProperty, QStringLiteral( "extent" ), Qt::CaseInsensitive ) == 0 )
5118  {
5119  QgsGeometry extentGeom = QgsGeometry::fromRect( layer->extent() );
5120  QVariant result = QVariant::fromValue( extentGeom );
5121  return result;
5122  }
5123  else if ( QString::compare( layerProperty, QStringLiteral( "distance_units" ), Qt::CaseInsensitive ) == 0 )
5124  return QgsUnitTypes::encodeUnit( layer->crs().mapUnits() );
5125  else if ( QString::compare( layerProperty, QStringLiteral( "type" ), Qt::CaseInsensitive ) == 0 )
5126  {
5127  switch ( layer->type() )
5128  {
5130  return QCoreApplication::translate( "expressions", "Vector" );
5132  return QCoreApplication::translate( "expressions", "Raster" );
5134  return QCoreApplication::translate( "expressions", "Mesh" );
5136  return QCoreApplication::translate( "expressions", "Vector Tile" );
5138  return QCoreApplication::translate( "expressions", "Plugin" );
5140  return QCoreApplication::translate( "expressions", "Annotation" );
5141  }
5142  }
5143  else
5144  {
5145  //vector layer methods
5146  QgsVectorLayer *vLayer = qobject_cast< QgsVectorLayer * >( layer );
5147  if ( vLayer )
5148  {
5149  if ( QString::compare( layerProperty, QStringLiteral( "storage_type" ), Qt::CaseInsensitive ) == 0 )
5150  return vLayer->storageType();
5151  else if ( QString::compare( layerProperty, QStringLiteral( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
5153  else if ( QString::compare( layerProperty, QStringLiteral( "feature_count" ), Qt::CaseInsensitive ) == 0 )
5154  return QVariant::fromValue( vLayer->featureCount() );
5155  else if ( QString::compare( layerProperty, QStringLiteral( "path" ), Qt::CaseInsensitive ) == 0 )
5156  {
5157  if ( vLayer->dataProvider() )
5158  {
5159  const QVariantMap decodedUri = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
5160  return decodedUri.value( QStringLiteral( "path" ) );
5161  }
5162  }
5163  }
5164  }
5165 
5166  return QVariant();
5167 }
5168 
5169 static QVariant fcnDecodeUri( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5170 {
5171  QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
5172  if ( !layer )
5173  {
5174  parent->setEvalErrorString( QObject::tr( "Cannot find layer %1" ).arg( values.at( 0 ).toString() ) );
5175  return QVariant();
5176  }
5177 
5178  if ( !layer->dataProvider() )
5179  {
5180  parent->setEvalErrorString( QObject::tr( "Layer %1 has invalid data provider" ).arg( layer->name() ) );
5181  return QVariant();
5182  }
5183 
5184  const QString uriPart = values.at( 1 ).toString();
5185 
5186  const QVariantMap decodedUri = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
5187 
5188  if ( !uriPart.isNull() )
5189  {
5190  return decodedUri.value( values.at( 1 ).toString() );
5191  }
5192  else
5193  {
5194  return decodedUri;
5195  }
5196 }
5197 
5198 static QVariant fcnGetRasterBandStat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5199 {
5200  QString layerIdOrName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5201 
5202  //try to find a matching layer by name
5203  QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerIdOrName ); //search by id first
5204  if ( !layer )
5205  {
5206  QList<QgsMapLayer *> layersByName = QgsProject::instance()->mapLayersByName( layerIdOrName );
5207  if ( !layersByName.isEmpty() )
5208  {
5209  layer = layersByName.at( 0 );
5210  }
5211  }
5212 
5213  if ( !layer )
5214  return QVariant();
5215 
5216  QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer );
5217  if ( !rl )
5218  return QVariant();
5219 
5220  int band = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
5221  if ( band < 1 || band > rl->bandCount() )
5222  {
5223  parent->setEvalErrorString( QObject::tr( "Invalid band number %1 for layer %2" ).arg( band ).arg( layerIdOrName ) );
5224  return QVariant();
5225  }
5226 
5227  QString layerProperty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
5228  int stat = 0;
5229 
5230  if ( QString::compare( layerProperty, QStringLiteral( "avg" ), Qt::CaseInsensitive ) == 0 )
5231  stat = QgsRasterBandStats::Mean;
5232  else if ( QString::compare( layerProperty, QStringLiteral( "stdev" ), Qt::CaseInsensitive ) == 0 )
5234  else if ( QString::compare( layerProperty, QStringLiteral( "min" ), Qt::CaseInsensitive ) == 0 )
5235  stat = QgsRasterBandStats::Min;
5236  else if ( QString::compare( layerProperty, QStringLiteral( "max" ), Qt::CaseInsensitive ) == 0 )
5237  stat = QgsRasterBandStats::Max;
5238  else if ( QString::compare( layerProperty, QStringLiteral( "range" ), Qt::CaseInsensitive ) == 0 )
5240  else if ( QString::compare( layerProperty, QStringLiteral( "sum" ), Qt::CaseInsensitive ) == 0 )
5241  stat = QgsRasterBandStats::Sum;
5242  else
5243  {
5244  parent->setEvalErrorString( QObject::tr( "Invalid raster statistic: '%1'" ).arg( layerProperty ) );
5245  return QVariant();
5246  }
5247 
5248  QgsRasterBandStats stats = rl->dataProvider()->bandStatistics( band, stat );
5249  switch ( stat )
5250  {
5252  return stats.mean;
5254  return stats.stdDev;
5256  return stats.minimumValue;
5258  return stats.maximumValue;
5260  return stats.range;
5262  return stats.sum;
5263  }
5264  return QVariant();
5265 }
5266 
5267 static QVariant fcnArray( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
5268 {
5269  return values;
5270 }
5271 
5272 static QVariant fcnArraySort( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5273 {
5274  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5275  bool ascending = values.value( 1 ).toBool();
5276  std::sort( list.begin(), list.end(), [ascending]( QVariant a, QVariant b ) -> bool { return ( !ascending ? qgsVariantLessThan( b, a ) : qgsVariantLessThan( a, b ) ); } );
5277  return list;
5278 }
5279 
5280 static QVariant fcnArrayLength( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5281 {
5282  return QgsExpressionUtils::getListValue( values.at( 0 ), parent ).length();
5283 }
5284 
5285 static QVariant fcnArrayContains( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5286 {
5287  return QVariant( QgsExpressionUtils::getListValue( values.at( 0 ), parent ).contains( values.at( 1 ) ) );
5288 }
5289 
5290 static QVariant fcnArrayAll( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5291 {
5292  QVariantList listA = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5293  QVariantList listB = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
5294  int match = 0;
5295  for ( const auto &item : listB )
5296  {
5297  if ( listA.contains( item ) )
5298  match++;
5299  }
5300 
5301  return QVariant( match == listB.count() );
5302 }
5303 
5304 static QVariant fcnArrayFind( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5305 {
5306  return QgsExpressionUtils::getListValue( values.at( 0 ), parent ).indexOf( values.at( 1 ) );
5307 }
5308 
5309 static QVariant fcnArrayGet( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5310 {
5311  const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5312  const int pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
5313  if ( pos < 0 || pos >= list.length() ) return QVariant();
5314  return list.at( pos );
5315 }
5316 
5317 static QVariant fcnArrayFirst( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5318 {
5319  const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5320  return list.value( 0 );
5321 }
5322 
5323 static QVariant fcnArrayLast( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5324 {
5325  const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5326  return list.value( list.size() - 1 );
5327 }
5328 
5329 static QVariant convertToSameType( const QVariant &value, QVariant::Type type )
5330 {
5331  QVariant result = value;
5332  result.convert( static_cast<int>( type ) );
5333  return result;
5334 }
5335 
5336 static QVariant fcnArrayAppend( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5337 {
5338  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5339  list.append( values.at( 1 ) );
5340  return convertToSameType( list, values.at( 0 ).type() );
5341 }
5342 
5343 static QVariant fcnArrayPrepend( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5344 {
5345  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5346  list.prepend( values.at( 1 ) );
5347  return convertToSameType( list, values.at( 0 ).type() );
5348 }
5349 
5350 static QVariant fcnArrayInsert( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5351 {
5352  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5353  list.insert( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ), values.at( 2 ) );
5354  return convertToSameType( list, values.at( 0 ).type() );
5355 }
5356 
5357 static QVariant fcnArrayRemoveAt( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5358 {
5359  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5360  list.removeAt( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
5361  return convertToSameType( list, values.at( 0 ).type() );
5362 }
5363 
5364 static QVariant fcnArrayRemoveAll( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5365 {
5366  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5367  list.removeAll( values.at( 1 ) );
5368  return convertToSameType( list, values.at( 0 ).type() );
5369 }
5370 
5371 static QVariant fcnArrayCat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5372 {
5373  QVariantList list;
5374  for ( const QVariant &cur : values )
5375  {
5376  list += QgsExpressionUtils::getListValue( cur, parent );
5377  }
5378  return convertToSameType( list, values.at( 0 ).type() );
5379 }
5380 
5381 static QVariant fcnArraySlice( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5382 {
5383  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5384  int start_pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
5385  const int end_pos = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
5386  int slice_length = 0;
5387  // negative positions means positions taken relative to the end of the array
5388  if ( start_pos < 0 )
5389  {
5390  start_pos = list.length() + start_pos;
5391  }
5392  if ( end_pos >= 0 )
5393  {
5394  slice_length = end_pos - start_pos + 1;
5395  }
5396  else
5397  {
5398  slice_length = list.length() + end_pos - start_pos + 1;
5399  }
5400  //avoid negative lengths in QList.mid function
5401  if ( slice_length < 0 )
5402  {
5403  slice_length = 0;
5404  }
5405  list = list.mid( start_pos, slice_length );
5406  return list;
5407 }
5408 
5409 static QVariant fcnArrayReverse( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5410 {
5411  QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5412  std::reverse( list.begin(), list.end() );
5413  return list;
5414 }
5415 
5416 static QVariant fcnArrayIntersect( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5417 {
5418  const QVariantList array1 = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5419  const QVariantList array2 = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
5420  for ( const QVariant &cur : array2 )
5421  {
5422  if ( array1.contains( cur ) )
5423  return QVariant( true );
5424  }
5425  return QVariant( false );
5426 }
5427 
5428 static QVariant fcnArrayDistinct( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5429 {
5430  QVariantList array = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5431 
5432  QVariantList distinct;
5433 
5434  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
5435  {
5436  if ( !distinct.contains( *it ) )
5437  {
5438  distinct += ( *it );
5439  }
5440  }
5441 
5442  return distinct;
5443 }
5444 
5445 static QVariant fcnArrayToString( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5446 {
5447  QVariantList array = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5448  QString delimiter = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5449  QString empty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
5450 
5451  QString str;
5452 
5453  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
5454  {
5455  str += ( !( *it ).toString().isEmpty() ) ? ( *it ).toString() : empty;
5456  if ( it != ( array.constEnd() - 1 ) )
5457  {
5458  str += delimiter;
5459  }
5460  }
5461 
5462  return QVariant( str );
5463 }
5464 
5465 static QVariant fcnStringToArray( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5466 {
5467  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5468  QString delimiter = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5469  QString empty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
5470 
5471  QStringList list = str.split( delimiter );
5472  QVariantList array;
5473 
5474  for ( QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
5475  {
5476  array += ( !( *it ).isEmpty() ) ? *it : empty;
5477  }
5478 
5479  return array;
5480 }
5481 
5482 static QVariant fcnLoadJson( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5483 {
5484  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5485  QJsonDocument document = QJsonDocument::fromJson( str.toUtf8() );
5486  if ( document.isNull() )
5487  return QVariant();
5488 
5489  return document.toVariant();
5490 }
5491 
5492 static QVariant fcnWriteJson( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5493 {
5494  Q_UNUSED( parent )
5495  QJsonDocument document = QJsonDocument::fromVariant( values.at( 0 ) );
5496  return document.toJson( QJsonDocument::Compact );
5497 }
5498 
5499 static QVariant fcnHstoreToMap( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5500 {
5501  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5502  if ( str.isEmpty() )
5503  return QVariantMap();
5504  str = str.trimmed();
5505 
5506  return QgsHstoreUtils::parse( str );
5507 }
5508 
5509 static QVariant fcnMapToHstore( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5510 {
5511  QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
5512  return QgsHstoreUtils::build( map );
5513 }
5514 
5515 static QVariant fcnMap( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5516 {
5517  QVariantMap result;
5518  for ( int i = 0; i + 1 < values.length(); i += 2 )
5519  {
5520  result.insert( QgsExpressionUtils::getStringValue( values.at( i ), parent ), values.at( i + 1 ) );
5521  }
5522  return result;
5523 }
5524 
5525 static QVariant fcnMapGet( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5526 {
5527  return QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).value( values.at( 1 ).toString() );
5528 }
5529 
5530 static QVariant fcnMapExist( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5531 {
5532  return QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).contains( values.at( 1 ).toString() );
5533 }
5534 
5535 static QVariant fcnMapDelete( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5536 {
5537  QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
5538  map.remove( values.at( 1 ).toString() );
5539  return map;
5540 }
5541 
5542 static QVariant fcnMapInsert( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5543 {
5544  QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
5545  map.insert( values.at( 1 ).toString(), values.at( 2 ) );
5546  return map;
5547 }
5548 
5549 static QVariant fcnMapConcat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5550 {
5551  QVariantMap result;
5552  for ( const QVariant &cur : values )
5553  {
5554  const QVariantMap curMap = QgsExpressionUtils::getMapValue( cur, parent );
5555  for ( QVariantMap::const_iterator it = curMap.constBegin(); it != curMap.constEnd(); ++it )
5556  result.insert( it.key(), it.value() );
5557  }
5558  return result;
5559 }
5560 
5561 static QVariant fcnMapAKeys( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5562 {
5563  return QStringList( QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).keys() );
5564 }
5565 
5566 static QVariant fcnMapAVals( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5567 {
5568  return QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).values();
5569 }
5570 
5571 static QVariant fcnEnvVar( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
5572 {
5573  QString envVarName = values.at( 0 ).toString();
5574  return QProcessEnvironment::systemEnvironment().value( envVarName );
5575 }
5576 
5577 static QVariant fcnBaseFileName( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5578 {
5579  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5580  return QFileInfo( file ).completeBaseName();
5581 }
5582 
5583 static QVariant fcnFileSuffix( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5584 {
5585  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5586  return QFileInfo( file ).completeSuffix();
5587 }
5588 
5589 static QVariant fcnFileExists( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5590 {
5591  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5592  return QFileInfo::exists( file );
5593 }
5594 
5595 static QVariant fcnFileName( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5596 {
5597  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5598  return QFileInfo( file ).fileName();
5599 }
5600 
5601 static QVariant fcnPathIsFile( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5602 {
5603  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5604  return QFileInfo( file ).isFile();
5605 }
5606 
5607 static QVariant fcnPathIsDir( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5608 {
5609  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5610  return QFileInfo( file ).isDir();
5611 }
5612 
5613 static QVariant fcnFilePath( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5614 {
5615  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5616  return QDir::toNativeSeparators( QFileInfo( file ).path() );
5617 }
5618 
5619 static QVariant fcnFileSize( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5620 {
5621  const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5622  return QFileInfo( file ).size();
5623 }
5624 
5625 static QVariant fcnHash( const QString str, const QCryptographicHash::Algorithm algorithm )
5626 {
5627  return QString( QCryptographicHash::hash( str.toUtf8(), algorithm ).toHex() );
5628 }
5629 
5630 static QVariant fcnGenericHash( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5631 {
5632  QVariant hash;
5633  QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5634  QString method = QgsExpressionUtils::getStringValue( values.at( 1 ), parent ).toLower();
5635 
5636  if ( method == QLatin1String( "md4" ) )
5637  {
5638  hash = fcnHash( str, QCryptographicHash::Md4 );
5639  }
5640  else if ( method == QLatin1String( "md5" ) )
5641  {
5642  hash = fcnHash( str, QCryptographicHash::Md5 );
5643  }
5644  else if ( method == QLatin1String( "sha1" ) )
5645  {
5646  hash = fcnHash( str, QCryptographicHash::Sha1 );
5647  }
5648  else if ( method == QLatin1String( "sha224" ) )
5649  {
5650  hash = fcnHash( str, QCryptographicHash::Sha224 );
5651  }
5652  else if ( method == QLatin1String( "sha256" ) )
5653  {
5654  hash = fcnHash( str, QCryptographicHash::Sha256 );
5655  }
5656  else if ( method == QLatin1String( "sha384" ) )
5657  {
5658  hash = fcnHash( str, QCryptographicHash::Sha384 );
5659  }
5660  else if ( method == QLatin1String( "sha512" ) )
5661  {
5662  hash = fcnHash( str, QCryptographicHash::Sha512 );
5663  }
5664  else if ( method == QLatin1String( "sha3_224" ) )
5665  {
5666  hash = fcnHash( str, QCryptographicHash::Sha3_224 );
5667  }
5668  else if ( method == QLatin1String( "sha3_256" ) )
5669  {
5670  hash = fcnHash( str, QCryptographicHash::Sha3_256 );
5671  }
5672  else if ( method == QLatin1String( "sha3_384" ) )
5673  {
5674  hash = fcnHash( str, QCryptographicHash::Sha3_384 );
5675  }
5676  else if ( method == QLatin1String( "sha3_512" ) )
5677  {
5678  hash = fcnHash( str, QCryptographicHash::Sha3_512 );
5679  }
5680 #if QT_VERSION >= QT_VERSION_CHECK( 5, 9, 2 )
5681  else if ( method == QLatin1String( "keccak_224" ) )
5682  {
5683  hash = fcnHash( str, QCryptographicHash::Keccak_224 );
5684  }
5685  else if ( method == QLatin1String( "keccak_256" ) )
5686  {
5687  hash = fcnHash( str, QCryptographicHash::Keccak_256 );
5688  }
5689  else if ( method == QLatin1String( "keccak_384" ) )
5690  {
5691  hash = fcnHash( str, QCryptographicHash::Keccak_384 );
5692  }
5693  else if ( method == QLatin1String( "keccak_512" ) )
5694  {
5695  hash = fcnHash( str, QCryptographicHash::Keccak_512 );
5696  }
5697 #endif
5698  else
5699  {
5700  parent->setEvalErrorString( QObject::tr( "Hash method %1 is not available on this system." ).arg( str ) );
5701  }
5702  return hash;
5703 }
5704 
5705 static QVariant fcnHashMd5( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5706 {
5707  return fcnHash( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), QCryptographicHash::Md5 );
5708 }
5709 
5710 static QVariant fcnHashSha256( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5711 {
5712  return fcnHash( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), QCryptographicHash::Sha256 );
5713 }
5714 
5715 static QVariant fcnToBase64( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
5716 {
5717  const QByteArray input = values.at( 0 ).toByteArray();
5718  return QVariant( QString( input.toBase64() ) );
5719 }
5720 
5721 static QVariant fcnFromBase64( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5722 {
5723  const QString value = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5724  const QByteArray base64 = value.toLocal8Bit();
5725  const QByteArray decoded = QByteArray::fromBase64( base64 );
5726  return QVariant( decoded );
5727 }
5728 
5729 typedef bool ( QgsGeometry::*RelationFunction )( const QgsGeometry &geometry ) const;
5730 
5731 static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const RelationFunction &relationFunction, bool invert = false, double bboxGrow = 0, bool isNearestFunc = false )
5732 {
5733 
5734  const QVariant sourceLayerRef = context->variable( QStringLiteral( "layer" ) ); //used to detect if sourceLayer and targetLayer are the same
5735  QgsVectorLayer *sourceLayer = QgsExpressionUtils::getVectorLayer( sourceLayerRef, parent );
5736 
5737  QgsFeatureRequest request;
5738  request.setTimeout( 10000 );
5739  request.setRequestMayBeNested( true );
5740 
5741  // First parameter is the overlay layer
5742  QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
5744 
5745  const bool layerCanBeCached = node->isStatic( parent, context );
5746  QVariant targetLayerValue = node->eval( parent, context );
5748 
5749  // Second parameter is the expression to evaluate (or null for testonly)
5750  node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
5752  QString subExpString = node->dump();
5753 
5754  bool testOnly = ( subExpString == "NULL" );
5755  QgsVectorLayer *targetLayer = QgsExpressionUtils::getVectorLayer( targetLayerValue, parent );
5756  if ( !targetLayer ) // No layer, no joy
5757  {
5758  parent->setEvalErrorString( QObject::tr( "Layer '%1' could not be loaded." ).arg( targetLayerValue.toString() ) );
5759  return QVariant();
5760  }
5761 
5762  // Third parameter is the filtering expression
5763  node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
5765  QString filterString = node->dump();
5766  if ( filterString != "NULL" )
5767  {
5768  request.setFilterExpression( filterString ); //filter cached features
5769  }
5770 
5771  // Fourth parameter is the limit
5772  node = QgsExpressionUtils::getNode( values.at( 3 ), parent ); //in expressions overlay functions throw the exception: Eval Error: Cannot convert '' to int
5774  QVariant limitValue = node->eval( parent, context );
5776  qlonglong limit = QgsExpressionUtils::getIntValue( limitValue, parent );
5777 
5778  // Fifth parameter (for nearest only) is the max distance
5779  double max_distance = 0;
5780  if ( isNearestFunc ) //maxdistance param handling
5781  {
5782  node = QgsExpressionUtils::getNode( values.at( 4 ), parent );
5784  QVariant distanceValue = node->eval( parent, context );
5786  max_distance = QgsExpressionUtils::getDoubleValue( distanceValue, parent );
5787  }
5788 
5789  // Fifth or sixth (for nearest only) parameter is the cache toggle
5790  node = QgsExpressionUtils::getNode( values.at( isNearestFunc ? 5 : 4 ), parent );
5792  QVariant cacheValue = node->eval( parent, context );
5794  bool cacheEnabled = cacheValue.toBool();
5795 
5796 
5797  FEAT_FROM_CONTEXT( context, feat )
5798  const QgsGeometry geometry = feat.geometry();
5799 
5800  if ( sourceLayer && targetLayer->crs() != sourceLayer->crs() )
5801  {
5802  QgsCoordinateTransformContext TransformContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
5803  request.setDestinationCrs( sourceLayer->crs(), TransformContext ); //if crs are not the same, cached target will be reprojected to source crs
5804  }
5805 
5806  bool sameLayers = ( sourceLayer && sourceLayer->id() == targetLayer->id() );
5807 
5808  QgsRectangle intDomain = geometry.boundingBox();
5809  if ( bboxGrow != 0 )
5810  {
5811  intDomain.grow( bboxGrow ); //optional parameter to enlarge boundary context for touches and equals methods
5812  }
5813 
5814  const QString cacheBase { QStringLiteral( "%1:%2" ).arg( targetLayer->id(), subExpString ) };
5815 
5816  // Cache (a local spatial index) is always enabled for nearest function (as we need QgsSpatialIndex::nearestNeighbor)
5817  // Otherwise, it can be toggled by the user
5818  QgsSpatialIndex spatialIndex;
5819  QgsVectorLayer *cachedTarget;
5820  QList<QgsFeature> features;
5821  if ( isNearestFunc || ( layerCanBeCached && cacheEnabled ) )
5822  {
5823  // If the cache (local spatial index) is enabled, we materialize the whole
5824  // layer, then do the request on that layer instead.
5825  const QString cacheLayer { QStringLiteral( "ovrlaylyr:%1" ).arg( cacheBase ) };
5826  const QString cacheIndex { QStringLiteral( "ovrlayidx:%1" ).arg( cacheBase ) };
5827 
5828  if ( !context->hasCachedValue( cacheLayer ) ) // should check for same crs. if not the same we could think to reproject target layer before charging cache
5829  {
5830  cachedTarget = targetLayer->materialize( request );
5831  if ( layerCanBeCached )
5832  context->setCachedValue( cacheLayer, QVariant::fromValue( cachedTarget ) );
5833  }
5834  else
5835  {
5836  cachedTarget = context->cachedValue( cacheLayer ).value<QgsVectorLayer *>();
5837  }
5838 
5839  if ( !context->hasCachedValue( cacheIndex ) )
5840  {
5841  spatialIndex = QgsSpatialIndex( cachedTarget->getFeatures(), nullptr, QgsSpatialIndex::FlagStoreFeatureGeometries );
5842  if ( layerCanBeCached )
5843  context->setCachedValue( cacheIndex, QVariant::fromValue( spatialIndex ) );
5844  }
5845  else
5846  {
5847  spatialIndex = context->cachedValue( cacheIndex ).value<QgsSpatialIndex>();
5848  }
5849 
5850  QList<QgsFeatureId> fidsList;
5851  if ( isNearestFunc )
5852  {
5853  fidsList = spatialIndex.nearestNeighbor( geometry, sameLayers ? limit + 1 : limit, max_distance );
5854  }
5855  else
5856  {
5857  fidsList = spatialIndex.intersects( intDomain );
5858  }
5859 
5860  QListIterator<QgsFeatureId> i( fidsList );
5861  while ( i.hasNext() )
5862  {
5863  QgsFeatureId fId2 = i.next();
5864  if ( sameLayers && feat.id() == fId2 )
5865  continue;
5866  features.append( cachedTarget->getFeature( fId2 ) );
5867  }
5868 
5869  }
5870  else
5871  {
5872  // If the cache (local spatial index) is not enabled, we directly
5873  // get the features from the target layer
5874  request.setFilterRect( intDomain );
5875  QgsFeatureIterator fit = targetLayer->getFeatures( request );
5876  QgsFeature feat2;
5877  while ( fit.nextFeature( feat2 ) )
5878  {
5879  if ( sameLayers && feat.id() == feat2.id() )
5880  continue;
5881  features.append( feat2 );
5882  }
5883  }
5884 
5885  QgsExpression subExpression;
5886  QgsExpressionContext subContext;
5887  if ( !testOnly )
5888  {
5889  const QString expCacheKey { QStringLiteral( "exp:%1" ).arg( cacheBase ) };
5890  const QString ctxCacheKey { QStringLiteral( "ctx:%1" ).arg( cacheBase ) };
5891 
5892  if ( !context->hasCachedValue( expCacheKey ) || !context->hasCachedValue( ctxCacheKey ) )
5893  {
5894  subExpression = QgsExpression( subExpString );
5896  subExpression.prepare( &subContext );
5897  }
5898  else
5899  {
5900  subExpression = context->cachedValue( expCacheKey ).value<QgsExpression>();
5901  subContext = context->cachedValue( ctxCacheKey ).value<QgsExpressionContext>();
5902  }
5903  }
5904 
5905 
5906  bool found = false;
5907  int foundCount = 0;
5908  QVariantList results;
5909 
5910  QListIterator<QgsFeature> i( features );
5911  while ( i.hasNext() && ( limit == -1 || foundCount < limit ) )
5912  {
5913  QgsFeature feat2 = i.next();
5914 
5915  if ( ! relationFunction || ( geometry.*relationFunction )( feat2.geometry() ) ) // Calls the method provided as template argument for the function (e.g. QgsGeometry::intersects)
5916  {
5917  found = true;
5918  foundCount++;
5919 
5920  // We just want a single boolean result if there is any intersect: finish and return true
5921  if ( testOnly )
5922  break;
5923 
5924  if ( !invert )
5925  {
5926  // We want a list of attributes / geometries / other expression values, evaluate now
5927  subContext.setFeature( feat2 );
5928  results.append( subExpression.evaluate( &subContext ) );
5929  }
5930  else
5931  {
5932  // If not, results is a list of found ids, which we'll inverse and evaluate below
5933  results.append( feat2.id() );
5934  }
5935  }
5936  }
5937 
5938  if ( testOnly )
5939  {
5940  if ( invert )
5941  found = !found;//for disjoint condition
5942  return found;
5943  }
5944 
5945  if ( !invert )
5946  return results;
5947 
5948  // for disjoint condition returns the results for cached layers not intersected feats
5949  QVariantList disjoint_results;
5950  QgsFeature feat2;
5951  QgsFeatureRequest request2;
5952  request2.setLimit( limit );
5953  QgsFeatureIterator fi = targetLayer->getFeatures( request2 );
5954  while ( fi.nextFeature( feat2 ) )
5955  {
5956  if ( !results.contains( feat2.id() ) )
5957  {
5958  subContext.setFeature( feat2 );
5959  disjoint_results.append( subExpression.evaluate( &subContext ) );
5960  }
5961  }
5962  return disjoint_results;
5963 
5964 }
5965 
5966 // Intersect functions:
5967 
5968 static QVariant fcnGeomOverlayIntersects( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5969 {
5970  return executeGeomOverlay( values, context, parent, &QgsGeometry::intersects );
5971 }
5972 
5973 static QVariant fcnGeomOverlayContains( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5974 {
5975  return executeGeomOverlay( values, context, parent, &QgsGeometry::contains );
5976 }
5977 
5978 static QVariant fcnGeomOverlayCrosses( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5979 {
5980  return executeGeomOverlay( values, context, parent, &QgsGeometry::crosses );
5981 }
5982 
5983 static QVariant fcnGeomOverlayEquals( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5984 {
5985  return executeGeomOverlay( values, context, parent, &QgsGeometry::equals, false, 0.01 ); //grow amount should adapt to current units
5986 }
5987 
5988 static QVariant fcnGeomOverlayTouches( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5989 {
5990  return executeGeomOverlay( values, context, parent, &QgsGeometry::touches, false, 0.01 ); //grow amount should adapt to current units
5991 }
5992 
5993 static QVariant fcnGeomOverlayWithin( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5994 {
5995  return executeGeomOverlay( values, context, parent, &QgsGeometry::within );
5996 }
5997 
5998 static QVariant fcnGeomOverlayDisjoint( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
5999 {
6000  return executeGeomOverlay( values, context, parent, &QgsGeometry::intersects, true );
6001 }
6002 
6003 static QVariant fcnGeomOverlayNearest( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6004 {
6005  return executeGeomOverlay( values, context, parent, nullptr, false, 0, true );
6006 }
6007 
6008 const QList<QgsExpressionFunction *> &QgsExpression::Functions()
6009 {
6010  // The construction of the list isn't thread-safe, and without the mutex,
6011  // crashes in the WFS provider may occur, since it can parse expressions
6012  // in parallel.
6013  // The mutex needs to be recursive.
6014  static QMutex sFunctionsMutex( QMutex::Recursive );
6015  QMutexLocker locker( &sFunctionsMutex );
6016 
6017  QList<QgsExpressionFunction *> &functions = *sFunctions();
6018 
6019  if ( functions.isEmpty() )
6020  {
6022  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) )
6023  << QgsExpressionFunction::Parameter( QStringLiteral( "group_by" ), true )
6024  << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true );
6025 
6026  QgsExpressionFunction::ParameterList aggParamsConcat = aggParams;
6027  aggParamsConcat << QgsExpressionFunction::Parameter( QStringLiteral( "concatenator" ), true )
6028  << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true );
6029 
6030  QgsExpressionFunction::ParameterList aggParamsArray = aggParams;
6031  aggParamsArray << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true );
6032 
6033  functions
6034  << new QgsStaticExpressionFunction( QStringLiteral( "sqrt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnSqrt, QStringLiteral( "Math" ) )
6035  << new QgsStaticExpressionFunction( QStringLiteral( "radians" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "degrees" ) ), fcnRadians, QStringLiteral( "Math" ) )
6036  << new QgsStaticExpressionFunction( QStringLiteral( "degrees" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "radians" ) ), fcnDegrees, QStringLiteral( "Math" ) )
6037  << new QgsStaticExpressionFunction( QStringLiteral( "azimuth" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point_b" ) ), fcnAzimuth, QStringList() << QStringLiteral( "Math" ) << QStringLiteral( "GeometryGroup" ) )
6038  << new QgsStaticExpressionFunction( QStringLiteral( "inclination" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point_b" ) ), fcnInclination, QStringList() << QStringLiteral( "Math" ) << QStringLiteral( "GeometryGroup" ) )
6039  << 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" ) )
6040  << new QgsStaticExpressionFunction( QStringLiteral( "abs" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAbs, QStringLiteral( "Math" ) )
6041  << new QgsStaticExpressionFunction( QStringLiteral( "cos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "angle" ) ), fcnCos, QStringLiteral( "Math" ) )
6042  << new QgsStaticExpressionFunction( QStringLiteral( "sin" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "angle" ) ), fcnSin, QStringLiteral( "Math" ) )
6043  << new QgsStaticExpressionFunction( QStringLiteral( "tan" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "angle" ) ), fcnTan, QStringLiteral( "Math" ) )
6044  << new QgsStaticExpressionFunction( QStringLiteral( "asin" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAsin, QStringLiteral( "Math" ) )
6045  << new QgsStaticExpressionFunction( QStringLiteral( "acos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAcos, QStringLiteral( "Math" ) )
6046  << new QgsStaticExpressionFunction( QStringLiteral( "atan" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAtan, QStringLiteral( "Math" ) )
6047  << new QgsStaticExpressionFunction( QStringLiteral( "atan2" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "dx" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "dy" ) ), fcnAtan2, QStringLiteral( "Math" ) )
6048  << new QgsStaticExpressionFunction( QStringLiteral( "exp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnExp, QStringLiteral( "Math" ) )
6049  << new QgsStaticExpressionFunction( QStringLiteral( "ln" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLn, QStringLiteral( "Math" ) )
6050  << new QgsStaticExpressionFunction( QStringLiteral( "log10" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLog10, QStringLiteral( "Math" ) )
6051  << new QgsStaticExpressionFunction( QStringLiteral( "log" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "base" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLog, QStringLiteral( "Math" ) )
6052  << new QgsStaticExpressionFunction( QStringLiteral( "round" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "places" ), true, 0 ), fcnRound, QStringLiteral( "Math" ) );
6053 
6054  QgsStaticExpressionFunction *randFunc = new QgsStaticExpressionFunction( QStringLiteral( "rand" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "max" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "seed" ), true ), fcnRnd, QStringLiteral( "Math" ) );
6055  randFunc->setIsStatic( false );
6056  functions << randFunc;
6057 
6058  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" ) );
6059  randfFunc->setIsStatic( false );
6060  functions << randfFunc;
6061 
6062  functions
6063  << new QgsStaticExpressionFunction( QStringLiteral( "max" ), -1, fcnMax, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList(), /* handlesNull = */ true )
6064  << new QgsStaticExpressionFunction( QStringLiteral( "min" ), -1, fcnMin, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList(), /* handlesNull = */ true )
6065  << new QgsStaticExpressionFunction( QStringLiteral( "clamp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "max" ) ), fcnClamp, QStringLiteral( "Math" ) )
6066  << new QgsStaticExpressionFunction( QStringLiteral( "scale_linear" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "domain_min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "domain_max" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "range_min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "range_max" ) ), fcnLinearScale, QStringLiteral( "Math" ) )
6067  << new QgsStaticExpressionFunction( QStringLiteral( "scale_exp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << 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" ) )
6068  << new QgsStaticExpressionFunction( QStringLiteral( "floor" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnFloor, QStringLiteral( "Math" ) )
6069  << new QgsStaticExpressionFunction( QStringLiteral( "ceil" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnCeil, QStringLiteral( "Math" ) )
6070  << new QgsStaticExpressionFunction( QStringLiteral( "pi" ), 0, fcnPi, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$pi" ) )
6071  << new QgsStaticExpressionFunction( QStringLiteral( "to_int" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToInt, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toint" ) )
6072  << new QgsStaticExpressionFunction( QStringLiteral( "to_real" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToReal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toreal" ) )
6073  << 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" ) )
6074  << 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" ) )
6075  << 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" ) )
6076  << 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" ) )
6077  << 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" ) )
6078  << 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" ) )
6079  << 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" ) )
6080  << new QgsStaticExpressionFunction( QStringLiteral( "to_decimal" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToDecimal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todecimal" ) )
6081  << new QgsStaticExpressionFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6082  << new QgsStaticExpressionFunction( QStringLiteral( "nullif" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value2" ) ), fcnNullIf, QStringLiteral( "Conditionals" ) )
6083  << 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 )
6084  << new QgsStaticExpressionFunction( QStringLiteral( "try" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "alternative" ), true, QVariant() ), fcnTry, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )
6085 
6086  << new QgsStaticExpressionFunction( QStringLiteral( "aggregate" ),
6088  << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6089  << QgsExpressionFunction::Parameter( QStringLiteral( "aggregate" ) )
6090  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), false, QVariant(), true )
6091  << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true, QVariant(), true )
6092  << QgsExpressionFunction::Parameter( QStringLiteral( "concatenator" ), true )
6093  << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true ),
6094  fcnAggregate,
6095  QStringLiteral( "Aggregates" ),
6096  QString(),
6097  []( const QgsExpressionNodeFunction * node )
6098  {
6099  // usesGeometry callback: return true if @parent variable is referenced
6100 
6101  if ( !node )
6102  return true;
6103 
6104  if ( !node->args() )
6105  return false;
6106 
6107  QSet<QString> referencedVars;
6108  if ( node->args()->count() > 2 )
6109  {
6110  QgsExpressionNode *subExpressionNode = node->args()->at( 2 );
6111  referencedVars = subExpressionNode->referencedVariables();
6112  }
6113 
6114  if ( node->args()->count() > 3 )
6115  {
6116  QgsExpressionNode *filterNode = node->args()->at( 3 );
6117  referencedVars.unite( filterNode->referencedVariables() );
6118  }
6119  return referencedVars.contains( QStringLiteral( "parent" ) ) || referencedVars.contains( QString() );
6120  },
6121  []( const QgsExpressionNodeFunction * node )
6122  {
6123  // referencedColumns callback: return AllAttributes if @parent variable is referenced
6124 
6125  if ( !node )
6126  return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
6127 
6128  if ( !node->args() )
6129  return QSet<QString>();
6130 
6131  QSet<QString> referencedCols;
6132  QSet<QString> referencedVars;
6133 
6134  if ( node->args()->count() > 2 )
6135  {
6136  QgsExpressionNode *subExpressionNode = node->args()->at( 2 );
6137  referencedVars = subExpressionNode->referencedVariables();
6138  referencedCols = subExpressionNode->referencedColumns();
6139  }
6140  if ( node->args()->count() > 3 )
6141  {
6142  QgsExpressionNode *filterNode = node->args()->at( 3 );
6143  referencedVars = filterNode->referencedVariables();
6144  referencedCols.unite( filterNode->referencedColumns() );
6145  }
6146 
6147  if ( referencedVars.contains( QStringLiteral( "parent" ) ) || referencedVars.contains( QString() ) )
6148  return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
6149  else
6150  return referencedCols;
6151  },
6152  true
6153  )
6154 
6155  << new QgsStaticExpressionFunction( QStringLiteral( "relation_aggregate" ), QgsExpressionFunction::ParameterList()
6156  << QgsExpressionFunction::Parameter( QStringLiteral( "relation" ) )
6157  << QgsExpressionFunction::Parameter( QStringLiteral( "aggregate" ) )
6158  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), false, QVariant(), true )
6159  << QgsExpressionFunction::Parameter( QStringLiteral( "concatenator" ), true )
6160  << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true ),
6161  fcnAggregateRelation, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true )
6162 
6163  << new QgsStaticExpressionFunction( QStringLiteral( "count" ), aggParams, fcnAggregateCount, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6164  << new QgsStaticExpressionFunction( QStringLiteral( "count_distinct" ), aggParams, fcnAggregateCountDistinct, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6165  << new QgsStaticExpressionFunction( QStringLiteral( "count_missing" ), aggParams, fcnAggregateCountMissing, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6166  << new QgsStaticExpressionFunction( QStringLiteral( "minimum" ), aggParams, fcnAggregateMin, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6167  << new QgsStaticExpressionFunction( QStringLiteral( "maximum" ), aggParams, fcnAggregateMax, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6168  << new QgsStaticExpressionFunction( QStringLiteral( "sum" ), aggParams, fcnAggregateSum, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6169  << new QgsStaticExpressionFunction( QStringLiteral( "mean" ), aggParams, fcnAggregateMean, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6170  << new QgsStaticExpressionFunction( QStringLiteral( "median" ), aggParams, fcnAggregateMedian, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6171  << new QgsStaticExpressionFunction( QStringLiteral( "stdev" ), aggParams, fcnAggregateStdev, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6172  << new QgsStaticExpressionFunction( QStringLiteral( "range" ), aggParams, fcnAggregateRange, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6173  << new QgsStaticExpressionFunction( QStringLiteral( "minority" ), aggParams, fcnAggregateMinority, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6174  << new QgsStaticExpressionFunction( QStringLiteral( "majority" ), aggParams, fcnAggregateMajority, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6175  << new QgsStaticExpressionFunction( QStringLiteral( "q1" ), aggParams, fcnAggregateQ1, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6176  << new QgsStaticExpressionFunction( QStringLiteral( "q3" ), aggParams, fcnAggregateQ3, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6177  << new QgsStaticExpressionFunction( QStringLiteral( "iqr" ), aggParams, fcnAggregateIQR, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6178  << new QgsStaticExpressionFunction( QStringLiteral( "min_length" ), aggParams, fcnAggregateMinLength, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6179  << new QgsStaticExpressionFunction( QStringLiteral( "max_length" ), aggParams, fcnAggregateMaxLength, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6180  << new QgsStaticExpressionFunction( QStringLiteral( "collect" ), aggParams, fcnAggregateCollectGeometry, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6181  << new QgsStaticExpressionFunction( QStringLiteral( "concatenate" ), aggParamsConcat, fcnAggregateStringConcat, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6182  << new QgsStaticExpressionFunction( QStringLiteral( "concatenate_unique" ), aggParamsConcat, fcnAggregateStringConcatUnique, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6183  << new QgsStaticExpressionFunction( QStringLiteral( "array_agg" ), aggParamsArray, fcnAggregateArray, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6184 
6185  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_match" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ), fcnRegexpMatch, QStringList() << QStringLiteral( "Conditionals" ) << QStringLiteral( "String" ) )
6186  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_matches" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnRegexpMatches, QStringLiteral( "Arrays" ) )
6187 
6188  << new QgsStaticExpressionFunction( QStringLiteral( "now" ), 0, fcnNow, QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$now" ) )
6189  << new QgsStaticExpressionFunction( QStringLiteral( "age" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime1" ) )
6190  << QgsExpressionFunction::Parameter( QStringLiteral( "datetime2" ) ),
6191  fcnAge, QStringLiteral( "Date and Time" ) )
6192  << new QgsStaticExpressionFunction( QStringLiteral( "year" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnYear, QStringLiteral( "Date and Time" ) )
6193  << new QgsStaticExpressionFunction( QStringLiteral( "month" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnMonth, QStringLiteral( "Date and Time" ) )
6194  << new QgsStaticExpressionFunction( QStringLiteral( "week" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnWeek, QStringLiteral( "Date and Time" ) )
6195  << new QgsStaticExpressionFunction( QStringLiteral( "day" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnDay, QStringLiteral( "Date and Time" ) )
6196  << new QgsStaticExpressionFunction( QStringLiteral( "hour" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnHour, QStringLiteral( "Date and Time" ) )
6197  << new QgsStaticExpressionFunction( QStringLiteral( "minute" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnMinute, QStringLiteral( "Date and Time" ) )
6198  << new QgsStaticExpressionFunction( QStringLiteral( "second" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnSeconds, QStringLiteral( "Date and Time" ) )
6199  << new QgsStaticExpressionFunction( QStringLiteral( "epoch" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnEpoch, QStringLiteral( "Date and Time" ) )
6200  << new QgsStaticExpressionFunction( QStringLiteral( "datetime_from_epoch" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "long" ) ), fcnDateTimeFromEpoch, QStringLiteral( "Date and Time" ) )
6201  << new QgsStaticExpressionFunction( QStringLiteral( "day_of_week" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnDayOfWeek, QStringLiteral( "Date and Time" ) )
6202  << new QgsStaticExpressionFunction( QStringLiteral( "make_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "year" ) )
6203  << QgsExpressionFunction::Parameter( QStringLiteral( "month" ) )
6204  << QgsExpressionFunction::Parameter( QStringLiteral( "day" ) ),
6205  fcnMakeDate, QStringLiteral( "Date and Time" ) )
6206  << new QgsStaticExpressionFunction( QStringLiteral( "make_time" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hour" ) )
6207  << QgsExpressionFunction::Parameter( QStringLiteral( "minute" ) )
6208  << QgsExpressionFunction::Parameter( QStringLiteral( "second" ) ),
6209  fcnMakeTime, QStringLiteral( "Date and Time" ) )
6210  << new QgsStaticExpressionFunction( QStringLiteral( "make_datetime" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "year" ) )
6211  << QgsExpressionFunction::Parameter( QStringLiteral( "month" ) )
6212  << QgsExpressionFunction::Parameter( QStringLiteral( "day" ) )
6213  << QgsExpressionFunction::Parameter( QStringLiteral( "hour" ) )
6214  << QgsExpressionFunction::Parameter( QStringLiteral( "minute" ) )
6215  << QgsExpressionFunction::Parameter( QStringLiteral( "second" ) ),
6216  fcnMakeDateTime, QStringLiteral( "Date and Time" ) )
6217  << new QgsStaticExpressionFunction( QStringLiteral( "make_interval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "years" ), true, 0 )
6218  << QgsExpressionFunction::Parameter( QStringLiteral( "months" ), true, 0 )
6219  << QgsExpressionFunction::Parameter( QStringLiteral( "weeks" ), true, 0 )
6220  << QgsExpressionFunction::Parameter( QStringLiteral( "days" ), true, 0 )
6221  << QgsExpressionFunction::Parameter( QStringLiteral( "hours" ), true, 0 )
6222  << QgsExpressionFunction::Parameter( QStringLiteral( "minutes" ), true, 0 )
6223  << QgsExpressionFunction::Parameter( QStringLiteral( "seconds" ), true, 0 ),
6224  fcnMakeInterval, QStringLiteral( "Date and Time" ) )
6225  << new QgsStaticExpressionFunction( QStringLiteral( "lower" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnLower, QStringLiteral( "String" ) )
6226  << new QgsStaticExpressionFunction( QStringLiteral( "upper" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnUpper, QStringLiteral( "String" ) )
6227  << new QgsStaticExpressionFunction( QStringLiteral( "title" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTitle, QStringLiteral( "String" ) )
6228  << new QgsStaticExpressionFunction( QStringLiteral( "trim" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTrim, QStringLiteral( "String" ) )
6229  << new QgsStaticExpressionFunction( QStringLiteral( "levenshtein" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnLevenshtein, QStringLiteral( "Fuzzy Matching" ) )
6230  << new QgsStaticExpressionFunction( QStringLiteral( "longest_common_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnLCS, QStringLiteral( "Fuzzy Matching" ) )
6231  << new QgsStaticExpressionFunction( QStringLiteral( "hamming_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnHamming, QStringLiteral( "Fuzzy Matching" ) )
6232  << new QgsStaticExpressionFunction( QStringLiteral( "soundex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnSoundex, QStringLiteral( "Fuzzy Matching" ) )
6233  << new QgsStaticExpressionFunction( QStringLiteral( "char" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "code" ) ), fcnChar, QStringLiteral( "String" ) )
6234  << new QgsStaticExpressionFunction( QStringLiteral( "ascii" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnAscii, QStringLiteral( "String" ) )
6235  << new QgsStaticExpressionFunction( QStringLiteral( "wordwrap" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "" ), fcnWordwrap, QStringLiteral( "String" ) )
6236  << new QgsStaticExpressionFunction( QStringLiteral( "length" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ), true, "" ), fcnLength, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "GeometryGroup" ) )
6237  << new QgsStaticExpressionFunction( QStringLiteral( "replace" ), -1, fcnReplace, QStringLiteral( "String" ) )
6238  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_replace" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "input_string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) )
6239  << QgsExpressionFunction::Parameter( QStringLiteral( "replacement" ) ), fcnRegexpReplace, QStringLiteral( "String" ) )
6240  << new QgsStaticExpressionFunction( QStringLiteral( "regexp_substr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "input_string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ), fcnRegexpSubstr, QStringLiteral( "String" ) )
6241  << new QgsStaticExpressionFunction( QStringLiteral( "substr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "start " ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ), true ), fcnSubstr, QStringLiteral( "String" ), QString(),
6242  false, QSet< QString >(), false, QStringList(), true )
6243  << new QgsStaticExpressionFunction( QStringLiteral( "concat" ), -1, fcnConcat, QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6244  << new QgsStaticExpressionFunction( QStringLiteral( "strpos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "haystack" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "needle" ) ), fcnStrpos, QStringLiteral( "String" ) )
6245  << new QgsStaticExpressionFunction( QStringLiteral( "left" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ), fcnLeft, QStringLiteral( "String" ) )
6246  << new QgsStaticExpressionFunction( QStringLiteral( "right" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ), fcnRight, QStringLiteral( "String" ) )
6247  << new QgsStaticExpressionFunction( QStringLiteral( "rpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnRPad, QStringLiteral( "String" ) )
6248  << new QgsStaticExpressionFunction( QStringLiteral( "lpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnLPad, QStringLiteral( "String" ) )
6249  << new QgsStaticExpressionFunction( QStringLiteral( "format" ), -1, fcnFormatString, QStringLiteral( "String" ) )
6250  << new QgsStaticExpressionFunction( QStringLiteral( "format_number" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "number" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "places" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatNumber, QStringLiteral( "String" ) )
6251  << 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" ) )
6252  << new QgsStaticExpressionFunction( QStringLiteral( "color_grayscale_average" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ), fcnColorGrayscaleAverage, QStringLiteral( "Color" ) )
6253  << new QgsStaticExpressionFunction( QStringLiteral( "color_mix_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color1" ) )
6254  << QgsExpressionFunction::Parameter( QStringLiteral( "color2" ) )
6255  << QgsExpressionFunction::Parameter( QStringLiteral( "ratio" ) ),
6256  fcnColorMixRgb, QStringLiteral( "Color" ) )
6257  << new QgsStaticExpressionFunction( QStringLiteral( "color_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "red" ) )
6258  << QgsExpressionFunction::Parameter( QStringLiteral( "green" ) )
6259  << QgsExpressionFunction::Parameter( QStringLiteral( "blue" ) ),
6260  fcnColorRgb, QStringLiteral( "Color" ) )
6261  << new QgsStaticExpressionFunction( QStringLiteral( "color_rgba" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "red" ) )
6262  << QgsExpressionFunction::Parameter( QStringLiteral( "green" ) )
6263  << QgsExpressionFunction::Parameter( QStringLiteral( "blue" ) )
6264  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6265  fncColorRgba, QStringLiteral( "Color" ) )
6266  << new QgsStaticExpressionFunction( QStringLiteral( "ramp_color" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "ramp_name" ) )
6267  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6268  fcnRampColor, QStringLiteral( "Color" ) )
6269  << new QgsStaticExpressionFunction( QStringLiteral( "create_ramp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) )
6270  << QgsExpressionFunction::Parameter( QStringLiteral( "discrete" ), true, false ),
6271  fcnCreateRamp, QStringLiteral( "Color" ) )
6272  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsl" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6273  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6274  << QgsExpressionFunction::Parameter( QStringLiteral( "lightness" ) ),
6275  fcnColorHsl, QStringLiteral( "Color" ) )
6276  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsla" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6277  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6278  << QgsExpressionFunction::Parameter( QStringLiteral( "lightness" ) )
6279  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6280  fncColorHsla, QStringLiteral( "Color" ) )
6281  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsv" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6282  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6283  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6284  fcnColorHsv, QStringLiteral( "Color" ) )
6285  << new QgsStaticExpressionFunction( QStringLiteral( "color_hsva" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6286  << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6287  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) )
6288  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6289  fncColorHsva, QStringLiteral( "Color" ) )
6290  << new QgsStaticExpressionFunction( QStringLiteral( "color_cmyk" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "cyan" ) )
6291  << QgsExpressionFunction::Parameter( QStringLiteral( "magenta" ) )
6292  << QgsExpressionFunction::Parameter( QStringLiteral( "yellow" ) )
6293  << QgsExpressionFunction::Parameter( QStringLiteral( "black" ) ),
6294  fcnColorCmyk, QStringLiteral( "Color" ) )
6295  << new QgsStaticExpressionFunction( QStringLiteral( "color_cmyka" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "cyan" ) )
6296  << QgsExpressionFunction::Parameter( QStringLiteral( "magenta" ) )
6297  << QgsExpressionFunction::Parameter( QStringLiteral( "yellow" ) )
6298  << QgsExpressionFunction::Parameter( QStringLiteral( "black" ) )
6299  << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6300  fncColorCmyka, QStringLiteral( "Color" ) )
6301  << new QgsStaticExpressionFunction( QStringLiteral( "color_part" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
6302  << QgsExpressionFunction::Parameter( QStringLiteral( "component" ) ),
6303  fncColorPart, QStringLiteral( "Color" ) )
6304  << new QgsStaticExpressionFunction( QStringLiteral( "darker" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
6305  << QgsExpressionFunction::Parameter( QStringLiteral( "factor" ) ),
6306  fncDarker, QStringLiteral( "Color" ) )
6307  << new QgsStaticExpressionFunction( QStringLiteral( "lighter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
6308  << QgsExpressionFunction::Parameter( QStringLiteral( "factor" ) ),
6309  fncLighter, QStringLiteral( "Color" ) )
6310  << new QgsStaticExpressionFunction( QStringLiteral( "set_color_part" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "component" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fncSetColorPart, QStringLiteral( "Color" ) )
6311 
6312  // file info
6313  << new QgsStaticExpressionFunction( QStringLiteral( "base_file_name" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6314  fcnBaseFileName, QStringLiteral( "Files and Paths" ) )
6315  << new QgsStaticExpressionFunction( QStringLiteral( "file_suffix" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6316  fcnFileSuffix, QStringLiteral( "Files and Paths" ) )
6317  << new QgsStaticExpressionFunction( QStringLiteral( "file_exists" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6318  fcnFileExists, QStringLiteral( "Files and Paths" ) )
6319  << new QgsStaticExpressionFunction( QStringLiteral( "file_name" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6320  fcnFileName, QStringLiteral( "Files and Paths" ) )
6321  << new QgsStaticExpressionFunction( QStringLiteral( "is_file" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6322  fcnPathIsFile, QStringLiteral( "Files and Paths" ) )
6323  << new QgsStaticExpressionFunction( QStringLiteral( "is_directory" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6324  fcnPathIsDir, QStringLiteral( "Files and Paths" ) )
6325  << new QgsStaticExpressionFunction( QStringLiteral( "file_path" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6326  fcnFilePath, QStringLiteral( "Files and Paths" ) )
6327  << new QgsStaticExpressionFunction( QStringLiteral( "file_size" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6328  fcnFileSize, QStringLiteral( "Files and Paths" ) )
6329 
6330  // hash
6331  << new QgsStaticExpressionFunction( QStringLiteral( "hash" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "method" ) ),
6332  fcnGenericHash, QStringLiteral( "Conversions" ) )
6333  << new QgsStaticExpressionFunction( QStringLiteral( "md5" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
6334  fcnHashMd5, QStringLiteral( "Conversions" ) )
6335  << new QgsStaticExpressionFunction( QStringLiteral( "sha256" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
6336  fcnHashSha256, QStringLiteral( "Conversions" ) )
6337 
6338  //base64
6339  << new QgsStaticExpressionFunction( QStringLiteral( "to_base64" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6340  fcnToBase64, QStringLiteral( "Conversions" ) )
6341  << new QgsStaticExpressionFunction( QStringLiteral( "from_base64" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
6342  fcnFromBase64, QStringLiteral( "Conversions" ) )
6343 
6344  // deprecated stuff - hidden from users
6345  << new QgsStaticExpressionFunction( QStringLiteral( "$scale" ), QgsExpressionFunction::ParameterList(), fcnMapScale, QStringLiteral( "deprecated" ) );
6346 
6347  QgsStaticExpressionFunction *geomFunc = new QgsStaticExpressionFunction( QStringLiteral( "$geometry" ), 0, fcnGeometry, QStringLiteral( "GeometryGroup" ), QString(), true );
6348  geomFunc->setIsStatic( false );
6349  functions << geomFunc;
6350 
6351  QgsStaticExpressionFunction *areaFunc = new QgsStaticExpressionFunction( QStringLiteral( "$area" ), 0, fcnGeomArea, QStringLiteral( "GeometryGroup" ), QString(), true );
6352  areaFunc->setIsStatic( false );
6353  functions << areaFunc;
6354 
6355  functions << new QgsStaticExpressionFunction( QStringLiteral( "area" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnArea, QStringLiteral( "GeometryGroup" ) );
6356 
6357  QgsStaticExpressionFunction *lengthFunc = new QgsStaticExpressionFunction( QStringLiteral( "$length" ), 0, fcnGeomLength, QStringLiteral( "GeometryGroup" ), QString(), true );
6358  lengthFunc->setIsStatic( false );
6359  functions << lengthFunc;
6360 
6361  QgsStaticExpressionFunction *perimeterFunc = new QgsStaticExpressionFunction( QStringLiteral( "$perimeter" ), 0, fcnGeomPerimeter, QStringLiteral( "GeometryGroup" ), QString(), true );
6362  perimeterFunc->setIsStatic( false );
6363  functions << perimeterFunc;
6364 
6365  functions << new QgsStaticExpressionFunction( QStringLiteral( "perimeter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnPerimeter, QStringLiteral( "GeometryGroup" ) );
6366 
6367  QgsStaticExpressionFunction *xFunc = new QgsStaticExpressionFunction( QStringLiteral( "$x" ), 0, fcnX, QStringLiteral( "GeometryGroup" ), QString(), true );
6368  xFunc->setIsStatic( false );
6369  functions << xFunc;
6370 
6371  QgsStaticExpressionFunction *yFunc = new QgsStaticExpressionFunction( QStringLiteral( "$y" ), 0, fcnY, QStringLiteral( "GeometryGroup" ), QString(), true );
6372  yFunc->setIsStatic( false );
6373  functions << yFunc;
6374 
6375  QMap< QString, QgsExpressionFunction::FcnEval > geometry_overlay_definitions
6376  {
6377  { QStringLiteral( "overlay_intersects" ), fcnGeomOverlayIntersects },
6378  { QStringLiteral( "overlay_contains" ), fcnGeomOverlayContains },
6379  { QStringLiteral( "overlay_crosses" ), fcnGeomOverlayCrosses },
6380  { QStringLiteral( "overlay_equals" ), fcnGeomOverlayEquals },
6381  { QStringLiteral( "overlay_touches" ), fcnGeomOverlayTouches },
6382  { QStringLiteral( "overlay_disjoint" ), fcnGeomOverlayDisjoint },
6383  { QStringLiteral( "overlay_within" ), fcnGeomOverlayWithin },
6384  };
6385  QMapIterator< QString, QgsExpressionFunction::FcnEval > i( geometry_overlay_definitions );
6386  while ( i.hasNext() )
6387  {
6388  i.next();
6390  << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6391  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), true, QVariant(), true )
6392  << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true, QVariant(), true )
6393  << QgsExpressionFunction::Parameter( QStringLiteral( "limit" ), true, QVariant( -1 ), true )
6394  << QgsExpressionFunction::Parameter( QStringLiteral( "cache" ), true, QVariant( false ), false ),
6395  i.value(), QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true );
6396 
6397  // The current feature is accessed for the geometry, so this should not be cached
6398  fcnGeomOverlayFunc->setIsStatic( false );
6399  functions << fcnGeomOverlayFunc;
6400  }
6401 
6402  QgsStaticExpressionFunction *fcnGeomOverlayNearestFunc = new QgsStaticExpressionFunction( QStringLiteral( "overlay_nearest" ), QgsExpressionFunction::ParameterList()
6403  << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6404  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), true, QVariant(), true )
6405  << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true, QVariant(), true )
6406  << QgsExpressionFunction::Parameter( QStringLiteral( "limit" ), true, QVariant( 1 ), true )
6407  << QgsExpressionFunction::Parameter( QStringLiteral( "max_distance" ), true, 0 )
6408  << QgsExpressionFunction::Parameter( QStringLiteral( "cache" ), true, QVariant( false ), false ),
6409  fcnGeomOverlayNearest, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true );
6410  // The current feature is accessed for the geometry, so this should not be cached
6411  fcnGeomOverlayNearestFunc->setIsStatic( false );
6412  functions << fcnGeomOverlayNearestFunc;
6413 
6414  functions
6415  << new QgsStaticExpressionFunction( QStringLiteral( "is_valid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomIsValid, QStringLiteral( "GeometryGroup" ) )
6416  << new QgsStaticExpressionFunction( QStringLiteral( "x" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomX, QStringLiteral( "GeometryGroup" ) )
6417  << new QgsStaticExpressionFunction( QStringLiteral( "y" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomY, QStringLiteral( "GeometryGroup" ) )
6418  << new QgsStaticExpressionFunction( QStringLiteral( "z" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomZ, QStringLiteral( "GeometryGroup" ) )
6419  << new QgsStaticExpressionFunction( QStringLiteral( "m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomM, QStringLiteral( "GeometryGroup" ) )
6420  << new QgsStaticExpressionFunction( QStringLiteral( "point_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ), fcnPointN, QStringLiteral( "GeometryGroup" ) )
6421  << new QgsStaticExpressionFunction( QStringLiteral( "start_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnStartPoint, QStringLiteral( "GeometryGroup" ) )
6422  << new QgsStaticExpressionFunction( QStringLiteral( "end_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnEndPoint, QStringLiteral( "GeometryGroup" ) )
6423  << new QgsStaticExpressionFunction( QStringLiteral( "nodes_to_points" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6424  << QgsExpressionFunction::Parameter( QStringLiteral( "ignore_closing_nodes" ), true, false ),
6425  fcnNodesToPoints, QStringLiteral( "GeometryGroup" ) )
6426  << new QgsStaticExpressionFunction( QStringLiteral( "segments_to_lines" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnSegmentsToLines, QStringLiteral( "GeometryGroup" ) )
6427  << new QgsStaticExpressionFunction( QStringLiteral( "collect_geometries" ), -1, fcnCollectGeometries, QStringLiteral( "GeometryGroup" ) )
6428  << new QgsStaticExpressionFunction( QStringLiteral( "make_point" ), -1, fcnMakePoint, QStringLiteral( "GeometryGroup" ) )
6429  << new QgsStaticExpressionFunction( QStringLiteral( "make_point_m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "x" ) )
6430  << QgsExpressionFunction::Parameter( QStringLiteral( "y" ) )
6431  << QgsExpressionFunction::Parameter( QStringLiteral( "m" ) ),
6432  fcnMakePointM, QStringLiteral( "GeometryGroup" ) )
6433  << new QgsStaticExpressionFunction( QStringLiteral( "make_line" ), -1, fcnMakeLine, QStringLiteral( "GeometryGroup" ) )
6434  << new QgsStaticExpressionFunction( QStringLiteral( "make_polygon" ), -1, fcnMakePolygon, QStringLiteral( "GeometryGroup" ) )
6435  << new QgsStaticExpressionFunction( QStringLiteral( "make_triangle" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6436  << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) )
6437  << QgsExpressionFunction::Parameter( QStringLiteral( "point3" ) ),
6438  fcnMakeTriangle, QStringLiteral( "GeometryGroup" ) )
6439  << new QgsStaticExpressionFunction( QStringLiteral( "make_circle" ), QgsExpressionFunction::ParameterList()
6440  << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6441  << QgsExpressionFunction::Parameter( QStringLiteral( "radius" ) )
6442  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6443  fcnMakeCircle, QStringLiteral( "GeometryGroup" ) )
6444  << new QgsStaticExpressionFunction( QStringLiteral( "make_ellipse" ), QgsExpressionFunction::ParameterList()
6445  << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6446  << QgsExpressionFunction::Parameter( QStringLiteral( "semi_major_axis" ) )
6447  << QgsExpressionFunction::Parameter( QStringLiteral( "semi_minor_axis" ) )
6448  << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
6449  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6450  fcnMakeEllipse, QStringLiteral( "GeometryGroup" ) )
6451  << new QgsStaticExpressionFunction( QStringLiteral( "make_regular_polygon" ), QgsExpressionFunction::ParameterList()
6452  << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6453  << QgsExpressionFunction::Parameter( QStringLiteral( "radius" ) )
6454  << QgsExpressionFunction::Parameter( QStringLiteral( "number_sides" ) )
6455  << QgsExpressionFunction::Parameter( QStringLiteral( "circle" ), true, 0 ),
6456  fcnMakeRegularPolygon, QStringLiteral( "GeometryGroup" ) )
6457  << new QgsStaticExpressionFunction( QStringLiteral( "make_square" ), QgsExpressionFunction::ParameterList()
6458  << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6459  << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) ),
6460  fcnMakeSquare, QStringLiteral( "GeometryGroup" ) )
6461  << new QgsStaticExpressionFunction( QStringLiteral( "make_rectangle_3points" ), QgsExpressionFunction::ParameterList()
6462  << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6463  << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) )
6464  << QgsExpressionFunction::Parameter( QStringLiteral( "point3" ) )
6465  << QgsExpressionFunction::Parameter( QStringLiteral( "option" ), true, 0 ),
6466  fcnMakeRectangleFrom3Points, QStringLiteral( "GeometryGroup" ) );
6467  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" ) );
6468  xAtFunc->setIsStatic( false );
6469  functions << xAtFunc;
6470 
6471  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" ) );
6472  yAtFunc->setIsStatic( false );
6473  functions << yAtFunc;
6474 
6475  functions
6476  << new QgsStaticExpressionFunction( QStringLiteral( "x_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnXMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmin" ) )
6477  << new QgsStaticExpressionFunction( QStringLiteral( "x_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnXMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmax" ) )
6478  << new QgsStaticExpressionFunction( QStringLiteral( "y_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnYMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymin" ) )
6479  << new QgsStaticExpressionFunction( QStringLiteral( "y_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnYMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymax" ) )
6480  << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_wkt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ) ), fcnGeomFromWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromWKT" ) )
6481  << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_wkb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "binary" ) ), fcnGeomFromWKB, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false )
6482  << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_gml" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "gml" ) ), fcnGeomFromGML, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromGML" ) )
6483  << new QgsStaticExpressionFunction( QStringLiteral( "flip_coordinates" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnFlipCoordinates, QStringLiteral( "GeometryGroup" ) )
6484  << new QgsStaticExpressionFunction( QStringLiteral( "relate" ), -1, fcnRelate, QStringLiteral( "GeometryGroup" ) )
6485  << new QgsStaticExpressionFunction( QStringLiteral( "intersects_bbox" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ), fcnBbox, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "bbox" ) )
6486  << new QgsStaticExpressionFunction( QStringLiteral( "disjoint" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6487  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6488  fcnDisjoint, QStringLiteral( "GeometryGroup" ) )
6489  << new QgsStaticExpressionFunction( QStringLiteral( "intersects" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6490  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6491  fcnIntersects, QStringLiteral( "GeometryGroup" ) )
6492  << new QgsStaticExpressionFunction( QStringLiteral( "touches" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6493  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6494  fcnTouches, QStringLiteral( "GeometryGroup" ) )
6495  << new QgsStaticExpressionFunction( QStringLiteral( "crosses" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6496  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6497  fcnCrosses, QStringLiteral( "GeometryGroup" ) )
6498  << new QgsStaticExpressionFunction( QStringLiteral( "contains" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6499  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6500  fcnContains, QStringLiteral( "GeometryGroup" ) )
6501  << new QgsStaticExpressionFunction( QStringLiteral( "overlaps" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6502  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6503  fcnOverlaps, QStringLiteral( "GeometryGroup" ) )
6504  << new QgsStaticExpressionFunction( QStringLiteral( "within" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6505  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6506  fcnWithin, QStringLiteral( "GeometryGroup" ) )
6507  << new QgsStaticExpressionFunction( QStringLiteral( "translate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6508  << QgsExpressionFunction::Parameter( QStringLiteral( "dx" ) )
6509  << QgsExpressionFunction::Parameter( QStringLiteral( "dy" ) ),
6510  fcnTranslate, QStringLiteral( "GeometryGroup" ) )
6511  << new QgsStaticExpressionFunction( QStringLiteral( "rotate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6512  << QgsExpressionFunction::Parameter( QStringLiteral( "rotation" ) )
6513  << QgsExpressionFunction::Parameter( QStringLiteral( "center" ), true ),
6514  fcnRotate, QStringLiteral( "GeometryGroup" ) )
6515  << new QgsStaticExpressionFunction( QStringLiteral( "buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6516  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6517  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 ),
6518  fcnBuffer, QStringLiteral( "GeometryGroup" ) )
6519  << new QgsStaticExpressionFunction( QStringLiteral( "force_rhr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6520  fcnForceRHR, QStringLiteral( "GeometryGroup" ) )
6521  << new QgsStaticExpressionFunction( QStringLiteral( "wedge_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6522  << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
6523  << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) )
6524  << QgsExpressionFunction::Parameter( QStringLiteral( "outer_radius" ) )
6525  << QgsExpressionFunction::Parameter( QStringLiteral( "inner_radius" ), true, 0.0 ), fcnWedgeBuffer, QStringLiteral( "GeometryGroup" ) )
6526  << new QgsStaticExpressionFunction( QStringLiteral( "tapered_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6527  << QgsExpressionFunction::Parameter( QStringLiteral( "start_width" ) )
6528  << QgsExpressionFunction::Parameter( QStringLiteral( "end_width" ) )
6529  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6530  , fcnTaperedBuffer, QStringLiteral( "GeometryGroup" ) )
6531  << new QgsStaticExpressionFunction( QStringLiteral( "buffer_by_m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6532  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6533  , fcnBufferByM, QStringLiteral( "GeometryGroup" ) )
6534  << new QgsStaticExpressionFunction( QStringLiteral( "offset_curve" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6535  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6536  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6537  << QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
6538  << QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2.0 ),
6539  fcnOffsetCurve, QStringLiteral( "GeometryGroup" ) )
6540  << new QgsStaticExpressionFunction( QStringLiteral( "single_sided_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6541  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6542  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6543  << QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
6544  << QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2.0 ),
6545  fcnSingleSidedBuffer, QStringLiteral( "GeometryGroup" ) )
6546  << new QgsStaticExpressionFunction( QStringLiteral( "extend" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6547  << QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) )
6548  << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ),
6549  fcnExtend, QStringLiteral( "GeometryGroup" ) )
6550  << new QgsStaticExpressionFunction( QStringLiteral( "centroid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnCentroid, QStringLiteral( "GeometryGroup" ) )
6551  << new QgsStaticExpressionFunction( QStringLiteral( "point_on_surface" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
6552  << new QgsStaticExpressionFunction( QStringLiteral( "pole_of_inaccessibility" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6553  << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
6554  << new QgsStaticExpressionFunction( QStringLiteral( "reverse" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnReverse, QStringLiteral( "GeometryGroup" ) )
6555  << new QgsStaticExpressionFunction( QStringLiteral( "exterior_ring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
6556  << new QgsStaticExpressionFunction( QStringLiteral( "interior_ring_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6557  << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ),
6558  fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )
6559  << new QgsStaticExpressionFunction( QStringLiteral( "geometry_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6560  << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ),
6561  fcnGeometryN, QStringLiteral( "GeometryGroup" ) )
6562  << new QgsStaticExpressionFunction( QStringLiteral( "boundary" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundary, QStringLiteral( "GeometryGroup" ) )
6563  << new QgsStaticExpressionFunction( QStringLiteral( "line_merge" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnLineMerge, QStringLiteral( "GeometryGroup" ) )
6564  << new QgsStaticExpressionFunction( QStringLiteral( "bounds" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBounds, QStringLiteral( "GeometryGroup" ) )
6565  << new QgsStaticExpressionFunction( QStringLiteral( "simplify" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnSimplify, QStringLiteral( "GeometryGroup" ) )
6566  << new QgsStaticExpressionFunction( QStringLiteral( "simplify_vw" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnSimplifyVW, QStringLiteral( "GeometryGroup" ) )
6567  << new QgsStaticExpressionFunction( QStringLiteral( "smooth" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "iterations" ), true, 1 )
6568  << QgsExpressionFunction::Parameter( QStringLiteral( "offset" ), true, 0.25 )
6569  << QgsExpressionFunction::Parameter( QStringLiteral( "min_length" ), true, -1 )
6570  << QgsExpressionFunction::Parameter( QStringLiteral( "max_angle" ), true, 180 ), fcnSmooth, QStringLiteral( "GeometryGroup" ) )
6571  << new QgsStaticExpressionFunction( QStringLiteral( "num_points" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumPoints, QStringLiteral( "GeometryGroup" ) )
6572  << new QgsStaticExpressionFunction( QStringLiteral( "num_interior_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumInteriorRings, QStringLiteral( "GeometryGroup" ) )
6573  << new QgsStaticExpressionFunction( QStringLiteral( "num_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumRings, QStringLiteral( "GeometryGroup" ) )
6574  << new QgsStaticExpressionFunction( QStringLiteral( "num_geometries" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumGeometries, QStringLiteral( "GeometryGroup" ) )
6575  << new QgsStaticExpressionFunction( QStringLiteral( "bounds_width" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundsWidth, QStringLiteral( "GeometryGroup" ) )
6576  << new QgsStaticExpressionFunction( QStringLiteral( "bounds_height" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) )
6577  << new QgsStaticExpressionFunction( QStringLiteral( "is_closed" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnIsClosed, QStringLiteral( "GeometryGroup" ) )
6578  << new QgsStaticExpressionFunction( QStringLiteral( "close_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnCloseLine, QStringLiteral( "GeometryGroup" ) )
6579  << new QgsStaticExpressionFunction( QStringLiteral( "is_empty" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnIsEmpty, QStringLiteral( "GeometryGroup" ) )
6580  << new QgsStaticExpressionFunction( QStringLiteral( "is_empty_or_null" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnIsEmptyOrNull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6581  << new QgsStaticExpressionFunction( QStringLiteral( "convex_hull" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "convexHull" ) )
6582  << new QgsStaticExpressionFunction( QStringLiteral( "oriented_bbox" ), QgsExpressionFunction::ParameterList()
6583  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6584  fcnOrientedBBox, QStringLiteral( "GeometryGroup" ) )
6585  << new QgsStaticExpressionFunction( QStringLiteral( "main_angle" ), QgsExpressionFunction::ParameterList()
6586  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6587  fcnMainAngle, QStringLiteral( "GeometryGroup" ) )
6588  << new QgsStaticExpressionFunction( QStringLiteral( "minimal_circle" ), QgsExpressionFunction::ParameterList()
6589  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6590  << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6591  fcnMinimalCircle, QStringLiteral( "GeometryGroup" ) )
6592  << new QgsStaticExpressionFunction( QStringLiteral( "difference" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6593  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6594  fcnDifference, QStringLiteral( "GeometryGroup" ) )
6595  << new QgsStaticExpressionFunction( QStringLiteral( "distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6596  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6597  fcnDistance, QStringLiteral( "GeometryGroup" ) )
6598  << new QgsStaticExpressionFunction( QStringLiteral( "hausdorff_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) )
6599  << QgsExpressionFunction::Parameter( QStringLiteral( "densify_fraction" ), true ),
6600  fcnHausdorffDistance, QStringLiteral( "GeometryGroup" ) )
6601  << new QgsStaticExpressionFunction( QStringLiteral( "intersection" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6602  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6603  fcnIntersection, QStringLiteral( "GeometryGroup" ) )
6604  << new QgsStaticExpressionFunction( QStringLiteral( "sym_difference" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6605  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6606  fcnSymDifference, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "symDifference" ) )
6607  << new QgsStaticExpressionFunction( QStringLiteral( "combine" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6608  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6609  fcnCombine, QStringLiteral( "GeometryGroup" ) )
6610  << new QgsStaticExpressionFunction( QStringLiteral( "union" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6611  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6612  fcnCombine, QStringLiteral( "GeometryGroup" ) )
6613  << new QgsStaticExpressionFunction( QStringLiteral( "geom_to_wkt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6614  << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ), true, 8.0 ),
6615  fcnGeomToWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomToWKT" ) )
6616  << new QgsStaticExpressionFunction( QStringLiteral( "geom_to_wkb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6617  fcnGeomToWKB, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false )
6618  << new QgsStaticExpressionFunction( QStringLiteral( "geometry" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ) ), fcnGetGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
6619  << new QgsStaticExpressionFunction( QStringLiteral( "transform" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6620  << QgsExpressionFunction::Parameter( QStringLiteral( "source_auth_id" ) )
6621  << QgsExpressionFunction::Parameter( QStringLiteral( "dest_auth_id" ) ),
6622  fcnTransformGeometry, QStringLiteral( "GeometryGroup" ) )
6623  << new QgsStaticExpressionFunction( QStringLiteral( "extrude" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6624  << QgsExpressionFunction::Parameter( QStringLiteral( "x" ) )
6625  << QgsExpressionFunction::Parameter( QStringLiteral( "y" ) ),
6626  fcnExtrude, QStringLiteral( "GeometryGroup" ), QString() )
6627  << new QgsStaticExpressionFunction( QStringLiteral( "is_multipart" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6628  fcnGeomIsMultipart, QStringLiteral( "GeometryGroup" ) )
6629  << new QgsStaticExpressionFunction( QStringLiteral( "z_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6630  fcnZMax, QStringLiteral( "GeometryGroup" ) )
6631  << new QgsStaticExpressionFunction( QStringLiteral( "z_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6632  fcnZMin, QStringLiteral( "GeometryGroup" ) )
6633  << new QgsStaticExpressionFunction( QStringLiteral( "m_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6634  fcnMMax, QStringLiteral( "GeometryGroup" ) )
6635  << new QgsStaticExpressionFunction( QStringLiteral( "m_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6636  fcnMMin, QStringLiteral( "GeometryGroup" ) );
6637 
6638 
6639  QgsStaticExpressionFunction *orderPartsFunc = new QgsStaticExpressionFunction( QStringLiteral( "order_parts" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6640  << QgsExpressionFunction::Parameter( QStringLiteral( "orderby" ) )
6641  << QgsExpressionFunction::Parameter( QStringLiteral( "ascending" ) ),
6642  fcnOrderParts, QStringLiteral( "GeometryGroup" ), QString() );
6643 
6644  orderPartsFunc->setIsStaticFunction(
6645  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6646  {
6647  const QList< QgsExpressionNode *> argList = node->args()->list();
6648  for ( QgsExpressionNode *argNode : argList )
6649  {
6650  if ( !argNode->isStatic( parent, context ) )
6651  return false;
6652  }
6653 
6654  if ( node->args()->count() > 1 )
6655  {
6656  QgsExpressionNode *argNode = node->args()->at( 1 );
6657 
6658  QString expString = argNode->eval( parent, context ).toString();
6659 
6660  QgsExpression e( expString );
6661 
6662  if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) )
6663  return true;
6664  }
6665 
6666  return true;
6667  } );
6668 
6669  orderPartsFunc->setPrepareFunction( []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6670  {
6671  if ( node->args()->count() > 1 )
6672  {
6673  QgsExpressionNode *argNode = node->args()->at( 1 );
6674  QString expression = argNode->eval( parent, context ).toString();
6675  QgsExpression e( expression );
6676  e.prepare( context );
6677  context->setCachedValue( expression, QVariant::fromValue( e ) );
6678  }
6679  return true;
6680  }
6681  );
6682  functions << orderPartsFunc;
6683 
6684  functions
6685  << new QgsStaticExpressionFunction( QStringLiteral( "closest_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6686  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6687  fcnClosestPoint, QStringLiteral( "GeometryGroup" ) )
6688  << new QgsStaticExpressionFunction( QStringLiteral( "shortest_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6689  << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6690  fcnShortestLine, QStringLiteral( "GeometryGroup" ) )
6691  << new QgsStaticExpressionFunction( QStringLiteral( "line_interpolate_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6692  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolatePoint, QStringLiteral( "GeometryGroup" ) )
6693  << new QgsStaticExpressionFunction( QStringLiteral( "line_interpolate_angle" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6694  << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolateAngle, QStringLiteral( "GeometryGroup" ) )
6695  << new QgsStaticExpressionFunction( QStringLiteral( "line_locate_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6696  << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnLineLocatePoint, QStringLiteral( "GeometryGroup" ) )
6697  << new QgsStaticExpressionFunction( QStringLiteral( "angle_at_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6698  << QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
6699  << new QgsStaticExpressionFunction( QStringLiteral( "distance_to_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6700  << QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
6701  << new QgsStaticExpressionFunction( QStringLiteral( "line_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6702  << QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ), fcnLineSubset, QStringLiteral( "GeometryGroup" ) );
6703 
6704 
6705  // **Record** functions
6706 
6707  QgsStaticExpressionFunction *idFunc = new QgsStaticExpressionFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record and Attributes" ) );
6708  idFunc->setIsStatic( false );
6709  functions << idFunc;
6710 
6711  QgsStaticExpressionFunction *currentFeatureFunc = new QgsStaticExpressionFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record and Attributes" ) );
6712  currentFeatureFunc->setIsStatic( false );
6713  functions << currentFeatureFunc;
6714 
6715  QgsStaticExpressionFunction *uuidFunc = new QgsStaticExpressionFunction( QStringLiteral( "uuid" ), 0, fcnUuid, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) );
6716  uuidFunc->setIsStatic( false );
6717  functions << uuidFunc;
6718 
6719  functions
6720  << new QgsStaticExpressionFunction( QStringLiteral( "get_feature" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6721  << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) )
6722  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6723  fcnGetFeature, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "QgsExpressionUtils::getFeature" ) )
6724  << new QgsStaticExpressionFunction( QStringLiteral( "get_feature_by_id" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6725  << QgsExpressionFunction::Parameter( QStringLiteral( "feature_id" ) ),
6726  fcnGetFeatureById, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false );
6727 
6728  QgsStaticExpressionFunction *attributesFunc = new QgsStaticExpressionFunction( QStringLiteral( "attributes" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ), true ),
6729  fcnAttributes, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
6730  attributesFunc->setIsStatic( false );
6731  functions << attributesFunc;
6732 
6734  QStringLiteral( "maptip" ),
6735  -1,
6736  fcnFeatureMaptip,
6737  QStringLiteral( "Record and Attributes" ),
6738  QString(),
6739  false,
6740  QSet<QString>()
6741  );
6742  maptipFunc->setIsStatic( false );
6743  functions << maptipFunc;
6744 
6746  QStringLiteral( "display_expression" ),
6747  -1,
6748  fcnFeatureDisplayExpression,
6749  QStringLiteral( "Record and Attributes" ),
6750  QString(),
6751  false,
6752  QSet<QString>()
6753  );
6754  displayFunc->setIsStatic( false );
6755  functions << displayFunc;
6756 
6758  QStringLiteral( "is_selected" ),
6759  -1,
6760  fcnIsSelected,
6761  QStringLiteral( "Record and Attributes" ),
6762  QString(),
6763  false,
6764  QSet<QString>()
6765  );
6766  isSelectedFunc->setIsStatic( false );
6767  functions << isSelectedFunc;
6768 
6769  functions
6771  QStringLiteral( "num_selected" ),
6772  -1,
6773  fcnNumSelected,
6774  QStringLiteral( "Record and Attributes" ),
6775  QString(),
6776  false,
6777  QSet<QString>()
6778  );
6779 
6780  functions
6782  QStringLiteral( "sqlite_fetch_and_increment" ),
6784  << QgsExpressionFunction::Parameter( QStringLiteral( "database" ) )
6785  << QgsExpressionFunction::Parameter( QStringLiteral( "table" ) )
6786  << QgsExpressionFunction::Parameter( QStringLiteral( "id_field" ) )
6787  << QgsExpressionFunction::Parameter( QStringLiteral( "filter_attribute" ) )
6788  << QgsExpressionFunction::Parameter( QStringLiteral( "filter_value" ) )
6789  << QgsExpressionFunction::Parameter( QStringLiteral( "default_values" ), true ),
6790  fcnSqliteFetchAndIncrement,
6791  QStringLiteral( "Record and Attributes" )
6792  );
6793 
6794  // **Fields and Values** functions
6795  QgsStaticExpressionFunction *representValueFunc = new QgsStaticExpressionFunction( QStringLiteral( "represent_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "field_name" ), true ), fcnRepresentValue, QStringLiteral( "Record and Attributes" ) );
6796 
6797  representValueFunc->setPrepareFunction( []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6798  {
6799  Q_UNUSED( context )
6800  if ( node->args()->count() == 1 )
6801  {
6802  QgsExpressionNodeColumnRef *colRef = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
6803  if ( colRef )
6804  {
6805  return true;
6806  }
6807  else
6808  {
6809  parent->setEvalErrorString( tr( "If represent_value is called with 1 parameter, it must be an attribute." ) );
6810  return false;
6811  }
6812  }
6813  else if ( node->args()->count() == 2 )
6814  {
6815  return true;
6816  }
6817  else
6818  {
6819  parent->setEvalErrorString( tr( "represent_value must be called with exactly 1 or 2 parameters." ) );
6820  return false;
6821  }
6822  }
6823  );
6824 
6825  functions << representValueFunc;
6826 
6827  // **General** functions
6828  functions
6829  << new QgsStaticExpressionFunction( QStringLiteral( "layer_property" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6830  << QgsExpressionFunction::Parameter( QStringLiteral( "property" ) ),
6831  fcnGetLayerProperty, QStringLiteral( "General" ) )
6832  << new QgsStaticExpressionFunction( QStringLiteral( "decode_uri" ),
6834  << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6835  << QgsExpressionFunction::Parameter( QStringLiteral( "part" ), true ),
6836  fcnDecodeUri, QStringLiteral( "Map Layers" ) )
6837  << new QgsStaticExpressionFunction( QStringLiteral( "raster_statistic" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6838  << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) )
6839  << QgsExpressionFunction::Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "Rasters" ) );
6840 
6841  // **var** function
6842  QgsStaticExpressionFunction *varFunction = new QgsStaticExpressionFunction( QStringLiteral( "var" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnGetVariable, QStringLiteral( "General" ) );
6843  varFunction->setIsStaticFunction(
6844  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6845  {
6846  /* A variable node is static if it has a static name and the name can be found at prepare
6847  * time and is tagged with isStatic.
6848  * It is not static if a variable is set during iteration or not tagged isStatic.
6849  * (e.g. geom_part variable)
6850  */
6851  if ( node->args()->count() > 0 )
6852  {
6853  QgsExpressionNode *argNode = node->args()->at( 0 );
6854 
6855  if ( !argNode->isStatic( parent, context ) )
6856  return false;
6857 
6858  QString varName = argNode->eval( parent, context ).toString();
6859 
6860  const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
6861  return scope ? scope->isStatic( varName ) : false;
6862  }
6863  return false;
6864  }
6865  );
6866 
6867  functions
6868  << varFunction;
6869 
6870  functions << new QgsStaticExpressionFunction( QStringLiteral( "eval_template" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "template" ) ), fcnEvalTemplate, QStringLiteral( "General" ), QString(), true );
6871 
6872  QgsStaticExpressionFunction *evalFunc = new QgsStaticExpressionFunction( QStringLiteral( "eval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ), fcnEval, QStringLiteral( "General" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
6873  evalFunc->setIsStaticFunction(
6874  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6875  {
6876  if ( node->args()->count() > 0 )
6877  {
6878  QgsExpressionNode *argNode = node->args()->at( 0 );
6879 
6880  if ( argNode->isStatic( parent, context ) )
6881  {
6882  QString expString = argNode->eval( parent, context ).toString();
6883 
6884  QgsExpression e( expString );
6885 
6886  if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) )
6887  return true;
6888  }
6889  }
6890 
6891  return false;
6892  } );
6893 
6894  functions << evalFunc;
6895 
6896  QgsStaticExpressionFunction *attributeFunc = new QgsStaticExpressionFunction( QStringLiteral( "attribute" ), -1, fcnAttribute, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
6897  attributeFunc->setIsStaticFunction(
6898  []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6899  {
6900  const QList< QgsExpressionNode *> argList = node->args()->list();
6901  for ( QgsExpressionNode *argNode : argList )
6902  {
6903  if ( !argNode->isStatic( parent, context ) )
6904  return false;
6905  }
6906 
6907  if ( node->args()->count() == 1 )
6908  {
6909  // not static -- this is the variant which uses the current feature taken direct from the expression context
6910  return false;
6911  }
6912 
6913  return true;
6914  } );
6915  functions << attributeFunc;
6916 
6917  functions
6918  << new QgsStaticExpressionFunction( QStringLiteral( "env" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnEnvVar, QStringLiteral( "General" ), QString() )
6920  << new QgsStaticExpressionFunction( QStringLiteral( "raster_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterValue, QStringLiteral( "Rasters" ) )
6921 
6922  // functions for arrays
6925  << new QgsStaticExpressionFunction( QStringLiteral( "array" ), -1, fcnArray, QStringLiteral( "Arrays" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6926  << new QgsStaticExpressionFunction( QStringLiteral( "array_sort" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "ascending" ), true, true ), fcnArraySort, QStringLiteral( "Arrays" ) )
6927  << new QgsStaticExpressionFunction( QStringLiteral( "array_length" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayLength, QStringLiteral( "Arrays" ) )
6928  << new QgsStaticExpressionFunction( QStringLiteral( "array_contains" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayContains, QStringLiteral( "Arrays" ) )
6929  << new QgsStaticExpressionFunction( QStringLiteral( "array_all" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array_b" ) ), fcnArrayAll, QStringLiteral( "Arrays" ) )
6930  << new QgsStaticExpressionFunction( QStringLiteral( "array_find" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayFind, QStringLiteral( "Arrays" ) )
6931  << new QgsStaticExpressionFunction( QStringLiteral( "array_get" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ), fcnArrayGet, QStringLiteral( "Arrays" ) )
6932  << new QgsStaticExpressionFunction( QStringLiteral( "array_first" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayFirst, QStringLiteral( "Arrays" ) )
6933  << new QgsStaticExpressionFunction( QStringLiteral( "array_last" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayLast, QStringLiteral( "Arrays" ) )
6934  << new QgsStaticExpressionFunction( QStringLiteral( "array_append" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayAppend, QStringLiteral( "Arrays" ) )
6935  << new QgsStaticExpressionFunction( QStringLiteral( "array_prepend" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayPrepend, QStringLiteral( "Arrays" ) )
6936  << new QgsStaticExpressionFunction( QStringLiteral( "array_insert" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayInsert, QStringLiteral( "Arrays" ) )
6937  << new QgsStaticExpressionFunction( QStringLiteral( "array_remove_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ), fcnArrayRemoveAt, QStringLiteral( "Arrays" ) )
6938  << new QgsStaticExpressionFunction( QStringLiteral( "array_remove_all" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayRemoveAll, QStringLiteral( "Arrays" ) )
6939  << new QgsStaticExpressionFunction( QStringLiteral( "array_cat" ), -1, fcnArrayCat, QStringLiteral( "Arrays" ) )
6940  << new QgsStaticExpressionFunction( QStringLiteral( "array_slice" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "start_pos" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_pos" ) ), fcnArraySlice, QStringLiteral( "Arrays" ) )
6941  << new QgsStaticExpressionFunction( QStringLiteral( "array_reverse" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayReverse, QStringLiteral( "Arrays" ) )
6942  << new QgsStaticExpressionFunction( QStringLiteral( "array_intersect" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array2" ) ), fcnArrayIntersect, QStringLiteral( "Arrays" ) )
6943  << new QgsStaticExpressionFunction( QStringLiteral( "array_distinct" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayDistinct, QStringLiteral( "Arrays" ) )
6944  << 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" ) )
6945  << 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" ) )
6946  << 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" ) )
6947 
6948  //functions for maps
6949  << new QgsStaticExpressionFunction( QStringLiteral( "json_to_map" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnLoadJson, QStringLiteral( "Maps" ) )
6950  << new QgsStaticExpressionFunction( QStringLiteral( "from_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLoadJson, QStringLiteral( "Maps" ) )
6951  << new QgsStaticExpressionFunction( QStringLiteral( "map_to_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnWriteJson, QStringLiteral( "Maps" ) )
6952  << new QgsStaticExpressionFunction( QStringLiteral( "to_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "json_string" ) ), fcnWriteJson, QStringLiteral( "Maps" ) )
6953  << new QgsStaticExpressionFunction( QStringLiteral( "hstore_to_map" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnHstoreToMap, QStringLiteral( "Maps" ) )
6954  << new QgsStaticExpressionFunction( QStringLiteral( "map_to_hstore" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapToHstore, QStringLiteral( "Maps" ) )
6955  << new QgsStaticExpressionFunction( QStringLiteral( "map" ), -1, fcnMap, QStringLiteral( "Maps" ) )
6956  << new QgsStaticExpressionFunction( QStringLiteral( "map_get" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapGet, QStringLiteral( "Maps" ) )
6957  << new QgsStaticExpressionFunction( QStringLiteral( "map_exist" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapExist, QStringLiteral( "Maps" ) )
6958  << new QgsStaticExpressionFunction( QStringLiteral( "map_delete" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapDelete, QStringLiteral( "Maps" ) )
6959  << new QgsStaticExpressionFunction( QStringLiteral( "map_insert" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnMapInsert, QStringLiteral( "Maps" ) )
6960  << new QgsStaticExpressionFunction( QStringLiteral( "map_concat" ), -1, fcnMapConcat, QStringLiteral( "Maps" ) )
6961  << new QgsStaticExpressionFunction( QStringLiteral( "map_akeys" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapAKeys, QStringLiteral( "Maps" ) )
6962  << new QgsStaticExpressionFunction( QStringLiteral( "map_avals" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapAVals, QStringLiteral( "Maps" ) )
6963  ;
6964 
6966 
6967  //QgsExpression has ownership of all built-in functions
6968  for ( QgsExpressionFunction *func : qgis::as_const( functions ) )
6969  {
6970  *sOwnedFunctions() << func;
6971  *sBuiltinFunctions() << func->name();
6972  sBuiltinFunctions()->append( func->aliases() );
6973  }
6974  }
6975  return functions;
6976 }
6977 
6978 bool QgsExpression::registerFunction( QgsExpressionFunction *function, bool transferOwnership )
6979 {
6980  int fnIdx = functionIndex( function->name() );
6981  if ( fnIdx != -1 )
6982  {
6983  return false;
6984  }
6985  sFunctions()->append( function );
6986  if ( transferOwnership )
6987  sOwnedFunctions()->append( function );
6988  return true;
6989 }
6990 
6991 bool QgsExpression::unregisterFunction( const QString &name )
6992 {
6993  // You can never override the built in functions.
6994  if ( QgsExpression::BuiltinFunctions().contains( name ) )
6995  {
6996  return false;
6997  }
6998  int fnIdx = functionIndex( name );
6999  if ( fnIdx != -1 )
7000  {
7001  sFunctions()->removeAt( fnIdx );
7002  return true;
7003  }
7004  return false;
7005 }
7006 
7008 {
7009  qDeleteAll( *sOwnedFunctions() );
7010  sOwnedFunctions()->clear();
7011 }
7012 
7014 {
7015  if ( sBuiltinFunctions()->isEmpty() )
7016  {
7017  Functions(); // this method builds the gmBuiltinFunctions as well
7018  }
7019  return *sBuiltinFunctions();
7020 }
7021 
7022 
7024  : QgsExpressionFunction( QStringLiteral( "array_foreach" ), QgsExpressionFunction::ParameterList()
7025  << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) )
7026  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
7027  QStringLiteral( "Arrays" ) )
7028 {
7029 
7030 }
7031 
7033 {
7034  bool isStatic = false;
7035 
7036  QgsExpressionNode::NodeList *args = node->args();
7037 
7038  if ( args->count() < 2 )
7039  return false;
7040 
7041  if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
7042  {
7043  isStatic = true;
7044  }
7045  return isStatic;
7046 }
7047 
7049 {
7050  Q_UNUSED( node )
7051  QVariantList result;
7052 
7053  if ( args->count() < 2 )
7054  // error
7055  return result;
7056 
7057  QVariantList array = args->at( 0 )->eval( parent, context ).toList();
7058 
7059  QgsExpressionContext *subContext = const_cast<QgsExpressionContext *>( context );
7060  std::unique_ptr< QgsExpressionContext > tempContext;
7061  if ( !subContext )
7062  {
7063  tempContext = qgis::make_unique< QgsExpressionContext >();
7064  subContext = tempContext.get();
7065  }
7066 
7068  subContext->appendScope( subScope );
7069 
7070  for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
7071  {
7072  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), *it, true ) );
7073  result << args->at( 1 )->eval( parent, subContext );
7074  }
7075 
7076  if ( context )
7077  delete subContext->popScope();
7078 
7079  return result;
7080 }
7081 
7082 QVariant QgsArrayForeachExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7083 {
7084  // This is a dummy function, all the real handling is in run
7085  Q_UNUSED( values )
7086  Q_UNUSED( context )
7087  Q_UNUSED( parent )
7088  Q_UNUSED( node )
7089 
7090  Q_ASSERT( false );
7091  return QVariant();
7092 }
7093 
7095 {
7096  QgsExpressionNode::NodeList *args = node->args();
7097 
7098  if ( args->count() < 2 )
7099  // error
7100  return false;
7101 
7102  args->at( 0 )->prepare( parent, context );
7103 
7104  QgsExpressionContext subContext;
7105  if ( context )
7106  subContext = *context;
7107 
7109  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), QVariant(), true ) );
7110  subContext.appendScope( subScope );
7111 
7112  args->at( 1 )->prepare( parent, &subContext );
7113 
7114  return true;
7115 }
7116 
7118  : QgsExpressionFunction( QStringLiteral( "array_filter" ), QgsExpressionFunction::ParameterList()
7119  << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) )
7120  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
7121  QStringLiteral( "Arrays" ) )
7122 {
7123 
7124 }
7125 
7127 {
7128  bool isStatic = false;
7129 
7130  QgsExpressionNode::NodeList *args = node->args();
7131 
7132  if ( args->count() < 2 )
7133  return false;
7134 
7135  if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
7136  {
7137  isStatic = true;
7138  }
7139  return isStatic;
7140 }
7141 
7143 {
7144  Q_UNUSED( node )
7145  QVariantList result;
7146 
7147  if ( args->count() < 2 )
7148  // error
7149  return result;
7150 
7151  const QVariantList array = args->at( 0 )->eval( parent, context ).toList();
7152 
7153  QgsExpressionContext *subContext = const_cast<QgsExpressionContext *>( context );
7154  std::unique_ptr< QgsExpressionContext > tempContext;
7155  if ( !subContext )
7156  {
7157  tempContext = qgis::make_unique< QgsExpressionContext >();
7158  subContext = tempContext.get();
7159  }
7160 
7162  subContext->appendScope( subScope );
7163 
7164  for ( const QVariant &value : array )
7165  {
7166  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), value, true ) );
7167  if ( args->at( 1 )->eval( parent, subContext ).toBool() )
7168  result << value;
7169  }
7170 
7171  if ( context )
7172  delete subContext->popScope();
7173 
7174  return result;
7175 }
7176 
7177 QVariant QgsArrayFilterExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7178 {
7179  // This is a dummy function, all the real handling is in run
7180  Q_UNUSED( values )
7181  Q_UNUSED( context )
7182  Q_UNUSED( parent )
7183  Q_UNUSED( node )
7184 
7185  Q_ASSERT( false );
7186  return QVariant();
7187 }
7188 
7190 {
7191  QgsExpressionNode::NodeList *args = node->args();
7192 
7193  if ( args->count() < 2 )
7194  // error
7195  return false;
7196 
7197  args->at( 0 )->prepare( parent, context );
7198 
7199  QgsExpressionContext subContext;
7200  if ( context )
7201  subContext = *context;
7202 
7204  subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), QVariant(), true ) );
7205  subContext.appendScope( subScope );
7206 
7207  args->at( 1 )->prepare( parent, &subContext );
7208 
7209  return true;
7210 }
7212  : QgsExpressionFunction( QStringLiteral( "with_variable" ), QgsExpressionFunction::ParameterList() <<
7213  QgsExpressionFunction::Parameter( QStringLiteral( "name" ) )
7214  << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) )
7215  << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
7216  QStringLiteral( "General" ) )
7217 {
7218 
7219 }
7220 
7222 {
7223  bool isStatic = false;
7224 
7225  QgsExpressionNode::NodeList *args = node->args();
7226 
7227  if ( args->count() < 3 )
7228  return false;
7229 
7230  // We only need to check if the node evaluation is static, if both - name and value - are static.
7231  if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
7232  {
7233  QVariant name = args->at( 0 )->eval( parent, context );
7234  QVariant value = args->at( 1 )->eval( parent, context );
7235 
7236  // Temporarily append a new scope to provide the variable
7237  appendTemporaryVariable( context, name.toString(), value );
7238  if ( args->at( 2 )->isStatic( parent, context ) )
7239  isStatic = true;
7240  popTemporaryVariable( context );
7241  }
7242 
7243  return isStatic;
7244 }
7245 
7247 {
7248  Q_UNUSED( node )
7249  QVariant result;
7250 
7251  if ( args->count() < 3 )
7252  // error
7253  return result;
7254 
7255  QVariant name = args->at( 0 )->eval( parent, context );
7256  QVariant value = args->at( 1 )->eval( parent, context );
7257 
7258  const QgsExpressionContext *updatedContext = context;
7259  std::unique_ptr< QgsExpressionContext > tempContext;
7260  if ( !updatedContext )
7261  {
7262  tempContext = qgis::make_unique< QgsExpressionContext >();
7263  updatedContext = tempContext.get();
7264  }
7265 
7266  appendTemporaryVariable( updatedContext, name.toString(), value );
7267  result = args->at( 2 )->eval( parent, updatedContext );
7268 
7269  if ( context )
7270  popTemporaryVariable( updatedContext );
7271 
7272  return result;
7273 }
7274 
7275 QVariant QgsWithVariableExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7276 {
7277  // This is a dummy function, all the real handling is in run
7278  Q_UNUSED( values )
7279  Q_UNUSED( context )
7280  Q_UNUSED( parent )
7281  Q_UNUSED( node )
7282 
7283  Q_ASSERT( false );
7284  return QVariant();
7285 }
7286 
7288 {
7289  QgsExpressionNode::NodeList *args = node->args();
7290 
7291  if ( args->count() < 3 )
7292  // error
7293  return false;
7294 
7295  QVariant name = args->at( 0 )->prepare( parent, context );
7296  QVariant value = args->at( 1 )->prepare( parent, context );
7297 
7298  const QgsExpressionContext *updatedContext = context;
7299  std::unique_ptr< QgsExpressionContext > tempContext;
7300  if ( !updatedContext )
7301  {
7302  tempContext = qgis::make_unique< QgsExpressionContext >();
7303  updatedContext = tempContext.get();
7304  }
7305 
7306  appendTemporaryVariable( updatedContext, name.toString(), value );
7307  args->at( 2 )->prepare( parent, updatedContext );
7308 
7309  if ( context )
7310  popTemporaryVariable( updatedContext );
7311 
7312  return true;
7313 }
7314 
7315 void QgsWithVariableExpressionFunction::popTemporaryVariable( const QgsExpressionContext *context ) const
7316 {
7317  QgsExpressionContext *updatedContext = const_cast<QgsExpressionContext *>( context );
7318  delete updatedContext->popScope();
7319 }
7320 
7321 void QgsWithVariableExpressionFunction::appendTemporaryVariable( const QgsExpressionContext *context, const QString &name, const QVariant &value ) const
7322 {
7325 
7326  QgsExpressionContext *updatedContext = const_cast<QgsExpressionContext *>( context );
7327  updatedContext->appendScope( scope );
7328 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
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:2402
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:81
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
QgsGeometry::lastError
QString lastError() const SIP_HOLDGIL
Returns an error string referring to the last error encountered either when this geometry was created...
Definition: qgsgeometry.cpp:2995
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:370
QgsGeometry::hausdorffDistanceDensify
double hausdorffDistanceDensify(const QgsGeometry &geom, double densifyFraction) const
Returns the Hausdorff distance between this geometry and geom.
Definition: qgsgeometry.cpp:1824
QgsCoordinateSequence
QVector< QgsRingSequence > QgsCoordinateSequence
Definition: qgsabstractgeometry.h:51
QgsProject::relationManager
QgsRelationManager * relationManager
Definition: qgsproject.h:105
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
formatter
Definition: qgsbasicnumericformat.cpp:25
QgsColorRamp
Abstract base class for color ramps.
Definition: qgscolorramp.h:32
QgsFeatureRequest::OrderByClause
The OrderByClause class represents an order by clause for a QgsFeatureRequest.
Definition: qgsfeaturerequest.h:130
qgsexpressioncontextutils.h
qgsrasterbandstats.h
QgsEllipse
Ellipse geometry type.
Definition: qgsellipse.h:40
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
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QgsRasterLayer::bandCount
int bandCount() const
Returns the number of bands in this layer.
Definition: qgsrasterlayer.cpp:217
QgsFeature::id
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
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:181
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:2813
QgsGeometry::distance
double distance(const QgsGeometry &geom) const
Returns the minimum distance between this geometry and another geometry.
Definition: qgsgeometry.cpp:1794
QgsMapLayer::attributionUrl
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:401
QgsCoordinateReferenceSystem::description
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
Definition: qgscoordinatereferencesystem.cpp:1326
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:58
qgsrasterlayer.h
QgsCoordinateReferenceSystem::mapUnits
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:209
qgsfeaturerequest.h
QgsGeometry::within
bool within(const QgsGeometry &geometry) const
Returns true if the geometry is completely within another geometry.
Definition: qgsgeometry.cpp:1264
QgsGradientColorRamp
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:151
QgsCircle
Circle geometry type.
Definition: qgscircle.h:44
QgsExpressionNodeLiteral
An expression node for literal values.
Definition: qgsexpressionnodeimpl.h:365
QgsLineString::setPoints
void setPoints(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
Definition: qgslinestring.cpp:809
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:558
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
QgsExpressionContext::activeScopeForVariable
QgsExpressionContextScope * activeScopeForVariable(const QString &name)
Returns the currently active scope from the context for a specified variable name.
Definition: qgsexpressioncontext.cpp:352
QgsEditorWidgetSetup
Holder for the widget type and its configuration for a field.
Definition: qgseditorwidgetsetup.h:29
QgsQuadrilateral
Quadrilateral geometry type.
Definition: qgsquadrilateral.h:36
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:229
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:38
QgsProject::mapLayersByName
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
Definition: qgsproject.cpp:3213
qgscoordinateutils.h
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
The RasterBandStats struct is a container for statistics about a single raster band.
Definition: qgsrasterbandstats.h:35
QgsAggregateCalculator::AggregateParameters
A bundle of parameters controlling aggregate calculation.
Definition: qgsaggregatecalculator.h:92
QgsCurve::reversed
virtual QgsCurve * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:87
QgsAggregateCalculator::CountDistinct
@ CountDistinct
Number of distinct values.
Definition: qgsaggregatecalculator.h:67
QgsGeometry::isNull
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
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.
QgsRectangle::center
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
qgsstringutils.h
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
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:35
QgsGeometry::interpolate
QgsGeometry interpolate(double distance) const
Returns an interpolated point on the geometry at the specified distance.
Definition: qgsgeometry.cpp:2257
QgsExpressionNodeColumnRef
An expression node which takes it value from a feature's field.
Definition: qgsexpressionnodeimpl.h:401
QgsMultiPoint::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultipoint.cpp:148
QgsQuadrilateral::ConstructionOption
ConstructionOption
A quadrilateral can be constructed from 3 points where the second distance can be determined by the t...
Definition: qgsquadrilateral.h:70
QgsStyle::colorRampRef
const QgsColorRamp * colorRampRef(const QString &name) const
Returns a const pointer to a symbol (doesn't create new instance)
Definition: qgsstyle.cpp:444
QgsExpressionContextUtils::registerContextFunctions
static void registerContextFunctions()
Registers all known core functions provided by QgsExpressionContextScope objects.
Definition: qgsexpressioncontextutils.cpp:825
qgssymbollayerutils.h
QgsRegularPolygon::CircumscribedCircle
@ CircumscribedCircle
Circumscribed about a circle (the radius is the distance from the center to the midpoints of the side...
Definition: qgsregularpolygon.h:52
QgsFields::count
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
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:51
QgsArrayFilterExpressionFunction
Handles the array_filter(array, expression) expression function.
Definition: qgsexpressionfunction.h:534
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:7189
QgsMultiLineString
Multi line string geometry collection.
Definition: qgsmultilinestring.h:32
QgsRasterBandStats::mean
double mean
The mean cell value for the band. NO_DATA values are excluded.
Definition: qgsrasterbandstats.h:97
QgsGeometry::centroid
QgsGeometry centroid() const
Returns the center of mass of a geometry.
Definition: qgsgeometry.cpp:2138
QgsAggregateCalculator::CountMissing
@ CountMissing
Number of missing (null) values.
Definition: qgsaggregatecalculator.h:68
qgsmultipoint.h
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:67
qgsfieldformatterregistry.h
QgsPoint::z
double z
Definition: qgspoint.h:43
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:4287
QgsWkbTypes::geometryDisplayString
static QString geometryDisplayString(GeometryType type) SIP_HOLDGIL
Returns a display string for a geometry type.
Definition: qgswkbtypes.cpp:155
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:468
QgsRelationManager::relation
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Definition: qgsrelationmanager.cpp:96
QgsRegularPolygon::InscribedCircle
@ InscribedCircle
Inscribed in a circle (the radius is the distance between the center and vertices)
Definition: qgsregularpolygon.h:51
QgsQuadrilateral::Projected
@ Projected
Second distance is equal to the distance of the perpendicualr projection of the 3rd point on the segm...
Definition: qgsquadrilateral.h:72
QgsRasterBandStats::range
double range
The range is the distance between min & max.
Definition: qgsrasterbandstats.h:100
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:639
QgsMapLayer::abstract
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:309
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:815
QgsStringUtils::hammingDistance
static int hammingDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Hamming distance between two strings.
Definition: qgsstringutils.cpp:282
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:7275
QgsGeometry::minimalEnclosingCircle
QgsGeometry minimalEnclosingCircle(QgsPointXY &center, double &radius, unsigned int segments=36) const
Returns the minimal enclosing circle for the geometry.
Definition: qgsgeometry.cpp:1069
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:307
QgsExpression::BuiltinFunctions
static const QStringList & BuiltinFunctions()
Definition: qgsexpressionfunction.cpp:7013
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
This class allows including a set of layers in a database-side transaction, provided the layer data p...
Definition: qgstransaction.h:57
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:4583
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsProject::mapLayer
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Definition: qgsproject.cpp:3208
QgsDataProvider::dataSourceUri
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
Definition: qgsdataprovider.h:159
QgsGeometry::overlaps
bool overlaps(const QgsGeometry &geometry) const
Returns true if the geometry overlaps another geometry.
Definition: qgsgeometry.cpp:1252
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:1904
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
QgsCurvePolygon::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgscurvepolygon.cpp:918
Q_GLOBAL_STATIC
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
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:81
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
qgsogcutils.h
QgsMapLayer::dataUrl
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:345
QgsPoint::project
QgsPoint project(double distance, double azimuth, double inclination=90.0) const SIP_HOLDGIL
Returns a new point which correspond to this point projected by a specified distance with specified a...
Definition: qgspoint.cpp:715
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:2421
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:7094
QgsGeometryCollection::numGeometries
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
Definition: qgsgeometrycollection.h:57
QgsRasterBandStats::Range
@ Range
Definition: qgsrasterbandstats.h:42
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:2380
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:155
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:98
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:1617
QgsRelation::referencingLayer
QgsVectorLayer * referencingLayer
Definition: qgsrelation.h:46
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:124
QgsGeometry::isMultipart
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
Definition: qgsgeometry.cpp:377
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:127
Q_DECLARE_METATYPE
Q_DECLARE_METATYPE(QgsMeshTimeSettings)
QgsExpressionFunction::aliases
virtual QStringList aliases() const
Returns a list of possible aliases for the function.
Definition: qgsexpressionfunction.cpp:118
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
Second distance is equal to the distance between 2nd and 3rd point.
Definition: qgsquadrilateral.h:71
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:139
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
QgsAbstractGeometry::isMeasure
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:215
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
QgsFeatureRequest::setFilterRect
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
Definition: qgsfeaturerequest.cpp:92
QgsRasterBandStats::maximumValue
double maximumValue
The maximum cell value in the raster band.
Definition: qgsrasterbandstats.h:88
QgsFeatureRequest::ALL_ATTRIBUTES
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
Definition: qgsfeaturerequest.h:282
QgsWkbTypes::PointM
@ PointM
Definition: qgswkbtypes.h:99
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:7032
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:77
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:138
QgsCoordinateFormatter::FormatDegreesMinutes
@ FormatDegreesMinutes
Degrees and decimal minutes, eg 30degrees 45.55'.
Definition: qgscoordinateformatter.h:51
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QgsEditorWidgetSetup::type
QString type() const
Definition: qgseditorwidgetsetup.h:46
QgsPoint::y
double y
Definition: qgspoint.h:42
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:7126
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:76
precision
int precision
Definition: qgswfsgetfeature.cpp:49
QgsGeometryCollection
Geometry collection.
Definition: qgsgeometrycollection.h:36
QgsQuadrilateral::squareFromDiagonal
static QgsQuadrilateral squareFromDiagonal(const QgsPoint &p1, const QgsPoint &p2) SIP_HOLDGIL
Construct a QgsQuadrilateral as a square from a diagonal.
Definition: qgsquadrilateral.cpp:159
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:2177
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:1129
QgsQuadrilateral::rectangleFrom3Points
static QgsQuadrilateral rectangleFrom3Points(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, ConstructionOption mode) SIP_HOLDGIL
Construct a QgsQuadrilateral as a Rectangle from 3 points.
Definition: qgsquadrilateral.cpp:33
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
QgsWkbTypes::PointZM
@ PointZM
Definition: qgswkbtypes.h:112
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:6991
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:202
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:7246
QgsGeometryCollection::partCount
int partCount() const override
Returns count of parts contained in the geometry.
Definition: qgsgeometrycollection.cpp:852
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:7082
qgshstoreutils.h
QgsExpressionFunction::Parameter
Represents a single parameter passed to a function.
Definition: qgsexpressionfunction.h:55
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::keywordList
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:325
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:139
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:218
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:194
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:2058
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:185
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:1942
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:3148
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:330
QgsGeometry::equals
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
Definition: qgsgeometry.cpp:1221
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:2051
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:2044
QgsExpressionFunction::operator==
bool operator==(const QgsExpressionFunction &other) const
Definition: qgsexpressionfunction.cpp:150
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:266
QgsVectorLayer::selectedFeatureIds
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
Definition: qgsvectorlayer.cpp:3441
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:1321
QgsAbstractGeometry::clone
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QgsRasterBandStats::StdDev
@ StdDev
Definition: qgsrasterbandstats.h:45
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:2184
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:86
QgsPoint::x
Q_GADGET double x
Definition: qgspoint.h:41
QgsRasterLayer::dataProvider
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Definition: qgsrasterlayer.cpp:234
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:924
QgsWithVariableExpressionFunction::QgsWithVariableExpressionFunction
QgsWithVariableExpressionFunction()
Definition: qgsexpressionfunction.cpp:7211
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:433
QgsPoint::m
double m
Definition: qgspoint.h:44
QgsGeometry::length
double length() const
Returns the planar, 2-dimensional length of geometry.
Definition: qgsgeometry.cpp:1783
QgsRasterBandStats::Min
@ Min
Definition: qgsrasterbandstats.h:40
QgsExpressionContextScope::isStatic
bool isStatic(const QString &name) const
Tests whether the variable with the specified name is static and can be cached.
Definition: qgsexpressioncontext.cpp:164
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
QgsMapLayer::isEditable
virtual bool isEditable() const
Returns true if the layer can be edited.
Definition: qgsmaplayer.cpp:1740
qgsquadrilateral.h
QgsSpatialIndex
A spatial index for QgsFeature objects.
Definition: qgsspatialindex.h:68
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:148
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:2481
QgsMapLayer::title
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:293
qgsvectorlayerfeatureiterator.h
qgsregularpolygon.h
QgsArrayForeachExpressionFunction
Handles the array_foreach(array, expression) expression function.
Definition: qgsexpressionfunction.h:511
QgsGeometry::crosses
bool crosses(const QgsGeometry &geometry) const
Returns true if the geometry crosses another geometry.
Definition: qgsgeometry.cpp:1276
QgsAbstractGeometry::nCoordinates
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
Definition: qgsabstractgeometry.cpp:116
QgsWeakMapLayerPointer
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1688
QgsStaticExpressionFunction
c++ helper class for defining QgsExpression functions.
Definition: qgsexpressionfunction.h:350
QgsCurvePolygon::ringCount
int ringCount(int part=0) const override SIP_HOLDGIL
Returns the number of rings of which this geometry is built.
Definition: qgscurvepolygon.cpp:1159
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
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:50
QgsRasterLayer
Represents a raster layer.
Definition: qgsrasterlayer.h:71
QgsAggregateCalculator::Max
@ Max
Max of values.
Definition: qgsaggregatecalculator.h:70
QgsRasterBandStats::Mean
@ Mean
Definition: qgsrasterbandstats.h:44
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:100
QgsGeometry::SideLeft
@ SideLeft
Buffer to left of line.
Definition: qgsgeometry.h:1134
QgsCoordinateReferenceSystem::toProj
QString toProj() const
Returns a Proj string representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1420
QgsExpressionNodeFunction
An expression node for expression functions.
Definition: qgsexpressionnodeimpl.h:317
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:320
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:145
QgsExpression::prepare
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
Definition: qgsexpression.cpp:323
QgsInterval::minutes
double minutes() const
Returns the interval duration in minutes.
Definition: qgsinterval.h:155
QgsRingSequence
QVector< QgsPointSequence > QgsRingSequence
Definition: qgsabstractgeometry.h:50
QgsGeometry::pointOnSurface
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
Definition: qgsgeometry.cpp:2162
qgscurvepolygon.h
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:128
QgsMapLayer::minimumScale
double minimumScale() const
Returns the minimum map scale (i.e.
Definition: qgsmaplayer.cpp:743
QgsGeometry::touches
bool touches(const QgsGeometry &geometry) const
Returns true if the geometry touches another geometry.
Definition: qgsgeometry.cpp:1240
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:30
QgsMapLayer::maximumScale
double maximumScale() const
Returns the maximum map scale (i.e.
Definition: qgsmaplayer.cpp:727
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:43
QgsExpression::Functions
static const QList< QgsExpressionFunction * > & Functions()
Definition: qgsexpressionfunction.cpp:6008
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsExpression::evaluate
QVariant evaluate()
Evaluate the feature and return the result.
Definition: qgsexpression.cpp:346
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:74
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:131
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext.
Definition: qgsexpressioncontext.h:112
QgsGeometry::simplify
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
Definition: qgsgeometry.cpp:2098
QgsPoint::inclination
double inclination(const QgsPoint &other) const SIP_HOLDGIL
Calculates Cartesian inclination between this point and other one (starting from zenith = 0 to nadir ...
Definition: qgspoint.cpp:703
QgsApplication::fieldFormatterRegistry
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
Definition: qgsapplication.cpp:2278
qgsstyle.h
qgsgeometryutils.h
QgsAbstractGeometry::is3D
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:206
QgsGeometry::vertexAt
QgsPoint vertexAt(int atVertex) const
Returns coordinates of a vertex.
Definition: qgsgeometry.cpp:588
QgsMapToPixelSimplifier
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
Definition: qgsmaptopixelgeometrysimplifier.h:39
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:186
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:490
qgsvectorlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
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:109
QgsRasterBandStats::minimumValue
double minimumValue
The minimum cell value in the raster band.
Definition: qgsrasterbandstats.h:94
QgsExpressionNode
Abstract base class for all nodes that can appear in an expression.
Definition: qgsexpressionnode.h:35
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:1812
QgsCurve::clone
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
QgsSpatialIndex::FlagStoreFeatureGeometries
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
Definition: qgsspatialindex.h:77
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:1544
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:41
qgstransaction.h
QgsStringUtils::soundex
static QString soundex(const QString &string)
Returns the Soundex representation of a string.
Definition: qgsstringutils.cpp:321
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:3636
QgsAggregateCalculator::ThirdQuartile
@ ThirdQuartile
Third quartile (numeric fields only)
Definition: qgsaggregatecalculator.h:80
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
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:1288
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
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:2326
QgsExpressionFunction::usesGeometry
virtual bool usesGeometry(const QgsExpressionNodeFunction *node) const
Does this function use a geometry object.
Definition: qgsexpressionfunction.cpp:112
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:331
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QgsGeometryCollection::geometryN
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
Definition: qgsgeometrycollection.h:85
QgsVectorLayer::mapTipTemplate
QString mapTipTemplate
Definition: qgsvectorlayer.h:392
QgsExpressionFunction::lazyEval
bool lazyEval() const
true if this function should use lazy evaluation.
Definition: qgsexpressionfunction.h:232
ExpressionFunctionList
QList< QgsExpressionFunction * > ExpressionFunctionList
Definition: qgsexpressionfunction.cpp:64
QgsAggregateCalculator::Aggregate
Aggregate
Available aggregates to calculate.
Definition: qgsaggregatecalculator.h:65
qgsthreadingutils.h
qgsexpressionnodeimpl.h
QgsFeatureRequest::OrderBy
Represents a list of OrderByClauses, with the most important first and the least important last.
Definition: qgsfeaturerequest.h:230
QgsExpressionNodeColumnRef::name
QString name() const
The name of the column.
Definition: qgsexpressionnodeimpl.h:414
QgsSpatialIndex::nearestNeighbor
QList< QgsFeatureId > nearestNeighbor(const QgsPointXY &point, int neighbors=1, double maxDistance=0) const
Returns nearest neighbors to a point.
Definition: qgsspatialindex.cpp:501
QgsGeometry::shortestLine
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Definition: qgsgeometry.cpp:625
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:79
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:374
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:46
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
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsExpressionFunction
A abstract base class for defining QgsExpression functions.
Definition: qgsexpressionfunction.h:41
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:210
QgsRegularPolygon
Regular Polygon geometry type.
Definition: qgsregularpolygon.h:42
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
QgsGeometry::JoinStyleRound
@ JoinStyleRound
Use rounded joins.
Definition: qgsgeometry.h:1151
QgsFeatureSource::materialize
QgsVectorLayer * materialize(const QgsFeatureRequest &request, QgsFeedback *feedback=nullptr)
Materializes a request (query) made against this feature source, by running it over the source and re...
Definition: qgsfeaturesource.cpp:132
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:173
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:7048
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
QgsCoordinateFormatter::Format
Format
Available formats for displaying coordinates.
Definition: qgscoordinateformatter.h:48
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:2000
sqlite3_database_unique_ptr::exec
int exec(const QString &sql, QString &errorMessage) const
Executes the sql command in the database.
Definition: qgssqliteutils.cpp:109
QgsRelation::isValid
bool isValid
Definition: qgsrelation.h:49
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:41
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:802
QgsExpressionFunction::name
QString name() const
The name of the function.
Definition: qgsexpressionfunction.h:190
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:229
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1059
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:2628
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:86
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
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:585
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:42
QgsGeometry::asMultiPoint
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
Definition: qgsgeometry.cpp:1640
QgsRasterBandStats::stdDev
double stdDev
The standard deviation of the cell values.
Definition: qgsrasterbandstats.h:103
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:234
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
QgsSpatialIndex::intersects
QList< QgsFeatureId > intersects(const QgsRectangle &rectangle) const
Returns a list of features with a bounding box which intersects the specified rectangle.
Definition: qgsspatialindex.cpp:488
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:7142
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:996
QgsExpression::registerFunction
static bool registerFunction(QgsExpressionFunction *function, bool transferOwnership=false)
Registers a function to the expression engine.
Definition: qgsexpressionfunction.cpp:6978
QgsMultiLineString::addGeometry
bool addGeometry(QgsAbstractGeometry *g) override
Adds a geometry and takes ownership. Returns true in case of success.
Definition: qgsmultilinestring.cpp:131
QgsDistanceArea
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
Definition: qgsdistancearea.h:50
qgsspatialindex.h
QgsFeature::fields
QgsFields fields
Definition: qgsfeature.h:66
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:2950
qgsexception.h
QgsAggregateCalculator::Sum
@ Sum
Sum of values.
Definition: qgsaggregatecalculator.h:71
qgsdistancearea.h
QgsArrayForeachExpressionFunction::QgsArrayForeachExpressionFunction
QgsArrayForeachExpressionFunction()
Definition: qgsexpressionfunction.cpp:7023
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:1150
QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds
@ FlagDegreesPadMinutesSeconds
Pad minute and second values with leading zeros, eg '05' instead of '5'.
Definition: qgscoordinateformatter.h:61
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
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:123
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:7177
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:137
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:2461
QgsGeometry::contains
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
Definition: qgsgeometry.cpp:1184
ENSURE_GEOM_TYPE
#define ENSURE_GEOM_TYPE(f, g, geomtype)
Definition: qgsexpressionfunction.cpp:2310
RelationFunction
bool(QgsGeometry::* RelationFunction)(const QgsGeometry &geometry) const
Definition: qgsexpressionfunction.cpp:5729
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:1843
QgsFeatureRequest::setDestinationCrs
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
Definition: qgsfeaturerequest.cpp:258
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:201
QgsVectorLayer::getFeature
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
Definition: qgsvectorlayer.h:1194
QgsRectangle::grow
void grow(double delta)
Grows the rectangle in place by the specified amount.
Definition: qgsrectangle.h:275
QgsVectorLayer::selectedFeatureCount
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
Definition: qgsvectorlayer.cpp:3436
QgsGeometry::isGeosValid
bool isGeosValid(QgsGeometry::ValidityFlags flags=QgsGeometry::ValidityFlags()) const
Checks validity of the geometry using GEOS.
Definition: qgsgeometry.cpp:2711
QgsCurve::segmentize
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
Definition: qgscurve.cpp:166
QgsGeometry::vertices_begin
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsgeometry.cpp:1836
QgsCurve::isClosed
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgscurve.cpp:40
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
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:119
QgsField::editorWidgetSetup
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:559
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:1005
QgsExpression::cleanRegisteredFunctions
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine.
Definition: qgsexpressionfunction.cpp:7007
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
qgscoordinateformatter.h
QgsVectorLayer::displayExpression
QString displayExpression
Definition: qgsvectorlayer.h:391
QgsPoint::isValid
bool isValid(QString &error, int flags=0) const override SIP_HOLDGIL
Checks validity of the geometry, and returns true if the geometry is valid.
Definition: qgspoint.cpp:419
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsArrayFilterExpressionFunction::QgsArrayFilterExpressionFunction
QgsArrayFilterExpressionFunction()
Definition: qgsexpressionfunction.cpp:7117
sqlite3_database_unique_ptr
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
Definition: qgssqliteutils.h:119
QgsGeometry::type
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
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:7287
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:265
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
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsGeometry::area
double area() const
Returns the planar, 2-dimensional area of the geometry.
Definition: qgsgeometry.cpp:1760
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
A field formatter helps to handle and display values for a field.
Definition: qgsfieldformatter.h:73
QgsFeatureRequest::setFlags
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
Definition: qgsfeaturerequest.cpp:179
QgsSqliteUtils::quotedIdentifier
static QString quotedIdentifier(const QString &identifier)
Returns a properly quoted version of identifier.
Definition: qgssqliteutils.cpp:259
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:223
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
QgsInterval::isValid
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:181
QgsGradientStop
Represents a color stop within a QgsGradientColorRamp color ramp.
Definition: qgscolorramp.h:113
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:2441
QgsMapLayerType::PluginLayer
@ PluginLayer
QgsMapLayer::metadata
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:88
QgsMapLayer::dataProvider
virtual QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Definition: qgsmaplayer.cpp:169
sqlite3_statement_unique_ptr
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
Definition: qgssqliteutils.h:70
QgsGeometry::JoinStyleBevel
@ JoinStyleBevel
Use beveled joins.
Definition: qgsgeometry.h:1153
qgsmultilinestring.h
qgsfieldformatter.h
QgsOgcUtils::Context
The Context struct stores the current layer and coordinate transform context.
Definition: qgsogcutils.h:59
QgsTriangle
Triangle geometry type.
Definition: qgstriangle.h:34
QgsExpressionNode::NodeList
A list of expression nodes.
Definition: qgsexpressionnode.h:118
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
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
qgsmessagelog.h
QgsQuadrilateral::toPolygon
QgsPolygon * toPolygon(bool force2D=false) const
Returns the quadrilateral as a new polygon.
Definition: qgsquadrilateral.cpp:369
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:521
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:219
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:7221
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:2307
QgsGeometry::disjoint
bool disjoint(const QgsGeometry &geometry) const
Returns true if the geometry is disjoint of another geometry.
Definition: qgsgeometry.cpp:1209
QgsMapLayer::type
QgsMapLayerType type
Definition: qgsmaplayer.h:90