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