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