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