QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpression.cpp
3  -------------------
4  begin : August 2011
5  copyright : (C) 2011 Martin Dobias
6  email : wonder.sk at gmail dot com
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 "qgsexpression.h"
17 
18 #include <QtDebug>
19 #include <QDomDocument>
20 #include <QDate>
21 #include <QRegExp>
22 #include <QColor>
23 #include <QUuid>
24 #include <QMutex>
25 
26 #include <math.h>
27 #include <limits>
28 
29 #include "qgsdistancearea.h"
30 #include "qgsfeature.h"
31 #include "qgsgeometry.h"
32 #include "qgsgeometryengine.h"
33 #include "qgsgeometryutils.h"
34 #include "qgslogger.h"
35 #include "qgsmaplayerregistry.h"
36 #include "qgsogcutils.h"
37 #include "qgsvectorlayer.h"
38 #include "qgssymbollayerv2utils.h"
39 #include "qgsvectorcolorrampv2.h"
40 #include "qgsstylev2.h"
41 #include "qgsexpressioncontext.h"
42 #include "qgsproject.h"
43 #include "qgsstringutils.h"
45 #include "qgspointv2.h"
46 #include "qgspolygonv2.h"
47 #include "qgsmultipointv2.h"
48 #include "qgsmultilinestringv2.h"
49 #include "qgscurvepolygonv2.h"
50 #include "qgsexpressionprivate.h"
51 #include "qgsexpressionsorter.h"
52 #include "qgscrscache.h"
53 #include "qgsmessagelog.h"
54 #include "qgscsexception.h"
55 
56 #if QT_VERSION < 0x050000
57 #include <qtextdocument.h>
58 #endif
59 
60 // from parser
61 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
62 
64 // three-value logic
65 
66 enum TVL
67 {
71 };
72 
73 static TVL AND[3][3] =
74 {
75  // false true unknown
76  { False, False, False }, // false
77  { False, True, Unknown }, // true
78  { False, Unknown, Unknown } // unknown
79 };
80 
81 static TVL OR[3][3] =
82 {
83  { False, True, Unknown }, // false
84  { True, True, True }, // true
85  { Unknown, True, Unknown } // unknown
86 };
87 
88 static TVL NOT[3] = { True, False, Unknown };
89 
91 {
92  switch ( v )
93  {
94  case False:
95  return 0;
96  case True:
97  return 1;
98  case Unknown:
99  default:
100  return QVariant();
101  }
102 }
103 
104 #define TVL_True QVariant(1)
105 #define TVL_False QVariant(0)
106 #define TVL_Unknown QVariant()
107 
109 // QVariant checks and conversions
110 
111 inline bool isIntSafe( const QVariant& v )
112 {
113  if ( v.type() == QVariant::Int ) return true;
114  if ( v.type() == QVariant::UInt ) return true;
115  if ( v.type() == QVariant::LongLong ) return true;
116  if ( v.type() == QVariant::ULongLong ) return true;
117  if ( v.type() == QVariant::Double ) return false;
118  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
119  return false;
120 }
121 inline bool isDoubleSafe( const QVariant& v )
122 {
123  if ( v.type() == QVariant::Double ) return true;
124  if ( v.type() == QVariant::Int ) return true;
125  if ( v.type() == QVariant::UInt ) return true;
126  if ( v.type() == QVariant::LongLong ) return true;
127  if ( v.type() == QVariant::ULongLong ) return true;
128  if ( v.type() == QVariant::String )
129  {
130  bool ok;
131  double val = v.toString().toDouble( &ok );
132  ok = ok && qIsFinite( val ) && !qIsNaN( val );
133  return ok;
134  }
135  return false;
136 }
137 
138 inline bool isDateTimeSafe( const QVariant& v )
139 {
140  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
141  v.type() == QVariant::Time;
142 }
143 
144 inline bool isIntervalSafe( const QVariant& v )
145 {
146  if ( v.canConvert<QgsInterval>() )
147  {
148  return true;
149  }
150 
151  if ( v.type() == QVariant::String )
152  {
153  return QgsInterval::fromString( v.toString() ).isValid();
154  }
155  return false;
156 }
157 
158 inline bool isNull( const QVariant& v ) { return v.isNull(); }
159 
161 // evaluation error macros
162 
163 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
164 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
165 
167 // operators
168 
169 const char* QgsExpression::BinaryOperatorText[] =
170 {
171  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
172  "OR", "AND",
173  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
174  "+", "-", "*", "/", "//", "%", "^",
175  "||"
176 };
177 
178 const char* QgsExpression::UnaryOperatorText[] =
179 {
180  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
181  "NOT", "-"
182 };
183 
185 // functions
186 
187 // implicit conversion to string
189 {
190  return value.toString();
191 }
192 
193 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
194 {
195  bool ok;
196  double x = value.toDouble( &ok );
197  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
198  {
199  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
200  return 0;
201  }
202  return x;
203 }
204 
205 static int getIntValue( const QVariant& value, QgsExpression* parent )
206 {
207  bool ok;
208  qint64 x = value.toLongLong( &ok );
210  {
211  return x;
212  }
213  else
214  {
215  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
216  return 0;
217  }
218 }
219 
220 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
221 {
222  QDateTime d = value.toDateTime();
223  if ( d.isValid() )
224  {
225  return d;
226  }
227  else
228  {
229  QTime t = value.toTime();
230  if ( t.isValid() )
231  {
232  return QDateTime( QDate( 1, 1, 1 ), t );
233  }
234 
235  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
236  return QDateTime();
237  }
238 }
239 
240 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
241 {
242  QDate d = value.toDate();
243  if ( d.isValid() )
244  {
245  return d;
246  }
247  else
248  {
249  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
250  return QDate();
251  }
252 }
253 
254 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
255 {
256  QTime t = value.toTime();
257  if ( t.isValid() )
258  {
259  return t;
260  }
261  else
262  {
263  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
264  return QTime();
265  }
266 }
267 
268 static QgsInterval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
269 {
270  if ( value.canConvert<QgsInterval>() )
271  return value.value<QgsInterval>();
272 
273  QgsInterval inter = QgsInterval::fromString( value.toString() );
274  if ( inter.isValid() )
275  {
276  return inter;
277  }
278  // If we get here then we can't convert so we just error and return invalid.
279  if ( report_error )
280  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
281 
282  return QgsInterval();
283 }
284 
285 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
286 {
287  if ( value.canConvert<QgsGeometry>() )
288  return value.value<QgsGeometry>();
289 
290  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
291  return QgsGeometry();
292 }
293 
294 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
295 {
296  if ( value.canConvert<QgsFeature>() )
297  return value.value<QgsFeature>();
298 
299  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
300  return 0;
301 }
302 
303 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
304  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
305 
306 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
307 {
308  if ( value.canConvert<QgsExpression::Node*>() )
309  return value.value<QgsExpression::Node*>();
310 
311  parent->setEvalErrorString( "Cannot convert to Node" );
312  return nullptr;
313 }
314 
316 {
317  QString layerString = value.toString();
318  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
319  if ( !vl )
320  {
321  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
322  if ( !layersByName.isEmpty() )
323  {
324  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
325  }
326  }
327 
328  return vl;
329 }
330 
331 
332 // this handles also NULL values
333 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
334 {
335  // we need to convert to TVL
336  if ( value.isNull() )
337  return Unknown;
338 
339  //handle some special cases
340  if ( value.canConvert<QgsGeometry>() )
341  {
342  //geom is false if empty
343  QgsGeometry geom = value.value<QgsGeometry>();
344  return geom.isEmpty() ? False : True;
345  }
346  else if ( value.canConvert<QgsFeature>() )
347  {
348  //feat is false if non-valid
349  QgsFeature feat = value.value<QgsFeature>();
350  return feat.isValid() ? True : False;
351  }
352 
353  if ( value.type() == QVariant::Int )
354  return value.toInt() != 0 ? True : False;
355 
356  bool ok;
357  double x = value.toDouble( &ok );
358  if ( !ok )
359  {
360  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
361  return Unknown;
362  }
363  return !qgsDoubleNear( x, 0.0 ) ? True : False;
364 }
365 
367 
368 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
369 {
370  if ( !context )
371  return QVariant();
372 
373  QString name = getStringValue( values.at( 0 ), parent );
374  return context->variable( name );
375 }
376 
377 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
378 {
379  if ( !context )
380  return QVariant();
381 
382  QString expString = getStringValue( values.at( 0 ), parent );
383  QgsExpression expression( expString );
384  return expression.evaluate( context );
385 }
386 
387 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
388 {
389  double x = getDoubleValue( values.at( 0 ), parent );
390  return QVariant( sqrt( x ) );
391 }
392 
393 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
394 {
395  double val = getDoubleValue( values.at( 0 ), parent );
396  return QVariant( fabs( val ) );
397 }
398 
399 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
400 {
401  double deg = getDoubleValue( values.at( 0 ), parent );
402  return ( deg * M_PI ) / 180;
403 }
404 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
405 {
406  double rad = getDoubleValue( values.at( 0 ), parent );
407  return ( 180 * rad ) / M_PI;
408 }
409 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
410 {
411  double x = getDoubleValue( values.at( 0 ), parent );
412  return QVariant( sin( x ) );
413 }
414 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
415 {
416  double x = getDoubleValue( values.at( 0 ), parent );
417  return QVariant( cos( x ) );
418 }
419 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
420 {
421  double x = getDoubleValue( values.at( 0 ), parent );
422  return QVariant( tan( x ) );
423 }
424 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
425 {
426  double x = getDoubleValue( values.at( 0 ), parent );
427  return QVariant( asin( x ) );
428 }
429 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
430 {
431  double x = getDoubleValue( values.at( 0 ), parent );
432  return QVariant( acos( x ) );
433 }
434 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
435 {
436  double x = getDoubleValue( values.at( 0 ), parent );
437  return QVariant( atan( x ) );
438 }
439 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
440 {
441  double y = getDoubleValue( values.at( 0 ), parent );
442  double x = getDoubleValue( values.at( 1 ), parent );
443  return QVariant( atan2( y, x ) );
444 }
445 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
446 {
447  double x = getDoubleValue( values.at( 0 ), parent );
448  return QVariant( exp( x ) );
449 }
450 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
451 {
452  double x = getDoubleValue( values.at( 0 ), parent );
453  if ( x <= 0 )
454  return QVariant();
455  return QVariant( log( x ) );
456 }
457 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
458 {
459  double x = getDoubleValue( values.at( 0 ), parent );
460  if ( x <= 0 )
461  return QVariant();
462  return QVariant( log10( x ) );
463 }
464 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
465 {
466  double b = getDoubleValue( values.at( 0 ), parent );
467  double x = getDoubleValue( values.at( 1 ), parent );
468  if ( x <= 0 || b <= 0 )
469  return QVariant();
470  return QVariant( log( x ) / log( b ) );
471 }
472 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
473 {
474  double min = getDoubleValue( values.at( 0 ), parent );
475  double max = getDoubleValue( values.at( 1 ), parent );
476  if ( max < min )
477  return QVariant();
478 
479  // Return a random double in the range [min, max] (inclusive)
480  double f = static_cast< double >( qrand() ) / RAND_MAX;
481  return QVariant( min + f * ( max - min ) );
482 }
483 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
484 {
485  int min = getIntValue( values.at( 0 ), parent );
486  int max = getIntValue( values.at( 1 ), parent );
487  if ( max < min )
488  return QVariant();
489 
490  // Return a random integer in the range [min, max] (inclusive)
491  return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
492 }
493 
494 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
495 {
496  double val = getDoubleValue( values.at( 0 ), parent );
497  double domainMin = getDoubleValue( values.at( 1 ), parent );
498  double domainMax = getDoubleValue( values.at( 2 ), parent );
499  double rangeMin = getDoubleValue( values.at( 3 ), parent );
500  double rangeMax = getDoubleValue( values.at( 4 ), parent );
501 
502  if ( domainMin >= domainMax )
503  {
504  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
505  return QVariant();
506  }
507 
508  // outside of domain?
509  if ( val >= domainMax )
510  {
511  return rangeMax;
512  }
513  else if ( val <= domainMin )
514  {
515  return rangeMin;
516  }
517 
518  // calculate linear scale
519  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
520  double c = rangeMin - ( domainMin * m );
521 
522  // Return linearly scaled value
523  return QVariant( m * val + c );
524 }
525 
526 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
527 {
528  double val = getDoubleValue( values.at( 0 ), parent );
529  double domainMin = getDoubleValue( values.at( 1 ), parent );
530  double domainMax = getDoubleValue( values.at( 2 ), parent );
531  double rangeMin = getDoubleValue( values.at( 3 ), parent );
532  double rangeMax = getDoubleValue( values.at( 4 ), parent );
533  double exponent = getDoubleValue( values.at( 5 ), parent );
534 
535  if ( domainMin >= domainMax )
536  {
537  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
538  return QVariant();
539  }
540  if ( exponent <= 0 )
541  {
542  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
543  return QVariant();
544  }
545 
546  // outside of domain?
547  if ( val >= domainMax )
548  {
549  return rangeMax;
550  }
551  else if ( val <= domainMin )
552  {
553  return rangeMin;
554  }
555 
556  // Return exponentially scaled value
557  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
558 }
559 
560 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
561 {
562  //initially set max as first value
563  double maxVal = getDoubleValue( values.at( 0 ), parent );
564 
565  //check against all other values
566  for ( int i = 1; i < values.length(); ++i )
567  {
568  double testVal = getDoubleValue( values[i], parent );
569  if ( testVal > maxVal )
570  {
571  maxVal = testVal;
572  }
573  }
574 
575  return QVariant( maxVal );
576 }
577 
578 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
579 {
580  //initially set min as first value
581  double minVal = getDoubleValue( values.at( 0 ), parent );
582 
583  //check against all other values
584  for ( int i = 1; i < values.length(); ++i )
585  {
586  double testVal = getDoubleValue( values[i], parent );
587  if ( testVal < minVal )
588  {
589  minVal = testVal;
590  }
591  }
592 
593  return QVariant( minVal );
594 }
595 
596 static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
597 {
598  //lazy eval, so we need to evaluate nodes now
599 
600  //first node is layer id or name
601  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
603  QVariant value = node->eval( parent, context );
605  QgsVectorLayer* vl = getVectorLayer( value, parent );
606  if ( !vl )
607  {
608  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
609  return QVariant();
610  }
611 
612  // second node is aggregate type
613  node = getNode( values.at( 1 ), parent );
615  value = node->eval( parent, context );
617  bool ok = false;
619  if ( !ok )
620  {
621  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
622  return QVariant();
623  }
624 
625  // third node is subexpression (or field name)
626  node = getNode( values.at( 2 ), parent );
628  QString subExpression = node->dump();
629 
631  //optional forth node is filter
632  if ( values.count() > 3 )
633  {
634  node = getNode( values.at( 3 ), parent );
636  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
637  if ( !nl || nl->value().isValid() )
638  parameters.filter = node->dump();
639  }
640 
641  //optional fifth node is concatenator
642  if ( values.count() > 4 )
643  {
644  node = getNode( values.at( 4 ), parent );
646  value = node->eval( parent, context );
648  parameters.delimiter = value.toString();
649  }
650 
651  QString cacheKey = QString( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( static_cast< int >( aggregate ) ), subExpression, parameters.filter );
652  if ( context && context->hasCachedValue( cacheKey ) )
653  return context->cachedValue( cacheKey );
654 
655  QVariant result;
656  if ( context )
657  {
658  QgsExpressionContext subContext( *context );
659  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
660  }
661  else
662  {
663  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
664  }
665  if ( !ok )
666  {
667  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
668  return QVariant();
669  }
670 
671  // cache value
672  if ( context )
673  context->setCachedValue( cacheKey, result );
674  return result;
675 }
676 
677 static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
678 {
679  if ( !context )
680  {
681  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
682  return QVariant();
683  }
684 
685  // first step - find current layer
686  QString layerId = context->variable( "layer_id" ).toString();
687  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
688  if ( !vl )
689  {
690  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
691  return QVariant();
692  }
693 
694  //lazy eval, so we need to evaluate nodes now
695 
696  //first node is relation name
697  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
699  QVariant value = node->eval( parent, context );
701  QString relationId = value.toString();
702  // check relation exists
703  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
704  if ( !relation.isValid() || relation.referencedLayer() != vl )
705  {
706  // check for relations by name
708  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
709  {
710  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
711  return QVariant();
712  }
713  else
714  {
715  relation = relations.at( 0 );
716  }
717  }
718 
719  QgsVectorLayer* childLayer = relation.referencingLayer();
720 
721  // second node is aggregate type
722  node = getNode( values.at( 1 ), parent );
724  value = node->eval( parent, context );
726  bool ok = false;
728  if ( !ok )
729  {
730  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
731  return QVariant();
732  }
733 
734  //third node is subexpression (or field name)
735  node = getNode( values.at( 2 ), parent );
737  QString subExpression = node->dump();
738 
739  //optional fourth node is concatenator
741  if ( values.count() > 3 )
742  {
743  node = getNode( values.at( 3 ), parent );
745  value = node->eval( parent, context );
747  parameters.delimiter = value.toString();
748  }
749 
750  FEAT_FROM_CONTEXT( context, f );
751  parameters.filter = relation.getRelatedFeaturesFilter( f );
752 
753  QString cacheKey = QString( "relagg:%1:%2:%3:%4" ).arg( vl->id(),
754  QString::number( static_cast< int >( aggregate ) ),
755  subExpression,
756  parameters.filter );
757  if ( context && context->hasCachedValue( cacheKey ) )
758  return context->cachedValue( cacheKey );
759 
760  QVariant result;
761  ok = false;
762 
763 
764  QgsExpressionContext subContext( *context );
765  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
766 
767  if ( !ok )
768  {
769  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
770  return QVariant();
771  }
772 
773  // cache value
774  if ( context )
775  context->setCachedValue( cacheKey, result );
776  return result;
777 }
778 
779 
781 {
782  if ( !context )
783  {
784  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
785  return QVariant();
786  }
787 
788  // first step - find current layer
789  QString layerId = context->variable( "layer_id" ).toString();
790  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
791  if ( !vl )
792  {
793  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
794  return QVariant();
795  }
796 
797  //lazy eval, so we need to evaluate nodes now
798 
799  //first node is subexpression (or field name)
800  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
802  QString subExpression = node->dump();
803 
804  //optional second node is group by
805  QString groupBy;
806  if ( values.count() > 1 )
807  {
808  node = getNode( values.at( 1 ), parent );
810  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
811  if ( !nl || nl->value().isValid() )
812  groupBy = node->dump();
813  }
814 
815  //optional third node is filter
816  if ( values.count() > 2 )
817  {
818  node = getNode( values.at( 2 ), parent );
820  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
821  if ( !nl || nl->value().isValid() )
822  parameters.filter = node->dump();
823  }
824 
825  // build up filter with group by
826 
827  // find current group by value
828  if ( !groupBy.isEmpty() )
829  {
830  QgsExpression groupByExp( groupBy );
831  QVariant groupByValue = groupByExp.evaluate( context );
832  if ( !parameters.filter.isEmpty() )
833  parameters.filter = QString( "(%1) AND (%2=%3)" ).arg( parameters.filter, groupBy, QgsExpression::quotedValue( groupByValue ) );
834  else
835  parameters.filter = QString( "(%2 = %3)" ).arg( groupBy, QgsExpression::quotedValue( groupByValue ) );
836  }
837 
838  QString cacheKey = QString( "agg:%1:%2:%3:%4" ).arg( vl->id(),
839  QString::number( static_cast< int >( aggregate ) ),
840  subExpression,
841  parameters.filter );
842  if ( context && context->hasCachedValue( cacheKey ) )
843  return context->cachedValue( cacheKey );
844 
845  QVariant result;
846  bool ok = false;
847 
848  QgsExpressionContext subContext( *context );
849  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
850 
851  if ( !ok )
852  {
853  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
854  return QVariant();
855  }
856 
857  // cache value
858  if ( context )
859  context->setCachedValue( cacheKey, result );
860  return result;
861 }
862 
863 
864 static QVariant fcnAggregateCount( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
865 {
867 }
868 
869 static QVariant fcnAggregateCountDistinct( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
870 {
872 }
873 
874 static QVariant fcnAggregateCountMissing( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
875 {
877 }
878 
879 static QVariant fcnAggregateMin( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
880 {
882 }
883 
884 static QVariant fcnAggregateMax( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
885 {
887 }
888 
889 static QVariant fcnAggregateSum( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
890 {
892 }
893 
894 static QVariant fcnAggregateMean( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
895 {
897 }
898 
899 static QVariant fcnAggregateMedian( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
900 {
902 }
903 
904 static QVariant fcnAggregateStdev( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
905 {
907 }
908 
909 static QVariant fcnAggregateRange( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
910 {
912 }
913 
914 static QVariant fcnAggregateMinority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
915 {
917 }
918 
919 static QVariant fcnAggregateMajority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
920 {
922 }
923 
924 static QVariant fcnAggregateQ1( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
925 {
927 }
928 
929 static QVariant fcnAggregateQ3( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
930 {
932 }
933 
934 static QVariant fcnAggregateIQR( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
935 {
937 }
938 
939 static QVariant fcnAggregateMinLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
940 {
942 }
943 
944 static QVariant fcnAggregateMaxLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
945 {
947 }
948 
949 static QVariant fcnAggregateStringConcat( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
950 {
952 
953  //fourth node is concatenator
954  if ( values.count() > 3 )
955  {
956  QgsExpression::Node* node = getNode( values.at( 3 ), parent );
958  QVariant value = node->eval( parent, context );
960  parameters.delimiter = value.toString();
961  }
962 
963  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent );
964 }
965 
966 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
967 {
968  double minValue = getDoubleValue( values.at( 0 ), parent );
969  double testValue = getDoubleValue( values.at( 1 ), parent );
970  double maxValue = getDoubleValue( values.at( 2 ), parent );
971 
972  // force testValue to sit inside the range specified by the min and max value
973  if ( testValue <= minValue )
974  {
975  return QVariant( minValue );
976  }
977  else if ( testValue >= maxValue )
978  {
979  return QVariant( maxValue );
980  }
981  else
982  {
983  return QVariant( testValue );
984  }
985 }
986 
987 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
988 {
989  double x = getDoubleValue( values.at( 0 ), parent );
990  return QVariant( floor( x ) );
991 }
992 
993 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
994 {
995  double x = getDoubleValue( values.at( 0 ), parent );
996  return QVariant( ceil( x ) );
997 }
998 
999 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1000 {
1001  return QVariant( getIntValue( values.at( 0 ), parent ) );
1002 }
1003 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1004 {
1005  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
1006 }
1007 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1008 {
1009  return QVariant( getStringValue( values.at( 0 ), parent ) );
1010 }
1011 
1012 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1013 {
1014  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
1015 }
1016 
1017 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
1018 {
1019  Q_FOREACH ( const QVariant &value, values )
1020  {
1021  if ( value.isNull() )
1022  continue;
1023  return value;
1024  }
1025  return QVariant();
1026 }
1027 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1028 {
1029  QString str = getStringValue( values.at( 0 ), parent );
1030  return QVariant( str.toLower() );
1031 }
1032 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1033 {
1034  QString str = getStringValue( values.at( 0 ), parent );
1035  return QVariant( str.toUpper() );
1036 }
1037 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1038 {
1039  QString str = getStringValue( values.at( 0 ), parent );
1040  QStringList elems = str.split( ' ' );
1041  for ( int i = 0; i < elems.size(); i++ )
1042  {
1043  if ( elems[i].size() > 1 )
1044  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1045  }
1046  return QVariant( elems.join( " " ) );
1047 }
1048 
1049 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1050 {
1051  QString str = getStringValue( values.at( 0 ), parent );
1052  return QVariant( str.trimmed() );
1053 }
1054 
1055 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1056 {
1057  QString string1 = getStringValue( values.at( 0 ), parent );
1058  QString string2 = getStringValue( values.at( 1 ), parent );
1059  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1060 }
1061 
1062 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1063 {
1064  QString string1 = getStringValue( values.at( 0 ), parent );
1065  QString string2 = getStringValue( values.at( 1 ), parent );
1066  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1067 }
1068 
1069 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1070 {
1071  QString string1 = getStringValue( values.at( 0 ), parent );
1072  QString string2 = getStringValue( values.at( 1 ), parent );
1073  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1074  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1075 }
1076 
1077 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1078 {
1079  QString string = getStringValue( values.at( 0 ), parent );
1080  return QVariant( QgsStringUtils::soundex( string ) );
1081 }
1082 
1083 static QVariant fcnChar( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1084 {
1085  QChar character = QChar( getIntValue( values.at( 0 ), parent ) );
1086  return QVariant( QString( character ) );
1087 }
1088 
1089 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1090 {
1091  if ( values.length() == 2 || values.length() == 3 )
1092  {
1093  QString str = getStringValue( values.at( 0 ), parent );
1094  int wrap = getIntValue( values.at( 1 ), parent );
1095 
1096  if ( !str.isEmpty() && wrap != 0 )
1097  {
1098  QString newstr;
1099  QString delimiterstr;
1100  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
1101  if ( delimiterstr.isEmpty() ) delimiterstr = ' ';
1102  int delimiterlength = delimiterstr.length();
1103 
1104  QStringList lines = str.split( '\n' );
1105  int strlength, strcurrent, strhit, lasthit;
1106 
1107  for ( int i = 0; i < lines.size(); i++ )
1108  {
1109  strlength = lines[i].length();
1110  strcurrent = 0;
1111  strhit = 0;
1112  lasthit = 0;
1113 
1114  while ( strcurrent < strlength )
1115  {
1116  // positive wrap value = desired maximum line width to wrap
1117  // negative wrap value = desired minimum line width before wrap
1118  if ( wrap > 0 )
1119  {
1120  //first try to locate delimiter backwards
1121  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
1122  if ( strhit == lasthit || strhit == -1 )
1123  {
1124  //if no new backward delimiter found, try to locate forward
1125  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1126  }
1127  lasthit = strhit;
1128  }
1129  else
1130  {
1131  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1132  }
1133  if ( strhit > -1 )
1134  {
1135  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
1136  newstr.append( '\n' );
1137  strcurrent = strhit + delimiterlength;
1138  }
1139  else
1140  {
1141  newstr.append( lines[i].midRef( strcurrent ) );
1142  strcurrent = strlength;
1143  }
1144  }
1145  if ( i < lines.size() - 1 ) newstr.append( '\n' );
1146  }
1147 
1148  return QVariant( newstr );
1149  }
1150  }
1151 
1152  return QVariant();
1153 }
1154 
1155 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1156 {
1157  // two variants, one for geometry, one for string
1158  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1159  {
1160  //geometry variant
1161  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1162  if ( geom.type() != QGis::Line )
1163  return QVariant();
1164 
1165  return QVariant( geom.length() );
1166  }
1167 
1168  //otherwise fall back to string variant
1169  QString str = getStringValue( values.at( 0 ), parent );
1170  return QVariant( str.length() );
1171 }
1172 
1173 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1174 {
1175  QString str = getStringValue( values.at( 0 ), parent );
1176  QString before = getStringValue( values.at( 1 ), parent );
1177  QString after = getStringValue( values.at( 2 ), parent );
1178  return QVariant( str.replace( before, after ) );
1179 }
1180 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1181 {
1182  QString str = getStringValue( values.at( 0 ), parent );
1183  QString regexp = getStringValue( values.at( 1 ), parent );
1184  QString after = getStringValue( values.at( 2 ), parent );
1185 
1186  QRegExp re( regexp );
1187  if ( !re.isValid() )
1188  {
1189  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1190  return QVariant();
1191  }
1192  return QVariant( str.replace( re, after ) );
1193 }
1194 
1195 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1196 {
1197  QString str = getStringValue( values.at( 0 ), parent );
1198  QString regexp = getStringValue( values.at( 1 ), parent );
1199 
1200  QRegExp re( regexp );
1201  if ( !re.isValid() )
1202  {
1203  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1204  return QVariant();
1205  }
1206  return QVariant( str.contains( re ) ? 1 : 0 );
1207 }
1208 
1209 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1210 {
1211  QString str = getStringValue( values.at( 0 ), parent );
1212  QString regexp = getStringValue( values.at( 1 ), parent );
1213 
1214  QRegExp re( regexp );
1215  if ( !re.isValid() )
1216  {
1217  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1218  return QVariant();
1219  }
1220 
1221  // extract substring
1222  ( void )re.indexIn( str );
1223  if ( re.captureCount() > 0 )
1224  {
1225  // return first capture
1226  return QVariant( re.capturedTexts().at( 1 ) );
1227  }
1228  else
1229  {
1230  return QVariant( "" );
1231  }
1232 }
1233 
1234 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
1235 {
1236  return QUuid::createUuid().toString();
1237 }
1238 
1239 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1240 {
1241  QString str = getStringValue( values.at( 0 ), parent );
1242  int from = getIntValue( values.at( 1 ), parent );
1243  int len = getIntValue( values.at( 2 ), parent );
1244  return QVariant( str.mid( from -1, len ) );
1245 }
1246 
1247 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1248 {
1249  if ( context && context->hasVariable( "row_number" ) )
1250  return context->variable( "row_number" );
1251 
1253  return QVariant( parent->currentRowNumber() );
1255  //when above is removed - return QVariant()
1256 }
1257 
1258 static QVariant fcnMapId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1259 {
1260  if ( context && context->hasVariable( "map_id" ) )
1261  return context->variable( "map_id" );
1262 
1264  return QgsExpression::specialColumn( "$map" );
1266 }
1267 
1268 static QVariant fcnComposerNumPages( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1269 {
1270  if ( context && context->hasVariable( "layout_numpages" ) )
1271  return context->variable( "layout_numpages" );
1272 
1274  return QgsExpression::specialColumn( "$numpages" );
1276 }
1277 
1278 static QVariant fcnComposerPage( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1279 {
1280  if ( context && context->hasVariable( "layout_page" ) )
1281  return context->variable( "layout_page" );
1282 
1284  return QgsExpression::specialColumn( "$page" );
1286 }
1287 
1288 static QVariant fcnAtlasFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1289 {
1290  if ( context && context->hasVariable( "atlas_featurenumber" ) )
1291  return context->variable( "atlas_featurenumber" );
1292 
1294  return QgsExpression::specialColumn( "$feature" );
1296 }
1297 
1298 static QVariant fcnAtlasFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1299 {
1300  if ( context && context->hasVariable( "atlas_featureid" ) )
1301  return context->variable( "atlas_featureid" );
1302 
1304  return QgsExpression::specialColumn( "$atlasfeatureid" );
1306 }
1307 
1308 
1309 static QVariant fcnAtlasCurrentFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1310 {
1311  if ( context && context->hasVariable( "atlas_feature" ) )
1312  return context->variable( "atlas_feature" );
1313 
1315  return QgsExpression::specialColumn( "$atlasfeature" );
1317 }
1318 
1319 static QVariant fcnAtlasCurrentGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1320 {
1321  if ( context && context->hasVariable( "atlas_geometry" ) )
1322  return context->variable( "atlas_geometry" );
1323 
1325  return QgsExpression::specialColumn( "$atlasgeometry" );
1327 }
1328 
1329 static QVariant fcnAtlasNumFeatures( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1330 {
1331  if ( context && context->hasVariable( "atlas_totalfeatures" ) )
1332  return context->variable( "atlas_totalfeatures" );
1333 
1335  return QgsExpression::specialColumn( "$numfeatures" );
1337 }
1338 
1339 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1340 {
1341  FEAT_FROM_CONTEXT( context, f );
1342  // TODO: handling of 64-bit feature ids?
1343  return QVariant( static_cast< int >( f.id() ) );
1344 }
1345 
1346 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1347 {
1348  if ( !context )
1349  return QVariant();
1350 
1351  return context->feature();
1352 }
1353 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1354 {
1355  QgsFeature feat = getFeature( values.at( 0 ), parent );
1356  QString attr = getStringValue( values.at( 1 ), parent );
1357 
1358  return feat.attribute( attr );
1359 }
1360 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1361 {
1362  QString concat;
1363  Q_FOREACH ( const QVariant &value, values )
1364  {
1365  concat += getStringValue( value, parent );
1366  }
1367  return concat;
1368 }
1369 
1370 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1371 {
1372  QString string = getStringValue( values.at( 0 ), parent );
1373  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) ) + 1;
1374 }
1375 
1376 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1377 {
1378  QString string = getStringValue( values.at( 0 ), parent );
1379  int pos = getIntValue( values.at( 1 ), parent );
1380  return string.right( pos );
1381 }
1382 
1383 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1384 {
1385  QString string = getStringValue( values.at( 0 ), parent );
1386  int pos = getIntValue( values.at( 1 ), parent );
1387  return string.left( pos );
1388 }
1389 
1390 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1391 {
1392  QString string = getStringValue( values.at( 0 ), parent );
1393  int length = getIntValue( values.at( 1 ), parent );
1394  QString fill = getStringValue( values.at( 2 ), parent );
1395  return string.leftJustified( length, fill.at( 0 ), true );
1396 }
1397 
1398 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1399 {
1400  QString string = getStringValue( values.at( 0 ), parent );
1401  int length = getIntValue( values.at( 1 ), parent );
1402  QString fill = getStringValue( values.at( 2 ), parent );
1403  return string.rightJustified( length, fill.at( 0 ), true );
1404 }
1405 
1406 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1407 {
1408  QString string = getStringValue( values.at( 0 ), parent );
1409  for ( int n = 1; n < values.length(); n++ )
1410  {
1411  string = string.arg( getStringValue( values.at( n ), parent ) );
1412  }
1413  return string;
1414 }
1415 
1416 
1417 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1418 {
1420 }
1421 
1422 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1423 {
1424  return QVariant( getDateValue( values.at( 0 ), parent ) );
1425 }
1426 
1427 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1428 {
1429  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1430 }
1431 
1432 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1433 {
1434  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1435 }
1436 
1437 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1438 {
1439  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1440  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1441  int seconds = d2.secsTo( d1 );
1442  return QVariant::fromValue( QgsInterval( seconds ) );
1443 }
1444 
1445 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1446 {
1447  if ( !values.at( 0 ).canConvert<QDate>() )
1448  return QVariant();
1449 
1450  QDate date = getDateValue( values.at( 0 ), parent );
1451  if ( !date.isValid() )
1452  return QVariant();
1453 
1454  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1455  // (to match PostgreSQL behaviour)
1456  return date.dayOfWeek() % 7;
1457 }
1458 
1459 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1460 {
1461  QVariant value = values.at( 0 );
1462  QgsInterval inter = getInterval( value, parent, false );
1463  if ( inter.isValid() )
1464  {
1465  return QVariant( inter.days() );
1466  }
1467  else
1468  {
1469  QDateTime d1 = getDateTimeValue( value, parent );
1470  return QVariant( d1.date().day() );
1471  }
1472 }
1473 
1474 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1475 {
1476  QVariant value = values.at( 0 );
1477  QgsInterval inter = getInterval( value, parent, false );
1478  if ( inter.isValid() )
1479  {
1480  return QVariant( inter.years() );
1481  }
1482  else
1483  {
1484  QDateTime d1 = getDateTimeValue( value, parent );
1485  return QVariant( d1.date().year() );
1486  }
1487 }
1488 
1489 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1490 {
1491  QVariant value = values.at( 0 );
1492  QgsInterval inter = getInterval( value, parent, false );
1493  if ( inter.isValid() )
1494  {
1495  return QVariant( inter.months() );
1496  }
1497  else
1498  {
1499  QDateTime d1 = getDateTimeValue( value, parent );
1500  return QVariant( d1.date().month() );
1501  }
1502 }
1503 
1504 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1505 {
1506  QVariant value = values.at( 0 );
1507  QgsInterval inter = getInterval( value, parent, false );
1508  if ( inter.isValid() )
1509  {
1510  return QVariant( inter.weeks() );
1511  }
1512  else
1513  {
1514  QDateTime d1 = getDateTimeValue( value, parent );
1515  return QVariant( d1.date().weekNumber() );
1516  }
1517 }
1518 
1519 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1520 {
1521  QVariant value = values.at( 0 );
1522  QgsInterval inter = getInterval( value, parent, false );
1523  if ( inter.isValid() )
1524  {
1525  return QVariant( inter.hours() );
1526  }
1527  else
1528  {
1529  QTime t1 = getTimeValue( value, parent );
1530  return QVariant( t1.hour() );
1531  }
1532 }
1533 
1534 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1535 {
1536  QVariant value = values.at( 0 );
1537  QgsInterval inter = getInterval( value, parent, false );
1538  if ( inter.isValid() )
1539  {
1540  return QVariant( inter.minutes() );
1541  }
1542  else
1543  {
1544  QTime t1 = getTimeValue( value, parent );
1545  return QVariant( t1.minute() );
1546  }
1547 }
1548 
1549 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1550 {
1551  QVariant value = values.at( 0 );
1552  QgsInterval inter = getInterval( value, parent, false );
1553  if ( inter.isValid() )
1554  {
1555  return QVariant( inter.seconds() );
1556  }
1557  else
1558  {
1559  QTime t1 = getTimeValue( value, parent );
1560  return QVariant( t1.second() );
1561  }
1562 }
1563 
1564 
1565 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1566  if (!g || g->type() != geomtype) return QVariant();
1567 
1568 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1569 {
1570  FEAT_FROM_CONTEXT( context, f );
1571  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1572  if ( g->isMultipart() )
1573  {
1574  return g->asMultiPoint().at( 0 ).x();
1575  }
1576  else
1577  {
1578  return g->asPoint().x();
1579  }
1580 }
1581 
1582 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1583 {
1584  FEAT_FROM_CONTEXT( context, f );
1585  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1586  if ( g->isMultipart() )
1587  {
1588  return g->asMultiPoint().at( 0 ).y();
1589  }
1590  else
1591  {
1592  return g->asPoint().y();
1593  }
1594 }
1595 
1596 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1597 {
1598  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1599  if ( geom.isEmpty() )
1600  return QVariant();
1601 
1602  //if single point, return the point's x coordinate
1603  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1604  {
1605  return geom.asPoint().x();
1606  }
1607 
1608  //otherwise return centroid x
1609  QgsGeometry* centroid = geom.centroid();
1610  QVariant result( centroid->asPoint().x() );
1611  delete centroid;
1612  return result;
1613 }
1614 
1615 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1616 {
1617  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1618  if ( geom.isEmpty() )
1619  return QVariant();
1620 
1621  //if single point, return the point's y coordinate
1622  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1623  {
1624  return geom.asPoint().y();
1625  }
1626 
1627  //otherwise return centroid y
1628  QgsGeometry* centroid = geom.centroid();
1629  QVariant result( centroid->asPoint().y() );
1630  delete centroid;
1631  return result;
1632 }
1633 
1634 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1635 {
1636  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1637  if ( geom.isEmpty() )
1638  return QVariant(); //or 0?
1639 
1640  //if single point, return the point's z coordinate
1641  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1642  {
1643  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1644  if ( point )
1645  return point->z();
1646  }
1647 
1648  return QVariant();
1649 }
1650 
1651 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1652 {
1653  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1654  if ( geom.isEmpty() )
1655  return QVariant(); //or 0?
1656 
1657  //if single point, return the point's m value
1658  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1659  {
1660  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1661  if ( point )
1662  return point->m();
1663  }
1664 
1665  return QVariant();
1666 }
1667 
1668 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1669 {
1670  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1671 
1672  if ( geom.isEmpty() )
1673  return QVariant();
1674 
1675  //idx is 1 based
1676  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1677 
1678  QgsVertexId vId;
1679  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1680  {
1681  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1682  return QVariant();
1683  }
1684 
1685  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1686  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1687 }
1688 
1689 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1690 {
1691  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1692 
1693  if ( geom.isEmpty() )
1694  return QVariant();
1695 
1696  QgsVertexId vId;
1697  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1698  {
1699  return QVariant();
1700  }
1701 
1702  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1703  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1704 }
1705 
1706 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1707 {
1708  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1709 
1710  if ( geom.isEmpty() )
1711  return QVariant();
1712 
1713  QgsVertexId vId;
1714  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1715  {
1716  return QVariant();
1717  }
1718 
1719  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1720  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1721 }
1722 
1723 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1724 {
1725  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1726 
1727  if ( geom.isEmpty() )
1728  return QVariant();
1729 
1730  bool ignoreClosing = false;
1731  if ( values.length() > 1 )
1732  {
1733  ignoreClosing = getIntValue( values.at( 1 ), parent );
1734  }
1735 
1736  QgsMultiPointV2* mp = new QgsMultiPointV2();
1737 
1738  Q_FOREACH ( const QgsRingSequenceV2 &part, geom.geometry()->coordinateSequence() )
1739  {
1740  Q_FOREACH ( const QgsPointSequenceV2 &ring, part )
1741  {
1742  bool skipLast = false;
1743  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1744  {
1745  skipLast = true;
1746  }
1747 
1748  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1749  {
1750  mp->addGeometry( ring.at( i ).clone() );
1751  }
1752  }
1753  }
1754 
1755  return QVariant::fromValue( QgsGeometry( mp ) );
1756 }
1757 
1758 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1759 {
1760  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1761 
1762  if ( geom.isEmpty() )
1763  return QVariant();
1764 
1766 
1767  //ok, now we have a complete list of segmentized lines from the geometry
1769  Q_FOREACH ( QgsLineStringV2* line, linesToProcess )
1770  {
1771  for ( int i = 0; i < line->numPoints() - 1; ++i )
1772  {
1773  QgsLineStringV2* segment = new QgsLineStringV2();
1774  segment->setPoints( QgsPointSequenceV2()
1775  << line->pointN( i )
1776  << line->pointN( i + 1 ) );
1777  ml->addGeometry( segment );
1778  }
1779  delete line;
1780  }
1781 
1782  return QVariant::fromValue( QgsGeometry( ml ) );
1783 }
1784 
1785 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1786 {
1787  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1788 
1789  if ( geom.isEmpty() )
1790  return QVariant();
1791 
1792  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1793  if ( !curvePolygon )
1794  return QVariant();
1795 
1796  //idx is 1 based
1797  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1798 
1799  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1800  return QVariant();
1801 
1802  QgsCurveV2* curve = static_cast< QgsCurveV2* >( curvePolygon->interiorRing( idx )->clone() );
1803  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1804  return result;
1805 }
1806 
1807 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1808 {
1809  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1810 
1811  if ( geom.isEmpty() )
1812  return QVariant();
1813 
1814  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1815  if ( !collection )
1816  return QVariant();
1817 
1818  //idx is 1 based
1819  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1820 
1821  if ( idx < 0 || idx >= collection->numGeometries() )
1822  return QVariant();
1823 
1824  QgsAbstractGeometryV2* part = collection->geometryN( idx )->clone();
1825  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
1826  return result;
1827 }
1828 
1829 static QVariant fcnBoundary( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1830 {
1831  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1832 
1833  if ( geom.isEmpty() )
1834  return QVariant();
1835 
1836  QgsAbstractGeometryV2* boundary = geom.geometry()->boundary();
1837  if ( !boundary )
1838  return QVariant();
1839 
1840  return QVariant::fromValue( QgsGeometry( boundary ) );
1841 }
1842 
1843 static QVariant fcnLineMerge( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1844 {
1845  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1846 
1847  if ( geom.isEmpty() )
1848  return QVariant();
1849 
1850  QgsGeometry merged = geom.mergeLines();
1851  if ( merged.isEmpty() )
1852  return QVariant();
1853 
1854  return QVariant::fromValue( merged );
1855 }
1856 
1857 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1858 {
1859  if ( values.count() < 2 || values.count() > 4 )
1860  {
1861  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
1862  return QVariant();
1863  }
1864 
1865  double x = getDoubleValue( values.at( 0 ), parent );
1866  double y = getDoubleValue( values.at( 1 ), parent );
1867  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
1868  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
1869  switch ( values.count() )
1870  {
1871  case 2:
1872  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1873  case 3:
1874  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
1875  case 4:
1876  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
1877  }
1878  return QVariant(); //avoid warning
1879 }
1880 
1881 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1882 {
1883  double x = getDoubleValue( values.at( 0 ), parent );
1884  double y = getDoubleValue( values.at( 1 ), parent );
1885  double m = getDoubleValue( values.at( 2 ), parent );
1886  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
1887 }
1888 
1889 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1890 {
1891  if ( values.count() < 2 )
1892  {
1893  return QVariant();
1894  }
1895 
1896  QgsLineStringV2* lineString = new QgsLineStringV2();
1897  lineString->clear();
1898 
1899  Q_FOREACH ( const QVariant& value, values )
1900  {
1901  QgsGeometry geom = getGeometry( value, parent );
1902  if ( geom.isEmpty() )
1903  continue;
1904 
1905  if ( geom.type() != QGis::Point || geom.isMultipart() )
1906  continue;
1907 
1908  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1909  if ( !point )
1910  continue;
1911 
1912  lineString->addVertex( *point );
1913  }
1914 
1915  return QVariant::fromValue( QgsGeometry( lineString ) );
1916 }
1917 
1918 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1919 {
1920  if ( values.count() < 1 )
1921  {
1922  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
1923  return QVariant();
1924  }
1925 
1926  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
1927  if ( outerRing.type() != QGis::Line || outerRing.isMultipart() || outerRing.isEmpty() )
1928  return QVariant();
1929 
1930  QgsPolygonV2* polygon = new QgsPolygonV2();
1931  polygon->setExteriorRing( dynamic_cast< QgsCurveV2* >( outerRing.geometry()->clone() ) );
1932 
1933  for ( int i = 1; i < values.count(); ++i )
1934  {
1935  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
1936  if ( ringGeom.isEmpty() )
1937  continue;
1938 
1939  if ( ringGeom.type() != QGis::Line || ringGeom.isMultipart() || ringGeom.isEmpty() )
1940  continue;
1941 
1942  polygon->addInteriorRing( dynamic_cast< QgsCurveV2* >( ringGeom.geometry()->clone() ) );
1943  }
1944 
1945  return QVariant::fromValue( QgsGeometry( polygon ) );
1946 }
1947 
1948 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1949 {
1950  FEAT_FROM_CONTEXT( context, f );
1951  int idx = getIntValue( values.at( 0 ), parent );
1952  const QgsGeometry* g = f.constGeometry();
1953  if ( !g || g->isEmpty() )
1954  return QVariant();
1955 
1956  if ( idx < 0 )
1957  {
1958  idx += g->geometry()->nCoordinates();
1959  }
1960  if ( idx < 0 || idx >= g->geometry()->nCoordinates() )
1961  {
1962  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1963  return QVariant();
1964  }
1965 
1966  QgsPoint p = g->vertexAt( idx );
1967  return QVariant( QPointF( p.x(), p.y() ) );
1968 }
1969 
1970 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1971 {
1972  QVariant v = pointAt( values, f, parent );
1973  if ( v.type() == QVariant::PointF )
1974  return QVariant( v.toPointF().x() );
1975  else
1976  return QVariant();
1977 }
1978 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1979 {
1980  QVariant v = pointAt( values, f, parent );
1981  if ( v.type() == QVariant::PointF )
1982  return QVariant( v.toPointF().y() );
1983  else
1984  return QVariant();
1985 }
1986 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1987 {
1988  FEAT_FROM_CONTEXT( context, f );
1989  const QgsGeometry* geom = f.constGeometry();
1990  if ( geom )
1991  return QVariant::fromValue( *geom );
1992  else
1993  return QVariant();
1994 }
1995 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1996 {
1997  QString wkt = getStringValue( values.at( 0 ), parent );
1998  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1999  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2000  delete geom;
2001  return result;
2002 }
2003 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2004 {
2005  QString gml = getStringValue( values.at( 0 ), parent );
2007  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2008  delete geom;
2009  return result;
2010 }
2011 
2012 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2013 {
2014  FEAT_FROM_CONTEXT( context, f );
2016  QgsDistanceArea* calc = parent->geomCalculator();
2017  if ( calc )
2018  {
2019  double area = calc->measureArea( f.constGeometry() );
2020  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
2021  return QVariant( area );
2022  }
2023  else
2024  {
2025  return QVariant( f.constGeometry()->area() );
2026  }
2027 }
2028 
2029 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2030 {
2031  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2032 
2033  if ( geom.type() != QGis::Polygon )
2034  return QVariant();
2035 
2036  return QVariant( geom.area() );
2037 }
2038 
2039 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2040 {
2041  FEAT_FROM_CONTEXT( context, f );
2042  ENSURE_GEOM_TYPE( f, g, QGis::Line );
2043  QgsDistanceArea* calc = parent->geomCalculator();
2044  if ( calc )
2045  {
2046  double len = calc->measureLength( f.constGeometry() );
2047  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2048  return QVariant( len );
2049  }
2050  else
2051  {
2052  return QVariant( f.constGeometry()->length() );
2053  }
2054 }
2055 
2056 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2057 {
2058  FEAT_FROM_CONTEXT( context, f );
2060  QgsDistanceArea* calc = parent->geomCalculator();
2061  if ( calc )
2062  {
2063  double len = calc->measurePerimeter( f.constGeometry() );
2064  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2065  return QVariant( len );
2066  }
2067  else
2068  {
2069  return f.constGeometry()->isEmpty() ? QVariant( 0 ) : QVariant( f.constGeometry()->geometry()->perimeter() );
2070  }
2071 }
2072 
2073 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2074 {
2075  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2076 
2077  if ( geom.type() != QGis::Polygon )
2078  return QVariant();
2079 
2080  //length for polygons = perimeter
2081  return QVariant( geom.length() );
2082 }
2083 
2084 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2085 {
2086  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2087  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
2088 }
2089 
2090 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2091 {
2092  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2093  if ( geom.isEmpty() )
2094  return QVariant();
2095 
2096  return QVariant( geom.geometry()->partCount() );
2097 }
2098 
2099 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2100 {
2101  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2102 
2103  if ( geom.isEmpty() )
2104  return QVariant();
2105 
2106  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2107  if ( curvePolygon )
2108  return QVariant( curvePolygon->numInteriorRings() );
2109 
2110  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2111  if ( collection )
2112  {
2113  //find first CurvePolygon in collection
2114  for ( int i = 0; i < collection->numGeometries(); ++i )
2115  {
2116  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2117  if ( !curvePolygon )
2118  continue;
2119 
2120  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
2121  }
2122  }
2123 
2124  return QVariant();
2125 }
2126 
2127 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2128 {
2129  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2130 
2131  if ( geom.isEmpty() )
2132  return QVariant();
2133 
2134  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2135  if ( curvePolygon )
2136  return QVariant( curvePolygon->ringCount() );
2137 
2138  bool foundPoly = false;
2139  int ringCount = 0;
2140  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2141  if ( collection )
2142  {
2143  //find CurvePolygons in collection
2144  for ( int i = 0; i < collection->numGeometries(); ++i )
2145  {
2146  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2147  if ( !curvePolygon )
2148  continue;
2149 
2150  foundPoly = true;
2151  ringCount += curvePolygon->ringCount();
2152  }
2153  }
2154 
2155  if ( !foundPoly )
2156  return QVariant();
2157 
2158  return QVariant( ringCount );
2159 }
2160 
2161 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2162 {
2163  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2164  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
2165  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
2166  delete geomBounds;
2167  return result;
2168 }
2169 
2170 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2171 {
2172  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2173  return QVariant::fromValue( geom.boundingBox().width() );
2174 }
2175 
2176 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2177 {
2178  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2179  return QVariant::fromValue( geom.boundingBox().height() );
2180 }
2181 
2182 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2183 {
2184  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2185  return QVariant::fromValue( geom.boundingBox().xMinimum() );
2186 }
2187 
2188 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2189 {
2190  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2191  return QVariant::fromValue( geom.boundingBox().xMaximum() );
2192 }
2193 
2194 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2195 {
2196  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2197  return QVariant::fromValue( geom.boundingBox().yMinimum() );
2198 }
2199 
2200 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2201 {
2202  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2203  return QVariant::fromValue( geom.boundingBox().yMaximum() );
2204 }
2205 
2206 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2207 {
2208  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2209  if ( fGeom.isEmpty() )
2210  return QVariant();
2211 
2212  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2213  if ( !curve )
2214  return QVariant();
2215 
2216  return QVariant::fromValue( curve->isClosed() );
2217 }
2218 
2219 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2220 {
2221  if ( values.length() < 2 || values.length() > 3 )
2222  return QVariant();
2223 
2224  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2225  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2226 
2227  if ( fGeom.isEmpty() || sGeom.isEmpty() )
2228  return QVariant();
2229 
2231 
2232  if ( values.length() == 2 )
2233  {
2234  //two geometry arguments, return relation
2235  QString result = engine->relate( *sGeom.geometry() );
2236  return QVariant::fromValue( result );
2237  }
2238  else
2239  {
2240  //three arguments, test pattern
2241  QString pattern = getStringValue( values.at( 2 ), parent );
2242  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
2243  return QVariant::fromValue( result );
2244  }
2245 }
2246 
2247 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2248 {
2249  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2250  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2251  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
2252 }
2253 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2254 {
2255  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2256  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2257  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
2258 }
2259 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2260 {
2261  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2262  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2263  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
2264 }
2265 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2266 {
2267  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2268  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2269  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
2270 }
2271 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2272 {
2273  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2274  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2275  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
2276 }
2277 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2278 {
2279  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2280  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2281  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
2282 }
2283 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2284 {
2285  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2286  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2287  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
2288 }
2289 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2290 {
2291  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2292  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2293  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
2294 }
2295 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2296 {
2297  if ( values.length() < 2 || values.length() > 3 )
2298  return QVariant();
2299 
2300  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2301  double dist = getDoubleValue( values.at( 1 ), parent );
2302  int seg = 8;
2303  if ( values.length() == 3 )
2304  seg = getIntValue( values.at( 2 ), parent );
2305 
2306  QgsGeometry* geom = fGeom.buffer( dist, seg );
2307  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2308  delete geom;
2309  return result;
2310 }
2311 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2312 {
2313  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2314  double dx = getDoubleValue( values.at( 1 ), parent );
2315  double dy = getDoubleValue( values.at( 2 ), parent );
2316  fGeom.translate( dx, dy );
2317  return QVariant::fromValue( fGeom );
2318 }
2319 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2320 {
2321  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2322  QgsGeometry* geom = fGeom.centroid();
2323  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2324  delete geom;
2325  return result;
2326 }
2327 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2328 {
2329  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2330  QgsGeometry* geom = fGeom.pointOnSurface();
2331  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2332  delete geom;
2333  return result;
2334 }
2335 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2336 {
2337  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2338  QgsGeometry* geom = fGeom.convexHull();
2339  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2340  delete geom;
2341  return result;
2342 }
2343 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2344 {
2345  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2346  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2347  QgsGeometry* geom = fGeom.difference( &sGeom );
2348  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2349  delete geom;
2350  return result;
2351 }
2352 
2353 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2354 {
2355  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2356  if ( fGeom.isEmpty() )
2357  return QVariant();
2358 
2359  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2360  if ( !curve )
2361  return QVariant();
2362 
2363  QgsCurveV2* reversed = curve->reversed();
2364  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2365  return result;
2366 }
2367 
2368 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2369 {
2370  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2371  if ( fGeom.isEmpty() )
2372  return QVariant();
2373 
2374  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( fGeom.geometry() );
2375  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2376  return QVariant();
2377 
2378  QgsCurveV2* exterior = static_cast< QgsCurveV2* >( curvePolygon->exteriorRing()->clone() );
2379  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2380  return result;
2381 }
2382 
2383 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2384 {
2385  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2386  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2387  return QVariant( fGeom.distance( sGeom ) );
2388 }
2389 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2390 {
2391  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2392  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2393  QgsGeometry* geom = fGeom.intersection( &sGeom );
2394  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2395  delete geom;
2396  return result;
2397 }
2398 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2399 {
2400  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2401  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2402  QgsGeometry* geom = fGeom.symDifference( &sGeom );
2403  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2404  delete geom;
2405  return result;
2406 }
2407 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2408 {
2409  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2410  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2411  QgsGeometry* geom = fGeom.combine( &sGeom );
2412  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2413  delete geom;
2414  return result;
2415 }
2416 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2417 {
2418  if ( values.length() < 1 || values.length() > 2 )
2419  return QVariant();
2420 
2421  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2422  int prec = 8;
2423  if ( values.length() == 2 )
2424  prec = getIntValue( values.at( 1 ), parent );
2425  QString wkt = fGeom.exportToWkt( prec );
2426  return QVariant( wkt );
2427 }
2428 
2429 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2430 {
2431  if ( values.length() != 2 )
2432  {
2433  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2434  return QVariant();
2435  }
2436 
2437  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2438  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2439 
2440  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2441  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2442 
2443  if ( !pt1 || !pt2 )
2444  {
2445  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2446  return QVariant();
2447  }
2448 
2449  // Code from postgis
2450  if ( pt1->x() == pt2->x() )
2451  {
2452  if ( pt1->y() < pt2->y() )
2453  return 0.0;
2454  else if ( pt1->y() > pt2->y() )
2455  return M_PI;
2456  else
2457  return 0;
2458  }
2459 
2460  if ( pt1->y() == pt2->y() )
2461  {
2462  if ( pt1->x() < pt2->x() )
2463  return M_PI / 2;
2464  else if ( pt1->x() > pt2->x() )
2465  return M_PI + ( M_PI / 2 );
2466  else
2467  return 0;
2468  }
2469 
2470  if ( pt1->x() < pt2->x() )
2471  {
2472  if ( pt1->y() < pt2->y() )
2473  {
2474  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2475  }
2476  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2477  {
2478  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2479  + ( M_PI / 2 );
2480  }
2481  }
2482 
2483  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2484  {
2485  if ( pt1->y() > pt2->y() )
2486  {
2487  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2488  + M_PI;
2489  }
2490  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2491  {
2492  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2493  + ( M_PI + ( M_PI / 2 ) );
2494  }
2495  }
2496 }
2497 
2498 static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2499 {
2500  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2501 
2502  if ( geom.type() != QGis::Point )
2503  {
2504  parent->setEvalErrorString( "'project' requires a point geometry" );
2505  return QVariant();
2506  }
2507 
2508  double distance = getDoubleValue( values.at( 1 ), parent );
2509  double bearing = getDoubleValue( values.at( 2 ), parent );
2510 
2511  QgsPoint p = geom.asPoint();
2512  QgsPoint newPoint = p.project( distance, ( 180 * bearing ) / M_PI );
2513 
2514  return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint.x(), newPoint.y() ) ) );
2515 }
2516 
2517 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2518 {
2519  if ( values.length() != 3 )
2520  return QVariant();
2521 
2522  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2523  double x = getDoubleValue( values.at( 1 ), parent );
2524  double y = getDoubleValue( values.at( 2 ), parent );
2525 
2526  QgsGeometry geom = fGeom.extrude( x, y );
2527 
2528  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2529  return result;
2530 }
2531 
2532 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2533 {
2534  if ( values.length() < 2 )
2535  return QVariant();
2536 
2537  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2538 
2539  if ( !fGeom.isMultipart() )
2540  return values.at( 0 );
2541 
2542  QString expString = getStringValue( values.at( 1 ), parent );
2543  bool asc = values.value( 2 ).toBool();
2544 
2545  QgsExpressionContext* unconstedContext;
2546  QgsFeature f;
2547  if ( ctx )
2548  {
2549  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2550  // so no reason to worry
2551  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2552  f = ctx->feature();
2553  }
2554  else
2555  {
2556  // If there's no context provided, create a fake one
2557  unconstedContext = new QgsExpressionContext();
2558  }
2559 
2560  QgsGeometryCollectionV2* collection = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry() );
2561  Q_ASSERT( collection ); // Should have failed the multipart check above
2562 
2564  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2565  QgsExpressionSorter sorter( orderBy );
2566 
2567  QList<QgsFeature> partFeatures;
2568  for ( int i = 0; i < collection->partCount(); ++i )
2569  {
2570  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2571  partFeatures << f;
2572  }
2573 
2574  sorter.sortFeatures( partFeatures, unconstedContext );
2575 
2576  QgsGeometryCollectionV2* orderedGeom = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry()->clone() );
2577 
2578  Q_ASSERT( orderedGeom );
2579 
2580  while ( orderedGeom->partCount() )
2581  orderedGeom->removeGeometry( 0 );
2582 
2583  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2584  {
2585  orderedGeom->addGeometry( feature.constGeometry()->geometry()->clone() );
2586  }
2587 
2588  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2589 
2590  if ( !ctx )
2591  delete unconstedContext;
2592 
2593  return result;
2594 }
2595 
2596 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2597 {
2598  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2599  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2600 
2601  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2602 
2603  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2604  return result;
2605 }
2606 
2607 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2608 {
2609  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2610  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2611 
2612  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2613 
2614  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2615  return result;
2616 }
2617 
2618 static QVariant fcnLineInterpolatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2619 {
2620  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2621  double distance = getDoubleValue( values.at( 1 ), parent );
2622 
2623  QgsGeometry* geom = lineGeom.interpolate( distance );
2624 
2625  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2626  delete geom;
2627  return result;
2628 }
2629 
2630 static QVariant fcnLineInterpolateAngle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2631 {
2632  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2633  double distance = getDoubleValue( values.at( 1 ), parent );
2634 
2635  return lineGeom.interpolateAngle( distance ) * 180.0 / M_PI;
2636 }
2637 
2638 static QVariant fcnAngleAtVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2639 {
2640  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2641  int vertex = getIntValue( values.at( 1 ), parent );
2642 
2643  return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
2644 }
2645 
2646 static QVariant fcnDistanceToVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2647 {
2648  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2649  int vertex = getIntValue( values.at( 1 ), parent );
2650 
2651  return geom.distanceToVertex( vertex );
2652 }
2653 
2654 static QVariant fcnLineLocatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2655 {
2656  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2657  QgsGeometry pointGeom = getGeometry( values.at( 1 ), parent );
2658 
2659  double distance = lineGeom.lineLocatePoint( pointGeom );
2660 
2661  return distance >= 0 ? distance : QVariant();
2662 }
2663 
2664 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2665 {
2666  if ( values.length() == 2 )
2667  {
2668  double number = getDoubleValue( values.at( 0 ), parent );
2669  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2670  return QVariant( qRound( number * scaler ) / scaler );
2671  }
2672 
2673  if ( values.length() == 1 )
2674  {
2675  double number = getIntValue( values.at( 0 ), parent );
2676  return QVariant( qRound( number ) ).toInt();
2677  }
2678 
2679  return QVariant();
2680 }
2681 
2682 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2683 {
2684  Q_UNUSED( values );
2685  Q_UNUSED( parent );
2686  return M_PI;
2687 }
2688 
2689 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
2690 {
2691  return QVariant( parent->scale() );
2692 }
2693 
2694 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2695 {
2696  double value = getDoubleValue( values.at( 0 ), parent );
2697  int places = getIntValue( values.at( 1 ), parent );
2698  if ( places < 0 )
2699  {
2700  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2701  return QVariant();
2702  }
2703  return QString( "%L1" ).arg( value, 0, 'f', places );
2704 }
2705 
2706 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2707 {
2708  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2709  QString format = getStringValue( values.at( 1 ), parent );
2710  return dt.toString( format );
2711 }
2712 
2713 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2714 {
2715  int red = getIntValue( values.at( 0 ), parent );
2716  int green = getIntValue( values.at( 1 ), parent );
2717  int blue = getIntValue( values.at( 2 ), parent );
2718  QColor color = QColor( red, green, blue );
2719  if ( ! color.isValid() )
2720  {
2721  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
2722  color = QColor( 0, 0, 0 );
2723  }
2724 
2725  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2726 }
2727 
2728 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
2729 {
2730  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
2732  QVariant value = node->eval( parent, context );
2734  if ( value.toBool() )
2735  {
2736  node = getNode( values.at( 1 ), parent );
2738  value = node->eval( parent, context );
2740  }
2741  else
2742  {
2743  node = getNode( values.at( 2 ), parent );
2745  value = node->eval( parent, context );
2747  }
2748  return value;
2749 }
2750 
2751 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2752 {
2753  int red = getIntValue( values.at( 0 ), parent );
2754  int green = getIntValue( values.at( 1 ), parent );
2755  int blue = getIntValue( values.at( 2 ), parent );
2756  int alpha = getIntValue( values.at( 3 ), parent );
2757  QColor color = QColor( red, green, blue, alpha );
2758  if ( ! color.isValid() )
2759  {
2760  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
2761  color = QColor( 0, 0, 0 );
2762  }
2763  return QgsSymbolLayerV2Utils::encodeColor( color );
2764 }
2765 
2766 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2767 {
2768  QString rampName = getStringValue( values.at( 0 ), parent );
2769  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
2770  if ( ! mRamp )
2771  {
2772  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2773  return QColor( 0, 0, 0 ).name();
2774  }
2775  double value = getDoubleValue( values.at( 1 ), parent );
2776  QColor color = mRamp->color( value );
2777  return QgsSymbolLayerV2Utils::encodeColor( color );
2778 }
2779 
2780 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2781 {
2782  // Hue ranges from 0 - 360
2783  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2784  // Saturation ranges from 0 - 100
2785  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2786  // Lightness ranges from 0 - 100
2787  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2788 
2789  QColor color = QColor::fromHslF( hue, saturation, lightness );
2790 
2791  if ( ! color.isValid() )
2792  {
2793  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
2794  color = QColor( 0, 0, 0 );
2795  }
2796 
2797  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2798 }
2799 
2800 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2801 {
2802  // Hue ranges from 0 - 360
2803  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2804  // Saturation ranges from 0 - 100
2805  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2806  // Lightness ranges from 0 - 100
2807  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2808  // Alpha ranges from 0 - 255
2809  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2810 
2811  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
2812  if ( ! color.isValid() )
2813  {
2814  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
2815  color = QColor( 0, 0, 0 );
2816  }
2817  return QgsSymbolLayerV2Utils::encodeColor( color );
2818 }
2819 
2820 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2821 {
2822  // Hue ranges from 0 - 360
2823  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2824  // Saturation ranges from 0 - 100
2825  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2826  // Value ranges from 0 - 100
2827  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2828 
2829  QColor color = QColor::fromHsvF( hue, saturation, value );
2830 
2831  if ( ! color.isValid() )
2832  {
2833  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
2834  color = QColor( 0, 0, 0 );
2835  }
2836 
2837  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2838 }
2839 
2840 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2841 {
2842  // Hue ranges from 0 - 360
2843  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2844  // Saturation ranges from 0 - 100
2845  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2846  // Value ranges from 0 - 100
2847  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2848  // Alpha ranges from 0 - 255
2849  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2850 
2851  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
2852  if ( ! color.isValid() )
2853  {
2854  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
2855  color = QColor( 0, 0, 0 );
2856  }
2857  return QgsSymbolLayerV2Utils::encodeColor( color );
2858 }
2859 
2860 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2861 {
2862  // Cyan ranges from 0 - 100
2863  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2864  // Magenta ranges from 0 - 100
2865  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2866  // Yellow ranges from 0 - 100
2867  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2868  // Black ranges from 0 - 100
2869  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2870 
2871  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
2872 
2873  if ( ! color.isValid() )
2874  {
2875  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
2876  color = QColor( 0, 0, 0 );
2877  }
2878 
2879  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2880 }
2881 
2882 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2883 {
2884  // Cyan ranges from 0 - 100
2885  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2886  // Magenta ranges from 0 - 100
2887  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2888  // Yellow ranges from 0 - 100
2889  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2890  // Black ranges from 0 - 100
2891  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2892  // Alpha ranges from 0 - 255
2893  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
2894 
2895  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
2896  if ( ! color.isValid() )
2897  {
2898  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
2899  color = QColor( 0, 0, 0 );
2900  }
2901  return QgsSymbolLayerV2Utils::encodeColor( color );
2902 }
2903 
2904 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2905 {
2906  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2907  if ( ! color.isValid() )
2908  {
2909  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2910  return QVariant();
2911  }
2912 
2913  QString part = getStringValue( values.at( 1 ), parent );
2914  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2915  return color.red();
2916  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2917  return color.green();
2918  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2919  return color.blue();
2920  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2921  return color.alpha();
2922  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2923  return color.hsvHueF() * 360;
2924  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2925  return color.hsvSaturationF() * 100;
2926  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2927  return color.valueF() * 100;
2928  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2929  return color.hslHueF() * 360;
2930  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2931  return color.hslSaturationF() * 100;
2932  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2933  return color.lightnessF() * 100;
2934  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2935  return color.cyanF() * 100;
2936  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2937  return color.magentaF() * 100;
2938  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2939  return color.yellowF() * 100;
2940  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2941  return color.blackF() * 100;
2942 
2943  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2944  return QVariant();
2945 }
2946 
2947 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2948 {
2949  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2950  if ( ! color.isValid() )
2951  {
2952  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2953  return QVariant();
2954  }
2955 
2956  QString part = getStringValue( values.at( 1 ), parent );
2957  int value = getIntValue( values.at( 2 ), parent );
2958  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2959  color.setRed( value );
2960  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2961  color.setGreen( value );
2962  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2963  color.setBlue( value );
2964  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2965  color.setAlpha( value );
2966  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2967  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
2968  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2969  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
2970  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2971  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
2972  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2973  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
2974  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2975  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
2976  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2977  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
2978  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2979  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
2980  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2981  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
2982  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2983  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
2984  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2985  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
2986  else
2987  {
2988  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2989  return QVariant();
2990  }
2991  return QgsSymbolLayerV2Utils::encodeColor( color );
2992 }
2993 
2994 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2995 {
2996  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2997  if ( ! color.isValid() )
2998  {
2999  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3000  return QVariant();
3001  }
3002 
3003  color = color.darker( getIntValue( values.at( 1 ), parent ) );
3004 
3005  return QgsSymbolLayerV2Utils::encodeColor( color );
3006 }
3007 
3008 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3009 {
3010  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
3011  if ( ! color.isValid() )
3012  {
3013  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3014  return QVariant();
3015  }
3016 
3017  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
3018 
3019  return QgsSymbolLayerV2Utils::encodeColor( color );
3020 }
3021 
3022 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3023 {
3024  QString varName = getStringValue( values.at( 0 ), parent );
3026  return QgsExpression::specialColumn( varName );
3028 }
3029 
3030 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3031 {
3032  QgsFeature feat = getFeature( values.at( 0 ), parent );
3033  const QgsGeometry* geom = feat.constGeometry();
3034  if ( geom )
3035  return QVariant::fromValue( *geom );
3036  return QVariant();
3037 }
3038 
3039 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3040 {
3041  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
3042  QString sAuthId = getStringValue( values.at( 1 ), parent );
3043  QString dAuthId = getStringValue( values.at( 2 ), parent );
3044 
3046  if ( ! s.isValid() )
3047  return QVariant::fromValue( fGeom );
3049  if ( ! d.isValid() )
3050  return QVariant::fromValue( fGeom );
3051 
3052  QgsCoordinateTransform t( s, d );
3053  try
3054  {
3055  if ( fGeom.transform( t ) == 0 )
3056  return QVariant::fromValue( fGeom );
3057  }
3058  catch ( QgsCsException &cse )
3059  {
3060  QgsMessageLog::logMessage( QString( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
3061  return QVariant();
3062  }
3063  return QVariant();
3064 }
3065 
3066 
3067 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3068 {
3069  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
3070  QgsVectorLayer* vl = getVectorLayer( values.at( 0 ), parent );
3071 
3072  //no layer found
3073  if ( !vl )
3074  {
3075  return QVariant();
3076  }
3077 
3078  QString attribute = getStringValue( values.at( 1 ), parent );
3079  int attributeId = vl->fieldNameIndex( attribute );
3080  if ( attributeId == -1 )
3081  {
3082  return QVariant();
3083  }
3084 
3085  const QVariant& attVal = values.at( 2 );
3086  QgsFeatureRequest req;
3087  req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
3088  QgsExpression::quotedString( attVal.toString() ) ) );
3089  req.setLimit( 1 );
3090  if ( !parent->needsGeometry() )
3091  {
3093  }
3094  QgsFeatureIterator fIt = vl->getFeatures( req );
3095 
3096  QgsFeature fet;
3097  if ( fIt.nextFeature( fet ) )
3098  return QVariant::fromValue( fet );
3099 
3100  return QVariant();
3101 }
3102 
3103 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3104 {
3105  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3106 
3107  //try to find a matching layer by name
3108  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
3109  if ( !layer )
3110  {
3111  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
3112  if ( !layersByName.isEmpty() )
3113  {
3114  layer = layersByName.at( 0 );
3115  }
3116  }
3117 
3118  if ( !layer )
3119  return QVariant();
3120 
3121  QString layerProperty = getStringValue( values.at( 1 ), parent );
3122  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
3123  return layer->name();
3124  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
3125  return layer->id();
3126  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
3127  return layer->title();
3128  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
3129  return layer->abstract();
3130  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
3131  return layer->keywordList();
3132  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
3133  return layer->dataUrl();
3134  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
3135  return layer->attribution();
3136  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
3137  return layer->attributionUrl();
3138  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
3139  return layer->publicSource();
3140  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
3141  return layer->minimumScale();
3142  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
3143  return layer->maximumScale();
3144  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
3145  return layer->crs().authid();
3146  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
3147  return layer->crs().toProj4();
3148  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
3149  {
3150  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
3151  QVariant result = QVariant::fromValue( *extentGeom );
3152  delete extentGeom;
3153  return result;
3154  }
3155  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
3156  {
3157  switch ( layer->type() )
3158  {
3160  return QCoreApplication::translate( "expressions", "Vector" );
3162  return QCoreApplication::translate( "expressions", "Raster" );
3164  return QCoreApplication::translate( "expressions", "Plugin" );
3165  }
3166  }
3167  else
3168  {
3169  //vector layer methods
3170  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
3171  if ( vLayer )
3172  {
3173  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
3174  return vLayer->storageType();
3175  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
3176  return QGis::vectorGeometryType( vLayer->geometryType() );
3177  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
3178  return QVariant::fromValue( vLayer->featureCount() );
3179  }
3180  }
3181 
3182  return QVariant();
3183 }
3184 
3185 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
3186 {
3187  int fnIdx = functionIndex( function->name() );
3188  if ( fnIdx != -1 )
3189  {
3190  return false;
3191  }
3192  QgsExpression::gmFunctions.append( function );
3193  if ( transferOwnership )
3194  QgsExpression::gmOwnedFunctions.append( function );
3195  return true;
3196 }
3197 
3199 {
3200  // You can never override the built in functions.
3201  if ( QgsExpression::BuiltinFunctions().contains( name ) )
3202  {
3203  return false;
3204  }
3205  int fnIdx = functionIndex( name );
3206  if ( fnIdx != -1 )
3207  {
3208  QgsExpression::gmFunctions.removeAt( fnIdx );
3209  return true;
3210  }
3211  return false;
3212 }
3213 
3215 {
3216  qDeleteAll( QgsExpression::gmOwnedFunctions );
3218 }
3219 
3221 
3223 {
3224  if ( gmBuiltinFunctions.isEmpty() )
3225  {
3227  << "abs" << "sqrt" << "cos" << "sin" << "tan"
3228  << "asin" << "acos" << "atan" << "atan2"
3229  << "exp" << "ln" << "log10" << "log"
3230  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
3231  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
3232  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
3233  << "todatetime" << "to_datetime" << "todate" << "to_date"
3234  << "totime" << "to_time" << "tointerval" << "to_interval"
3235  << "coalesce" << "if" << "regexp_match" << "age" << "year"
3236  << "month" << "week" << "day" << "hour" << "day_of_week"
3237  << "minute" << "second" << "lower" << "upper"
3238  << "title" << "length" << "replace" << "trim" << "wordwrap"
3239  << "regexp_replace" << "regexp_substr"
3240  << "substr" << "concat" << "strpos" << "left"
3241  << "right" << "rpad" << "lpad" << "format"
3242  << "format_number" << "format_date"
3243  << "color_rgb" << "color_rgba" << "ramp_color"
3244  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
3245  << "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
3246  << "xat" << "yat" << "$area" << "area" << "perimeter"
3247  << "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
3248  << "num_interior_rings" << "num_rings" << "num_geometries"
3249  << "geometry_n" << "interior_ring_n"
3250  << "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
3251  << "nodes_to_points" << "segments_to_lines"
3252  << "make_line" << "make_polygon"
3253  << "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
3254  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
3255  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
3256  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
3257  << "relate"
3258  << "overlaps" << "within" << "buffer" << "centroid" << "bounds" << "reverse" << "exterior_ring"
3259  << "boundary" << "line_merge"
3260  << "bounds_width" << "bounds_height" << "is_closed" << "convex_hull" << "difference"
3261  << "distance" << "intersection" << "sym_difference" << "combine"
3262  << "extrude" << "azimuth" << "project" << "closest_point" << "shortest_line"
3263  << "line_locate_point" << "line_interpolate_point"
3264  << "line_interpolate_angle" << "angle_at_vertex" << "distance_to_vertex"
3265  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
3266  << "transform" << "get_feature" << "getFeature"
3267  << "levenshtein" << "longest_common_substring" << "hamming_distance"
3268  << "soundex"
3269  << "aggregate" << "relation_aggregate" << "count" << "count_distinct"
3270  << "count_missing" << "minimum" << "maximum" << "sum" << "mean"
3271  << "median" << "stdev" << "range" << "minority" << "majority"
3272  << "q1" << "q3" << "iqr" << "min_length" << "max_length" << "concatenate"
3273  << "attribute" << "var" << "layer_property"
3274  << "$id" << "$scale" << "_specialcol_";
3275  }
3276  return gmBuiltinFunctions;
3277 }
3278 
3281 
3283 {
3284  // The construction of the list isn't thread-safe, and without the mutex,
3285  // crashes in the WFS provider may occur, since it can parse expressions
3286  // in parallel.
3287  // The mutex needs to be recursive.
3288  static QMutex sFunctionsMutex( QMutex::Recursive );
3289  QMutexLocker locker( &sFunctionsMutex );
3290 
3291  if ( gmFunctions.isEmpty() )
3292  {
3293  ParameterList aggParams = ParameterList() << Parameter( "expression" )
3294  << Parameter( "group_by", true )
3295  << Parameter( "filter", true );
3296 
3297  gmFunctions
3298  << new StaticFunction( "sqrt", ParameterList() << Parameter( "value" ), fcnSqrt, "Math" )
3299  << new StaticFunction( "radians", ParameterList() << Parameter( "degrees" ), fcnRadians, "Math" )
3300  << new StaticFunction( "degrees", ParameterList() << Parameter( "radians" ), fcnDegrees, "Math" )
3301  << new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, QStringList() << "Math" << "GeometryGroup" )
3302  << new StaticFunction( "project", ParameterList() << Parameter( "point" ) << Parameter( "distance" ) << Parameter( "bearing" ), fcnProject, "GeometryGroup" )
3303  << new StaticFunction( "abs", ParameterList() << Parameter( "value" ), fcnAbs, "Math" )
3304  << new StaticFunction( "cos", ParameterList() << Parameter( "angle" ), fcnCos, "Math" )
3305  << new StaticFunction( "sin", ParameterList() << Parameter( "angle" ), fcnSin, "Math" )
3306  << new StaticFunction( "tan", ParameterList() << Parameter( "angle" ), fcnTan, "Math" )
3307  << new StaticFunction( "asin", ParameterList() << Parameter( "value" ), fcnAsin, "Math" )
3308  << new StaticFunction( "acos", ParameterList() << Parameter( "value" ), fcnAcos, "Math" )
3309  << new StaticFunction( "atan", ParameterList() << Parameter( "value" ), fcnAtan, "Math" )
3310  << new StaticFunction( "atan2", ParameterList() << Parameter( "dx" ) << Parameter( "dy" ), fcnAtan2, "Math" )
3311  << new StaticFunction( "exp", ParameterList() << Parameter( "value" ), fcnExp, "Math" )
3312  << new StaticFunction( "ln", ParameterList() << Parameter( "value" ), fcnLn, "Math" )
3313  << new StaticFunction( "log10", ParameterList() << Parameter( "value" ), fcnLog10, "Math" )
3314  << new StaticFunction( "log", ParameterList() << Parameter( "base" ) << Parameter( "value" ), fcnLog, "Math" )
3315  << new StaticFunction( "round", ParameterList() << Parameter( "value" ) << Parameter( "places", true, 0 ), fcnRound, "Math" )
3316  << new StaticFunction( "rand", ParameterList() << Parameter( "min" ) << Parameter( "max" ), fcnRnd, "Math" )
3317  << new StaticFunction( "randf", ParameterList() << Parameter( "min", true, 0.0 ) << Parameter( "max", true, 1.0 ), fcnRndF, "Math" )
3318  << new StaticFunction( "max", -1, fcnMax, "Math" )
3319  << new StaticFunction( "min", -1, fcnMin, "Math" )
3320  << new StaticFunction( "clamp", ParameterList() << Parameter( "min" ) << Parameter( "value" ) << Parameter( "max" ), fcnClamp, "Math" )
3321  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
3322  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
3323  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
3324  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
3325  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
3326  << new StaticFunction( "to_int", ParameterList() << Parameter( "value" ), fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
3327  << new StaticFunction( "to_real", ParameterList() << Parameter( "value" ), fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
3328  << new StaticFunction( "to_string", ParameterList() << Parameter( "value" ), fcnToString, QStringList() << "Conversions" << "String", QString(), false, QStringList(), false, QStringList() << "tostring" )
3329  << new StaticFunction( "to_datetime", ParameterList() << Parameter( "value" ), fcnToDateTime, QStringList() << "Conversions" << "Date and Time", QString(), false, QStringList(), false, QStringList() << "todatetime" )
3330  << new StaticFunction( "to_date", ParameterList() << Parameter( "value" ), fcnToDate, QStringList() << "Conversions" << "Date and Time", QString(), false, QStringList(), false, QStringList() << "todate" )
3331  << new StaticFunction( "to_time", ParameterList() << Parameter( "value" ), fcnToTime, QStringList() << "Conversions" << "Date and Time", QString(), false, QStringList(), false, QStringList() << "totime" )
3332  << new StaticFunction( "to_interval", ParameterList() << Parameter( "value" ), fcnToInterval, QStringList() << "Conversions" << "Date and Time", QString(), false, QStringList(), false, QStringList() << "tointerval" )
3333  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
3334  << new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QStringList(), true )
3335  << new StaticFunction( "aggregate", ParameterList() << Parameter( "layer" ) << Parameter( "aggregate" ) << Parameter( "expression" )
3336  << Parameter( "filter", true ) << Parameter( "concatenator", true ), fcnAggregate, "Aggregates", QString(), False, QStringList(), true )
3337  << new StaticFunction( "relation_aggregate", ParameterList() << Parameter( "relation" ) << Parameter( "aggregate" ) << Parameter( "expression" ) << Parameter( "concatenator", true ),
3339 
3340  << new StaticFunction( "count", aggParams, fcnAggregateCount, "Aggregates", QString(), False, QStringList(), true )
3341  << new StaticFunction( "count_distinct", aggParams, fcnAggregateCountDistinct, "Aggregates", QString(), False, QStringList(), true )
3342  << new StaticFunction( "count_missing", aggParams, fcnAggregateCountMissing, "Aggregates", QString(), False, QStringList(), true )
3343  << new StaticFunction( "minimum", aggParams, fcnAggregateMin, "Aggregates", QString(), False, QStringList(), true )
3344  << new StaticFunction( "maximum", aggParams, fcnAggregateMax, "Aggregates", QString(), False, QStringList(), true )
3345  << new StaticFunction( "sum", aggParams, fcnAggregateSum, "Aggregates", QString(), False, QStringList(), true )
3346  << new StaticFunction( "mean", aggParams, fcnAggregateMean, "Aggregates", QString(), False, QStringList(), true )
3347  << new StaticFunction( "median", aggParams, fcnAggregateMedian, "Aggregates", QString(), False, QStringList(), true )
3348  << new StaticFunction( "stdev", aggParams, fcnAggregateStdev, "Aggregates", QString(), False, QStringList(), true )
3349  << new StaticFunction( "range", aggParams, fcnAggregateRange, "Aggregates", QString(), False, QStringList(), true )
3350  << new StaticFunction( "minority", aggParams, fcnAggregateMinority, "Aggregates", QString(), False, QStringList(), true )
3351  << new StaticFunction( "majority", aggParams, fcnAggregateMajority, "Aggregates", QString(), False, QStringList(), true )
3352  << new StaticFunction( "q1", aggParams, fcnAggregateQ1, "Aggregates", QString(), False, QStringList(), true )
3353  << new StaticFunction( "q3", aggParams, fcnAggregateQ3, "Aggregates", QString(), False, QStringList(), true )
3354  << new StaticFunction( "iqr", aggParams, fcnAggregateIQR, "Aggregates", QString(), False, QStringList(), true )
3355  << new StaticFunction( "min_length", aggParams, fcnAggregateMinLength, "Aggregates", QString(), False, QStringList(), true )
3356  << new StaticFunction( "max_length", aggParams, fcnAggregateMaxLength, "Aggregates", QString(), False, QStringList(), true )
3357  << new StaticFunction( "concatenate", aggParams << Parameter( "concatenator", true ), fcnAggregateStringConcat, "Aggregates", QString(), False, QStringList(), true )
3358 
3359  << new StaticFunction( "regexp_match", ParameterList() << Parameter( "string" ) << Parameter( "regex" ), fcnRegexpMatch, QStringList() << "Conditionals" << "String" )
3360  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
3361  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
3362  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
3363  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
3364  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
3365  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
3366  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
3367  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
3368  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
3369  << new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
3370  << new StaticFunction( "lower", 1, fcnLower, "String" )
3371  << new StaticFunction( "upper", 1, fcnUpper, "String" )
3372  << new StaticFunction( "title", 1, fcnTitle, "String" )
3373  << new StaticFunction( "trim", 1, fcnTrim, "String" )
3374  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
3375  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
3376  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
3377  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
3378  << new StaticFunction( "char", 1, fcnChar, "String" )
3379  << new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, " " ), fcnWordwrap, "String" )
3380  << new StaticFunction( "length", ParameterList() << Parameter( "text", true, "" ), fcnLength, QStringList() << "String" << "GeometryGroup" )
3381  << new StaticFunction( "replace", 3, fcnReplace, "String" )
3382  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
3383  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
3384  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
3385  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
3386  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
3387  << new StaticFunction( "left", 2, fcnLeft, "String" )
3388  << new StaticFunction( "right", 2, fcnRight, "String" )
3389  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
3390  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
3391  << new StaticFunction( "format", -1, fcnFormatString, "String" )
3392  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
3393  << new StaticFunction( "format_date", ParameterList() << Parameter( "date" ) << Parameter( "format" ), fcnFormatDate, QStringList() << "String" << "Date and Time" )
3394  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
3395  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
3396  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
3397  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
3398  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
3399  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
3400  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
3401  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
3402  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
3403  << new StaticFunction( "color_part", 2, fncColorPart, "Color" )
3404  << new StaticFunction( "darker", 2, fncDarker, "Color" )
3405  << new StaticFunction( "lighter", 2, fncLighter, "Color" )
3406  << new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
3407  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
3408  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
3409  << new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
3410  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", QString(), true )
3411  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", QString(), true )
3412  << new StaticFunction( "perimeter", 1, fcnPerimeter, "GeometryGroup" )
3413  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", QString(), true )
3414  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
3415  << new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
3416  << new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
3417  << new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
3418  << new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
3419  << new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
3420  << new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
3421  << new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
3422  << new StaticFunction( "nodes_to_points", -1, fcnNodesToPoints, "GeometryGroup" )
3423  << new StaticFunction( "segments_to_lines", 1, fcnSegmentsToLines, "GeometryGroup" )
3424  << new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
3425  << new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
3426  << new StaticFunction( "make_line", -1, fcnMakeLine, "GeometryGroup" )
3427  << new StaticFunction( "make_polygon", -1, fcnMakePolygon, "GeometryGroup" )
3428  << new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
3429  << new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
3430  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
3431  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmax" )
3432  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymin" )
3433  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
3434  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
3435  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
3436  << new StaticFunction( "relate", -1, fcnRelate, "GeometryGroup" )
3437  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
3438  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
3439  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
3440  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
3441  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
3442  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
3443  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
3444  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
3445  << new StaticFunction( "translate", 3, fcnTranslate, "GeometryGroup" )
3446  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
3447  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
3448  << new StaticFunction( "point_on_surface", 1, fcnPointOnSurface, "GeometryGroup" )
3449  << new StaticFunction( "reverse", 1, fcnReverse, "GeometryGroup" )
3450  << new StaticFunction( "exterior_ring", 1, fcnExteriorRing, "GeometryGroup" )
3451  << new StaticFunction( "interior_ring_n", 2, fcnInteriorRingN, "GeometryGroup" )
3452  << new StaticFunction( "geometry_n", 2, fcnGeometryN, "GeometryGroup" )
3453  << new StaticFunction( "boundary", ParameterList() << Parameter( "geometry" ), fcnBoundary, "GeometryGroup" )
3454  << new StaticFunction( "line_merge", ParameterList() << Parameter( "geometry" ), fcnLineMerge, "GeometryGroup" )
3455  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup" )
3456  << new StaticFunction( "num_points", 1, fcnGeomNumPoints, "GeometryGroup" )
3457  << new StaticFunction( "num_interior_rings", 1, fcnGeomNumInteriorRings, "GeometryGroup" )
3458  << new StaticFunction( "num_rings", 1, fcnGeomNumRings, "GeometryGroup" )
3459  << new StaticFunction( "num_geometries", 1, fcnGeomNumGeometries, "GeometryGroup" )
3460  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup" )
3461  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup" )
3462  << new StaticFunction( "is_closed", 1, fcnIsClosed, "GeometryGroup" )
3463  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
3464  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
3465  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
3466  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
3467  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
3468  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
3469  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
3470  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
3471  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
3472  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
3473  << new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
3474  << new StaticFunction( "order_parts", 3, fcnOrderParts, "GeometryGroup", QString() )
3475  << new StaticFunction( "closest_point", 2, fcnClosestPoint, "GeometryGroup" )
3476  << new StaticFunction( "shortest_line", 2, fcnShortestLine, "GeometryGroup" )
3477  << new StaticFunction( "line_interpolate_point", ParameterList() << Parameter( "geometry" )
3478  << Parameter( "distance" ), fcnLineInterpolatePoint, "GeometryGroup" )
3479  << new StaticFunction( "line_interpolate_angle", ParameterList() << Parameter( "geometry" )
3480  << Parameter( "distance" ), fcnLineInterpolateAngle, "GeometryGroup" )
3481  << new StaticFunction( "line_locate_point", ParameterList() << Parameter( "geometry" )
3482  << Parameter( "point" ), fcnLineLocatePoint, "GeometryGroup" )
3483  << new StaticFunction( "angle_at_vertex", ParameterList() << Parameter( "geometry" )
3484  << Parameter( "vertex" ), fcnAngleAtVertex, "GeometryGroup" )
3485  << new StaticFunction( "distance_to_vertex", ParameterList() << Parameter( "geometry" )
3486  << Parameter( "vertex" ), fcnDistanceToVertex, "GeometryGroup" )
3487  << new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
3488  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
3489  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
3490  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
3491  << new StaticFunction( "$map", 0, fcnMapId, "deprecated" )
3492  << new StaticFunction( "$numpages", 0, fcnComposerNumPages, "deprecated" )
3493  << new StaticFunction( "$page", 0, fcnComposerPage, "deprecated" )
3494  << new StaticFunction( "$feature", 0, fcnAtlasFeature, "deprecated" )
3495  << new StaticFunction( "$atlasfeatureid", 0, fcnAtlasFeatureId, "deprecated" )
3496  << new StaticFunction( "$atlasfeature", 0, fcnAtlasCurrentFeature, "deprecated" )
3497  << new StaticFunction( "$atlasgeometry", 0, fcnAtlasCurrentGeometry, "deprecated" )
3498  << new StaticFunction( "$numfeatures", 0, fcnAtlasNumFeatures, "deprecated" )
3499  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
3500  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
3501  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
3502  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
3503 
3504  //return all attributes string for referencedColumns - this is caught by
3505  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
3506  // feature request
3507  << new StaticFunction( "eval", 1, fcnEval, "General", QString(), true, QStringList( QgsFeatureRequest::AllAttributes ) )
3508  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
3509 
3510  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
3511  ;
3512 
3514 
3515  //QgsExpression has ownership of all built-in functions
3516  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
3517  {
3518  gmOwnedFunctions << func;
3519  }
3520  }
3521  return gmFunctions;
3522 }
3523 
3526 
3527 void QgsExpression::setSpecialColumn( const QString& name, const QVariant& variant )
3528 {
3529  int fnIdx = functionIndex( name );
3530  if ( fnIdx != -1 )
3531  {
3532  // function of the same name already exists
3533  return;
3534  }
3535  gmSpecialColumns[ name ] = variant;
3536 }
3537 
3539 {
3541  if ( fit != gmSpecialColumns.end() )
3542  {
3543  gmSpecialColumns.erase( fit );
3544  }
3545 }
3546 
3548 {
3549  int fnIdx = functionIndex( name );
3550  if ( fnIdx != -1 )
3551  {
3552  // function of the same name already exists
3553  return QVariant();
3554  }
3556  if ( it == gmSpecialColumns.constEnd() )
3557  {
3558  return QVariant();
3559  }
3560  return it.value();
3561 }
3562 
3564 {
3565  if ( functionIndex( name ) != -1 )
3566  return false;
3567  return gmSpecialColumns.contains( name );
3568 }
3569 
3570 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
3571 {
3573  return isValid( text, &context, errorMessage );
3574 }
3575 
3576 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
3577 {
3578  QgsExpression exp( text );
3579  exp.prepare( context );
3580  errorMessage = exp.parserErrorString();
3581  return !exp.hasParserError();
3582 }
3583 
3585 {
3586  detach();
3587  d->mRootNode = ::parseExpression( expression, d->mParserErrorString );
3588  d->mEvalErrorString = QString();
3589  d->mExp = expression;
3590 }
3591 
3592 void QgsExpression::setScale( double scale ) { d->mScale = scale; }
3593 
3594 double QgsExpression::scale() { return d->mScale; }
3595 
3597 {
3598  if ( !d->mExp.isNull() )
3599  return d->mExp;
3600  else
3601  return dump();
3602 }
3603 
3605 {
3606  QList<Function*> defs;
3608  {
3609  //check for special column group name
3610  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
3611  defs << new StaticFunction( it.key(), 0, static_cast< FcnEvalContext >( nullptr ), group );
3612  }
3613  return defs;
3614 }
3615 
3617 {
3618  return QString( "\"%1\"" ).arg( name.replace( '\"', "\"\"" ) );
3619 }
3620 
3622 {
3623  text.replace( '\'', "''" );
3624  text.replace( '\\', "\\\\" );
3625  text.replace( '\n', "\\n" );
3626  text.replace( '\t', "\\t" );
3627  return QString( "'%1'" ).arg( text );
3628 }
3629 
3631 {
3632  return quotedValue( value, value.type() );
3633 }
3634 
3635 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
3636 {
3637  if ( value.isNull() )
3638  return "NULL";
3639 
3640  switch ( type )
3641  {
3642  case QVariant::Int:
3643  case QVariant::LongLong:
3644  case QVariant::Double:
3645  return value.toString();
3646 
3647  case QVariant::Bool:
3648  return value.toBool() ? "TRUE" : "FALSE";
3649 
3650  default:
3651  case QVariant::String:
3652  return quotedString( value.toString() );
3653  }
3654 
3655 }
3656 
3658 {
3659  return functionIndex( name ) != -1;
3660 }
3661 
3663 {
3664  int count = functionCount();
3665  for ( int i = 0; i < count; i++ )
3666  {
3667  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
3668  return i;
3669  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
3670  {
3671  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
3672  return i;
3673  }
3674  }
3675  return -1;
3676 }
3677 
3679 {
3680  return Functions().size();
3681 }
3682 
3683 
3685  : d( new QgsExpressionPrivate )
3686 {
3687  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
3688  d->mExp = expr;
3689  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
3690 }
3691 
3693  : d( other.d )
3694 {
3695  d->ref.ref();
3696 }
3697 
3699 {
3700  if ( !d->ref.deref() )
3701  {
3702  delete d;
3703  }
3704 
3705  d = other.d;
3706  d->ref.ref();
3707  return *this;
3708 }
3709 
3711  : d( new QgsExpressionPrivate )
3712 {
3713 }
3714 
3716 {
3717  Q_ASSERT( d );
3718  if ( !d->ref.deref() )
3719  delete d;
3720 }
3721 
3722 bool QgsExpression::operator==( const QgsExpression& other ) const
3723 {
3724  if ( d == other.d || d->mExp == other.d->mExp )
3725  return true;
3726  return false;
3727 }
3728 
3730 {
3731  return d->mRootNode;
3732 }
3733 
3734 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
3735 
3736 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
3737 
3739 {
3740  if ( !d->mRootNode )
3741  return QStringList();
3742 
3743  QStringList columns = d->mRootNode->referencedColumns();
3744 
3745  // filter out duplicates
3746  for ( int i = 0; i < columns.count(); i++ )
3747  {
3748  QString col = columns.at( i );
3749  for ( int j = i + 1; j < columns.count(); j++ )
3750  {
3751  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
3752  {
3753  // this column is repeated: remove it!
3754  columns.removeAt( j-- );
3755  }
3756  }
3757  }
3758 
3759  return columns;
3760 }
3761 
3763 {
3764  if ( !d->mRootNode )
3765  return false;
3766  return d->mRootNode->needsGeometry();
3767 }
3768 
3770 {
3771  if ( d->mCalc.data() )
3772  return;
3773 
3774  // Use planimetric as default
3776  d->mCalc->setEllipsoidalMode( false );
3777 }
3778 
3780 {
3781  Q_ASSERT( d );
3782 
3783  if ( d->ref > 1 )
3784  {
3785  ( void )d->ref.deref();
3786 
3787  d = new QgsExpressionPrivate( *d );
3788  }
3789 }
3790 
3792 {
3793  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea( calc ) );
3794 }
3795 
3796 bool QgsExpression::prepare( const QgsFields& fields )
3797 {
3798  detach();
3800  return prepare( &fc );
3801 }
3802 
3804 {
3805  detach();
3806  d->mEvalErrorString = QString();
3807  if ( !d->mRootNode )
3808  {
3809  //re-parse expression. Creation of QgsExpressionContexts may have added extra
3810  //known functions since this expression was created, so we have another try
3811  //at re-parsing it now that the context must have been created
3812  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
3813  }
3814 
3815  if ( !d->mRootNode )
3816  {
3817  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3818  return false;
3819  }
3820 
3821  return d->mRootNode->prepare( this, context );
3822 }
3823 
3825 {
3826  d->mEvalErrorString = QString();
3827  if ( !d->mRootNode )
3828  {
3829  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3830  return QVariant();
3831  }
3832 
3834  return d->mRootNode->eval( this, &context );
3835 }
3836 
3838 {
3840  return evaluate( &f );
3842 }
3843 
3845 {
3846  // first prepare
3848  bool res = prepare( &context );
3849  if ( !res )
3850  return QVariant();
3851 
3852  // then evaluate
3853  return evaluate( &context );
3854 }
3855 
3856 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
3857 {
3859  return evaluate( &f, fields );
3861 }
3862 
3864 {
3865  d->mEvalErrorString = QString();
3866  if ( !d->mRootNode )
3867  {
3868  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3869  return QVariant();
3870  }
3871 
3872  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
3873 }
3874 
3876 {
3877  d->mEvalErrorString = QString();
3878  if ( !d->mRootNode )
3879  {
3880  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3881  return QVariant();
3882  }
3883 
3884  return d->mRootNode->eval( this, context );
3885 }
3886 
3888 {
3889  return !d->mEvalErrorString.isNull();
3890 }
3891 
3893 {
3894  return d->mEvalErrorString;
3895 }
3896 
3898 {
3899  d->mEvalErrorString = str;
3900 }
3901 
3903 {
3904  d->mRowNumber = rowNumber;
3905 }
3906 
3907 int QgsExpression::currentRowNumber() { return d->mRowNumber; }
3908 
3910 {
3911  if ( !d->mRootNode )
3912  return QString();
3913 
3914  return d->mRootNode->dump();
3915 }
3916 
3918 {
3919  return d->mCalc.data();
3920 }
3921 
3923 {
3924  return d->mDistanceUnit;
3925 }
3926 
3928 {
3929  d->mDistanceUnit = unit;
3930 }
3931 
3933 {
3934  return d->mAreaUnit;
3935 }
3936 
3938 {
3939  d->mAreaUnit = unit;
3940 }
3941 
3943 {
3944  if ( d->mRootNode )
3945  d->mRootNode->accept( v );
3946 }
3947 
3949  QgsVectorLayer *layer,
3950  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3951 {
3952  QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( feat ? *feat : QgsFeature(), layer ? layer->fields() : QgsFields() );
3953  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
3954 }
3955 
3956 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3957 {
3958  QString expr_action;
3959 
3960  QMap<QString, QVariant> savedValues;
3961  if ( substitutionMap )
3962  {
3963  // variables with a local scope (must be restored after evaluation)
3964  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
3965  {
3967  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
3968  if ( !oldValue.isNull() )
3969  savedValues.insert( sit.key(), oldValue );
3970 
3971  // set the new value
3972  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3974  }
3975  }
3976 
3977  int index = 0;
3978  while ( index < action.size() )
3979  {
3980  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
3981 
3982  int pos = rx.indexIn( action, index );
3983  if ( pos < 0 )
3984  break;
3985 
3986  int start = index;
3987  index = pos + rx.matchedLength();
3988  QString to_replace = rx.cap( 1 ).trimmed();
3989  QgsDebugMsg( "Found expression: " + to_replace );
3990 
3991  QgsExpression exp( to_replace );
3992  if ( exp.hasParserError() )
3993  {
3994  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
3995  expr_action += action.midRef( start, index - start );
3996  continue;
3997  }
3998 
3999  if ( distanceArea )
4000  {
4001  //if QgsDistanceArea specified for area/distance conversion, use it
4002  exp.setGeomCalculator( *distanceArea );
4003  }
4004 
4005  QVariant result = exp.evaluate( context );
4006 
4007  if ( exp.hasEvalError() )
4008  {
4009  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
4010  expr_action += action.midRef( start, index - start );
4011  continue;
4012  }
4013 
4014  QgsDebugMsg( "Expression result is: " + result.toString() );
4015  expr_action += action.mid( start, pos - start ) + result.toString();
4016  }
4017 
4018  expr_action += action.midRef( index );
4019 
4020  // restore overwritten local values
4022  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
4023  {
4024  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
4025  }
4027 
4028  return expr_action;
4029 }
4030 
4031 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
4032 {
4033  bool ok;
4034  //first test if text is directly convertible to double
4035  double convertedValue = text.toDouble( &ok );
4036  if ( ok )
4037  {
4038  return convertedValue;
4039  }
4040 
4041  //otherwise try to evalute as expression
4042  QgsExpression expr( text );
4043 
4044  QgsExpressionContext context;
4047 
4048  QVariant result = expr.evaluate( &context );
4049  convertedValue = result.toDouble( &ok );
4050  if ( expr.hasEvalError() || !ok )
4051  {
4052  return fallbackValue;
4053  }
4054  return convertedValue;
4055 }
4056 
4057 
4059 // nodes
4060 
4062 {
4063  NodeList* nl = new NodeList;
4064  Q_FOREACH ( Node* node, mList )
4065  {
4066  nl->mList.append( node->clone() );
4067  }
4068  nl->mNameList = mNameList;
4069 
4070  return nl;
4071 }
4072 
4074 {
4075  QString msg;
4076  bool first = true;
4077  Q_FOREACH ( Node* n, mList )
4078  {
4079  if ( !first ) msg += ", ";
4080  else first = false;
4081  msg += n->dump();
4082  }
4083  return msg;
4084 }
4085 
4086 
4087 //
4088 
4090 {
4091  QVariant val = mOperand->eval( parent, context );
4093 
4094  switch ( mOp )
4095  {
4096  case uoNot:
4097  {
4098  TVL tvl = getTVLValue( val, parent );
4100  return tvl2variant( NOT[tvl] );
4101  }
4102 
4103  case uoMinus:
4104  if ( isIntSafe( val ) )
4105  return QVariant( - getIntValue( val, parent ) );
4106  else if ( isDoubleSafe( val ) )
4107  return QVariant( - getDoubleValue( val, parent ) );
4108  else
4109  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
4110  default:
4111  Q_ASSERT( 0 && "unknown unary operation" );
4112  }
4113  return QVariant();
4114 }
4115 
4117 {
4118  return mOperand->prepare( parent, context );
4119 }
4120 
4122 {
4123  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
4124 }
4125 
4127 {
4128  return new NodeUnaryOperator( mOp, mOperand->clone() );
4129 }
4130 
4131 //
4132 
4134 {
4135  QVariant vL = mOpLeft->eval( parent, context );
4137  QVariant vR = mOpRight->eval( parent, context );
4139 
4140  switch ( mOp )
4141  {
4142  case boPlus:
4143  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
4144  {
4145  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
4147  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
4149  return QVariant( sL + sR );
4150  }
4151  //intentional fall-through
4152  FALLTHROUGH;
4153  case boMinus:
4154  case boMul:
4155  case boDiv:
4156  case boMod:
4157  {
4158  if ( isNull( vL ) || isNull( vR ) )
4159  return QVariant();
4160  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
4161  {
4162  // both are integers - let's use integer arithmetics
4163  int iL = getIntValue( vL, parent );
4165  int iR = getIntValue( vR, parent );
4167 
4168  if ( mOp == boMod && iR == 0 )
4169  return QVariant();
4170 
4171  return QVariant( computeInt( iL, iR ) );
4172  }
4173  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
4174  {
4175  QDateTime dL = getDateTimeValue( vL, parent );
4177  QgsInterval iL = getInterval( vR, parent );
4179  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
4180  {
4181  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
4182  return QVariant();
4183  }
4184  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
4185  }
4186  else if ( mOp == boPlus && (( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
4187  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
4188  {
4189  QDate date = getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
4191  QTime time = getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
4193  QDateTime dt = QDateTime( date, time );
4194  return QVariant( dt );
4195  }
4196  else if ( mOp == boMinus && vL.type() == QVariant::Date && vR.type() == QVariant::Date )
4197  {
4198  QDate date1 = getDateValue( vL, parent );
4200  QDate date2 = getDateValue( vR, parent );
4202  return date1 - date2;
4203  }
4204  else if ( mOp == boMinus && vL.type() == QVariant::Time && vR.type() == QVariant::Time )
4205  {
4206  QTime time1 = getTimeValue( vL, parent );
4208  QTime time2 = getTimeValue( vR, parent );
4210  return time1 - time2;
4211  }
4212  else if ( mOp == boMinus && vL.type() == QVariant::DateTime && vR.type() == QVariant::DateTime )
4213  {
4214  QDateTime datetime1 = getDateTimeValue( vL, parent );
4216  QDateTime datetime2 = getDateTimeValue( vR, parent );
4218  return datetime1 - datetime2;
4219  }
4220  else
4221  {
4222  // general floating point arithmetic
4223  double fL = getDoubleValue( vL, parent );
4225  double fR = getDoubleValue( vR, parent );
4227  if (( mOp == boDiv || mOp == boMod ) && fR == 0. )
4228  return QVariant(); // silently handle division by zero and return NULL
4229  return QVariant( computeDouble( fL, fR ) );
4230  }
4231  }
4232  case boIntDiv:
4233  {
4234  //integer division
4235  double fL = getDoubleValue( vL, parent );
4237  double fR = getDoubleValue( vR, parent );
4239  if ( fR == 0. )
4240  return QVariant(); // silently handle division by zero and return NULL
4241  return QVariant( qFloor( fL / fR ) );
4242  }
4243  case boPow:
4244  if ( isNull( vL ) || isNull( vR ) )
4245  return QVariant();
4246  else
4247  {
4248  double fL = getDoubleValue( vL, parent );
4250  double fR = getDoubleValue( vR, parent );
4252  return QVariant( pow( fL, fR ) );
4253  }
4254 
4255  case boAnd:
4256  {
4257  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4259  return tvl2variant( AND[tvlL][tvlR] );
4260  }
4261 
4262  case boOr:
4263  {
4264  TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
4266  return tvl2variant( OR[tvlL][tvlR] );
4267  }
4268 
4269  case boEQ:
4270  case boNE:
4271  case boLT:
4272  case boGT:
4273  case boLE:
4274  case boGE:
4275  if ( isNull( vL ) || isNull( vR ) )
4276  {
4277  return TVL_Unknown;
4278  }
4279  else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4280  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4281  {
4282  // do numeric comparison if both operators can be converted to numbers,
4283  // and they aren't both string
4284  double fL = getDoubleValue( vL, parent );
4286  double fR = getDoubleValue( vR, parent );
4288  return compare( fL - fR ) ? TVL_True : TVL_False;
4289  }
4290  else
4291  {
4292  // do string comparison otherwise
4293  QString sL = getStringValue( vL, parent );
4295  QString sR = getStringValue( vR, parent );
4297  int diff = QString::compare( sL, sR );
4298  return compare( diff ) ? TVL_True : TVL_False;
4299  }
4300 
4301  case boIs:
4302  case boIsNot:
4303  if ( isNull( vL ) && isNull( vR ) ) // both operators null
4304  return ( mOp == boIs ? TVL_True : TVL_False );
4305  else if ( isNull( vL ) || isNull( vR ) ) // one operator null
4306  return ( mOp == boIs ? TVL_False : TVL_True );
4307  else // both operators non-null
4308  {
4309  bool equal = false;
4310  if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) &&
4311  ( vL.type() != QVariant::String || vR.type() != QVariant::String ) )
4312  {
4313  double fL = getDoubleValue( vL, parent );
4315  double fR = getDoubleValue( vR, parent );
4317  equal = qgsDoubleNear( fL, fR );
4318  }
4319  else
4320  {
4321  QString sL = getStringValue( vL, parent );
4323  QString sR = getStringValue( vR, parent );
4325  equal = QString::compare( sL, sR ) == 0;
4326  }
4327  if ( equal )
4328  return mOp == boIs ? TVL_True : TVL_False;
4329  else
4330  return mOp == boIs ? TVL_False : TVL_True;
4331  }
4332 
4333  case boRegexp:
4334  case boLike:
4335  case boNotLike:
4336  case boILike:
4337  case boNotILike:
4338  if ( isNull( vL ) || isNull( vR ) )
4339  return TVL_Unknown;
4340  else
4341  {
4342  QString str = getStringValue( vL, parent );
4344  QString regexp = getStringValue( vR, parent );
4346  // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant)
4347  bool matches;
4348  if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp
4349  {
4350  QString esc_regexp = QRegExp::escape( regexp );
4351  // manage escape % and _
4352  if ( esc_regexp.startsWith( '%' ) )
4353  {
4354  esc_regexp.replace( 0, 1, ".*" );
4355  }
4356  QRegExp rx( "[^\\\\](%)" );
4357  int pos = 0;
4358  while (( pos = rx.indexIn( esc_regexp, pos ) ) != -1 )
4359  {
4360  esc_regexp.replace( pos + 1, 1, ".*" );
4361  pos += 1;
4362  }
4363  rx.setPattern( "\\\\%" );
4364  esc_regexp.replace( rx, "%" );
4365  if ( esc_regexp.startsWith( '_' ) )
4366  {
4367  esc_regexp.replace( 0, 1, "." );
4368  }
4369  rx.setPattern( "[^\\\\](_)" );
4370  pos = 0;
4371  while (( pos = rx.indexIn( esc_regexp, pos ) ) != -1 )
4372  {
4373  esc_regexp.replace( pos + 1, 1, '.' );
4374  pos += 1;
4375  }
4376  rx.setPattern( "\\\\_" );
4377  esc_regexp.replace( rx, "_" );
4378  matches = QRegExp( esc_regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str );
4379  }
4380  else
4381  {
4382  matches = QRegExp( regexp ).indexIn( str ) != -1;
4383  }
4384 
4385  if ( mOp == boNotLike || mOp == boNotILike )
4386  {
4387  matches = !matches;
4388  }
4389 
4390  return matches ? TVL_True : TVL_False;
4391  }
4392 
4393  case boConcat:
4394  if ( isNull( vL ) || isNull( vR ) )
4395  return QVariant();
4396  else
4397  {
4398  QString sL = getStringValue( vL, parent );
4400  QString sR = getStringValue( vR, parent );
4402  return QVariant( sL + sR );
4403  }
4404 
4405  default:
4406  break;
4407  }
4408  Q_ASSERT( false );
4409  return QVariant();
4410 }
4411 
4413 {
4414  switch ( mOp )
4415  {
4416  case boEQ:
4417  return qgsDoubleNear( diff, 0.0 );
4418  case boNE:
4419  return !qgsDoubleNear( diff, 0.0 );
4420  case boLT:
4421  return diff < 0;
4422  case boGT:
4423  return diff > 0;
4424  case boLE:
4425  return diff <= 0;
4426  case boGE:
4427  return diff >= 0;
4428  default:
4429  Q_ASSERT( false );
4430  return false;
4431  }
4432 }
4433 
4435 {
4436  switch ( mOp )
4437  {
4438  case boPlus:
4439  return x + y;
4440  case boMinus:
4441  return x -y;
4442  case boMul:
4443  return x*y;
4444  case boDiv:
4445  return x / y;
4446  case boMod:
4447  return x % y;
4448  default:
4449  Q_ASSERT( false );
4450  return 0;
4451  }
4452 }
4453 
4455 {
4456  switch ( mOp )
4457  {
4458  case boPlus:
4459  return d.addSecs( i->seconds() );
4460  case boMinus:
4461  return d.addSecs( -i->seconds() );
4462  default:
4463  Q_ASSERT( false );
4464  return QDateTime();
4465  }
4466 }
4467 
4469 {
4470  switch ( mOp )
4471  {
4472  case boPlus:
4473  return x + y;
4474  case boMinus:
4475  return x -y;
4476  case boMul:
4477  return x*y;
4478  case boDiv:
4479  return x / y;
4480  case boMod:
4481  return fmod( x, y );
4482  default:
4483  Q_ASSERT( false );
4484  return 0;
4485  }
4486 }
4487 
4489 {
4490  bool resL = mOpLeft->prepare( parent, context );
4491  bool resR = mOpRight->prepare( parent, context );
4492  return resL && resR;
4493 }
4494 
4496 {
4497  // see left/right in qgsexpressionparser.yy
4498  switch ( mOp )
4499  {
4500  case boOr:
4501  return 1;
4502 
4503  case boAnd:
4504  return 2;
4505 
4506  case boEQ:
4507  case boNE:
4508  case boLE:
4509  case boGE:
4510  case boLT:
4511  case boGT:
4512  case boRegexp:
4513  case boLike:
4514  case boILike:
4515  case boNotLike:
4516  case boNotILike:
4517  case boIs:
4518  case boIsNot:
4519  return 3;
4520 
4521  case boPlus:
4522  case boMinus:
4523  return 4;
4524 
4525  case boMul:
4526  case boDiv:
4527  case boIntDiv:
4528  case boMod:
4529  return 5;
4530 
4531  case boPow:
4532  return 6;
4533 
4534  case boConcat:
4535  return 7;
4536  }
4537  Q_ASSERT( 0 && "unexpected binary operator" );
4538  return -1;
4539 }
4540 
4542 {
4543  // see left/right in qgsexpressionparser.yy
4544  switch ( mOp )
4545  {
4546  case boOr:
4547  case boAnd:
4548  case boEQ:
4549  case boNE:
4550  case boLE:
4551  case boGE:
4552  case boLT:
4553  case boGT:
4554  case boRegexp:
4555  case boLike:
4556  case boILike:
4557  case boNotLike:
4558  case boNotILike:
4559  case boIs:
4560  case boIsNot:
4561  case boPlus:
4562  case boMinus:
4563  case boMul:
4564  case boDiv:
4565  case boIntDiv:
4566  case boMod:
4567  case boConcat:
4568  return true;
4569 
4570  case boPow:
4571  return false;
4572  }
4573  Q_ASSERT( 0 && "unexpected binary operator" );
4574  return false;
4575 }
4576 
4578 {
4579  QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
4580  QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );
4581  QgsExpression::NodeUnaryOperator *ruOp = dynamic_cast<QgsExpression::NodeUnaryOperator *>( mOpRight );
4582 
4583  QString rdump( mOpRight->dump() );
4584 
4585  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
4586  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
4587  {
4588  rdump.prepend( '(' ).append( ')' );
4589  }
4590 
4591  QString fmt;
4592  if ( leftAssociative() )
4593  {
4594  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
4595  fmt += " %2 ";
4596  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
4597  }
4598  else
4599  {
4600  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
4601  fmt += " %2 ";
4602  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
4603  }
4604 
4605  return fmt.arg( mOpLeft->dump(), BinaryOperatorText[mOp], rdump );
4606 }
4607 
4609 {
4610  return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
4611 }
4612 
4613 //
4614 
4616 {
4617  if ( mList->count() == 0 )
4618  return mNotIn ? TVL_True : TVL_False;
4619  QVariant v1 = mNode->eval( parent, context );
4621  if ( isNull( v1 ) )
4622  return TVL_Unknown;
4623 
4624  bool listHasNull = false;
4625 
4626  Q_FOREACH ( Node* n, mList->list() )
4627  {
4628  QVariant v2 = n->eval( parent, context );
4630  if ( isNull( v2 ) )
4631  listHasNull = true;
4632  else
4633  {
4634  bool equal = false;
4635  // check whether they are equal
4636  if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) )
4637  {
4638  double f1 = getDoubleValue( v1, parent );
4640  double f2 = getDoubleValue( v2, parent );
4642  equal = qgsDoubleNear( f1, f2 );
4643  }
4644  else
4645  {
4646  QString s1 = getStringValue( v1, parent );
4648  QString s2 = getStringValue( v2, parent );
4650  equal = QString::compare( s1, s2 ) == 0;
4651  }
4652 
4653  if ( equal ) // we know the result
4654  return mNotIn ? TVL_False : TVL_True;
4655  }
4656  }
4657 
4658  // item not found
4659  if ( listHasNull )
4660  return TVL_Unknown;
4661  else
4662  return mNotIn ? TVL_True : TVL_False;
4663 }
4664 
4666 {
4667  bool res = mNode->prepare( parent, context );
4668  Q_FOREACH ( Node* n, mList->list() )
4669  {
4670  res = res && n->prepare( parent, context );
4671  }
4672  return res;
4673 }
4674 
4676 {
4677  return QString( "%1 %2 IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT" : "", mList->dump() );
4678 }
4679 
4681 {
4682  return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
4683 }
4684 
4685 //
4686 
4688 {
4689  QString name = Functions()[mFnIndex]->name();
4690  Function* fd = context && context->hasFunction( name ) ? context->function( name ) : Functions()[mFnIndex];
4691 
4692  // evaluate arguments
4693  QVariantList argValues;
4694  if ( mArgs )
4695  {
4696  Q_FOREACH ( Node* n, mArgs->list() )
4697  {
4698  QVariant v;
4699  if ( fd->lazyEval() )
4700  {
4701  // Pass in the node for the function to eval as it needs.
4702  v = QVariant::fromValue( n );
4703  }
4704  else
4705  {
4706  v = n->eval( parent, context );
4708  if ( isNull( v ) && !fd->handlesNull() )
4709  return QVariant(); // all "normal" functions return NULL, when any parameter is NULL (so coalesce is abnormal)
4710  }
4711  argValues.append( v );
4712  }
4713  }
4714 
4715  // run the function
4716  QVariant res = fd->func( argValues, context, parent );
4718 
4719  // everything went fine
4720  return res;
4721 }
4722 
4724 {
4725  Function* fd = Functions()[mFnIndex];
4726 
4727  bool res = true;
4728  if ( mArgs && !fd->lazyEval() )
4729  {
4730  Q_FOREACH ( Node* n, mArgs->list() )
4731  {
4732  res = res && n->prepare( parent, context );
4733  }
4734  }
4735  return res;
4736 }
4737 
4739 {
4740  Function* fd = Functions()[mFnIndex];
4741  if ( fd->params() == 0 )
4742  return QString( "%1%2" ).arg( fd->name(), fd->name().startsWith( '$' ) ? "" : "()" ); // special column
4743  else
4744  return QString( "%1(%2)" ).arg( fd->name(), mArgs ? mArgs->dump() : QString() ); // function
4745 }
4746 
4748 {
4749  Function* fd = Functions()[mFnIndex];
4750  QStringList functionColumns = fd->referencedColumns();
4751 
4752  if ( !mArgs )
4753  {
4754  //no referenced columns in arguments, just return function's referenced columns
4755  return functionColumns;
4756  }
4757 
4758  Q_FOREACH ( Node* n, mArgs->list() )
4759  {
4760  functionColumns.append( n->referencedColumns() );
4761  }
4762 
4763  //remove duplicates and return
4764  return functionColumns.toSet().toList();
4765 }
4766 
4768 {
4769  return new NodeFunction( mFnIndex, mArgs ? mArgs->clone() : nullptr );
4770 }
4771 
4772 //
4773 
4775 {
4776  Q_UNUSED( context );
4777  Q_UNUSED( parent );
4778  return mValue;
4779 }
4780 
4782 {
4783  Q_UNUSED( parent );
4784  Q_UNUSED( context );
4785  return true;
4786 }
4787 
4788 
4790 {
4791  if ( mValue.isNull() )
4792  return "NULL";
4793 
4794  switch ( mValue.type() )
4795  {
4796  case QVariant::Int:
4797  return QString::number( mValue.toInt() );
4798  case QVariant::Double:
4799  return QString::number( mValue.toDouble() );
4800  case QVariant::String:
4801  return quotedString( mValue.toString() );
4802  case QVariant::Bool:
4803  return mValue.toBool() ? "TRUE" : "FALSE";
4804  default:
4805  return tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName(), mValue.toString() );
4806  }
4807 }
4808 
4810 {
4811  return new NodeLiteral( mValue );
4812 }
4813 
4814 //
4815 
4817 {
4818  Q_UNUSED( parent );
4819  int index = mIndex;
4820 
4821  if ( index < 0 )
4822  {
4823  // have not yet found field index - first check explicitly set fields collection
4824  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
4825  {
4826  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
4827  index = fields.fieldNameIndex( mName );
4828  }
4829  }
4830 
4831  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
4832  {
4833  QgsFeature feature = context->feature();
4834  if ( index >= 0 )
4835  return feature.attribute( index );
4836  else
4837  return feature.attribute( mName );
4838  }
4839  return QVariant( '[' + mName + ']' );
4840 }
4841 
4843 {
4844  if ( !context || !context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
4845  return false;
4846 
4847  QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
4848 
4849  mIndex = fields.fieldNameIndex( mName );
4850  if ( mIndex >= 0 )
4851  {
4852  return true;
4853  }
4854  else
4855  {
4856  parent->d->mEvalErrorString = tr( "Column '%1' not found" ).arg( mName );
4857  mIndex = -1;
4858  return false;
4859  }
4860 }
4861 
4863 {
4864  return QRegExp( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" ).exactMatch( mName ) ? mName : quotedColumnRef( mName );
4865 }
4866 
4868 {
4869  return new NodeColumnRef( mName );
4870 }
4871 
4872 //
4873 
4875 {
4876  Q_FOREACH ( WhenThen* cond, mConditions )
4877  {
4878  QVariant vWhen = cond->mWhenExp->eval( parent, context );
4879  TVL tvl = getTVLValue( vWhen, parent );
4881  if ( tvl == True )
4882  {
4883  QVariant vRes = cond->mThenExp->eval( parent, context );
4885  return vRes;
4886  }
4887  }
4888 
4889  if ( mElseExp )
4890  {
4891  QVariant vElse = mElseExp->eval( parent, context );
4893  return vElse;
4894  }
4895 
4896  // return NULL if no condition is matching
4897  return QVariant();
4898 }
4899 
4901 {
4902  bool res;
4903  Q_FOREACH ( WhenThen* cond, mConditions )
4904  {
4905  res = cond->mWhenExp->prepare( parent, context )
4906  & cond->mThenExp->prepare( parent, context );
4907  if ( !res ) return false;
4908  }
4909 
4910  if ( mElseExp )
4911  return mElseExp->prepare( parent, context );
4912 
4913  return true;
4914 }
4915 
4917 {
4918  QString msg( "CASE" );
4919  Q_FOREACH ( WhenThen* cond, mConditions )
4920  {
4921  msg += QString( " WHEN %1 THEN %2" ).arg( cond->mWhenExp->dump(), cond->mThenExp->dump() );
4922  }
4923  if ( mElseExp )
4924  msg += QString( " ELSE %1" ).arg( mElseExp->dump() );
4925  msg += QString( " END" );
4926  return msg;
4927 }
4928 
4930 {
4931  QStringList lst;
4932  Q_FOREACH ( WhenThen* cond, mConditions )
4933  {
4934  lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns();
4935  }
4936 
4937  if ( mElseExp )
4938  lst += mElseExp->referencedColumns();
4939 
4940  return lst;
4941 }
4942 
4944 {
4945  Q_FOREACH ( WhenThen* cond, mConditions )
4946  {
4947  if ( cond->mWhenExp->needsGeometry() ||
4948  cond->mThenExp->needsGeometry() )
4949  return true;
4950  }
4951 
4952  if ( mElseExp && mElseExp->needsGeometry() )
4953  return true;
4954 
4955  return false;
4956 }
4957 
4959 {
4960  WhenThenList conditions;
4961  Q_FOREACH ( WhenThen* wt, mConditions )
4962  conditions.append( new WhenThen( wt->mWhenExp->clone(), wt->mThenExp->clone() ) );
4963  return new NodeCondition( conditions, mElseExp ? mElseExp->clone() : nullptr );
4964 }
4965 
4966 
4968 {
4970 
4971  if ( !gFunctionHelpTexts.contains( name ) )
4972  return tr( "function help for %1 missing" ).arg( name );
4973 
4974  const Help &f = gFunctionHelpTexts[ name ];
4975 
4976  name = f.mName;
4977  if ( f.mType == tr( "group" ) )
4978  name = group( name );
4979 
4980 #if QT_VERSION < 0x050000
4981  name = Qt::escape( name );
4982 #else
4983  name = name.toHtmlEscaped();
4984 #endif
4985 
4986  QString helpContents( QString( "<h3>%1</h3>\n<div class=\"description\"><p>%2</p></div>" )
4987  .arg( tr( "%1 %2" ).arg( f.mType, name ),
4988  f.mDescription ) );
4989 
4990  Q_FOREACH ( const HelpVariant &v, f.mVariants )
4991  {
4992  if ( f.mVariants.size() > 1 )
4993  {
4994  helpContents += QString( "<h3>%1</h3>\n<div class=\"description\">%2</p></div>" ).arg( v.mName, v.mDescription );
4995  }
4996 
4997  if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
4998  helpContents += QString( "<h4>%1</h4>\n<div class=\"syntax\">\n" ).arg( tr( "Syntax" ) );
4999 
5000  if ( f.mType == tr( "operator" ) )
5001  {
5002  if ( v.mArguments.size() == 1 )
5003  {
5004  helpContents += QString( "<code><span class=\"functionname\">%1</span> <span class=\"argument\">%2</span></code>" )
5005  .arg( name, v.mArguments[0].mArg );
5006  }
5007  else if ( v.mArguments.size() == 2 )
5008  {
5009  helpContents += QString( "<code><span class=\"argument\">%1</span> <span class=\"functionname\">%2</span> <span class=\"argument\">%3</span></code>" )
5010  .arg( v.mArguments[0].mArg, name, v.mArguments[1].mArg );
5011  }
5012  }
5013  else if ( f.mType != tr( "group" ) && f.mType != tr( "expression" ) )
5014  {
5015  helpContents += QString( "<code><span class=\"functionname\">%1</span>" ).arg( name );
5016 
5017  if ( f.mType == tr( "function" ) && ( f.mName[0] != '$' || !v.mArguments.isEmpty() || v.mVariableLenArguments ) )
5018  {
5019  helpContents += '(';
5020 
5021  QString delim;
5022  Q_FOREACH ( const HelpArg &a, v.mArguments )
5023  {
5024  helpContents += delim;
5025  delim = ", ";
5026  if ( !a.mDescOnly )
5027  {
5028  helpContents += QString( "<span class=\"argument %1\">%2%3</span>" ).arg( a.mOptional ? "optional" : "", a.mArg,
5029  a.mDefaultVal.isEmpty() ? "" : '=' + a.mDefaultVal );
5030  }
5031  }
5032 
5033  if ( v.mVariableLenArguments )
5034  {
5035  helpContents += "...";
5036  }
5037 
5038  helpContents += ')';
5039  }
5040 
5041  helpContents += "</code>";
5042  }
5043 
5044  if ( !v.mArguments.isEmpty() )
5045  {
5046  helpContents += QString( "<h4>%1</h4>\n<div class=\"arguments\">\n<table>" ).arg( tr( "Arguments" ) );
5047 
5048  Q_FOREACH ( const HelpArg &a, v.mArguments )
5049  {
5050  if ( a.mSyntaxOnly )
5051  continue;
5052 
5053  helpContents += QString( "<tr><td class=\"argument\">%1</td><td>%2</td></tr>" ).arg( a.mArg, a.mDescription );
5054  }
5055 
5056  helpContents += "</table>\n</div>\n";
5057  }
5058 
5059  if ( !v.mExamples.isEmpty() )
5060  {
5061  helpContents += QString( "<h4>%1</h4>\n<div class=\"examples\">\n<ul>\n" ).arg( tr( "Examples" ) );
5062 
5063  Q_FOREACH ( const HelpExample &e, v.mExamples )
5064  {
5065  helpContents += "<li><code>" + e.mExpression + "</code> &rarr; <code>" + e.mReturns + "</code>";
5066 
5067  if ( !e.mNote.isEmpty() )
5068  helpContents += QString( " (%1)" ).arg( e.mNote );
5069 
5070  helpContents += "</li>\n";
5071  }
5072 
5073  helpContents += "</ul>\n</div>\n";
5074  }
5075 
5076  if ( !v.mNotes.isEmpty() )
5077  {
5078  helpContents += QString( "<h4>%1</h4>\n<div class=\"notes\"><p>%2</p></div>\n" ).arg( tr( "Notes" ), v.mNotes );
5079  }
5080  }
5081 
5082  return helpContents;
5083 }
5084 
5086 
5088 {
5089  if ( !gVariableHelpTexts.isEmpty() )
5090  return;
5091 
5092  //global variables
5093  gVariableHelpTexts.insert( "qgis_version", QCoreApplication::translate( "variable_help", "Current QGIS version string." ) );
5094  gVariableHelpTexts.insert( "qgis_version_no", QCoreApplication::translate( "variable_help", "Current QGIS version number." ) );
5095  gVariableHelpTexts.insert( "qgis_release_name", QCoreApplication::translate( "variable_help", "Current QGIS release name." ) );
5096  gVariableHelpTexts.insert( "qgis_os_name", QCoreApplication::translate( "variable_help", "Operating system name, eg 'windows', 'linux' or 'osx'." ) );
5097  gVariableHelpTexts.insert( "qgis_platform", QCoreApplication::translate( "variable_help", "QGIS platform, eg 'desktop' or 'server'." ) );
5098  gVariableHelpTexts.insert( "user_account_name", QCoreApplication::translate( "variable_help", "Current user's operating system account name." ) );
5099  gVariableHelpTexts.insert( "user_full_name", QCoreApplication::translate( "variable_help", "Current user's operating system user name (if available)." ) );
5100 
5101  //project variables
5102  gVariableHelpTexts.insert( "project_title", QCoreApplication::translate( "variable_help", "Title of current project." ) );
5103  gVariableHelpTexts.insert( "project_path", QCoreApplication::translate( "variable_help", "Full path (including file name) of current project." ) );
5104  gVariableHelpTexts.insert( "project_folder", QCoreApplication::translate( "variable_help", "Folder for current project." ) );
5105  gVariableHelpTexts.insert( "project_filename", QCoreApplication::translate( "variable_help", "Filename of current project." ) );
5106 
5107  //layer variables
5108  gVariableHelpTexts.insert( "layer_name", QCoreApplication::translate( "variable_help", "Name of current layer." ) );
5109  gVariableHelpTexts.insert( "layer_id", QCoreApplication::translate( "variable_help", "ID of current layer." ) );
5110 
5111  //composition variables
5112  gVariableHelpTexts.insert( "layout_numpages", QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
5113  gVariableHelpTexts.insert( "layout_pageheight", QCoreApplication::translate( "variable_help", "Composition page height in mm." ) );
5114  gVariableHelpTexts.insert( "layout_pagewidth", QCoreApplication::translate( "variable_help", "Composition page width in mm." ) );
5115  gVariableHelpTexts.insert( "layout_dpi", QCoreApplication::translate( "variable_help", "Composition resolution (DPI)." ) );
5116 
5117  //atlas variables
5118  gVariableHelpTexts.insert( "atlas_totalfeatures", QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
5119  gVariableHelpTexts.insert( "atlas_featurenumber", QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
5120  gVariableHelpTexts.insert( "atlas_filename", QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
5121  gVariableHelpTexts.insert( "atlas_pagename", QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
5122  gVariableHelpTexts.insert( "atlas_feature", QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
5123  gVariableHelpTexts.insert( "atlas_featureid", QCoreApplication::translate( "variable_help", "Current atlas feature ID." ) );
5124  gVariableHelpTexts.insert( "atlas_geometry", QCoreApplication::translate( "variable_help", "Current atlas feature geometry." ) );
5125 
5126  //composer item variables
5127  gVariableHelpTexts.insert( "item_id", QCoreApplication::translate( "variable_help", "Composer item user ID (not necessarily unique)." ) );
5128  gVariableHelpTexts.insert( "item_uuid", QCoreApplication::translate( "variable_help", "Composer item unique ID." ) );
5129  gVariableHelpTexts.insert( "item_left", QCoreApplication::translate( "variable_help", "Left position of composer item (in mm)." ) );
5130  gVariableHelpTexts.insert( "item_top", QCoreApplication::translate( "variable_help", "Top position of composer item (in mm)." ) );
5131  gVariableHelpTexts.insert( "item_width", QCoreApplication::translate( "variable_help", "Width of composer item (in mm)." ) );
5132  gVariableHelpTexts.insert( "item_height", QCoreApplication::translate( "variable_help", "Height of composer item (in mm)." ) );
5133 
5134  //map settings item variables
5135  gVariableHelpTexts.insert( "map_id", QCoreApplication::translate( "variable_help", "ID of current map destination. This will be 'canvas' for canvas renders, and the item ID for composer map renders." ) );
5136  gVariableHelpTexts.insert( "map_rotation", QCoreApplication::translate( "variable_help", "Current rotation of map." ) );
5137  gVariableHelpTexts.insert( "map_scale", QCoreApplication::translate( "variable_help", "Current scale of map." ) );
5138  gVariableHelpTexts.insert( "map_extent_center", QCoreApplication::translate( "variable_help", "Center of map." ) );
5139  gVariableHelpTexts.insert( "map_extent_width", QCoreApplication::translate( "variable_help", "Width of map." ) );
5140  gVariableHelpTexts.insert( "map_extent_height", QCoreApplication::translate( "variable_help", "Height of map." ) );
5141 
5142  gVariableHelpTexts.insert( "row_number", QCoreApplication::translate( "variable_help", "Stores the number of the current row." ) );
5143  gVariableHelpTexts.insert( "grid_number", QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
5144  gVariableHelpTexts.insert( "grid_axis", QCoreApplication::translate( "variable_help", "Current grid annotation axis (eg, 'x' for longitude, 'y' for latitude)." ) );
5145 
5146  //symbol variables
5147  gVariableHelpTexts.insert( "geometry_part_count", QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
5148  gVariableHelpTexts.insert( "geometry_part_num", QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );
5149  gVariableHelpTexts.insert( "geometry_point_count", QCoreApplication::translate( "variable_help", "Number of points in the rendered geometry's part. It is only meaningful for line geometries and for symbol layers that set this variable." ) );
5150  gVariableHelpTexts.insert( "geometry_point_num", QCoreApplication::translate( "variable_help", "Current point number in the rendered geometry's part. It is only meaningful for line geometries and for symbol layers that set this variable." ) );
5151 
5152  gVariableHelpTexts.insert( "symbol_color", QCoreApplication::translate( "symbol_color", "Color of symbol used to render the feature." ) );
5153  gVariableHelpTexts.insert( "symbol_angle", QCoreApplication::translate( "symbol_angle", "Angle of symbol used to render the feature (valid for marker symbols only)." ) );
5154 }
5155 
5156 QString QgsExpression::variableHelpText( const QString &variableName, bool showValue, const QVariant &value )
5157 {
5159  QString text = gVariableHelpTexts.contains( variableName ) ? QString( "<p>%1</p>" ).arg( gVariableHelpTexts.value( variableName ) ) : QString();
5160  if ( showValue )
5161  {
5162  QString valueString;
5163  if ( !value.isValid() )
5164  {
5165  valueString = QCoreApplication::translate( "variable_help", "not set" );
5166  }
5167  else
5168  {
5169  valueString = QString( "<b>%1</b>" ).arg( formatPreviewString( value ) );
5170  }
5171  text.append( QCoreApplication::translate( "variable_help", "<p>Current value: %1</p>" ).arg( valueString ) );
5172  }
5173  return text;
5174 }
5175 
5177 
5179 {
5180  if ( gGroups.isEmpty() )
5181  {
5182  gGroups.insert( "General", tr( "General" ) );
5183  gGroups.insert( "Operators", tr( "Operators" ) );
5184  gGroups.insert( "Conditionals", tr( "Conditionals" ) );
5185  gGroups.insert( "Fields and Values", tr( "Fields and Values" ) );
5186  gGroups.insert( "Math", tr( "Math" ) );
5187  gGroups.insert( "Conversions", tr( "Conversions" ) );
5188  gGroups.insert( "Date and Time", tr( "Date and Time" ) );
5189  gGroups.insert( "String", tr( "String" ) );
5190  gGroups.insert( "Color", tr( "Color" ) );
5191  gGroups.insert( "GeometryGroup", tr( "Geometry" ) );
5192  gGroups.insert( "Record", tr( "Record" ) );
5193  gGroups.insert( "Variables", tr( "Variables" ) );
5194  gGroups.insert( "Fuzzy Matching", tr( "Fuzzy Matching" ) );
5195  gGroups.insert( "Recent (%1)", tr( "Recent (%1)" ) );
5196  }
5197 
5198  //return the translated name for this group. If group does not
5199  //have a translated name in the gGroups hash, return the name
5200  //unchanged
5201  return gGroups.value( name, name );
5202 }
5203 
5205 {
5206  if ( value.canConvert<QgsGeometry>() )
5207  {
5208  //result is a geometry
5209  QgsGeometry geom = value.value<QgsGeometry>();
5210  if ( geom.isEmpty() )
5211  return tr( "<i>&lt;empty geometry&gt;</i>" );
5212  else
5213  return tr( "<i>&lt;geometry: %1&gt;</i>" ).arg( QgsWKBTypes::displayString( geom.geometry()->wkbType() ) );
5214  }
5215  else if ( !value.isValid() )
5216  {
5217  return tr( "<i>NULL</i>" );
5218  }
5219  else if ( value.canConvert< QgsFeature >() )
5220  {
5221  //result is a feature
5222  QgsFeature feat = value.value<QgsFeature>();
5223  return tr( "<i>&lt;feature: %1&gt;</i>" ).arg( feat.id() );
5224  }
5225  else if ( value.canConvert< QgsInterval >() )
5226  {
5227  //result is a feature
5228  QgsInterval interval = value.value<QgsInterval>();
5229  return tr( "<i>&lt;interval: %1 days&gt;</i>" ).arg( interval.days() );
5230  }
5231  else if ( value.type() == QVariant::Date )
5232  {
5233  QDate dt = value.toDate();
5234  return tr( "<i>&lt;date: %1&gt;</i>" ).arg( dt.toString( "yyyy-MM-dd" ) );
5235  }
5236  else if ( value.type() == QVariant::Time )
5237  {
5238  QTime tm = value.toTime();
5239  return tr( "<i>&lt;time: %1&gt;</i>" ).arg( tm.toString( "hh:mm:ss" ) );
5240  }
5241  else if ( value.type() == QVariant::DateTime )
5242  {
5243  QDateTime dt = value.toDateTime();
5244  return tr( "<i>&lt;datetime: %1&gt;</i>" ).arg( dt.toString( "yyyy-MM-dd hh:mm:ss" ) );
5245  }
5246  else if ( value.type() == QVariant::String )
5247  {
5248  QString previewString = value.toString();
5249  if ( previewString.length() > 63 )
5250  {
5251  return QString( tr( "'%1...'" ) ).arg( previewString.left( 60 ) );
5252  }
5253  else
5254  {
5255  return previewString.prepend( '\'' ).append( '\'' );
5256  }
5257  }
5258  else
5259  {
5260  return value.toString();
5261  }
5262 }
5263 
5264 QVariant QgsExpression::Function::func( const QVariantList& values, const QgsFeature* feature, QgsExpression* parent )
5265 {
5266  //default implementation creates a QgsFeatureBasedExpressionContext
5268  return func( values, &c, parent );
5269 }
5270 
5271 QVariant QgsExpression::Function::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
5272 {
5273  //base implementation calls deprecated func to avoid API breakage
5274  QgsFeature f;
5275  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
5276  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
5277 
5279  return func( values, &f, parent );
5281 }
5282 
5284 {
5285  //default implementation creates a QgsFeatureBasedExpressionContext
5287  return eval( parent, &c );
5288 }
5289 
5291 {
5292  //base implementation calls deprecated eval to avoid API breakage
5293  QgsFeature f;
5294  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) )
5295  f = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) );
5296 
5298  return eval( parent, &f );
5300 }
5301 
5303 {
5305  return prepare( parent, &c );
5306 }
5307 
5309 {
5310  //base implementation calls deprecated prepare to avoid API breakage
5311  QgsFields f;
5312  if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) )
5313  f = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) );
5314 
5316  return prepare( parent, f );
5318 }
5319 
5320 QVariant QgsExpression::StaticFunction::func( const QVariantList &values, const QgsFeature* f, QgsExpression* parent )
5321 {
5323  return mFnc ? mFnc( values, f, parent ) : QVariant();
5325 }
5326 
5328 {
5329  QString expr;
5330 
5331  if ( value.isNull() )
5332  expr = QString( "%1 IS NULL" ).arg( quotedColumnRef( fieldName ) );
5333  else
5334  expr = QString( "%1 = %2" ).arg( quotedColumnRef( fieldName ), quotedValue( value ) );
5335 
5336  return expr;
5337 }
5338 
5340 {
5341  return d->mRootNode;
5342 }
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the desired areal units for calculations involving geomCalculator(), eg "$area".
static bool isFunctionName(const QString &name)
tells whether the identifier is a name of existing function
static QVariant fcnDisjoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnConvexHull(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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:199
bool canConvert(Type t) const
Class for parsing and evaluation of expressions (formerly called "search strings").
qlonglong toLongLong(bool *ok) const
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
virtual QStringList referencedColumns() const =0
Abstract virtual method which returns a list of columns required to evaluate this node...
static QVariant fcnNodesToPoints(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGeomNumInteriorRings(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant cachedValue(const QString &key) const
Returns the matching cached value, if set.
Wrapper for iterator of features from vector data provider or vector layer.
static QVariant fcnAggregateMax(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Third quartile (numeric fields only)
QString toString(Qt::DateFormat format) const
static QVariant fcnGeomLength(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
int minute() const
bool isValid() const
Returns the validity of this relation.
QColor fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static QVariant fcnSin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static unsigned index
static QVariant fcnClosestPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const QgsCurveV2 * exteriorRing() const
virtual Q_DECL_DEPRECATED QVariant eval(QgsExpression *parent, const QgsFeature *f)
Abstract virtual eval method Errors are reported to the parent.
Base class for all map layer types.
Definition: qgsmaplayer.h:49
static QVariant fcnBoundsWidth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnY(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
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.
QString cap(int nth) const
static QVariant fcnGeomPerimeter(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
double convertLengthMeasurement(double length, QGis::UnitType toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
int numGeometries() const
Returns the number of geometries within the collection.
bool isEmpty() const
Returns true if the geometry is empty.
QString & append(QChar ch)
virtual Node * clone() const =0
Generate a clone of this node.
iterator insert(const Key &key, const T &value)
QString toUpper() const
static QVariant fcnAtlasCurrentGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnGeomFromWKT(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QColor darker(int factor) const
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
virtual Q_DECL_DEPRECATED QVariant func(const QVariantList &values, const QgsFeature *f, QgsExpression *parent) override
static QVariant fcnFormatDate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsCoordinateReferenceSystem crsByOgcWmsCrs(const QString &ogcCrs) const
Returns the CRS from a given OGC WMS-format Coordinate Reference System string.
iterator erase(iterator pos)
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
const QgsCurveV2 * interiorRing(int i) const
static QVariant fncLighter(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Median of values (numeric fields only)
QPointF toPointF() const
static QVariant fcnFormatString(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void acceptVisitor(Visitor &v) const
Entry function for the visitor pattern.
bool intersects(const QgsRectangle &r) const
Test for intersection with a rectangle (uses GEOS)
QgsGeometry * symDifference(const QgsGeometry *geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
bool contains(const Key &key) const
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
static QVariant fcnBuffer(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:142
virtual QgsCoordinateSequenceV2 coordinateSequence() const =0
Retrieves the sequence of geometries, rings and nodes.
qreal alphaF() const
static QVariant fcnGeomNumRings(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnShortestLine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnClamp(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGetGeometry(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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:76
QString toString(Qt::DateFormat format) const
static QVariant fcnMakeLine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString toString(Qt::DateFormat format) const
static QVariant fcnStrpos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static void initVariableHelp()
bool hasFunction(const QString &name) const
Checks whether a specified function is contained in the context.
QString name() const
static QVariant fcnXat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QDateTime computeDateTimeFromInterval(const QDateTime &d, QgsInterval *i)
Computes the result date time calculation from a start datetime and an interval.
static QString group(const QString &group)
Returns the translated name for a function group.
void initGeomCalculator()
static QVariant fcnWordwrap(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateSum(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QgsVectorLayer * getVectorLayer(const QVariant &value, QgsExpression *)
int length() const
A abstract base class for defining QgsExpression functions.
bool touches(const QgsGeometry *geometry) const
Test for if geometry touch another (uses GEOS)
double angleAtVertex(int vertex) const
Returns the bisector angle for this geometry at the specified vertex.
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
static QVariant fcnCentroid(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool operator==(const QgsExpression &other) const
Compares two expressions.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static QVariant fcnAggregateRelation(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
double computeDouble(double x, double y)
static QVariant fcnProject(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnIf(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
First quartile (numeric fields only)
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
Number of missing (null) values.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static QString encodeColor(const QColor &color)
QDateTime toDateTime() const
static QgsExpressionContext createFeatureBasedContext(const QgsFeature &feature, const QgsFields &fields)
Helper function for creating an expression context which contains just a feature and fields collectio...
QStringList referencedColumns() const
Get list of columns referenced by the expression.
QString & prepend(QChar ch)
virtual QString dump() const =0
Abstract virtual dump method.
int value() const
static QVariant fcnPi(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QDate getDateValue(const QVariant &value, QgsExpression *parent)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
virtual Node * clone() const override
Generate a clone of this node.
QString dump() const
Return an expression string, constructed from the internal abstract syntax tree.
static QVariant pointAt(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
bool hasCachedValue(const QString &key) const
Returns true if the expression context contains a cached value with a matching key.
QString escape(const QString &str)
static QVariant fcnAtan2(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QString helptext(QString name)
Returns the help text for a specified function.
#define FEAT_FROM_CONTEXT(c, f)
static QVariant fcnMapId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
const_iterator constBegin() const
static QVariant fcnRegexpMatch(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const T & at(int i) const
static QVariant fcnFloor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QTime toTime() const
QVariant evaluate()
Evaluate the feature and return the result.
int size() const
static QVariant fncColorCmyka(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAcos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAbs(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void removeAt(int i)
static QVariant fcnDistanceToVertex(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateRange(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:515
QgsExpression()
Create an empty expression.
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:131
bool isValid() const
static QVariant fcnAggregateMaxLength(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
QString evalErrorString() const
Returns evaluation error.
Abstract base class for all geometries.
T value() const
static QVariant fncColorHsva(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setBlue(int blue)
Container of fields for a vector layer.
Definition: qgsfield.h:252
static QgsInterval fromString(const QString &string)
Converts a string to an interval.
Definition: qgsinterval.cpp:52
static QVariant fcnAge(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToTime(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool hasVariable(const QString &name) const
Check whether a variable is specified by any scope within the context.
virtual Q_DECL_DEPRECATED bool prepare(QgsExpression *parent, const QgsFields &fields)
Abstract virtual preparation method Errors are reported to the parent.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void setAlpha(int alpha)
static const char * vectorGeometryType(GeometryType type)
description strings for geometry types
Definition: qgis.cpp:441
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
const_iterator constFind(const Key &key) const
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
QgsExpression::Node * parseExpression(const QString &str, QString &parserErrorMsg)
QSet< T > toSet() const
static QVariant fcnTouches(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QTime getTimeValue(const QVariant &value, QgsExpression *parent)
bool isDoubleSafe(const QVariant &v)
static QVariant fcnWithin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnExpScale(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateCountDistinct(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Multi point geometry collection.
c++ helper class for defining QgsExpression functions.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
double distanceToVertex(int vertex) const
Returns the distance along this geometry from its first vertex to the specified vertex.
static QString formatPreviewString(const QVariant &value)
Formats an expression result for friendly display to the user.
bool contains(const QgsPoint *p) const
Test for containment of a point (uses GEOS)
static QVariant fcnMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpVariant > mVariants
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
QgsRelationManager * relationManager() const
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
static QVariant fcnLCS(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
virtual QgsCurveV2 * clone() const override=0
Clones the geometry by performing a deep copy.
static QVariant fcnXMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setRed(int red)
static TVL getTVLValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnFormatNumber(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLineMerge(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int month() const
Q_DECL_DEPRECATED int currentRowNumber()
Return the number used for $rownum special column.
qreal hslHueF() const
double toDouble(bool *ok) const
QgsGeometry nearestPoint(const QgsGeometry &other) const
Returns the nearest point on this geometry to another geometry.
static QVariant fcnToDateTime(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal cyanF() const
static QVariant fncColorHsla(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int weekNumber(int *yearNumber) const
QString parserErrorString() const
Returns parser error.
Multi line string geometry collection.
QString tr(const char *sourceText, const char *disambiguation, int n)
static QVariant fncColorPart(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAzimuth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString delimiter
Delimiter to use for joining values with the StringConcatenate aggregate.
static QString soundex(const QString &string)
Returns the Soundex representation of a string.
bool lazyEval() const
True if this function should use lazy evaluation.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
int second() const
static QVariant fcnComposerPage(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
virtual Node * clone() const override
Generate a clone of this node.
static QVariant fncDarker(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
static QVariant fcnGeomArea(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnLevenshtein(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int size() const
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
QString what() const
Definition: qgsexception.h:36
void setEvalErrorString(const QString &str)
Set evaluation error (used internally by evaluation functions)
QgsGeometry * centroid() const
Returns the center of mass of a geometry.
static QgsGeometry getGeometry(const QVariant &value, QgsExpression *parent)
#define ENSURE_NO_EVAL_ERROR
virtual bool handlesNull() const
const QgsVectorColorRampV2 * colorRampRef(const QString &name) const
return a const pointer to a symbol (doesn&#39;t create new instance)
Definition: qgsstylev2.cpp:263
static QVariant fcnToReal(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static Q_DECL_DEPRECATED void setSpecialColumn(const QString &name, const QVariant &value)
Assign a special column.
static QVariant fcnYat(const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent)
QgsFields fields() const
Returns the list of fields of this layer.
virtual QString dump() const override
Abstract virtual dump method.
QgsGeometry * difference(const QgsGeometry *geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...
int lightness() const
static QVariant fcnCos(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QStringList & BuiltinFunctions()
int dayOfWeek() const
void setPattern(const QString &pattern)
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
static QVariant fcnSymDifference(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QStringList referencedColumns() const
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
static bool unregisterFunction(const QString &name)
Unregisters a function from the expression engine.
static const QList< Function * > & Functions()
static QVariant fcnAggregateIQR(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
int matchedLength() const
static QVariant fcnGetLayerProperty(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnSegmentsToLines(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnColorHsl(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnExteriorRing(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int indexIn(const QString &str, int offset, CaretMode caretMode) const
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
static QVariant fcnMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Polygon geometry type.
Definition: qgspolygonv2.h:29
QgsUnitTypes::AreaUnit areaUnits() const
Returns the desired areal units for calculations involving geomCalculator(), eg "$area".
static QVariant fcnAggregateMean(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fncSetColorPart(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static QVariant fcnAtlasFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static int functionCount()
Returns the number of functions defined in the parser.
static QVariant fcnRndF(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool needsGeometry() const override
Abstract virtual method which returns if the geometry is required to evaluate this expression...
static QVariant fcnMinute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateMin(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
void setGeometry(const QgsGeometry &geom)
Set this feature&#39;s geometry from another QgsGeometry object.
Definition: qgsfeature.cpp:124
static QVariant fcnTrim(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * convexHull() const
Returns the smallest convex polygon that contains all the points in the geometry. ...
static QVariant fcnAggregateMinority(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QString number(int n, int base)
int count(const T &value) const
static QVariant fcnMonth(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsDistanceArea * geomCalculator()
Return calculator used for distance and area calculations (used by $length, $area and $perimeter func...
static QVariant fcnTranslate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnStartPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal x() const
qreal y() const
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
void setGreen(int green)
void append(const T &value)
static QVariant fcnLn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnMakePoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsExpressionPrivate * d
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
static QVariant fcnGeomY(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define TVL_Unknown
virtual void setExteriorRing(QgsCurveV2 *ring) override
Sets the exterior ring of the polygon.
virtual Node * clone() const override
Generate a clone of this node.
#define FALLTHROUGH
Definition: qgis.h:539
virtual QgsCurveV2 * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
static void initFunctionHelp()
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
int toInt(bool *ok) const
bool isNull() const
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:29
static QVariant fcnIntersects(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< Parameter > ParameterList
List of parameters, used for function definition.
static QVariant fcnColorHsv(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * pointOnSurface() const
Returns a point within a geometry.
static QVariant fcnCoalesce(const QVariantList &values, const QgsExpressionContext *, QgsExpression *)
static int functionIndex(const QString &name)
return index of the function in Functions array
static QVariant fcnRelate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString rightJustified(int width, QChar fill, bool truncate) const
Utility class for identifying a unique vertex within a geometry.
virtual Q_DECL_DEPRECATED QVariant func(const QVariantList &, const QgsFeature *, QgsExpression *)
virtual QString dump() const override
Abstract virtual dump method.
bool isValid() const
Checks if this expression is valid.
Line string geometry type, with support for z-dimension and m-values.
static QVariant fcnScale(const QVariantList &, const QgsExpressionContext *, QgsExpression *parent)
static Aggregate stringToAggregate(const QString &string, bool *ok=nullptr)
Converts a string to a aggregate type.
int red() const
static QVariant fcnRowNumber(const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent)
qreal valueF() const
QList< QgsRelation > relationsByName(const QString &name) const
Returns a list of relations with matching names.
static QVariant fcnConcat(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
void setPoints(const QgsPointSequenceV2 &points)
Resets the line string to match the specified list of points.
static QVariant fcnGeomNumGeometries(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Minimum length of string (string fields only)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnHamming(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnOrderParts(const QVariantList &values, const QgsExpressionContext *ctx, QgsExpression *parent)
static QgsGeometry * geometryFromGML(const QString &xmlString)
Static method that creates geometry from GML.
#define SET_EVAL_ERROR(x)
static void cleanRegisteredFunctions()
Deletes all registered functions whose ownership have been transferred to the expression engine...
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 width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
QgsExpression & operator=(const QgsExpression &other)
Create a copy of this expression.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
int toInt(bool *ok, int base) const
static QHash< QString, QString > gGroups
bool isEmpty() const
static QVariant fcnAtlasFeatureId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static bool registerFunction(Function *function, bool transferOwnership=false)
Registers a function to the expression engine.
static QgsInterval getInterval(const QVariant &value, QgsExpression *parent, bool report_error=false)
static QgsStyleV2 * defaultStyle()
return default application-wide style
Definition: qgsstylev2.cpp:51
bool isEmpty() const
static bool hasSpecialColumn(const QString &name)
Check whether a special column exists.
QString trimmed() const
static QVariant fcnIntersection(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const_iterator constEnd() const
int day() const
static QVariant fcnRadians(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsGeometry * interpolate(double distance) const
Return interpolated point on line at distance.
static QVariant fcnAggregateGeneric(QgsAggregateCalculator::Aggregate aggregate, const QVariantList &values, QgsAggregateCalculator::AggregateParameters parameters, const QgsExpressionContext *context, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
static QVariant fcnUpper(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define M_PI
static QVariant fcnToInt(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToDate(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
qreal lightnessF() const
bool crosses(const QgsGeometry *geometry) const
Test for if geometry crosses another (uses GEOS)
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static QVariant fcnGeomX(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual Node * clone() const override
Generate a clone of this node.
bool isValid() const
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
void addInteriorRing(QgsCurveV2 *ring) override
Adds an interior ring to the geometry (takes ownership)
Represents a single parameter passed to a function.
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
static const QString AllAttributes
A special attribute that if set matches all attributes.
QString name() const
The name of the function.
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
static QVariant fcnExp(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnPointOnSurface(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual Node * clone() const override
Generate a clone of this node.
static QHash< QString, QString > gVariableHelpTexts
static QVariant fcnContains(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnToInterval(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define TVL_False
QString exportToWkt(int precision=17) const
Exports the geometry to WKT.
virtual int partCount() const override
Returns count of parts contained in the geometry.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
int year() const
QGis::GeometryType geometryType() const
Returns point, line or polygon.
static QVariant fcnLog10(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnBoundsHeight(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
T & first()
static QVariant fcnRight(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpArg > mArguments
static QList< Function * > gmFunctions
static QVariant fcnDifference(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
iterator end()
static QVariant fcnCrosses(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool within(const QgsGeometry *geometry) const
Test for if geometry is within another (uses GEOS)
static const QString EXPR_FIELDS
Inbuilt variable name for fields storage.
static QVariant fcnChar(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Q_DECL_DEPRECATED void setCurrentRowNumber(int rowNumber)
Set the number for $rownum special column.
static QVariant tvl2variant(TVL v)
static QVariant fcnLineInterpolatePoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define ENSURE_GEOM_TYPE(f, g, geomtype)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
qreal hsvHueF() const
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings.
static QVariant fcnAsin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnYMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGetFeature(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QList< HelpExample > mExamples
static QVariant fcnToString(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int alpha() const
bool isIntervalSafe(const QVariant &v)
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
Create an expression allowing to evaluate if a field is equal to a value.
A class to represent a point.
Definition: qgspoint.h:117
static QVariant fcnNow(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
iterator begin()
static QVariant fcnFeatureId(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnEval(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Majority of values (numeric fields only)
static QVariant fcnIsClosed(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnDistance(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static int getIntValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnAggregate(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
int translate(double dx, double dy)
Translate this geometry by dx, dy.
QgsGeometry * combine(const QgsGeometry *geometry) const
Returns a geometry representing all the points in this geometry and other (a union geometry operation...
double length() const
Returns the length of geometry using GEOS.
virtual int ringCount(int=0) const override
static QVariant fcnBbox(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnRound(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int hour() const
int green() const
static QVariant fcnGeomZ(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString toLower() const
const T value(const Key &key) const
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
static QVariant fcnAggregateQ1(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
QgsGeometry extrude(double x, double y)
Returns an extruded version of this geometry.
double weeks() const
Returns the interval duration in weeks.
Definition: qgsinterval.h:87
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometryV2 *geometry)
Creates and returns a new geometry engine.
static QVariant fcnGeomFromGML(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
int fieldNameIndex(const QString &fieldName) const
Look up field&#39;s index from name also looks up case-insensitive if there is no match otherwise...
Definition: qgsfield.cpp:571
bool contains(QChar ch, Qt::CaseSensitivity cs) const
static QVariant fcnAggregateMedian(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
virtual QgsAbstractGeometryV2 * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
void setHslF(qreal h, qreal s, qreal l, qreal a)
QVariant aggregate(QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression, const QgsAggregateCalculator::AggregateParameters &parameters=QgsAggregateCalculator::AggregateParameters(), QgsExpressionContext *context=nullptr, bool *ok=nullptr)
Calculates an aggregated value from the layer&#39;s features.
virtual QVariant eval(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual eval method Errors are reported to the parent.
static QVariant fcnSeconds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsVectorLayer * referencedLayer() const
Access the referenced (parent) layer.
static QVariant fcnMakePointM(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QString expression() const
Return the original, unmodified expression string.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:202
void setHsvF(qreal h, qreal s, qreal v, qreal a)
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
static QVariant fcnExtrude(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnArea(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnCeil(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnHour(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGeomNumPoints(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QColor lighter(int factor) const
QStringRef midRef(int position, int n) const
static QVariant fcnLeft(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fromValue(const T &value)
static QString getStringValue(const QVariant &value, QgsExpression *)
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:34
The OrderByClause class represents an order by clause for a QgsFeatureRequest.
static QVariant fcnDegrees(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:187
static QVariant fcnSoundex(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsFeature getFeature(const QVariant &value, QgsExpression *parent)
static QVariant fcnRPad(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateStringConcat(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnLog(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
double days() const
Returns the interval duration in days.
Definition: qgsinterval.h:98
static double getDoubleValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnLineInterpolateAngle(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:516
General purpose distance and area calculator.
QgsExpression::Function * function(const QString &name) const
Fetches a matching function from the context.
static QVariant fcnAtlasCurrentFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
virtual Node * clone() const override
Generate a clone of this node.
static QVariant fcnX(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QDate toDate() const
QString & replace(int position, int n, QChar after)
static QMap< QString, QString > gmSpecialColumnGroups
virtual QString dump() const override
Abstract virtual dump method.
static void registerContextFunctions()
Registers all known core functions provided by QgsExpressionContextScope objects. ...
Maximum length of string (string fields only)
void addVertex(const QgsPointV2 &pt)
Adds a new vertex to the end of the line string.
int blue() const
static QVariant fcnPointN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnBounds(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
qreal yellowF() const
QgsVectorLayer * referencingLayer() const
Access the referencing (child) layer This is the layer which has the field(s) which point to another ...
static QVariant fcnFeature(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnGetVariable(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
QVariant(* FcnEvalContext)(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
Function definition for evaluation against an expression context, using a list of values as parameter...
static QVariant fcnOverlaps(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QDateTime currentDateTime()
QString getRelatedFeaturesFilter(const QgsFeature &feature) const
Returns a filter expression which returns all the features on the referencing (child) layer which hav...
QString filter
Optional filter for calculating aggregate over a subset of features, or an empty string to use all fe...
bool isIntSafe(const QVariant &v)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
static QHash< QString, Help > gFunctionHelpTexts
QString mid(int position, int n) const
double years() const
Returns the interval duration in years (based on an average year length)
Definition: qgsinterval.h:65
QDate date() const
virtual QString dump() const
bool isDateTimeSafe(const QVariant &v)
static const char * UnaryOperatorText[]
static QVariant fcnDay(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Mean of values (numeric fields only)
static QVariant fcnGeometryN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static const QString EXPR_FEATURE
Inbuilt variable name for feature storage.
static QVariant fcnTransformGeometry(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QList< QgsLineStringV2 * > extractLineStrings(const QgsAbstractGeometryV2 *geom)
Returns list of linestrings extracted from the passed geometry.
static QVariant fcnComposerNumPages(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
int secsTo(const QDateTime &other) const
static QVariant fcnLPad(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isEmpty() const
static QgsExpression::Node * getNode(const QVariant &value, QgsExpression *parent)
QString escape(const QString &plain)
static QVariant fcnReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
qreal hsvSaturationF() const
double minutes() const
Returns the interval duration in minutes.
Definition: qgsinterval.h:120
static QList< Function * > specialColumns()
Returns a list of special Column definitions.
static TVL OR[3][3]
bool vertexIdFromVertexNr(int nr, QgsVertexId &id) const
Calculates the vertex ID from a vertex number.
QVariant value() const
The value of the literal.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
static TVL NOT[3]
QgsRectangle boundingBox() const
Returns the bounding box of this feature.
static QVariant fcnAtan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
T & last()
QgsGeometry shortestLine(const QgsGeometry &other) const
Returns the shortest line joining this geometry to another geometry.
Class for storing a coordinate reference system (CRS)
static QVariant fcnLineLocatePoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool addGeometry(QgsAbstractGeometryV2 *g)
Adds a geometry and takes ownership.
double hours() const
Returns the interval duration in hours.
Definition: qgsinterval.h:109
QString translate(const char *context, const char *sourceText, const char *disambiguation, Encoding encoding)
static QVariant fcnAggregateCount(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnAttribute(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QStringList referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node...
void setDistanceUnits(QGis::UnitType unit)
Sets the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perim...
static QVariant fcnAngleAtVertex(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnMakePolygon(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAtlasNumFeatures(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
QList< T > mid(int pos, int length) const
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
QgsGeometry * intersection(const QgsGeometry *geometry) const
Returns a geometry representing the points shared by this geometry and other.
static QVariant fcnXMax(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
Class for doing transforms between two map coordinate systems.
#define TVL_True
int length() const
Support for visitor pattern - algorithms dealing with the expressions may be implemented without modi...
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
static QVariant fcnAggregateStdev(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
bool toBool() const
QString leftJustified(int width, QChar fill, bool truncate) const
int lastIndexOf(const QRegExp &rx, int from) const
UnitType
Map units that qgis supports.
Definition: qgis.h:159
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:192
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
static QVariant fcnInteriorRingN(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
qreal hslSaturationF() const
void setHsl(int h, int s, int l, int a)
virtual bool needsGeometry() const =0
Abstract virtual method which returns if the geometry is required to evaluate this expression...
void setHsv(int h, int s, int v, int a)
QString left(int n) const
static QVariant fcnGeomToWKT(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static Q_DECL_DEPRECATED QString replaceExpressionText(const QString &action, const QgsFeature *feat, QgsVectorLayer *layer, const QMap< QString, QVariant > *substitutionMap=nullptr, const QgsDistanceArea *distanceArea=nullptr)
This function currently replaces each expression between [% and %] in the string with the result of i...
double measureLength(const QgsGeometry *geometry) const
Measures the length of a geometry.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
void setGeomCalculator(const QgsDistanceArea &calc)
Sets the geometry calculator used for distance and area calculations in expressions.
static QVariant fcnColorCmyk(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateMinLength(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnSqrt(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool isValid() const
static QVariant fcnTitle(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QStringList gmBuiltinFunctions
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:197
int indexOf(const QRegExp &rx, int from) const
static QVariant fcnRnd(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
bool disjoint(const QgsGeometry *geometry) const
Test for if geometry is disjoint of another (uses GEOS)
static QString variableHelpText(const QString &variableName, bool showValue=true, const QVariant &value=QVariant())
Returns the help text for a specified variable.
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
static QVariant fcnYMin(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnGeometry(const QVariantList &, const QgsExpressionContext *context, QgsExpression *)
static QVariant fcnUuid(const QVariantList &, const QgsExpressionContext *, QgsExpression *)
int params() const
The number of parameters this function takes.
qreal magentaF() const
static Q_DECL_DEPRECATED QVariant specialColumn(const QString &name)
Return the value of the given special column or a null QVariant if undefined.
Custom exception class for Coordinate Reference System related exceptions.
Curve polygon geometry type.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
static QVariant fcnBoundary(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QgsGeometry * fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
static QVariant fcnReverse(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnEndPoint(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
double area() const
Returns the area of the geometry using GEOS.
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
bool nextFeature(QgsFeature &f)
static QList< Function * > gmOwnedFunctions
List of functions owned by the expression engine.
static QVariant fcnTan(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
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)
QDateTime addSecs(int s) const
virtual QgsAbstractGeometryV2 * clone() const =0
Clones the geometry by performing a deep copy.
static QString displayString(Type type)
Returns a display string type for a WKB type, eg the geometry name used in WKT geometry representatio...
Definition: qgswkbtypes.cpp:48
Type type() const
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
static QVariant fcnPerimeter(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsPoint project(double distance, double bearing) const
Returns a new point which correponds to this point projected by a specified distance in a specified b...
Definition: qgspoint.cpp:380
Geometry is not required. It may still be returned if e.g. required for a filter condition.
void setScale(double scale)
static TVL AND[3][3]
QgsRelation relation(const QString &id) const
Get access to a relation by its id.
static QVariant fcnRegexpReplace(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Represents a vector layer which manages a vector based data sets.
int hslSaturation() const
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
int compare(const QString &other) const
Abstract base class for color ramps.
void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
Range of values (max - min) (numeric and datetime fields only)
static QVariant fcnAggregateQ3(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static QVariant fcnLinearScale(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
bool exactMatch(const QString &str) const
static double evaluateToDouble(const QString &text, const double fallbackValue)
Attempts to evaluate a text string as an expression to a resultant double value.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QString toString() const
virtual QStringList referencedColumns() const override
Abstract virtual method which returns a list of columns required to evaluate this node...
static QgsCRSCache * instance()
Returns a pointer to the QgsCRSCache singleton.
Definition: qgscrscache.cpp:91
static QVariant fcnAggregateCountMissing(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
void detach()
Helper for implicit sharing.
iterator find(const Key &key)
static QVariant fcnGeomM(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
AreaUnit
Units of area.
Definition: qgsunittypes.h:49
bool isNull(const QVariant &v)
double lineLocatePoint(const QgsGeometry &point) const
Returns a distance representing the location along this linestring of the closest point on this lines...
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
static QVariant fcnDayOfWeek(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual QString dump() const override
Abstract virtual dump method.
virtual void clear() override
Clears the geometry, ie reset it to a null geometry.
QGis::UnitType distanceUnits() const
Returns the desired distance units for calculations involving geomCalculator(), eg "$length" and "$pe...
virtual bool prepare(QgsExpression *parent, const QgsExpressionContext *context) override
Abstract virtual preparation method Errors are reported to the parent.
bool overlaps(const QgsGeometry *geometry) const
Test for if geometry overlaps another (uses GEOS)
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
static QVariant fcnSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QUuid createUuid()
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
virtual QgsPointV2 vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
QColor fromHsvF(qreal h, qreal s, qreal v, qreal a)
Sample standard deviation of values (numeric fields only)
Aggregate
Available aggregates to calculate.
static QVariant fcnYear(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static int hammingDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Hamming distance between two strings.
int hsvSaturation() const
qreal blackF() const
Represents a list of OrderByClauses, with the most important first and the least important last...
static QVariant fcnRegexpSubstr(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
virtual Node * clone() const override
Generate a clone of this node.
int numPoints() const override
Returns the number of points in the curve.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:212
bool isValid() const
QList< QgsPointV2 > QgsPointSequenceV2
QColor fromHslF(qreal h, qreal s, qreal l, qreal a)
NodeList * clone() const
Creates a deep copy of this list.
static QVariant fcnColorRgb(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fncColorRgba(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
const T value(const Key &key) const
A bundle of parameters controlling aggregate calculation.
static QDateTime getDateTimeValue(const QVariant &value, QgsExpression *parent)
static QVariant fcnCombine(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QVariant fcnRampColor(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnAggregateMajority(const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent)
static Q_DECL_DEPRECATED void unsetSpecialColumn(const QString &name)
Unset a special column.
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
static QVariant fcnSpecialColumn(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
static QVariant fcnLength(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
int numInteriorRings() const
static QVariant fcnLower(const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent)
QgsPointV2 pointN(int i) const
Returns the specified point from inside the line string.
static const char * BinaryOperatorText[]
static QMap< QString, QVariant > gmSpecialColumns