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