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