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