QGIS API Documentation  2.17.0-Master (0497e4a)
qgsexpression.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpression.cpp
3  -------------------
4  begin : August 2011
5  copyright : (C) 2011 Martin Dobias
6  email : wonder.sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsexpression.h"
17 
18 #include <QtDebug>
19 #include <QDomDocument>
20 #include <QDate>
21 #include <QRegExp>
22 #include <QColor>
23 #include <QUuid>
24 #include <QMutex>
25 
26 #include <math.h>
27 #include <limits>
28 
29 #include "qgsdistancearea.h"
30 #include "qgsfeature.h"
31 #include "qgsgeometry.h"
32 #include "qgsgeometryengine.h"
33 #include "qgsgeometryutils.h"
34 #include "qgslogger.h"
35 #include "qgsmaplayerregistry.h"
36 #include "qgsogcutils.h"
37 #include "qgsvectorlayer.h"
38 #include "qgssymbollayerv2utils.h"
39 #include "qgsvectorcolorrampv2.h"
40 #include "qgsstylev2.h"
41 #include "qgsexpressioncontext.h"
42 #include "qgsproject.h"
43 #include "qgsstringutils.h"
45 #include "qgspointv2.h"
46 #include "qgspolygonv2.h"
47 #include "qgsmultipointv2.h"
48 #include "qgsmultilinestringv2.h"
49 #include "qgscurvepolygonv2.h"
50 #include "qgsexpressionprivate.h"
51 #include "qgsexpressionsorter.h"
52 #include "qgscrscache.h"
53 #include "qgsmessagelog.h"
54 #include "qgscsexception.h"
55 
56 #if QT_VERSION < 0x050000
57 #include <qtextdocument.h>
58 #endif
59 
60 // from parser
61 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
62 
64 // three-value logic
65 
66 enum TVL
67 {
71 };
72 
73 static TVL AND[3][3] =
74 {
75  // false true unknown
76  { False, False, False }, // false
77  { False, True, Unknown }, // true
78  { False, Unknown, Unknown } // unknown
79 };
80 
81 static TVL OR[3][3] =
82 {
83  { False, True, Unknown }, // false
84  { True, True, True }, // true
85  { Unknown, True, Unknown } // unknown
86 };
87 
88 static TVL NOT[3] = { True, False, Unknown };
89 
91 {
92  switch ( v )
93  {
94  case False:
95  return 0;
96  case True:
97  return 1;
98  case Unknown:
99  default:
100  return QVariant();
101  }
102 }
103 
104 #define TVL_True QVariant(1)
105 #define TVL_False QVariant(0)
106 #define TVL_Unknown QVariant()
107 
109 // QVariant checks and conversions
110 
111 inline bool isIntSafe( const QVariant& v )
112 {
113  if ( v.type() == QVariant::Int ) return true;
114  if ( v.type() == QVariant::UInt ) return true;
115  if ( v.type() == QVariant::LongLong ) return true;
116  if ( v.type() == QVariant::ULongLong ) return true;
117  if ( v.type() == QVariant::Double ) return false;
118  if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
119  return false;
120 }
121 inline bool isDoubleSafe( const QVariant& v )
122 {
123  if ( v.type() == QVariant::Double ) return true;
124  if ( v.type() == QVariant::Int ) return true;
125  if ( v.type() == QVariant::UInt ) return true;
126  if ( v.type() == QVariant::LongLong ) return true;
127  if ( v.type() == QVariant::ULongLong ) return true;
128  if ( v.type() == QVariant::String )
129  {
130  bool ok;
131  double val = v.toString().toDouble( &ok );
132  ok = ok && qIsFinite( val ) && !qIsNaN( val );
133  return ok;
134  }
135  return false;
136 }
137 
138 inline bool isDateTimeSafe( const QVariant& v )
139 {
140  return v.type() == QVariant::DateTime || v.type() == QVariant::Date ||
141  v.type() == QVariant::Time;
142 }
143 
144 inline bool isIntervalSafe( const QVariant& v )
145 {
146  if ( v.canConvert<QgsInterval>() )
147  {
148  return true;
149  }
150 
151  if ( v.type() == QVariant::String )
152  {
153  return QgsInterval::fromString( v.toString() ).isValid();
154  }
155  return false;
156 }
157 
158 inline bool isNull( const QVariant& v ) { return v.isNull(); }
159 
161 // evaluation error macros
162 
163 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); }
164 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); }
165 
167 // operators
168 
169 const char* QgsExpression::BinaryOperatorText[] =
170 {
171  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
172  "OR", "AND",
173  "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
174  "+", "-", "*", "/", "//", "%", "^",
175  "||"
176 };
177 
178 const char* QgsExpression::UnaryOperatorText[] =
179 {
180  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
181  "NOT", "-"
182 };
183 
185 // functions
186 
187 // implicit conversion to string
189 {
190  return value.toString();
191 }
192 
193 static double getDoubleValue( const QVariant& value, QgsExpression* parent )
194 {
195  bool ok;
196  double x = value.toDouble( &ok );
197  if ( !ok || qIsNaN( x ) || !qIsFinite( x ) )
198  {
199  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) );
200  return 0;
201  }
202  return x;
203 }
204 
205 static int getIntValue( const QVariant& value, QgsExpression* parent )
206 {
207  bool ok;
208  qint64 x = value.toLongLong( &ok );
210  {
211  return x;
212  }
213  else
214  {
215  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) );
216  return 0;
217  }
218 }
219 
220 static QDateTime getDateTimeValue( const QVariant& value, QgsExpression* parent )
221 {
222  QDateTime d = value.toDateTime();
223  if ( d.isValid() )
224  {
225  return d;
226  }
227  else
228  {
229  QTime t = value.toTime();
230  if ( t.isValid() )
231  {
232  return QDateTime( QDate( 1, 1, 1 ), t );
233  }
234 
235  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( value.toString() ) );
236  return QDateTime();
237  }
238 }
239 
240 static QDate getDateValue( const QVariant& value, QgsExpression* parent )
241 {
242  QDate d = value.toDate();
243  if ( d.isValid() )
244  {
245  return d;
246  }
247  else
248  {
249  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( value.toString() ) );
250  return QDate();
251  }
252 }
253 
254 static QTime getTimeValue( const QVariant& value, QgsExpression* parent )
255 {
256  QTime t = value.toTime();
257  if ( t.isValid() )
258  {
259  return t;
260  }
261  else
262  {
263  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( value.toString() ) );
264  return QTime();
265  }
266 }
267 
268 static QgsInterval getInterval( const QVariant& value, QgsExpression* parent, bool report_error = false )
269 {
270  if ( value.canConvert<QgsInterval>() )
271  return value.value<QgsInterval>();
272 
273  QgsInterval inter = QgsInterval::fromString( value.toString() );
274  if ( inter.isValid() )
275  {
276  return inter;
277  }
278  // If we get here then we can't convert so we just error and return invalid.
279  if ( report_error )
280  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Interval" ).arg( value.toString() ) );
281 
282  return QgsInterval();
283 }
284 
285 static QgsGeometry getGeometry( const QVariant& value, QgsExpression* parent )
286 {
287  if ( value.canConvert<QgsGeometry>() )
288  return value.value<QgsGeometry>();
289 
290  parent->setEvalErrorString( "Cannot convert to QgsGeometry" );
291  return QgsGeometry();
292 }
293 
294 static QgsFeature getFeature( const QVariant& value, QgsExpression* parent )
295 {
296  if ( value.canConvert<QgsFeature>() )
297  return value.value<QgsFeature>();
298 
299  parent->setEvalErrorString( "Cannot convert to QgsFeature" );
300  return 0;
301 }
302 
303 #define FEAT_FROM_CONTEXT(c, f) if (!c || !c->hasVariable(QgsExpressionContext::EXPR_FEATURE)) return QVariant(); \
304  QgsFeature f = qvariant_cast<QgsFeature>( c->variable( QgsExpressionContext::EXPR_FEATURE ) );
305 
306 static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* parent )
307 {
308  if ( value.canConvert<QgsExpression::Node*>() )
309  return value.value<QgsExpression::Node*>();
310 
311  parent->setEvalErrorString( "Cannot convert to Node" );
312  return nullptr;
313 }
314 
316 {
317  QString layerString = value.toString();
318  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
319  if ( !vl )
320  {
321  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
322  if ( !layersByName.isEmpty() )
323  {
324  vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
325  }
326  }
327 
328  return vl;
329 }
330 
331 
332 // this handles also NULL values
333 static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
334 {
335  // we need to convert to TVL
336  if ( value.isNull() )
337  return Unknown;
338 
339  //handle some special cases
340  if ( value.canConvert<QgsGeometry>() )
341  {
342  //geom is false if empty
343  QgsGeometry geom = value.value<QgsGeometry>();
344  return geom.isEmpty() ? False : True;
345  }
346  else if ( value.canConvert<QgsFeature>() )
347  {
348  //feat is false if non-valid
349  QgsFeature feat = value.value<QgsFeature>();
350  return feat.isValid() ? True : False;
351  }
352 
353  if ( value.type() == QVariant::Int )
354  return value.toInt() != 0 ? True : False;
355 
356  bool ok;
357  double x = value.toDouble( &ok );
358  if ( !ok )
359  {
360  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
361  return Unknown;
362  }
363  return !qgsDoubleNear( x, 0.0 ) ? True : False;
364 }
365 
367 
368 static QVariant fcnGetVariable( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
369 {
370  if ( !context )
371  return QVariant();
372 
373  QString name = getStringValue( values.at( 0 ), parent );
374  return context->variable( name );
375 }
376 
377 static QVariant fcnEval( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
378 {
379  if ( !context )
380  return QVariant();
381 
382  QString expString = getStringValue( values.at( 0 ), parent );
383  QgsExpression expression( expString );
384  return expression.evaluate( context );
385 }
386 
387 static QVariant fcnSqrt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
388 {
389  double x = getDoubleValue( values.at( 0 ), parent );
390  return QVariant( sqrt( x ) );
391 }
392 
393 static QVariant fcnAbs( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
394 {
395  double val = getDoubleValue( values.at( 0 ), parent );
396  return QVariant( fabs( val ) );
397 }
398 
399 static QVariant fcnRadians( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
400 {
401  double deg = getDoubleValue( values.at( 0 ), parent );
402  return ( deg * M_PI ) / 180;
403 }
404 static QVariant fcnDegrees( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
405 {
406  double rad = getDoubleValue( values.at( 0 ), parent );
407  return ( 180 * rad ) / M_PI;
408 }
409 static QVariant fcnSin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
410 {
411  double x = getDoubleValue( values.at( 0 ), parent );
412  return QVariant( sin( x ) );
413 }
414 static QVariant fcnCos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
415 {
416  double x = getDoubleValue( values.at( 0 ), parent );
417  return QVariant( cos( x ) );
418 }
419 static QVariant fcnTan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
420 {
421  double x = getDoubleValue( values.at( 0 ), parent );
422  return QVariant( tan( x ) );
423 }
424 static QVariant fcnAsin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
425 {
426  double x = getDoubleValue( values.at( 0 ), parent );
427  return QVariant( asin( x ) );
428 }
429 static QVariant fcnAcos( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
430 {
431  double x = getDoubleValue( values.at( 0 ), parent );
432  return QVariant( acos( x ) );
433 }
434 static QVariant fcnAtan( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
435 {
436  double x = getDoubleValue( values.at( 0 ), parent );
437  return QVariant( atan( x ) );
438 }
439 static QVariant fcnAtan2( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
440 {
441  double y = getDoubleValue( values.at( 0 ), parent );
442  double x = getDoubleValue( values.at( 1 ), parent );
443  return QVariant( atan2( y, x ) );
444 }
445 static QVariant fcnExp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
446 {
447  double x = getDoubleValue( values.at( 0 ), parent );
448  return QVariant( exp( x ) );
449 }
450 static QVariant fcnLn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
451 {
452  double x = getDoubleValue( values.at( 0 ), parent );
453  if ( x <= 0 )
454  return QVariant();
455  return QVariant( log( x ) );
456 }
457 static QVariant fcnLog10( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
458 {
459  double x = getDoubleValue( values.at( 0 ), parent );
460  if ( x <= 0 )
461  return QVariant();
462  return QVariant( log10( x ) );
463 }
464 static QVariant fcnLog( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
465 {
466  double b = getDoubleValue( values.at( 0 ), parent );
467  double x = getDoubleValue( values.at( 1 ), parent );
468  if ( x <= 0 || b <= 0 )
469  return QVariant();
470  return QVariant( log( x ) / log( b ) );
471 }
472 static QVariant fcnRndF( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
473 {
474  double min = getDoubleValue( values.at( 0 ), parent );
475  double max = getDoubleValue( values.at( 1 ), parent );
476  if ( max < min )
477  return QVariant();
478 
479  // Return a random double in the range [min, max] (inclusive)
480  double f = static_cast< double >( qrand() ) / RAND_MAX;
481  return QVariant( min + f * ( max - min ) );
482 }
483 static QVariant fcnRnd( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
484 {
485  int min = getIntValue( values.at( 0 ), parent );
486  int max = getIntValue( values.at( 1 ), parent );
487  if ( max < min )
488  return QVariant();
489 
490  // Return a random integer in the range [min, max] (inclusive)
491  return QVariant( min + ( qrand() % static_cast< int >( max - min + 1 ) ) );
492 }
493 
494 static QVariant fcnLinearScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
495 {
496  double val = getDoubleValue( values.at( 0 ), parent );
497  double domainMin = getDoubleValue( values.at( 1 ), parent );
498  double domainMax = getDoubleValue( values.at( 2 ), parent );
499  double rangeMin = getDoubleValue( values.at( 3 ), parent );
500  double rangeMax = getDoubleValue( values.at( 4 ), parent );
501 
502  if ( domainMin >= domainMax )
503  {
504  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
505  return QVariant();
506  }
507 
508  // outside of domain?
509  if ( val >= domainMax )
510  {
511  return rangeMax;
512  }
513  else if ( val <= domainMin )
514  {
515  return rangeMin;
516  }
517 
518  // calculate linear scale
519  double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
520  double c = rangeMin - ( domainMin * m );
521 
522  // Return linearly scaled value
523  return QVariant( m * val + c );
524 }
525 
526 static QVariant fcnExpScale( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
527 {
528  double val = getDoubleValue( values.at( 0 ), parent );
529  double domainMin = getDoubleValue( values.at( 1 ), parent );
530  double domainMax = getDoubleValue( values.at( 2 ), parent );
531  double rangeMin = getDoubleValue( values.at( 3 ), parent );
532  double rangeMax = getDoubleValue( values.at( 4 ), parent );
533  double exponent = getDoubleValue( values.at( 5 ), parent );
534 
535  if ( domainMin >= domainMax )
536  {
537  parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
538  return QVariant();
539  }
540  if ( exponent <= 0 )
541  {
542  parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
543  return QVariant();
544  }
545 
546  // outside of domain?
547  if ( val >= domainMax )
548  {
549  return rangeMax;
550  }
551  else if ( val <= domainMin )
552  {
553  return rangeMin;
554  }
555 
556  // Return exponentially scaled value
557  return QVariant((( rangeMax - rangeMin ) / pow( domainMax - domainMin, exponent ) ) * pow( val - domainMin, exponent ) + rangeMin );
558 }
559 
560 static QVariant fcnMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
561 {
562  //initially set max as first value
563  double maxVal = getDoubleValue( values.at( 0 ), parent );
564 
565  //check against all other values
566  for ( int i = 1; i < values.length(); ++i )
567  {
568  double testVal = getDoubleValue( values[i], parent );
569  if ( testVal > maxVal )
570  {
571  maxVal = testVal;
572  }
573  }
574 
575  return QVariant( maxVal );
576 }
577 
578 static QVariant fcnMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
579 {
580  //initially set min as first value
581  double minVal = getDoubleValue( values.at( 0 ), parent );
582 
583  //check against all other values
584  for ( int i = 1; i < values.length(); ++i )
585  {
586  double testVal = getDoubleValue( values[i], parent );
587  if ( testVal < minVal )
588  {
589  minVal = testVal;
590  }
591  }
592 
593  return QVariant( minVal );
594 }
595 
596 static QVariant fcnAggregate( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
597 {
598  //lazy eval, so we need to evaluate nodes now
599 
600  //first node is layer id or name
601  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
603  QVariant value = node->eval( parent, context );
605  QgsVectorLayer* vl = getVectorLayer( value, parent );
606  if ( !vl )
607  {
608  parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
609  return QVariant();
610  }
611 
612  // second node is aggregate type
613  node = getNode( values.at( 1 ), parent );
615  value = node->eval( parent, context );
617  bool ok = false;
619  if ( !ok )
620  {
621  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
622  return QVariant();
623  }
624 
625  // third node is subexpression (or field name)
626  node = getNode( values.at( 2 ), parent );
628  QString subExpression = node->dump();
629 
631  //optional forth node is filter
632  if ( values.count() > 3 )
633  {
634  node = getNode( values.at( 3 ), parent );
636  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
637  if ( !nl || nl->value().isValid() )
638  parameters.filter = node->dump();
639  }
640 
641  //optional fifth node is concatenator
642  if ( values.count() > 4 )
643  {
644  node = getNode( values.at( 4 ), parent );
646  value = node->eval( parent, context );
648  parameters.delimiter = value.toString();
649  }
650 
651  QString cacheKey = QString( "aggfcn:%1:%2:%3:%4" ).arg( vl->id(), QString::number( static_cast< int >( aggregate ) ), subExpression, parameters.filter );
652  if ( context && context->hasCachedValue( cacheKey ) )
653  return context->cachedValue( cacheKey );
654 
655  QVariant result;
656  if ( context )
657  {
658  QgsExpressionContext subContext( *context );
659  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
660  }
661  else
662  {
663  result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
664  }
665  if ( !ok )
666  {
667  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
668  return QVariant();
669  }
670 
671  // cache value
672  if ( context )
673  context->setCachedValue( cacheKey, result );
674  return result;
675 }
676 
677 static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
678 {
679  if ( !context )
680  {
681  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
682  return QVariant();
683  }
684 
685  // first step - find current layer
686  QString layerId = context->variable( "layer_id" ).toString();
687  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
688  if ( !vl )
689  {
690  parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
691  return QVariant();
692  }
693 
694  //lazy eval, so we need to evaluate nodes now
695 
696  //first node is relation name
697  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
699  QVariant value = node->eval( parent, context );
701  QString relationId = value.toString();
702  // check relation exists
703  QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
704  if ( !relation.isValid() || relation.referencedLayer() != vl )
705  {
706  // check for relations by name
708  if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
709  {
710  parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
711  return QVariant();
712  }
713  else
714  {
715  relation = relations.at( 0 );
716  }
717  }
718 
719  QgsVectorLayer* childLayer = relation.referencingLayer();
720 
721  // second node is aggregate type
722  node = getNode( values.at( 1 ), parent );
724  value = node->eval( parent, context );
726  bool ok = false;
728  if ( !ok )
729  {
730  parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
731  return QVariant();
732  }
733 
734  //third node is subexpression (or field name)
735  node = getNode( values.at( 2 ), parent );
737  QString subExpression = node->dump();
738 
739  //optional fourth node is concatenator
741  if ( values.count() > 3 )
742  {
743  node = getNode( values.at( 3 ), parent );
745  value = node->eval( parent, context );
747  parameters.delimiter = value.toString();
748  }
749 
750  FEAT_FROM_CONTEXT( context, f );
751  parameters.filter = relation.getRelatedFeaturesFilter( f );
752 
753  QString cacheKey = QString( "relagg:%1:%2:%3:%4" ).arg( vl->id(),
754  QString::number( static_cast< int >( aggregate ) ),
755  subExpression,
756  parameters.filter );
757  if ( context && context->hasCachedValue( cacheKey ) )
758  return context->cachedValue( cacheKey );
759 
760  QVariant result;
761  ok = false;
762 
763 
764  QgsExpressionContext subContext( *context );
765  result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
766 
767  if ( !ok )
768  {
769  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
770  return QVariant();
771  }
772 
773  // cache value
774  if ( context )
775  context->setCachedValue( cacheKey, result );
776  return result;
777 }
778 
779 
781 {
782  if ( !context )
783  {
784  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
785  return QVariant();
786  }
787 
788  // first step - find current layer
789  QString layerId = context->variable( "layer_id" ).toString();
790  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
791  if ( !vl )
792  {
793  parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
794  return QVariant();
795  }
796 
797  //lazy eval, so we need to evaluate nodes now
798 
799  //first node is subexpression (or field name)
800  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
802  QString subExpression = node->dump();
803 
804  //optional second node is group by
805  QString groupBy;
806  if ( values.count() > 1 )
807  {
808  node = getNode( values.at( 1 ), parent );
810  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
811  if ( !nl || nl->value().isValid() )
812  groupBy = node->dump();
813  }
814 
815  //optional third node is filter
816  if ( values.count() > 2 )
817  {
818  node = getNode( values.at( 2 ), parent );
820  QgsExpression::NodeLiteral* nl = dynamic_cast< QgsExpression::NodeLiteral* >( node );
821  if ( !nl || nl->value().isValid() )
822  parameters.filter = node->dump();
823  }
824 
825  // build up filter with group by
826 
827  // find current group by value
828  if ( !groupBy.isEmpty() )
829  {
830  QgsExpression groupByExp( groupBy );
831  QVariant groupByValue = groupByExp.evaluate( context );
832  if ( !parameters.filter.isEmpty() )
833  parameters.filter = QString( "(%1) AND (%2=%3)" ).arg( parameters.filter, groupBy, QgsExpression::quotedValue( groupByValue ) );
834  else
835  parameters.filter = QString( "(%2 = %3)" ).arg( groupBy, QgsExpression::quotedValue( groupByValue ) );
836  }
837 
838  QString cacheKey = QString( "agg:%1:%2:%3:%4" ).arg( vl->id(),
839  QString::number( static_cast< int >( aggregate ) ),
840  subExpression,
841  parameters.filter );
842  if ( context && context->hasCachedValue( cacheKey ) )
843  return context->cachedValue( cacheKey );
844 
845  QVariant result;
846  bool ok = false;
847 
848  QgsExpressionContext subContext( *context );
849  result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
850 
851  if ( !ok )
852  {
853  parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
854  return QVariant();
855  }
856 
857  // cache value
858  if ( context )
859  context->setCachedValue( cacheKey, result );
860  return result;
861 }
862 
863 
864 static QVariant fcnAggregateCount( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
865 {
867 }
868 
869 static QVariant fcnAggregateCountDistinct( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
870 {
872 }
873 
874 static QVariant fcnAggregateCountMissing( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
875 {
877 }
878 
879 static QVariant fcnAggregateMin( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
880 {
882 }
883 
884 static QVariant fcnAggregateMax( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
885 {
887 }
888 
889 static QVariant fcnAggregateSum( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
890 {
892 }
893 
894 static QVariant fcnAggregateMean( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
895 {
897 }
898 
899 static QVariant fcnAggregateMedian( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
900 {
902 }
903 
904 static QVariant fcnAggregateStdev( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
905 {
907 }
908 
909 static QVariant fcnAggregateRange( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
910 {
912 }
913 
914 static QVariant fcnAggregateMinority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
915 {
917 }
918 
919 static QVariant fcnAggregateMajority( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
920 {
922 }
923 
924 static QVariant fcnAggregateQ1( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
925 {
927 }
928 
929 static QVariant fcnAggregateQ3( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
930 {
932 }
933 
934 static QVariant fcnAggregateIQR( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
935 {
937 }
938 
939 static QVariant fcnAggregateMinLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
940 {
942 }
943 
944 static QVariant fcnAggregateMaxLength( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
945 {
947 }
948 
949 static QVariant fcnAggregateStringConcat( const QVariantList& values, const QgsExpressionContext* context, QgsExpression *parent )
950 {
952 
953  //fourth node is concatenator
954  if ( values.count() > 3 )
955  {
956  QgsExpression::Node* node = getNode( values.at( 3 ), parent );
958  QVariant value = node->eval( parent, context );
960  parameters.delimiter = value.toString();
961  }
962 
963  return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent );
964 }
965 
966 static QVariant fcnClamp( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
967 {
968  double minValue = getDoubleValue( values.at( 0 ), parent );
969  double testValue = getDoubleValue( values.at( 1 ), parent );
970  double maxValue = getDoubleValue( values.at( 2 ), parent );
971 
972  // force testValue to sit inside the range specified by the min and max value
973  if ( testValue <= minValue )
974  {
975  return QVariant( minValue );
976  }
977  else if ( testValue >= maxValue )
978  {
979  return QVariant( maxValue );
980  }
981  else
982  {
983  return QVariant( testValue );
984  }
985 }
986 
987 static QVariant fcnFloor( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
988 {
989  double x = getDoubleValue( values.at( 0 ), parent );
990  return QVariant( floor( x ) );
991 }
992 
993 static QVariant fcnCeil( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
994 {
995  double x = getDoubleValue( values.at( 0 ), parent );
996  return QVariant( ceil( x ) );
997 }
998 
999 static QVariant fcnToInt( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1000 {
1001  return QVariant( getIntValue( values.at( 0 ), parent ) );
1002 }
1003 static QVariant fcnToReal( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1004 {
1005  return QVariant( getDoubleValue( values.at( 0 ), parent ) );
1006 }
1007 static QVariant fcnToString( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1008 {
1009  return QVariant( getStringValue( values.at( 0 ), parent ) );
1010 }
1011 
1012 static QVariant fcnToDateTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1013 {
1014  return QVariant( getDateTimeValue( values.at( 0 ), parent ) );
1015 }
1016 
1017 static QVariant fcnCoalesce( const QVariantList& values, const QgsExpressionContext*, QgsExpression* )
1018 {
1019  Q_FOREACH ( const QVariant &value, values )
1020  {
1021  if ( value.isNull() )
1022  continue;
1023  return value;
1024  }
1025  return QVariant();
1026 }
1027 static QVariant fcnLower( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1028 {
1029  QString str = getStringValue( values.at( 0 ), parent );
1030  return QVariant( str.toLower() );
1031 }
1032 static QVariant fcnUpper( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1033 {
1034  QString str = getStringValue( values.at( 0 ), parent );
1035  return QVariant( str.toUpper() );
1036 }
1037 static QVariant fcnTitle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1038 {
1039  QString str = getStringValue( values.at( 0 ), parent );
1040  QStringList elems = str.split( ' ' );
1041  for ( int i = 0; i < elems.size(); i++ )
1042  {
1043  if ( elems[i].size() > 1 )
1044  elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1045  }
1046  return QVariant( elems.join( " " ) );
1047 }
1048 
1049 static QVariant fcnTrim( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1050 {
1051  QString str = getStringValue( values.at( 0 ), parent );
1052  return QVariant( str.trimmed() );
1053 }
1054 
1055 static QVariant fcnLevenshtein( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1056 {
1057  QString string1 = getStringValue( values.at( 0 ), parent );
1058  QString string2 = getStringValue( values.at( 1 ), parent );
1059  return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1060 }
1061 
1062 static QVariant fcnLCS( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1063 {
1064  QString string1 = getStringValue( values.at( 0 ), parent );
1065  QString string2 = getStringValue( values.at( 1 ), parent );
1066  return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1067 }
1068 
1069 static QVariant fcnHamming( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1070 {
1071  QString string1 = getStringValue( values.at( 0 ), parent );
1072  QString string2 = getStringValue( values.at( 1 ), parent );
1073  int dist = QgsStringUtils::hammingDistance( string1, string2 );
1074  return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1075 }
1076 
1077 static QVariant fcnSoundex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1078 {
1079  QString string = getStringValue( values.at( 0 ), parent );
1080  return QVariant( QgsStringUtils::soundex( string ) );
1081 }
1082 
1083 static QVariant fcnChar( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1084 {
1085  QChar character = QChar( getIntValue( values.at( 0 ), parent ) );
1086  return QVariant( QString( character ) );
1087 }
1088 
1089 static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1090 {
1091  if ( values.length() == 2 || values.length() == 3 )
1092  {
1093  QString str = getStringValue( values.at( 0 ), parent );
1094  int wrap = getIntValue( values.at( 1 ), parent );
1095 
1096  if ( !str.isEmpty() && wrap != 0 )
1097  {
1098  QString newstr;
1099  QString delimiterstr;
1100  if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
1101  if ( delimiterstr.isEmpty() ) delimiterstr = ' ';
1102  int delimiterlength = delimiterstr.length();
1103 
1104  QStringList lines = str.split( '\n' );
1105  int strlength, strcurrent, strhit, lasthit;
1106 
1107  for ( int i = 0; i < lines.size(); i++ )
1108  {
1109  strlength = lines[i].length();
1110  strcurrent = 0;
1111  strhit = 0;
1112  lasthit = 0;
1113 
1114  while ( strcurrent < strlength )
1115  {
1116  // positive wrap value = desired maximum line width to wrap
1117  // negative wrap value = desired minimum line width before wrap
1118  if ( wrap > 0 )
1119  {
1120  //first try to locate delimiter backwards
1121  strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
1122  if ( strhit == lasthit || strhit == -1 )
1123  {
1124  //if no new backward delimiter found, try to locate forward
1125  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1126  }
1127  lasthit = strhit;
1128  }
1129  else
1130  {
1131  strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
1132  }
1133  if ( strhit > -1 )
1134  {
1135  newstr.append( lines[i].midRef( strcurrent, strhit - strcurrent ) );
1136  newstr.append( '\n' );
1137  strcurrent = strhit + delimiterlength;
1138  }
1139  else
1140  {
1141  newstr.append( lines[i].midRef( strcurrent ) );
1142  strcurrent = strlength;
1143  }
1144  }
1145  if ( i < lines.size() - 1 ) newstr.append( '\n' );
1146  }
1147 
1148  return QVariant( newstr );
1149  }
1150  }
1151 
1152  return QVariant();
1153 }
1154 
1155 static QVariant fcnLength( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1156 {
1157  // two variants, one for geometry, one for string
1158  if ( values.at( 0 ).canConvert<QgsGeometry>() )
1159  {
1160  //geometry variant
1161  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1162  if ( geom.type() != QGis::Line )
1163  return QVariant();
1164 
1165  return QVariant( geom.length() );
1166  }
1167 
1168  //otherwise fall back to string variant
1169  QString str = getStringValue( values.at( 0 ), parent );
1170  return QVariant( str.length() );
1171 }
1172 
1173 static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1174 {
1175  QString str = getStringValue( values.at( 0 ), parent );
1176  QString before = getStringValue( values.at( 1 ), parent );
1177  QString after = getStringValue( values.at( 2 ), parent );
1178  return QVariant( str.replace( before, after ) );
1179 }
1180 static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1181 {
1182  QString str = getStringValue( values.at( 0 ), parent );
1183  QString regexp = getStringValue( values.at( 1 ), parent );
1184  QString after = getStringValue( values.at( 2 ), parent );
1185 
1186  QRegExp re( regexp );
1187  if ( !re.isValid() )
1188  {
1189  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1190  return QVariant();
1191  }
1192  return QVariant( str.replace( re, after ) );
1193 }
1194 
1195 static QVariant fcnRegexpMatch( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1196 {
1197  QString str = getStringValue( values.at( 0 ), parent );
1198  QString regexp = getStringValue( values.at( 1 ), parent );
1199 
1200  QRegExp re( regexp );
1201  if ( !re.isValid() )
1202  {
1203  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1204  return QVariant();
1205  }
1206  return QVariant( str.contains( re ) ? 1 : 0 );
1207 }
1208 
1209 static QVariant fcnRegexpSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1210 {
1211  QString str = getStringValue( values.at( 0 ), parent );
1212  QString regexp = getStringValue( values.at( 1 ), parent );
1213 
1214  QRegExp re( regexp );
1215  if ( !re.isValid() )
1216  {
1217  parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1218  return QVariant();
1219  }
1220 
1221  // extract substring
1222  ( void )re.indexIn( str );
1223  if ( re.captureCount() > 0 )
1224  {
1225  // return first capture
1226  return QVariant( re.capturedTexts().at( 1 ) );
1227  }
1228  else
1229  {
1230  return QVariant( "" );
1231  }
1232 }
1233 
1234 static QVariant fcnUuid( const QVariantList&, const QgsExpressionContext*, QgsExpression* )
1235 {
1236  return QUuid::createUuid().toString();
1237 }
1238 
1239 static QVariant fcnSubstr( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1240 {
1241  QString str = getStringValue( values.at( 0 ), parent );
1242  int from = getIntValue( values.at( 1 ), parent );
1243  int len = getIntValue( values.at( 2 ), parent );
1244  return QVariant( str.mid( from -1, len ) );
1245 }
1246 
1247 static QVariant fcnRowNumber( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
1248 {
1249  if ( context && context->hasVariable( "row_number" ) )
1250  return context->variable( "row_number" );
1251 
1253  return QVariant( parent->currentRowNumber() );
1255  //when above is removed - return QVariant()
1256 }
1257 
1258 static QVariant fcnMapId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1259 {
1260  if ( context && context->hasVariable( "map_id" ) )
1261  return context->variable( "map_id" );
1262 
1264  return QgsExpression::specialColumn( "$map" );
1266 }
1267 
1268 static QVariant fcnComposerNumPages( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1269 {
1270  if ( context && context->hasVariable( "layout_numpages" ) )
1271  return context->variable( "layout_numpages" );
1272 
1274  return QgsExpression::specialColumn( "$numpages" );
1276 }
1277 
1278 static QVariant fcnComposerPage( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1279 {
1280  if ( context && context->hasVariable( "layout_page" ) )
1281  return context->variable( "layout_page" );
1282 
1284  return QgsExpression::specialColumn( "$page" );
1286 }
1287 
1288 static QVariant fcnAtlasFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1289 {
1290  if ( context && context->hasVariable( "atlas_featurenumber" ) )
1291  return context->variable( "atlas_featurenumber" );
1292 
1294  return QgsExpression::specialColumn( "$feature" );
1296 }
1297 
1298 static QVariant fcnAtlasFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1299 {
1300  if ( context && context->hasVariable( "atlas_featureid" ) )
1301  return context->variable( "atlas_featureid" );
1302 
1304  return QgsExpression::specialColumn( "$atlasfeatureid" );
1306 }
1307 
1308 
1309 static QVariant fcnAtlasCurrentFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1310 {
1311  if ( context && context->hasVariable( "atlas_feature" ) )
1312  return context->variable( "atlas_feature" );
1313 
1315  return QgsExpression::specialColumn( "$atlasfeature" );
1317 }
1318 
1319 static QVariant fcnAtlasCurrentGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1320 {
1321  if ( context && context->hasVariable( "atlas_geometry" ) )
1322  return context->variable( "atlas_geometry" );
1323 
1325  return QgsExpression::specialColumn( "$atlasgeometry" );
1327 }
1328 
1329 static QVariant fcnAtlasNumFeatures( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1330 {
1331  if ( context && context->hasVariable( "atlas_totalfeatures" ) )
1332  return context->variable( "atlas_totalfeatures" );
1333 
1335  return QgsExpression::specialColumn( "$numfeatures" );
1337 }
1338 
1339 static QVariant fcnFeatureId( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1340 {
1341  FEAT_FROM_CONTEXT( context, f );
1342  // TODO: handling of 64-bit feature ids?
1343  return QVariant( static_cast< int >( f.id() ) );
1344 }
1345 
1346 static QVariant fcnFeature( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1347 {
1348  if ( !context )
1349  return QVariant();
1350 
1351  return context->variable( QgsExpressionContext::EXPR_FEATURE );
1352 }
1353 static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1354 {
1355  QgsFeature feat = getFeature( values.at( 0 ), parent );
1356  QString attr = getStringValue( values.at( 1 ), parent );
1357 
1358  return feat.attribute( attr );
1359 }
1360 static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1361 {
1362  QString concat;
1363  Q_FOREACH ( const QVariant &value, values )
1364  {
1365  concat += getStringValue( value, parent );
1366  }
1367  return concat;
1368 }
1369 
1370 static QVariant fcnStrpos( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1371 {
1372  QString string = getStringValue( values.at( 0 ), parent );
1373  return string.indexOf( QRegExp( getStringValue( values.at( 1 ), parent ) ) ) + 1;
1374 }
1375 
1376 static QVariant fcnRight( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1377 {
1378  QString string = getStringValue( values.at( 0 ), parent );
1379  int pos = getIntValue( values.at( 1 ), parent );
1380  return string.right( pos );
1381 }
1382 
1383 static QVariant fcnLeft( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1384 {
1385  QString string = getStringValue( values.at( 0 ), parent );
1386  int pos = getIntValue( values.at( 1 ), parent );
1387  return string.left( pos );
1388 }
1389 
1390 static QVariant fcnRPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1391 {
1392  QString string = getStringValue( values.at( 0 ), parent );
1393  int length = getIntValue( values.at( 1 ), parent );
1394  QString fill = getStringValue( values.at( 2 ), parent );
1395  return string.leftJustified( length, fill.at( 0 ), true );
1396 }
1397 
1398 static QVariant fcnLPad( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1399 {
1400  QString string = getStringValue( values.at( 0 ), parent );
1401  int length = getIntValue( values.at( 1 ), parent );
1402  QString fill = getStringValue( values.at( 2 ), parent );
1403  return string.rightJustified( length, fill.at( 0 ), true );
1404 }
1405 
1406 static QVariant fcnFormatString( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1407 {
1408  QString string = getStringValue( values.at( 0 ), parent );
1409  for ( int n = 1; n < values.length(); n++ )
1410  {
1411  string = string.arg( getStringValue( values.at( n ), parent ) );
1412  }
1413  return string;
1414 }
1415 
1416 
1417 static QVariant fcnNow( const QVariantList&, const QgsExpressionContext*, QgsExpression * )
1418 {
1420 }
1421 
1422 static QVariant fcnToDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1423 {
1424  return QVariant( getDateValue( values.at( 0 ), parent ) );
1425 }
1426 
1427 static QVariant fcnToTime( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1428 {
1429  return QVariant( getTimeValue( values.at( 0 ), parent ) );
1430 }
1431 
1432 static QVariant fcnToInterval( const QVariantList& values, const QgsExpressionContext*, QgsExpression * parent )
1433 {
1434  return QVariant::fromValue( getInterval( values.at( 0 ), parent ) );
1435 }
1436 
1437 static QVariant fcnAge( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1438 {
1439  QDateTime d1 = getDateTimeValue( values.at( 0 ), parent );
1440  QDateTime d2 = getDateTimeValue( values.at( 1 ), parent );
1441  int seconds = d2.secsTo( d1 );
1442  return QVariant::fromValue( QgsInterval( seconds ) );
1443 }
1444 
1445 static QVariant fcnDayOfWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1446 {
1447  if ( !values.at( 0 ).canConvert<QDate>() )
1448  return QVariant();
1449 
1450  QDate date = getDateValue( values.at( 0 ), parent );
1451  if ( !date.isValid() )
1452  return QVariant();
1453 
1454  // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
1455  // (to match PostgreSQL behaviour)
1456  return date.dayOfWeek() % 7;
1457 }
1458 
1459 static QVariant fcnDay( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1460 {
1461  QVariant value = values.at( 0 );
1462  QgsInterval inter = getInterval( value, parent, false );
1463  if ( inter.isValid() )
1464  {
1465  return QVariant( inter.days() );
1466  }
1467  else
1468  {
1469  QDateTime d1 = getDateTimeValue( value, parent );
1470  return QVariant( d1.date().day() );
1471  }
1472 }
1473 
1474 static QVariant fcnYear( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1475 {
1476  QVariant value = values.at( 0 );
1477  QgsInterval inter = getInterval( value, parent, false );
1478  if ( inter.isValid() )
1479  {
1480  return QVariant( inter.years() );
1481  }
1482  else
1483  {
1484  QDateTime d1 = getDateTimeValue( value, parent );
1485  return QVariant( d1.date().year() );
1486  }
1487 }
1488 
1489 static QVariant fcnMonth( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1490 {
1491  QVariant value = values.at( 0 );
1492  QgsInterval inter = getInterval( value, parent, false );
1493  if ( inter.isValid() )
1494  {
1495  return QVariant( inter.months() );
1496  }
1497  else
1498  {
1499  QDateTime d1 = getDateTimeValue( value, parent );
1500  return QVariant( d1.date().month() );
1501  }
1502 }
1503 
1504 static QVariant fcnWeek( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1505 {
1506  QVariant value = values.at( 0 );
1507  QgsInterval inter = getInterval( value, parent, false );
1508  if ( inter.isValid() )
1509  {
1510  return QVariant( inter.weeks() );
1511  }
1512  else
1513  {
1514  QDateTime d1 = getDateTimeValue( value, parent );
1515  return QVariant( d1.date().weekNumber() );
1516  }
1517 }
1518 
1519 static QVariant fcnHour( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1520 {
1521  QVariant value = values.at( 0 );
1522  QgsInterval inter = getInterval( value, parent, false );
1523  if ( inter.isValid() )
1524  {
1525  return QVariant( inter.hours() );
1526  }
1527  else
1528  {
1529  QTime t1 = getTimeValue( value, parent );
1530  return QVariant( t1.hour() );
1531  }
1532 }
1533 
1534 static QVariant fcnMinute( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1535 {
1536  QVariant value = values.at( 0 );
1537  QgsInterval inter = getInterval( value, parent, false );
1538  if ( inter.isValid() )
1539  {
1540  return QVariant( inter.minutes() );
1541  }
1542  else
1543  {
1544  QTime t1 = getTimeValue( value, parent );
1545  return QVariant( t1.minute() );
1546  }
1547 }
1548 
1549 static QVariant fcnSeconds( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
1550 {
1551  QVariant value = values.at( 0 );
1552  QgsInterval inter = getInterval( value, parent, false );
1553  if ( inter.isValid() )
1554  {
1555  return QVariant( inter.seconds() );
1556  }
1557  else
1558  {
1559  QTime t1 = getTimeValue( value, parent );
1560  return QVariant( t1.second() );
1561  }
1562 }
1563 
1564 
1565 #define ENSURE_GEOM_TYPE(f, g, geomtype) const QgsGeometry* g = f.constGeometry(); \
1566  if (!g || g->type() != geomtype) return QVariant();
1567 
1568 static QVariant fcnX( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1569 {
1570  FEAT_FROM_CONTEXT( context, f );
1571  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1572  if ( g->isMultipart() )
1573  {
1574  return g->asMultiPoint().at( 0 ).x();
1575  }
1576  else
1577  {
1578  return g->asPoint().x();
1579  }
1580 }
1581 
1582 static QVariant fcnY( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1583 {
1584  FEAT_FROM_CONTEXT( context, f );
1585  ENSURE_GEOM_TYPE( f, g, QGis::Point );
1586  if ( g->isMultipart() )
1587  {
1588  return g->asMultiPoint().at( 0 ).y();
1589  }
1590  else
1591  {
1592  return g->asPoint().y();
1593  }
1594 }
1595 
1596 static QVariant fcnGeomX( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1597 {
1598  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1599  if ( geom.isEmpty() )
1600  return QVariant();
1601 
1602  //if single point, return the point's x coordinate
1603  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1604  {
1605  return geom.asPoint().x();
1606  }
1607 
1608  //otherwise return centroid x
1609  QgsGeometry* centroid = geom.centroid();
1610  QVariant result( centroid->asPoint().x() );
1611  delete centroid;
1612  return result;
1613 }
1614 
1615 static QVariant fcnGeomY( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1616 {
1617  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1618  if ( geom.isEmpty() )
1619  return QVariant();
1620 
1621  //if single point, return the point's y coordinate
1622  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1623  {
1624  return geom.asPoint().y();
1625  }
1626 
1627  //otherwise return centroid y
1628  QgsGeometry* centroid = geom.centroid();
1629  QVariant result( centroid->asPoint().y() );
1630  delete centroid;
1631  return result;
1632 }
1633 
1634 static QVariant fcnGeomZ( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1635 {
1636  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1637  if ( geom.isEmpty() )
1638  return QVariant(); //or 0?
1639 
1640  //if single point, return the point's z coordinate
1641  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1642  {
1643  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1644  if ( point )
1645  return point->z();
1646  }
1647 
1648  return QVariant();
1649 }
1650 
1651 static QVariant fcnGeomM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1652 {
1653  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1654  if ( geom.isEmpty() )
1655  return QVariant(); //or 0?
1656 
1657  //if single point, return the point's m value
1658  if ( geom.type() == QGis::Point && !geom.isMultipart() )
1659  {
1660  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1661  if ( point )
1662  return point->m();
1663  }
1664 
1665  return QVariant();
1666 }
1667 
1668 static QVariant fcnPointN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1669 {
1670  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1671 
1672  if ( geom.isEmpty() )
1673  return QVariant();
1674 
1675  //idx is 1 based
1676  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1677 
1678  QgsVertexId vId;
1679  if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
1680  {
1681  parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
1682  return QVariant();
1683  }
1684 
1685  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1686  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1687 }
1688 
1689 static QVariant fcnStartPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1690 {
1691  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1692 
1693  if ( geom.isEmpty() )
1694  return QVariant();
1695 
1696  QgsVertexId vId;
1697  if ( !geom.vertexIdFromVertexNr( 0, vId ) )
1698  {
1699  return QVariant();
1700  }
1701 
1702  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1703  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1704 }
1705 
1706 static QVariant fcnEndPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1707 {
1708  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1709 
1710  if ( geom.isEmpty() )
1711  return QVariant();
1712 
1713  QgsVertexId vId;
1714  if ( !geom.vertexIdFromVertexNr( geom.geometry()->nCoordinates() - 1, vId ) )
1715  {
1716  return QVariant();
1717  }
1718 
1719  QgsPointV2 point = geom.geometry()->vertexAt( vId );
1720  return QVariant::fromValue( QgsGeometry( new QgsPointV2( point ) ) );
1721 }
1722 
1723 static QVariant fcnNodesToPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1724 {
1725  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1726 
1727  if ( geom.isEmpty() )
1728  return QVariant();
1729 
1730  bool ignoreClosing = false;
1731  if ( values.length() > 1 )
1732  {
1733  ignoreClosing = getIntValue( values.at( 1 ), parent );
1734  }
1735 
1736  QgsMultiPointV2* mp = new QgsMultiPointV2();
1737 
1738  Q_FOREACH ( const QgsRingSequenceV2 &part, geom.geometry()->coordinateSequence() )
1739  {
1740  Q_FOREACH ( const QgsPointSequenceV2 &ring, part )
1741  {
1742  bool skipLast = false;
1743  if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
1744  {
1745  skipLast = true;
1746  }
1747 
1748  for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
1749  {
1750  mp->addGeometry( ring.at( i ).clone() );
1751  }
1752  }
1753  }
1754 
1755  return QVariant::fromValue( QgsGeometry( mp ) );
1756 }
1757 
1758 static QVariant fcnSegmentsToLines( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1759 {
1760  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1761 
1762  if ( geom.isEmpty() )
1763  return QVariant();
1764 
1766 
1767  //ok, now we have a complete list of segmentized lines from the geometry
1769  Q_FOREACH ( QgsLineStringV2* line, linesToProcess )
1770  {
1771  for ( int i = 0; i < line->numPoints() - 1; ++i )
1772  {
1773  QgsLineStringV2* segment = new QgsLineStringV2();
1774  segment->setPoints( QgsPointSequenceV2()
1775  << line->pointN( i )
1776  << line->pointN( i + 1 ) );
1777  ml->addGeometry( segment );
1778  }
1779  delete line;
1780  }
1781 
1782  return QVariant::fromValue( QgsGeometry( ml ) );
1783 }
1784 
1785 static QVariant fcnInteriorRingN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1786 {
1787  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1788 
1789  if ( geom.isEmpty() )
1790  return QVariant();
1791 
1792  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
1793  if ( !curvePolygon )
1794  return QVariant();
1795 
1796  //idx is 1 based
1797  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1798 
1799  if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
1800  return QVariant();
1801 
1802  QgsCurveV2* curve = static_cast< QgsCurveV2* >( curvePolygon->interiorRing( idx )->clone() );
1803  QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
1804  return result;
1805 }
1806 
1807 static QVariant fcnGeometryN( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1808 {
1809  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1810 
1811  if ( geom.isEmpty() )
1812  return QVariant();
1813 
1814  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
1815  if ( !collection )
1816  return QVariant();
1817 
1818  //idx is 1 based
1819  int idx = getIntValue( values.at( 1 ), parent ) - 1;
1820 
1821  if ( idx < 0 || idx >= collection->numGeometries() )
1822  return QVariant();
1823 
1824  QgsAbstractGeometryV2* part = collection->geometryN( idx )->clone();
1825  QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
1826  return result;
1827 }
1828 
1829 static QVariant fcnBoundary( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1830 {
1831  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1832 
1833  if ( geom.isEmpty() )
1834  return QVariant();
1835 
1836  QgsAbstractGeometryV2* boundary = geom.geometry()->boundary();
1837  if ( !boundary )
1838  return QVariant();
1839 
1840  return QVariant::fromValue( QgsGeometry( boundary ) );
1841 }
1842 
1843 static QVariant fcnLineMerge( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1844 {
1845  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
1846 
1847  if ( geom.isEmpty() )
1848  return QVariant();
1849 
1850  QgsGeometry merged = geom.mergeLines();
1851  if ( merged.isEmpty() )
1852  return QVariant();
1853 
1854  return QVariant::fromValue( merged );
1855 }
1856 
1857 static QVariant fcnMakePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1858 {
1859  if ( values.count() < 2 || values.count() > 4 )
1860  {
1861  parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
1862  return QVariant();
1863  }
1864 
1865  double x = getDoubleValue( values.at( 0 ), parent );
1866  double y = getDoubleValue( values.at( 1 ), parent );
1867  double z = values.count() >= 3 ? getDoubleValue( values.at( 2 ), parent ) : 0.0;
1868  double m = values.count() >= 4 ? getDoubleValue( values.at( 3 ), parent ) : 0.0;
1869  switch ( values.count() )
1870  {
1871  case 2:
1872  return QVariant::fromValue( QgsGeometry( new QgsPointV2( x, y ) ) );
1873  case 3:
1874  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZ, x, y, z ) ) );
1875  case 4:
1876  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointZM, x, y, z, m ) ) );
1877  }
1878  return QVariant(); //avoid warning
1879 }
1880 
1881 static QVariant fcnMakePointM( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1882 {
1883  double x = getDoubleValue( values.at( 0 ), parent );
1884  double y = getDoubleValue( values.at( 1 ), parent );
1885  double m = getDoubleValue( values.at( 2 ), parent );
1886  return QVariant::fromValue( QgsGeometry( new QgsPointV2( QgsWKBTypes::PointM, x, y, 0.0, m ) ) );
1887 }
1888 
1889 static QVariant fcnMakeLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1890 {
1891  if ( values.count() < 2 )
1892  {
1893  return QVariant();
1894  }
1895 
1896  QgsLineStringV2* lineString = new QgsLineStringV2();
1897  lineString->clear();
1898 
1899  Q_FOREACH ( const QVariant& value, values )
1900  {
1901  QgsGeometry geom = getGeometry( value, parent );
1902  if ( geom.isEmpty() )
1903  continue;
1904 
1905  if ( geom.type() != QGis::Point || geom.isMultipart() )
1906  continue;
1907 
1908  QgsPointV2* point = dynamic_cast< QgsPointV2* >( geom.geometry() );
1909  if ( !point )
1910  continue;
1911 
1912  lineString->addVertex( *point );
1913  }
1914 
1915  return QVariant::fromValue( QgsGeometry( lineString ) );
1916 }
1917 
1918 static QVariant fcnMakePolygon( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1919 {
1920  if ( values.count() < 1 )
1921  {
1922  parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
1923  return QVariant();
1924  }
1925 
1926  QgsGeometry outerRing = getGeometry( values.at( 0 ), parent );
1927  if ( outerRing.type() != QGis::Line || outerRing.isMultipart() || outerRing.isEmpty() )
1928  return QVariant();
1929 
1930  QgsPolygonV2* polygon = new QgsPolygonV2();
1931  polygon->setExteriorRing( dynamic_cast< QgsCurveV2* >( outerRing.geometry()->clone() ) );
1932 
1933  for ( int i = 1; i < values.count(); ++i )
1934  {
1935  QgsGeometry ringGeom = getGeometry( values.at( i ), parent );
1936  if ( ringGeom.isEmpty() )
1937  continue;
1938 
1939  if ( ringGeom.type() != QGis::Line || ringGeom.isMultipart() || ringGeom.isEmpty() )
1940  continue;
1941 
1942  polygon->addInteriorRing( dynamic_cast< QgsCurveV2* >( ringGeom.geometry()->clone() ) );
1943  }
1944 
1945  return QVariant::fromValue( QgsGeometry( polygon ) );
1946 }
1947 
1948 static QVariant pointAt( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) // helper function
1949 {
1950  FEAT_FROM_CONTEXT( context, f );
1951  int idx = getIntValue( values.at( 0 ), parent );
1952  const QgsGeometry* g = f.constGeometry();
1953  if ( !g || g->isEmpty() )
1954  return QVariant();
1955 
1956  if ( idx < 0 )
1957  {
1958  idx += g->geometry()->nCoordinates();
1959  }
1960  if ( idx < 0 || idx >= g->geometry()->nCoordinates() )
1961  {
1962  parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
1963  return QVariant();
1964  }
1965 
1966  QgsPoint p = g->vertexAt( idx );
1967  return QVariant( QPointF( p.x(), p.y() ) );
1968 }
1969 
1970 static QVariant fcnXat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1971 {
1972  QVariant v = pointAt( values, f, parent );
1973  if ( v.type() == QVariant::PointF )
1974  return QVariant( v.toPointF().x() );
1975  else
1976  return QVariant();
1977 }
1978 static QVariant fcnYat( const QVariantList& values, const QgsExpressionContext* f, QgsExpression* parent )
1979 {
1980  QVariant v = pointAt( values, f, parent );
1981  if ( v.type() == QVariant::PointF )
1982  return QVariant( v.toPointF().y() );
1983  else
1984  return QVariant();
1985 }
1986 static QVariant fcnGeometry( const QVariantList&, const QgsExpressionContext* context, QgsExpression* )
1987 {
1988  FEAT_FROM_CONTEXT( context, f );
1989  const QgsGeometry* geom = f.constGeometry();
1990  if ( geom )
1991  return QVariant::fromValue( *geom );
1992  else
1993  return QVariant();
1994 }
1995 static QVariant fcnGeomFromWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
1996 {
1997  QString wkt = getStringValue( values.at( 0 ), parent );
1998  QgsGeometry* geom = QgsGeometry::fromWkt( wkt );
1999  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2000  delete geom;
2001  return result;
2002 }
2003 static QVariant fcnGeomFromGML( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2004 {
2005  QString gml = getStringValue( values.at( 0 ), parent );
2007  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2008  delete geom;
2009  return result;
2010 }
2011 
2012 static QVariant fcnGeomArea( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2013 {
2014  FEAT_FROM_CONTEXT( context, f );
2016  QgsDistanceArea* calc = parent->geomCalculator();
2017  if ( calc )
2018  {
2019  double area = calc->measureArea( f.constGeometry() );
2020  area = calc->convertAreaMeasurement( area, parent->areaUnits() );
2021  return QVariant( area );
2022  }
2023  else
2024  {
2025  return QVariant( f.constGeometry()->area() );
2026  }
2027 }
2028 
2029 static QVariant fcnArea( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2030 {
2031  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2032 
2033  if ( geom.type() != QGis::Polygon )
2034  return QVariant();
2035 
2036  return QVariant( geom.area() );
2037 }
2038 
2039 static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2040 {
2041  FEAT_FROM_CONTEXT( context, f );
2042  ENSURE_GEOM_TYPE( f, g, QGis::Line );
2043  QgsDistanceArea* calc = parent->geomCalculator();
2044  if ( calc )
2045  {
2046  double len = calc->measureLength( f.constGeometry() );
2047  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2048  return QVariant( len );
2049  }
2050  else
2051  {
2052  return QVariant( f.constGeometry()->length() );
2053  }
2054 }
2055 
2056 static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContext* context, QgsExpression* parent )
2057 {
2058  FEAT_FROM_CONTEXT( context, f );
2060  QgsDistanceArea* calc = parent->geomCalculator();
2061  if ( calc )
2062  {
2063  double len = calc->measurePerimeter( f.constGeometry() );
2064  len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
2065  return QVariant( len );
2066  }
2067  else
2068  {
2069  return f.constGeometry()->isEmpty() ? QVariant( 0 ) : QVariant( f.constGeometry()->geometry()->perimeter() );
2070  }
2071 }
2072 
2073 static QVariant fcnPerimeter( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2074 {
2075  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2076 
2077  if ( geom.type() != QGis::Polygon )
2078  return QVariant();
2079 
2080  //length for polygons = perimeter
2081  return QVariant( geom.length() );
2082 }
2083 
2084 static QVariant fcnGeomNumPoints( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2085 {
2086  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2087  return QVariant( geom.isEmpty() ? 0 : geom.geometry()->nCoordinates() );
2088 }
2089 
2090 static QVariant fcnGeomNumGeometries( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2091 {
2092  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2093  if ( geom.isEmpty() )
2094  return QVariant();
2095 
2096  return QVariant( geom.geometry()->partCount() );
2097 }
2098 
2099 static QVariant fcnGeomNumInteriorRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2100 {
2101  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2102 
2103  if ( geom.isEmpty() )
2104  return QVariant();
2105 
2106  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2107  if ( curvePolygon )
2108  return QVariant( curvePolygon->numInteriorRings() );
2109 
2110  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2111  if ( collection )
2112  {
2113  //find first CurvePolygon in collection
2114  for ( int i = 0; i < collection->numGeometries(); ++i )
2115  {
2116  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2117  if ( !curvePolygon )
2118  continue;
2119 
2120  return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
2121  }
2122  }
2123 
2124  return QVariant();
2125 }
2126 
2127 static QVariant fcnGeomNumRings( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2128 {
2129  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2130 
2131  if ( geom.isEmpty() )
2132  return QVariant();
2133 
2134  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( geom.geometry() );
2135  if ( curvePolygon )
2136  return QVariant( curvePolygon->ringCount() );
2137 
2138  bool foundPoly = false;
2139  int ringCount = 0;
2140  QgsGeometryCollectionV2* collection = dynamic_cast< QgsGeometryCollectionV2* >( geom.geometry() );
2141  if ( collection )
2142  {
2143  //find CurvePolygons in collection
2144  for ( int i = 0; i < collection->numGeometries(); ++i )
2145  {
2146  curvePolygon = dynamic_cast< QgsCurvePolygonV2*>( collection->geometryN( i ) );
2147  if ( !curvePolygon )
2148  continue;
2149 
2150  foundPoly = true;
2151  ringCount += curvePolygon->ringCount();
2152  }
2153  }
2154 
2155  if ( !foundPoly )
2156  return QVariant();
2157 
2158  return QVariant( ringCount );
2159 }
2160 
2161 static QVariant fcnBounds( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2162 {
2163  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2164  QgsGeometry* geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
2165  QVariant result = geomBounds ? QVariant::fromValue( *geomBounds ) : QVariant();
2166  delete geomBounds;
2167  return result;
2168 }
2169 
2170 static QVariant fcnBoundsWidth( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2171 {
2172  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2173  return QVariant::fromValue( geom.boundingBox().width() );
2174 }
2175 
2176 static QVariant fcnBoundsHeight( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2177 {
2178  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2179  return QVariant::fromValue( geom.boundingBox().height() );
2180 }
2181 
2182 static QVariant fcnXMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2183 {
2184  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2185  return QVariant::fromValue( geom.boundingBox().xMinimum() );
2186 }
2187 
2188 static QVariant fcnXMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2189 {
2190  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2191  return QVariant::fromValue( geom.boundingBox().xMaximum() );
2192 }
2193 
2194 static QVariant fcnYMin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2195 {
2196  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2197  return QVariant::fromValue( geom.boundingBox().yMinimum() );
2198 }
2199 
2200 static QVariant fcnYMax( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2201 {
2202  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2203  return QVariant::fromValue( geom.boundingBox().yMaximum() );
2204 }
2205 
2206 static QVariant fcnIsClosed( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2207 {
2208  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2209  if ( fGeom.isEmpty() )
2210  return QVariant();
2211 
2212  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2213  if ( !curve )
2214  return QVariant();
2215 
2216  return QVariant::fromValue( curve->isClosed() );
2217 }
2218 
2219 static QVariant fcnRelate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2220 {
2221  if ( values.length() < 2 || values.length() > 3 )
2222  return QVariant();
2223 
2224  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2225  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2226 
2227  if ( fGeom.isEmpty() || sGeom.isEmpty() )
2228  return QVariant();
2229 
2231 
2232  if ( values.length() == 2 )
2233  {
2234  //two geometry arguments, return relation
2235  QString result = engine->relate( *sGeom.geometry() );
2236  return QVariant::fromValue( result );
2237  }
2238  else
2239  {
2240  //three arguments, test pattern
2241  QString pattern = getStringValue( values.at( 2 ), parent );
2242  bool result = engine->relatePattern( *sGeom.geometry(), pattern );
2243  return QVariant::fromValue( result );
2244  }
2245 }
2246 
2247 static QVariant fcnBbox( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2248 {
2249  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2250  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2251  return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
2252 }
2253 static QVariant fcnDisjoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2254 {
2255  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2256  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2257  return fGeom.disjoint( &sGeom ) ? TVL_True : TVL_False;
2258 }
2259 static QVariant fcnIntersects( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2260 {
2261  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2262  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2263  return fGeom.intersects( &sGeom ) ? TVL_True : TVL_False;
2264 }
2265 static QVariant fcnTouches( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2266 {
2267  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2268  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2269  return fGeom.touches( &sGeom ) ? TVL_True : TVL_False;
2270 }
2271 static QVariant fcnCrosses( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2272 {
2273  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2274  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2275  return fGeom.crosses( &sGeom ) ? TVL_True : TVL_False;
2276 }
2277 static QVariant fcnContains( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2278 {
2279  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2280  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2281  return fGeom.contains( &sGeom ) ? TVL_True : TVL_False;
2282 }
2283 static QVariant fcnOverlaps( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2284 {
2285  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2286  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2287  return fGeom.overlaps( &sGeom ) ? TVL_True : TVL_False;
2288 }
2289 static QVariant fcnWithin( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2290 {
2291  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2292  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2293  return fGeom.within( &sGeom ) ? TVL_True : TVL_False;
2294 }
2295 static QVariant fcnBuffer( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2296 {
2297  if ( values.length() < 2 || values.length() > 3 )
2298  return QVariant();
2299 
2300  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2301  double dist = getDoubleValue( values.at( 1 ), parent );
2302  int seg = 8;
2303  if ( values.length() == 3 )
2304  seg = getIntValue( values.at( 2 ), parent );
2305 
2306  QgsGeometry* geom = fGeom.buffer( dist, seg );
2307  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2308  delete geom;
2309  return result;
2310 }
2311 static QVariant fcnTranslate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2312 {
2313  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2314  double dx = getDoubleValue( values.at( 1 ), parent );
2315  double dy = getDoubleValue( values.at( 2 ), parent );
2316  fGeom.translate( dx, dy );
2317  return QVariant::fromValue( fGeom );
2318 }
2319 static QVariant fcnCentroid( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2320 {
2321  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2322  QgsGeometry* geom = fGeom.centroid();
2323  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2324  delete geom;
2325  return result;
2326 }
2327 static QVariant fcnPointOnSurface( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2328 {
2329  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2330  QgsGeometry* geom = fGeom.pointOnSurface();
2331  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2332  delete geom;
2333  return result;
2334 }
2335 static QVariant fcnConvexHull( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2336 {
2337  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2338  QgsGeometry* geom = fGeom.convexHull();
2339  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2340  delete geom;
2341  return result;
2342 }
2343 static QVariant fcnDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2344 {
2345  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2346  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2347  QgsGeometry* geom = fGeom.difference( &sGeom );
2348  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2349  delete geom;
2350  return result;
2351 }
2352 
2353 static QVariant fcnReverse( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2354 {
2355  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2356  if ( fGeom.isEmpty() )
2357  return QVariant();
2358 
2359  QgsCurveV2* curve = dynamic_cast< QgsCurveV2* >( fGeom.geometry() );
2360  if ( !curve )
2361  return QVariant();
2362 
2363  QgsCurveV2* reversed = curve->reversed();
2364  QVariant result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
2365  return result;
2366 }
2367 
2368 static QVariant fcnExteriorRing( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2369 {
2370  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2371  if ( fGeom.isEmpty() )
2372  return QVariant();
2373 
2374  QgsCurvePolygonV2* curvePolygon = dynamic_cast< QgsCurvePolygonV2* >( fGeom.geometry() );
2375  if ( !curvePolygon || !curvePolygon->exteriorRing() )
2376  return QVariant();
2377 
2378  QgsCurveV2* exterior = static_cast< QgsCurveV2* >( curvePolygon->exteriorRing()->clone() );
2379  QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
2380  return result;
2381 }
2382 
2383 static QVariant fcnDistance( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2384 {
2385  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2386  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2387  return QVariant( fGeom.distance( sGeom ) );
2388 }
2389 static QVariant fcnIntersection( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2390 {
2391  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2392  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2393  QgsGeometry* geom = fGeom.intersection( &sGeom );
2394  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2395  delete geom;
2396  return result;
2397 }
2398 static QVariant fcnSymDifference( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2399 {
2400  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2401  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2402  QgsGeometry* geom = fGeom.symDifference( &sGeom );
2403  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2404  delete geom;
2405  return result;
2406 }
2407 static QVariant fcnCombine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2408 {
2409  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2410  QgsGeometry sGeom = getGeometry( values.at( 1 ), parent );
2411  QgsGeometry* geom = fGeom.combine( &sGeom );
2412  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2413  delete geom;
2414  return result;
2415 }
2416 static QVariant fcnGeomToWKT( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2417 {
2418  if ( values.length() < 1 || values.length() > 2 )
2419  return QVariant();
2420 
2421  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2422  int prec = 8;
2423  if ( values.length() == 2 )
2424  prec = getIntValue( values.at( 1 ), parent );
2425  QString wkt = fGeom.exportToWkt( prec );
2426  return QVariant( wkt );
2427 }
2428 
2429 static QVariant fcnAzimuth( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2430 {
2431  if ( values.length() != 2 )
2432  {
2433  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
2434  return QVariant();
2435  }
2436 
2437  QgsGeometry fGeom1 = getGeometry( values.at( 0 ), parent );
2438  QgsGeometry fGeom2 = getGeometry( values.at( 1 ), parent );
2439 
2440  const QgsPointV2* pt1 = dynamic_cast<const QgsPointV2*>( fGeom1.geometry() );
2441  const QgsPointV2* pt2 = dynamic_cast<const QgsPointV2*>( fGeom2.geometry() );
2442 
2443  if ( !pt1 || !pt2 )
2444  {
2445  parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
2446  return QVariant();
2447  }
2448 
2449  // Code from postgis
2450  if ( pt1->x() == pt2->x() )
2451  {
2452  if ( pt1->y() < pt2->y() )
2453  return 0.0;
2454  else if ( pt1->y() > pt2->y() )
2455  return M_PI;
2456  else
2457  return 0;
2458  }
2459 
2460  if ( pt1->y() == pt2->y() )
2461  {
2462  if ( pt1->x() < pt2->x() )
2463  return M_PI / 2;
2464  else if ( pt1->x() > pt2->x() )
2465  return M_PI + ( M_PI / 2 );
2466  else
2467  return 0;
2468  }
2469 
2470  if ( pt1->x() < pt2->x() )
2471  {
2472  if ( pt1->y() < pt2->y() )
2473  {
2474  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) );
2475  }
2476  else /* ( pt1->y() > pt2->y() ) - equality case handled above */
2477  {
2478  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2479  + ( M_PI / 2 );
2480  }
2481  }
2482 
2483  else /* ( pt1->x() > pt2->x() ) - equality case handled above */
2484  {
2485  if ( pt1->y() > pt2->y() )
2486  {
2487  return atan( fabs( pt1->x() - pt2->x() ) / fabs( pt1->y() - pt2->y() ) )
2488  + M_PI;
2489  }
2490  else /* ( pt1->y() < pt2->y() ) - equality case handled above */
2491  {
2492  return atan( fabs( pt1->y() - pt2->y() ) / fabs( pt1->x() - pt2->x() ) )
2493  + ( M_PI + ( M_PI / 2 ) );
2494  }
2495  }
2496 }
2497 
2498 static QVariant fcnProject( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2499 {
2500  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2501 
2502  if ( geom.type() != QGis::Point )
2503  {
2504  parent->setEvalErrorString( "'project' requires a point geometry" );
2505  return QVariant();
2506  }
2507 
2508  double distance = getDoubleValue( values.at( 1 ), parent );
2509  double bearing = getDoubleValue( values.at( 2 ), parent );
2510 
2511  QgsPoint p = geom.asPoint();
2512  QgsPoint newPoint = p.project( distance, ( 180 * bearing ) / M_PI );
2513 
2514  return QVariant::fromValue( QgsGeometry( new QgsPointV2( newPoint.x(), newPoint.y() ) ) );
2515 }
2516 
2517 static QVariant fcnExtrude( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2518 {
2519  if ( values.length() != 3 )
2520  return QVariant();
2521 
2522  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2523  double x = getDoubleValue( values.at( 1 ), parent );
2524  double y = getDoubleValue( values.at( 2 ), parent );
2525 
2526  QgsGeometry geom = fGeom.extrude( x, y );
2527 
2528  QVariant result = geom.geometry() ? QVariant::fromValue( geom ) : QVariant();
2529  return result;
2530 }
2531 
2532 static QVariant fcnOrderParts( const QVariantList& values, const QgsExpressionContext* ctx, QgsExpression* parent )
2533 {
2534  if ( values.length() < 2 )
2535  return QVariant();
2536 
2537  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
2538 
2539  if ( !fGeom.isMultipart() )
2540  return values.at( 0 );
2541 
2542  QString expString = getStringValue( values.at( 1 ), parent );
2543  bool asc = values.value( 2 ).toBool();
2544 
2545  QgsExpressionContext* unconstedContext;
2546  QgsFeature f;
2547  if ( ctx )
2548  {
2549  // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
2550  // so no reason to worry
2551  unconstedContext = const_cast<QgsExpressionContext*>( ctx );
2552  f = ctx->feature();
2553  }
2554  else
2555  {
2556  // If there's no context provided, create a fake one
2557  unconstedContext = new QgsExpressionContext();
2558  }
2559 
2560  QgsGeometryCollectionV2* collection = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry() );
2561  Q_ASSERT( collection ); // Should have failed the multipart check above
2562 
2564  orderBy.append( QgsFeatureRequest::OrderByClause( expString, asc ) );
2565  QgsExpressionSorter sorter( orderBy );
2566 
2567  QList<QgsFeature> partFeatures;
2568  for ( int i = 0; i < collection->partCount(); ++i )
2569  {
2570  f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
2571  partFeatures << f;
2572  }
2573 
2574  sorter.sortFeatures( partFeatures, unconstedContext );
2575 
2576  QgsGeometryCollectionV2* orderedGeom = dynamic_cast<QgsGeometryCollectionV2*>( fGeom.geometry()->clone() );
2577 
2578  Q_ASSERT( orderedGeom );
2579 
2580  while ( orderedGeom->partCount() )
2581  orderedGeom->removeGeometry( 0 );
2582 
2583  Q_FOREACH ( const QgsFeature& feature, partFeatures )
2584  {
2585  orderedGeom->addGeometry( feature.constGeometry()->geometry()->clone() );
2586  }
2587 
2588  QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
2589 
2590  if ( !ctx )
2591  delete unconstedContext;
2592 
2593  return result;
2594 }
2595 
2596 static QVariant fcnClosestPoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2597 {
2598  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2599  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2600 
2601  QgsGeometry geom = fromGeom.nearestPoint( toGeom );
2602 
2603  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2604  return result;
2605 }
2606 
2607 static QVariant fcnShortestLine( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2608 {
2609  QgsGeometry fromGeom = getGeometry( values.at( 0 ), parent );
2610  QgsGeometry toGeom = getGeometry( values.at( 1 ), parent );
2611 
2612  QgsGeometry geom = fromGeom.shortestLine( toGeom );
2613 
2614  QVariant result = !geom.isEmpty() ? QVariant::fromValue( geom ) : QVariant();
2615  return result;
2616 }
2617 
2618 static QVariant fcnLineInterpolatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2619 {
2620  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2621  double distance = getDoubleValue( values.at( 1 ), parent );
2622 
2623  QgsGeometry* geom = lineGeom.interpolate( distance );
2624 
2625  QVariant result = geom ? QVariant::fromValue( *geom ) : QVariant();
2626  delete geom;
2627  return result;
2628 }
2629 
2630 static QVariant fcnLineInterpolateAngle( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2631 {
2632  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2633  double distance = getDoubleValue( values.at( 1 ), parent );
2634 
2635  return lineGeom.interpolateAngle( distance ) * 180.0 / M_PI;
2636 }
2637 
2638 static QVariant fcnAngleAtVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2639 {
2640  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2641  int vertex = getIntValue( values.at( 1 ), parent );
2642 
2643  return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
2644 }
2645 
2646 static QVariant fcnDistanceToVertex( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2647 {
2648  QgsGeometry geom = getGeometry( values.at( 0 ), parent );
2649  int vertex = getIntValue( values.at( 1 ), parent );
2650 
2651  return geom.distanceToVertex( vertex );
2652 }
2653 
2654 static QVariant fcnLineLocatePoint( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2655 {
2656  QgsGeometry lineGeom = getGeometry( values.at( 0 ), parent );
2657  QgsGeometry pointGeom = getGeometry( values.at( 1 ), parent );
2658 
2659  double distance = lineGeom.lineLocatePoint( pointGeom );
2660 
2661  return distance >= 0 ? distance : QVariant();
2662 }
2663 
2664 static QVariant fcnRound( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2665 {
2666  if ( values.length() == 2 )
2667  {
2668  double number = getDoubleValue( values.at( 0 ), parent );
2669  double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
2670  return QVariant( qRound( number * scaler ) / scaler );
2671  }
2672 
2673  if ( values.length() == 1 )
2674  {
2675  double number = getIntValue( values.at( 0 ), parent );
2676  return QVariant( qRound( number ) ).toInt();
2677  }
2678 
2679  return QVariant();
2680 }
2681 
2682 static QVariant fcnPi( const QVariantList& values, const QgsExpressionContext *, QgsExpression* parent )
2683 {
2684  Q_UNUSED( values );
2685  Q_UNUSED( parent );
2686  return M_PI;
2687 }
2688 
2689 static QVariant fcnScale( const QVariantList&, const QgsExpressionContext*, QgsExpression* parent )
2690 {
2691  return QVariant( parent->scale() );
2692 }
2693 
2694 static QVariant fcnFormatNumber( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2695 {
2696  double value = getDoubleValue( values.at( 0 ), parent );
2697  int places = getIntValue( values.at( 1 ), parent );
2698  if ( places < 0 )
2699  {
2700  parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
2701  return QVariant();
2702  }
2703  return QString( "%L1" ).arg( value, 0, 'f', places );
2704 }
2705 
2706 static QVariant fcnFormatDate( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
2707 {
2708  QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
2709  QString format = getStringValue( values.at( 1 ), parent );
2710  return dt.toString( format );
2711 }
2712 
2713 static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2714 {
2715  int red = getIntValue( values.at( 0 ), parent );
2716  int green = getIntValue( values.at( 1 ), parent );
2717  int blue = getIntValue( values.at( 2 ), parent );
2718  QColor color = QColor( red, green, blue );
2719  if ( ! color.isValid() )
2720  {
2721  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
2722  color = QColor( 0, 0, 0 );
2723  }
2724 
2725  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2726 }
2727 
2728 static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent )
2729 {
2730  QgsExpression::Node* node = getNode( values.at( 0 ), parent );
2732  QVariant value = node->eval( parent, context );
2734  if ( value.toBool() )
2735  {
2736  node = getNode( values.at( 1 ), parent );
2738  value = node->eval( parent, context );
2740  }
2741  else
2742  {
2743  node = getNode( values.at( 2 ), parent );
2745  value = node->eval( parent, context );
2747  }
2748  return value;
2749 }
2750 
2751 static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2752 {
2753  int red = getIntValue( values.at( 0 ), parent );
2754  int green = getIntValue( values.at( 1 ), parent );
2755  int blue = getIntValue( values.at( 2 ), parent );
2756  int alpha = getIntValue( values.at( 3 ), parent );
2757  QColor color = QColor( red, green, blue, alpha );
2758  if ( ! color.isValid() )
2759  {
2760  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
2761  color = QColor( 0, 0, 0 );
2762  }
2763  return QgsSymbolLayerV2Utils::encodeColor( color );
2764 }
2765 
2766 QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2767 {
2768  QString rampName = getStringValue( values.at( 0 ), parent );
2769  const QgsVectorColorRampV2 *mRamp = QgsStyleV2::defaultStyle()->colorRampRef( rampName );
2770  if ( ! mRamp )
2771  {
2772  parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
2773  return QColor( 0, 0, 0 ).name();
2774  }
2775  double value = getDoubleValue( values.at( 1 ), parent );
2776  QColor color = mRamp->color( value );
2777  return QgsSymbolLayerV2Utils::encodeColor( color );
2778 }
2779 
2780 static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent )
2781 {
2782  // Hue ranges from 0 - 360
2783  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2784  // Saturation ranges from 0 - 100
2785  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2786  // Lightness ranges from 0 - 100
2787  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2788 
2789  QColor color = QColor::fromHslF( hue, saturation, lightness );
2790 
2791  if ( ! color.isValid() )
2792  {
2793  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
2794  color = QColor( 0, 0, 0 );
2795  }
2796 
2797  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2798 }
2799 
2800 static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2801 {
2802  // Hue ranges from 0 - 360
2803  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2804  // Saturation ranges from 0 - 100
2805  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2806  // Lightness ranges from 0 - 100
2807  double lightness = getIntValue( values.at( 2 ), parent ) / 100.0;
2808  // Alpha ranges from 0 - 255
2809  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2810 
2811  QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
2812  if ( ! color.isValid() )
2813  {
2814  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
2815  color = QColor( 0, 0, 0 );
2816  }
2817  return QgsSymbolLayerV2Utils::encodeColor( color );
2818 }
2819 
2820 static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2821 {
2822  // Hue ranges from 0 - 360
2823  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2824  // Saturation ranges from 0 - 100
2825  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2826  // Value ranges from 0 - 100
2827  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2828 
2829  QColor color = QColor::fromHsvF( hue, saturation, value );
2830 
2831  if ( ! color.isValid() )
2832  {
2833  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
2834  color = QColor( 0, 0, 0 );
2835  }
2836 
2837  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2838 }
2839 
2840 static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2841 {
2842  // Hue ranges from 0 - 360
2843  double hue = getIntValue( values.at( 0 ), parent ) / 360.0;
2844  // Saturation ranges from 0 - 100
2845  double saturation = getIntValue( values.at( 1 ), parent ) / 100.0;
2846  // Value ranges from 0 - 100
2847  double value = getIntValue( values.at( 2 ), parent ) / 100.0;
2848  // Alpha ranges from 0 - 255
2849  double alpha = getIntValue( values.at( 3 ), parent ) / 255.0;
2850 
2851  QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
2852  if ( ! color.isValid() )
2853  {
2854  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
2855  color = QColor( 0, 0, 0 );
2856  }
2857  return QgsSymbolLayerV2Utils::encodeColor( color );
2858 }
2859 
2860 static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2861 {
2862  // Cyan ranges from 0 - 100
2863  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2864  // Magenta ranges from 0 - 100
2865  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2866  // Yellow ranges from 0 - 100
2867  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2868  // Black ranges from 0 - 100
2869  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2870 
2871  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
2872 
2873  if ( ! color.isValid() )
2874  {
2875  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
2876  color = QColor( 0, 0, 0 );
2877  }
2878 
2879  return QString( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
2880 }
2881 
2882 static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2883 {
2884  // Cyan ranges from 0 - 100
2885  double cyan = getIntValue( values.at( 0 ), parent ) / 100.0;
2886  // Magenta ranges from 0 - 100
2887  double magenta = getIntValue( values.at( 1 ), parent ) / 100.0;
2888  // Yellow ranges from 0 - 100
2889  double yellow = getIntValue( values.at( 2 ), parent ) / 100.0;
2890  // Black ranges from 0 - 100
2891  double black = getIntValue( values.at( 3 ), parent ) / 100.0;
2892  // Alpha ranges from 0 - 255
2893  double alpha = getIntValue( values.at( 4 ), parent ) / 255.0;
2894 
2895  QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
2896  if ( ! color.isValid() )
2897  {
2898  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
2899  color = QColor( 0, 0, 0 );
2900  }
2901  return QgsSymbolLayerV2Utils::encodeColor( color );
2902 }
2903 
2904 static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2905 {
2906  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2907  if ( ! color.isValid() )
2908  {
2909  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2910  return QVariant();
2911  }
2912 
2913  QString part = getStringValue( values.at( 1 ), parent );
2914  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2915  return color.red();
2916  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2917  return color.green();
2918  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2919  return color.blue();
2920  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2921  return color.alpha();
2922  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2923  return color.hsvHueF() * 360;
2924  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2925  return color.hsvSaturationF() * 100;
2926  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2927  return color.valueF() * 100;
2928  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2929  return color.hslHueF() * 360;
2930  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2931  return color.hslSaturationF() * 100;
2932  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2933  return color.lightnessF() * 100;
2934  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2935  return color.cyanF() * 100;
2936  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2937  return color.magentaF() * 100;
2938  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2939  return color.yellowF() * 100;
2940  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2941  return color.blackF() * 100;
2942 
2943  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2944  return QVariant();
2945 }
2946 
2947 static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2948 {
2949  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2950  if ( ! color.isValid() )
2951  {
2952  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
2953  return QVariant();
2954  }
2955 
2956  QString part = getStringValue( values.at( 1 ), parent );
2957  int value = getIntValue( values.at( 2 ), parent );
2958  if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
2959  color.setRed( value );
2960  else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
2961  color.setGreen( value );
2962  else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
2963  color.setBlue( value );
2964  else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
2965  color.setAlpha( value );
2966  else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
2967  color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
2968  else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
2969  color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
2970  else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
2971  color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
2972  else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
2973  color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
2974  else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
2975  color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
2976  else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
2977  color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
2978  else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
2979  color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
2980  else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
2981  color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
2982  else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
2983  color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
2984  else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
2985  color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
2986  else
2987  {
2988  parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
2989  return QVariant();
2990  }
2991  return QgsSymbolLayerV2Utils::encodeColor( color );
2992 }
2993 
2994 static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
2995 {
2996  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
2997  if ( ! color.isValid() )
2998  {
2999  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3000  return QVariant();
3001  }
3002 
3003  color = color.darker( getIntValue( values.at( 1 ), parent ) );
3004 
3005  return QgsSymbolLayerV2Utils::encodeColor( color );
3006 }
3007 
3008 static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext*, QgsExpression *parent )
3009 {
3010  QColor color = QgsSymbolLayerV2Utils::decodeColor( values.at( 0 ).toString() );
3011  if ( ! color.isValid() )
3012  {
3013  parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
3014  return QVariant();
3015  }
3016 
3017  color = color.lighter( getIntValue( values.at( 1 ), parent ) );
3018 
3019  return QgsSymbolLayerV2Utils::encodeColor( color );
3020 }
3021 
3022 static QVariant fcnSpecialColumn( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3023 {
3024  QString varName = getStringValue( values.at( 0 ), parent );
3026  return QgsExpression::specialColumn( varName );
3028 }
3029 
3030 static QVariant fcnGetGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3031 {
3032  QgsFeature feat = getFeature( values.at( 0 ), parent );
3033  const QgsGeometry* geom = feat.constGeometry();
3034  if ( geom )
3035  return QVariant::fromValue( *geom );
3036  return QVariant();
3037 }
3038 
3039 static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3040 {
3041  QgsGeometry fGeom = getGeometry( values.at( 0 ), parent );
3042  QString sAuthId = getStringValue( values.at( 1 ), parent );
3043  QString dAuthId = getStringValue( values.at( 2 ), parent );
3044 
3046  if ( ! s.isValid() )
3047  return QVariant::fromValue( fGeom );
3049  if ( ! d.isValid() )
3050  return QVariant::fromValue( fGeom );
3051 
3052  QgsCoordinateTransform t( s, d );
3053  try
3054  {
3055  if ( fGeom.transform( t ) == 0 )
3056  return QVariant::fromValue( fGeom );
3057  }
3058  catch ( QgsCsException &cse )
3059  {
3060  QgsMessageLog::logMessage( QString( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
3061  return QVariant();
3062  }
3063  return QVariant();
3064 }
3065 
3066 
3067 static QVariant fcnGetFeature( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3068 {
3069  //arguments: 1. layer id / name, 2. key attribute, 3. eq value
3070  QgsVectorLayer* vl = getVectorLayer( values.at( 0 ), parent );
3071 
3072  //no layer found
3073  if ( !vl )
3074  {
3075  return QVariant();
3076  }
3077 
3078  QString attribute = getStringValue( values.at( 1 ), parent );
3079  int attributeId = vl->fieldNameIndex( attribute );
3080  if ( attributeId == -1 )
3081  {
3082  return QVariant();
3083  }
3084 
3085  const QVariant& attVal = values.at( 2 );
3086  QgsFeatureRequest req;
3087  req.setFilterExpression( QString( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
3088  QgsExpression::quotedString( attVal.toString() ) ) );
3089  req.setLimit( 1 );
3090  if ( !parent->needsGeometry() )
3091  {
3093  }
3094  QgsFeatureIterator fIt = vl->getFeatures( req );
3095 
3096  QgsFeature fet;
3097  if ( fIt.nextFeature( fet ) )
3098  return QVariant::fromValue( fet );
3099 
3100  return QVariant();
3101 }
3102 
3103 static QVariant fcnGetLayerProperty( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
3104 {
3105  QString layerIdOrName = getStringValue( values.at( 0 ), parent );
3106 
3107  //try to find a matching layer by name
3108  QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerIdOrName ); //search by id first
3109  if ( !layer )
3110  {
3111  QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerIdOrName );
3112  if ( !layersByName.isEmpty() )
3113  {
3114  layer = layersByName.at( 0 );
3115  }
3116  }
3117 
3118  if ( !layer )
3119  return QVariant();
3120 
3121  QString layerProperty = getStringValue( values.at( 1 ), parent );
3122  if ( QString::compare( layerProperty, QString( "name" ), Qt::CaseInsensitive ) == 0 )
3123  return layer->name();
3124  else if ( QString::compare( layerProperty, QString( "id" ), Qt::CaseInsensitive ) == 0 )
3125  return layer->id();
3126  else if ( QString::compare( layerProperty, QString( "title" ), Qt::CaseInsensitive ) == 0 )
3127  return layer->title();
3128  else if ( QString::compare( layerProperty, QString( "abstract" ), Qt::CaseInsensitive ) == 0 )
3129  return layer->abstract();
3130  else if ( QString::compare( layerProperty, QString( "keywords" ), Qt::CaseInsensitive ) == 0 )
3131  return layer->keywordList();
3132  else if ( QString::compare( layerProperty, QString( "data_url" ), Qt::CaseInsensitive ) == 0 )
3133  return layer->dataUrl();
3134  else if ( QString::compare( layerProperty, QString( "attribution" ), Qt::CaseInsensitive ) == 0 )
3135  return layer->attribution();
3136  else if ( QString::compare( layerProperty, QString( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
3137  return layer->attributionUrl();
3138  else if ( QString::compare( layerProperty, QString( "source" ), Qt::CaseInsensitive ) == 0 )
3139  return layer->publicSource();
3140  else if ( QString::compare( layerProperty, QString( "min_scale" ), Qt::CaseInsensitive ) == 0 )
3141  return layer->minimumScale();
3142  else if ( QString::compare( layerProperty, QString( "max_scale" ), Qt::CaseInsensitive ) == 0 )
3143  return layer->maximumScale();
3144  else if ( QString::compare( layerProperty, QString( "crs" ), Qt::CaseInsensitive ) == 0 )
3145  return layer->crs().authid();
3146  else if ( QString::compare( layerProperty, QString( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
3147  return layer->crs().toProj4();
3148  else if ( QString::compare( layerProperty, QString( "extent" ), Qt::CaseInsensitive ) == 0 )
3149  {
3150  QgsGeometry* extentGeom = QgsGeometry::fromRect( layer->extent() );
3151  QVariant result = QVariant::fromValue( *extentGeom );
3152  delete extentGeom;
3153  return result;
3154  }
3155  else if ( QString::compare( layerProperty, QString( "type" ), Qt::CaseInsensitive ) == 0 )
3156  {
3157  switch ( layer->type() )
3158  {
3160  return QCoreApplication::translate( "expressions", "Vector" );
3162  return QCoreApplication::translate( "expressions", "Raster" );
3164  return QCoreApplication::translate( "expressions", "Plugin" );
3165  }
3166  }
3167  else
3168  {
3169  //vector layer methods
3170  QgsVectorLayer* vLayer = dynamic_cast< QgsVectorLayer* >( layer );
3171  if ( vLayer )
3172  {
3173  if ( QString::compare( layerProperty, QString( "storage_type" ), Qt::CaseInsensitive ) == 0 )
3174  return vLayer->storageType();
3175  else if ( QString::compare( layerProperty, QString( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
3176  return QGis::vectorGeometryType( vLayer->geometryType() );
3177  else if ( QString::compare( layerProperty, QString( "feature_count" ), Qt::CaseInsensitive ) == 0 )
3178  return QVariant::fromValue( vLayer->featureCount() );
3179  }
3180  }
3181 
3182  return QVariant();
3183 }
3184 
3185 bool QgsExpression::registerFunction( QgsExpression::Function* function, bool transferOwnership )
3186 {
3187  int fnIdx = functionIndex( function->name() );
3188  if ( fnIdx != -1 )
3189  {
3190  return false;
3191  }
3192  QgsExpression::gmFunctions.append( function );
3193  if ( transferOwnership )
3194  QgsExpression::gmOwnedFunctions.append( function );
3195  return true;
3196 }
3197 
3199 {
3200  // You can never override the built in functions.
3201  if ( QgsExpression::BuiltinFunctions().contains( name ) )
3202  {
3203  return false;
3204  }
3205  int fnIdx = functionIndex( name );
3206  if ( fnIdx != -1 )
3207  {
3208  QgsExpression::gmFunctions.removeAt( fnIdx );
3209  return true;
3210  }
3211  return false;
3212 }
3213 
3215 {
3216  qDeleteAll( QgsExpression::gmOwnedFunctions );
3218 }
3219 
3221 
3223 {
3224  if ( gmBuiltinFunctions.isEmpty() )
3225  {
3227  << "abs" << "sqrt" << "cos" << "sin" << "tan"
3228  << "asin" << "acos" << "atan" << "atan2"
3229  << "exp" << "ln" << "log10" << "log"
3230  << "round" << "rand" << "randf" << "max" << "min" << "clamp"
3231  << "scale_linear" << "scale_exp" << "floor" << "ceil" << "$pi"
3232  << "toint" << "to_int" << "toreal" << "to_real" << "tostring" << "to_string"
3233  << "todatetime" << "to_datetime" << "todate" << "to_date"
3234  << "totime" << "to_time" << "tointerval" << "to_interval"
3235  << "coalesce" << "if" << "regexp_match" << "age" << "year"
3236  << "month" << "week" << "day" << "hour" << "day_of_week"
3237  << "minute" << "second" << "lower" << "upper"
3238  << "title" << "length" << "replace" << "trim" << "wordwrap"
3239  << "regexp_replace" << "regexp_substr"
3240  << "substr" << "concat" << "strpos" << "left"
3241  << "right" << "rpad" << "lpad" << "format"
3242  << "format_number" << "format_date"
3243  << "color_rgb" << "color_rgba" << "ramp_color"
3244  << "color_hsl" << "color_hsla" << "color_hsv" << "color_hsva"
3245  << "color_cmyk" << "color_cmyka" << "color_part" << "set_color_part"
3246  << "xat" << "yat" << "$area" << "area" << "perimeter"
3247  << "$length" << "$perimeter" << "x" << "y" << "$x" << "$y" << "z" << "m" << "num_points"
3248  << "num_interior_rings" << "num_rings" << "num_geometries"
3249  << "geometry_n" << "interior_ring_n"
3250  << "point_n" << "start_point" << "end_point" << "make_point" << "make_point_m"
3251  << "nodes_to_points" << "segments_to_lines"
3252  << "make_line" << "make_polygon"
3253  << "$x_at" << "x_at" << "xat" << "$y_at" << "y_at" << "yat" << "x_min" << "xmin" << "x_max" << "xmax"
3254  << "y_min" << "ymin" << "y_max" << "ymax" << "geom_from_wkt" << "geomFromWKT"
3255  << "geom_from_gml" << "geomFromGML" << "intersects_bbox" << "bbox"
3256  << "disjoint" << "intersects" << "touches" << "crosses" << "contains"
3257  << "relate"
3258  << "overlaps" << "within" << "buffer" << "centroid" << "bounds" << "reverse" << "exterior_ring"
3259  << "boundary" << "line_merge"
3260  << "bounds_width" << "bounds_height" << "is_closed" << "convex_hull" << "difference"
3261  << "distance" << "intersection" << "sym_difference" << "combine"
3262  << "extrude" << "azimuth" << "project" << "closest_point" << "shortest_line"
3263  << "line_locate_point" << "line_interpolate_point"
3264  << "line_interpolate_angle" << "angle_at_vertex" << "distance_to_vertex"
3265  << "union" << "geom_to_wkt" << "geomToWKT" << "geometry"
3266  << "transform" << "get_feature" << "getFeature"
3267  << "levenshtein" << "longest_common_substring" << "hamming_distance"
3268  << "soundex"
3269  << "aggregate" << "relation_aggregate" << "count" << "count_distinct"
3270  << "count_missing" << "minimum" << "maximum" << "sum" << "mean"
3271  << "median" << "stdev" << "range" << "minority" << "majority"
3272  << "q1" << "q3" << "iqr" << "min_length" << "max_length" << "concatenate"
3273  << "attribute" << "var" << "layer_property"
3274  << "$id" << "$scale" << "_specialcol_";
3275  }
3276  return gmBuiltinFunctions;
3277 }
3278 
3281 
3283 {
3284  // The construction of the list isn't thread-safe, and without the mutex,
3285  // crashes in the WFS provider may occur, since it can parse expressions
3286  // in parallel.
3287  // The mutex needs to be recursive.
3288  static QMutex sFunctionsMutex( QMutex::Recursive );
3289  QMutexLocker locker( &sFunctionsMutex );
3290 
3291  if ( gmFunctions.isEmpty() )
3292  {
3293  ParameterList aggParams = ParameterList() << Parameter( "expression" )
3294  << Parameter( "group_by", true )
3295  << Parameter( "filter", true );
3296 
3297  gmFunctions
3298  << new StaticFunction( "sqrt", ParameterList() << Parameter( "value" ), fcnSqrt, "Math" )
3299  << new StaticFunction( "radians", ParameterList() << Parameter( "degrees" ), fcnRadians, "Math" )
3300  << new StaticFunction( "degrees", ParameterList() << Parameter( "radians" ), fcnDegrees, "Math" )
3301  << new StaticFunction( "azimuth", ParameterList() << Parameter( "point_a" ) << Parameter( "point_b" ), fcnAzimuth, "Math" )
3302  << new StaticFunction( "project", ParameterList() << Parameter( "point" ) << Parameter( "distance" ) << Parameter( "bearing" ), fcnProject, "GeometryGroup" )
3303  << new StaticFunction( "abs", ParameterList() << Parameter( "value" ), fcnAbs, "Math" )
3304  << new StaticFunction( "cos", ParameterList() << Parameter( "angle" ), fcnCos, "Math" )
3305  << new StaticFunction( "sin", ParameterList() << Parameter( "angle" ), fcnSin, "Math" )
3306  << new StaticFunction( "tan", ParameterList() << Parameter( "angle" ), fcnTan, "Math" )
3307  << new StaticFunction( "asin", ParameterList() << Parameter( "value" ), fcnAsin, "Math" )
3308  << new StaticFunction( "acos", ParameterList() << Parameter( "value" ), fcnAcos, "Math" )
3309  << new StaticFunction( "atan", ParameterList() << Parameter( "value" ), fcnAtan, "Math" )
3310  << new StaticFunction( "atan2", ParameterList() << Parameter( "dx" ) << Parameter( "dy" ), fcnAtan2, "Math" )
3311  << new StaticFunction( "exp", ParameterList() << Parameter( "value" ), fcnExp, "Math" )
3312  << new StaticFunction( "ln", ParameterList() << Parameter( "value" ), fcnLn, "Math" )
3313  << new StaticFunction( "log10", ParameterList() << Parameter( "value" ), fcnLog10, "Math" )
3314  << new StaticFunction( "log", ParameterList() << Parameter( "base" ) << Parameter( "value" ), fcnLog, "Math" )
3315  << new StaticFunction( "round", ParameterList() << Parameter( "value" ) << Parameter( "places", true, 0 ), fcnRound, "Math" )
3316  << new StaticFunction( "rand", ParameterList() << Parameter( "min" ) << Parameter( "max" ), fcnRnd, "Math" )
3317  << new StaticFunction( "randf", ParameterList() << Parameter( "min", true, 0.0 ) << Parameter( "max", true, 1.0 ), fcnRndF, "Math" )
3318  << new StaticFunction( "max", -1, fcnMax, "Math" )
3319  << new StaticFunction( "min", -1, fcnMin, "Math" )
3320  << new StaticFunction( "clamp", ParameterList() << Parameter( "min" ) << Parameter( "value" ) << Parameter( "max" ), fcnClamp, "Math" )
3321  << new StaticFunction( "scale_linear", 5, fcnLinearScale, "Math" )
3322  << new StaticFunction( "scale_exp", 6, fcnExpScale, "Math" )
3323  << new StaticFunction( "floor", 1, fcnFloor, "Math" )
3324  << new StaticFunction( "ceil", 1, fcnCeil, "Math" )
3325  << new StaticFunction( "pi", 0, fcnPi, "Math", QString(), false, QStringList(), false, QStringList() << "$pi" )
3326  << new StaticFunction( "to_int", 1, fcnToInt, "Conversions", QString(), false, QStringList(), false, QStringList() << "toint" )
3327  << new StaticFunction( "to_real", 1, fcnToReal, "Conversions", QString(), false, QStringList(), false, QStringList() << "toreal" )
3328  << new StaticFunction( "to_string", 1, fcnToString, "Conversions", QString(), false, QStringList(), false, QStringList() << "tostring" )
3329  << new StaticFunction( "to_datetime", 1, fcnToDateTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "todatetime" )
3330  << new StaticFunction( "to_date", 1, fcnToDate, "Conversions", QString(), false, QStringList(), false, QStringList() << "todate" )
3331  << new StaticFunction( "to_time", 1, fcnToTime, "Conversions", QString(), false, QStringList(), false, QStringList() << "totime" )
3332  << new StaticFunction( "to_interval", 1, fcnToInterval, "Conversions", QString(), false, QStringList(), false, QStringList() << "tointerval" )
3333  << new StaticFunction( "coalesce", -1, fcnCoalesce, "Conditionals", QString(), false, QStringList(), false, QStringList(), true )
3334  << new StaticFunction( "if", 3, fcnIf, "Conditionals", QString(), False, QStringList(), true )
3335  << new StaticFunction( "aggregate", ParameterList() << Parameter( "layer" ) << Parameter( "aggregate" ) << Parameter( "expression" )
3336  << Parameter( "filter", true ) << Parameter( "concatenator", true ), fcnAggregate, "Aggregates", QString(), False, QStringList(), true )
3337  << new StaticFunction( "relation_aggregate", ParameterList() << Parameter( "relation" ) << Parameter( "aggregate" ) << Parameter( "expression" ) << Parameter( "concatenator", true ),
3339 
3340  << new StaticFunction( "count", aggParams, fcnAggregateCount, "Aggregates", QString(), False, QStringList(), true )
3341  << new StaticFunction( "count_distinct", aggParams, fcnAggregateCountDistinct, "Aggregates", QString(), False, QStringList(), true )
3342  << new StaticFunction( "count_missing", aggParams, fcnAggregateCountMissing, "Aggregates", QString(), False, QStringList(), true )
3343  << new StaticFunction( "minimum", aggParams, fcnAggregateMin, "Aggregates", QString(), False, QStringList(), true )
3344  << new StaticFunction( "maximum", aggParams, fcnAggregateMax, "Aggregates", QString(), False, QStringList(), true )
3345  << new StaticFunction( "sum", aggParams, fcnAggregateSum, "Aggregates", QString(), False, QStringList(), true )
3346  << new StaticFunction( "mean", aggParams, fcnAggregateMean, "Aggregates", QString(), False, QStringList(), true )
3347  << new StaticFunction( "median", aggParams, fcnAggregateMedian, "Aggregates", QString(), False, QStringList(), true )
3348  << new StaticFunction( "stdev", aggParams, fcnAggregateStdev, "Aggregates", QString(), False, QStringList(), true )
3349  << new StaticFunction( "range", aggParams, fcnAggregateRange, "Aggregates", QString(), False, QStringList(), true )
3350  << new StaticFunction( "minority", aggParams, fcnAggregateMinority, "Aggregates", QString(), False, QStringList(), true )
3351  << new StaticFunction( "majority", aggParams, fcnAggregateMajority, "Aggregates", QString(), False, QStringList(), true )
3352  << new StaticFunction( "q1", aggParams, fcnAggregateQ1, "Aggregates", QString(), False, QStringList(), true )
3353  << new StaticFunction( "q3", aggParams, fcnAggregateQ3, "Aggregates", QString(), False, QStringList(), true )
3354  << new StaticFunction( "iqr", aggParams, fcnAggregateIQR, "Aggregates", QString(), False, QStringList(), true )
3355  << new StaticFunction( "min_length", aggParams, fcnAggregateMinLength, "Aggregates", QString(), False, QStringList(), true )
3356  << new StaticFunction( "max_length", aggParams, fcnAggregateMaxLength, "Aggregates", QString(), False, QStringList(), true )
3357  << new StaticFunction( "concatenate", aggParams << Parameter( "concatenator", true ), fcnAggregateStringConcat, "Aggregates", QString(), False, QStringList(), true )
3358 
3359  << new StaticFunction( "regexp_match", 2, fcnRegexpMatch, "Conditionals" )
3360  << new StaticFunction( "now", 0, fcnNow, "Date and Time", QString(), false, QStringList(), false, QStringList() << "$now" )
3361  << new StaticFunction( "age", 2, fcnAge, "Date and Time" )
3362  << new StaticFunction( "year", 1, fcnYear, "Date and Time" )
3363  << new StaticFunction( "month", 1, fcnMonth, "Date and Time" )
3364  << new StaticFunction( "week", 1, fcnWeek, "Date and Time" )
3365  << new StaticFunction( "day", 1, fcnDay, "Date and Time" )
3366  << new StaticFunction( "hour", 1, fcnHour, "Date and Time" )
3367  << new StaticFunction( "minute", 1, fcnMinute, "Date and Time" )
3368  << new StaticFunction( "second", 1, fcnSeconds, "Date and Time" )
3369  << new StaticFunction( "day_of_week", 1, fcnDayOfWeek, "Date and Time" )
3370  << new StaticFunction( "lower", 1, fcnLower, "String" )
3371  << new StaticFunction( "upper", 1, fcnUpper, "String" )
3372  << new StaticFunction( "title", 1, fcnTitle, "String" )
3373  << new StaticFunction( "trim", 1, fcnTrim, "String" )
3374  << new StaticFunction( "levenshtein", 2, fcnLevenshtein, "Fuzzy Matching" )
3375  << new StaticFunction( "longest_common_substring", 2, fcnLCS, "Fuzzy Matching" )
3376  << new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
3377  << new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
3378  << new StaticFunction( "char", 1, fcnChar, "String" )
3379  << new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, " " ), fcnWordwrap, "String" )
3380  << new StaticFunction( "length", 1, fcnLength, "String" )
3381  << new StaticFunction( "replace", 3, fcnReplace, "String" )
3382  << new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
3383  << new StaticFunction( "regexp_substr", 2, fcnRegexpSubstr, "String" )
3384  << new StaticFunction( "substr", 3, fcnSubstr, "String" )
3385  << new StaticFunction( "concat", -1, fcnConcat, "String", QString(), false, QStringList(), false, QStringList(), true )
3386  << new StaticFunction( "strpos", 2, fcnStrpos, "String" )
3387  << new StaticFunction( "left", 2, fcnLeft, "String" )
3388  << new StaticFunction( "right", 2, fcnRight, "String" )
3389  << new StaticFunction( "rpad", 3, fcnRPad, "String" )
3390  << new StaticFunction( "lpad", 3, fcnLPad, "String" )
3391  << new StaticFunction( "format", -1, fcnFormatString, "String" )
3392  << new StaticFunction( "format_number", 2, fcnFormatNumber, "String" )
3393  << new StaticFunction( "format_date", 2, fcnFormatDate, "String" )
3394  << new StaticFunction( "color_rgb", 3, fcnColorRgb, "Color" )
3395  << new StaticFunction( "color_rgba", 4, fncColorRgba, "Color" )
3396  << new StaticFunction( "ramp_color", 2, fcnRampColor, "Color" )
3397  << new StaticFunction( "color_hsl", 3, fcnColorHsl, "Color" )
3398  << new StaticFunction( "color_hsla", 4, fncColorHsla, "Color" )
3399  << new StaticFunction( "color_hsv", 3, fcnColorHsv, "Color" )
3400  << new StaticFunction( "color_hsva", 4, fncColorHsva, "Color" )
3401  << new StaticFunction( "color_cmyk", 4, fcnColorCmyk, "Color" )
3402  << new StaticFunction( "color_cmyka", 5, fncColorCmyka, "Color" )
3403  << new StaticFunction( "color_part", 2, fncColorPart, "Color" )
3404  << new StaticFunction( "darker", 2, fncDarker, "Color" )
3405  << new StaticFunction( "lighter", 2, fncLighter, "Color" )
3406  << new StaticFunction( "set_color_part", 3, fncSetColorPart, "Color" )
3407  << new StaticFunction( "$geometry", 0, fcnGeometry, "GeometryGroup", QString(), true )
3408  << new StaticFunction( "$area", 0, fcnGeomArea, "GeometryGroup", QString(), true )
3409  << new StaticFunction( "area", 1, fcnArea, "GeometryGroup" )
3410  << new StaticFunction( "$length", 0, fcnGeomLength, "GeometryGroup", QString(), true )
3411  << new StaticFunction( "$perimeter", 0, fcnGeomPerimeter, "GeometryGroup", QString(), true )
3412  << new StaticFunction( "perimeter", 1, fcnPerimeter, "GeometryGroup" )
3413  << new StaticFunction( "$x", 0, fcnX, "GeometryGroup", QString(), true )
3414  << new StaticFunction( "$y", 0, fcnY, "GeometryGroup", QString(), true )
3415  << new StaticFunction( "x", 1, fcnGeomX, "GeometryGroup" )
3416  << new StaticFunction( "y", 1, fcnGeomY, "GeometryGroup" )
3417  << new StaticFunction( "z", 1, fcnGeomZ, "GeometryGroup" )
3418  << new StaticFunction( "m", 1, fcnGeomM, "GeometryGroup" )
3419  << new StaticFunction( "point_n", 2, fcnPointN, "GeometryGroup" )
3420  << new StaticFunction( "start_point", 1, fcnStartPoint, "GeometryGroup" )
3421  << new StaticFunction( "end_point", 1, fcnEndPoint, "GeometryGroup" )
3422  << new StaticFunction( "nodes_to_points", -1, fcnNodesToPoints, "GeometryGroup" )
3423  << new StaticFunction( "segments_to_lines", 1, fcnSegmentsToLines, "GeometryGroup" )
3424  << new StaticFunction( "make_point", -1, fcnMakePoint, "GeometryGroup" )
3425  << new StaticFunction( "make_point_m", 3, fcnMakePointM, "GeometryGroup" )
3426  << new StaticFunction( "make_line", -1, fcnMakeLine, "GeometryGroup" )
3427  << new StaticFunction( "make_polygon", -1, fcnMakePolygon, "GeometryGroup" )
3428  << new StaticFunction( "$x_at", 1, fcnXat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "xat" << "x_at" )
3429  << new StaticFunction( "$y_at", 1, fcnYat, "GeometryGroup", QString(), true, QStringList(), false, QStringList() << "yat" << "y_at" )
3430  << new StaticFunction( "x_min", 1, fcnXMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmin" )
3431  << new StaticFunction( "x_max", 1, fcnXMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "xmax" )
3432  << new StaticFunction( "y_min", 1, fcnYMin, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymin" )
3433  << new StaticFunction( "y_max", 1, fcnYMax, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "ymax" )
3434  << new StaticFunction( "geom_from_wkt", 1, fcnGeomFromWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromWKT" )
3435  << new StaticFunction( "geom_from_gml", 1, fcnGeomFromGML, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomFromGML" )
3436  << new StaticFunction( "relate", -1, fcnRelate, "GeometryGroup" )
3437  << new StaticFunction( "intersects_bbox", 2, fcnBbox, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "bbox" )
3438  << new StaticFunction( "disjoint", 2, fcnDisjoint, "GeometryGroup" )
3439  << new StaticFunction( "intersects", 2, fcnIntersects, "GeometryGroup" )
3440  << new StaticFunction( "touches", 2, fcnTouches, "GeometryGroup" )
3441  << new StaticFunction( "crosses", 2, fcnCrosses, "GeometryGroup" )
3442  << new StaticFunction( "contains", 2, fcnContains, "GeometryGroup" )
3443  << new StaticFunction( "overlaps", 2, fcnOverlaps, "GeometryGroup" )
3444  << new StaticFunction( "within", 2, fcnWithin, "GeometryGroup" )
3445  << new StaticFunction( "translate", 3, fcnTranslate, "GeometryGroup" )
3446  << new StaticFunction( "buffer", -1, fcnBuffer, "GeometryGroup" )
3447  << new StaticFunction( "centroid", 1, fcnCentroid, "GeometryGroup" )
3448  << new StaticFunction( "point_on_surface", 1, fcnPointOnSurface, "GeometryGroup" )
3449  << new StaticFunction( "reverse", 1, fcnReverse, "GeometryGroup" )
3450  << new StaticFunction( "exterior_ring", 1, fcnExteriorRing, "GeometryGroup" )
3451  << new StaticFunction( "interior_ring_n", 2, fcnInteriorRingN, "GeometryGroup" )
3452  << new StaticFunction( "geometry_n", 2, fcnGeometryN, "GeometryGroup" )
3453  << new StaticFunction( "boundary", ParameterList() << Parameter( "geometry" ), fcnBoundary, "GeometryGroup" )
3454  << new StaticFunction( "line_merge", ParameterList() << Parameter( "geometry" ), fcnLineMerge, "GeometryGroup" )
3455  << new StaticFunction( "bounds", 1, fcnBounds, "GeometryGroup" )
3456  << new StaticFunction( "num_points", 1, fcnGeomNumPoints, "GeometryGroup" )
3457  << new StaticFunction( "num_interior_rings", 1, fcnGeomNumInteriorRings, "GeometryGroup" )
3458  << new StaticFunction( "num_rings", 1, fcnGeomNumRings, "GeometryGroup" )
3459  << new StaticFunction( "num_geometries", 1, fcnGeomNumGeometries, "GeometryGroup" )
3460  << new StaticFunction( "bounds_width", 1, fcnBoundsWidth, "GeometryGroup" )
3461  << new StaticFunction( "bounds_height", 1, fcnBoundsHeight, "GeometryGroup" )
3462  << new StaticFunction( "is_closed", 1, fcnIsClosed, "GeometryGroup" )
3463  << new StaticFunction( "convex_hull", 1, fcnConvexHull, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "convexHull" )
3464  << new StaticFunction( "difference", 2, fcnDifference, "GeometryGroup" )
3465  << new StaticFunction( "distance", 2, fcnDistance, "GeometryGroup" )
3466  << new StaticFunction( "intersection", 2, fcnIntersection, "GeometryGroup" )
3467  << new StaticFunction( "sym_difference", 2, fcnSymDifference, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "symDifference" )
3468  << new StaticFunction( "combine", 2, fcnCombine, "GeometryGroup" )
3469  << new StaticFunction( "union", 2, fcnCombine, "GeometryGroup" )
3470  << new StaticFunction( "geom_to_wkt", -1, fcnGeomToWKT, "GeometryGroup", QString(), false, QStringList(), false, QStringList() << "geomToWKT" )
3471  << new StaticFunction( "geometry", 1, fcnGetGeometry, "GeometryGroup", QString(), true )
3472  << new StaticFunction( "transform", 3, fcnTransformGeometry, "GeometryGroup" )
3473  << new StaticFunction( "extrude", 3, fcnExtrude, "GeometryGroup", QString() )
3474  << new StaticFunction( "order_parts", 3, fcnOrderParts, "GeometryGroup", QString() )
3475  << new StaticFunction( "closest_point", 2, fcnClosestPoint, "GeometryGroup" )
3476  << new StaticFunction( "shortest_line", 2, fcnShortestLine, "GeometryGroup" )
3477  << new StaticFunction( "line_interpolate_point", ParameterList() << Parameter( "geometry" )
3478  << Parameter( "distance" ), fcnLineInterpolatePoint, "GeometryGroup" )
3479  << new StaticFunction( "line_interpolate_angle", ParameterList() << Parameter( "geometry" )
3480  << Parameter( "distance" ), fcnLineInterpolateAngle, "GeometryGroup" )
3481  << new StaticFunction( "line_locate_point", ParameterList() << Parameter( "geometry" )
3482  << Parameter( "point" ), fcnLineLocatePoint, "GeometryGroup" )
3483  << new StaticFunction( "angle_at_vertex", ParameterList() << Parameter( "geometry" )
3484  << Parameter( "vertex" ), fcnAngleAtVertex, "GeometryGroup" )
3485  << new StaticFunction( "distance_to_vertex", ParameterList() << Parameter( "geometry" )
3486  << Parameter( "vertex" ), fcnDistanceToVertex, "GeometryGroup" )
3487  << new StaticFunction( "$rownum", 0, fcnRowNumber, "deprecated" )
3488  << new StaticFunction( "$id", 0, fcnFeatureId, "Record" )
3489  << new StaticFunction( "$currentfeature", 0, fcnFeature, "Record" )
3490  << new StaticFunction( "$scale", 0, fcnScale, "Record" )
3491  << new StaticFunction( "$map", 0, fcnMapId, "deprecated" )
3492  << new StaticFunction( "$numpages", 0, fcnComposerNumPages, "deprecated" )
3493  << new StaticFunction( "$page", 0, fcnComposerPage, "deprecated" )
3494  << new StaticFunction( "$feature", 0, fcnAtlasFeature, "deprecated" )
3495  << new StaticFunction( "$atlasfeatureid", 0, fcnAtlasFeatureId, "deprecated" )
3496  << new StaticFunction( "$atlasfeature", 0, fcnAtlasCurrentFeature, "deprecated" )
3497  << new StaticFunction( "$atlasgeometry", 0, fcnAtlasCurrentGeometry, "deprecated" )
3498  << new StaticFunction( "$numfeatures", 0, fcnAtlasNumFeatures, "deprecated" )
3499  << new StaticFunction( "uuid", 0, fcnUuid, "Record", QString(), false, QStringList(), false, QStringList() << "$uuid" )
3500  << new StaticFunction( "get_feature", 3, fcnGetFeature, "Record", QString(), false, QStringList(), false, QStringList() << "getFeature" )
3501  << new StaticFunction( "layer_property", 2, fcnGetLayerProperty, "General" )
3502  << new StaticFunction( "var", 1, fcnGetVariable, "General" )
3503 
3504  //return all attributes string for referencedColumns - this is caught by
3505  // QgsFeatureRequest::setSubsetOfAttributes and causes all attributes to be fetched by the
3506  // feature request
3507  << new StaticFunction( "eval", 1, fcnEval, "General", QString(), true, QStringList( QgsFeatureRequest::AllAttributes ) )
3508  << new StaticFunction( "attribute", 2, fcnAttribute, "Record", QString(), false, QStringList( QgsFeatureRequest::AllAttributes ) )
3509 
3510  << new StaticFunction( "_specialcol_", 1, fcnSpecialColumn, "Special" )
3511  ;
3512 
3514 
3515  //QgsExpression has ownership of all built-in functions
3516  Q_FOREACH ( QgsExpression::Function* func, gmFunctions )
3517  {
3518  gmOwnedFunctions << func;
3519  }
3520  }
3521  return gmFunctions;
3522 }
3523 
3526 
3527 void QgsExpression::setSpecialColumn( const QString& name, const QVariant& variant )
3528 {
3529  int fnIdx = functionIndex( name );
3530  if ( fnIdx != -1 )
3531  {
3532  // function of the same name already exists
3533  return;
3534  }
3535  gmSpecialColumns[ name ] = variant;
3536 }
3537 
3539 {
3541  if ( fit != gmSpecialColumns.end() )
3542  {
3543  gmSpecialColumns.erase( fit );
3544  }
3545 }
3546 
3548 {
3549  int fnIdx = functionIndex( name );
3550  if ( fnIdx != -1 )
3551  {
3552  // function of the same name already exists
3553  return QVariant();
3554  }
3556  if ( it == gmSpecialColumns.constEnd() )
3557  {
3558  return QVariant();
3559  }
3560  return it.value();
3561 }
3562 
3564 {
3565  if ( functionIndex( name ) != -1 )
3566  return false;
3567  return gmSpecialColumns.contains( name );
3568 }
3569 
3570 bool QgsExpression::isValid( const QString &text, const QgsFields &fields, QString &errorMessage )
3571 {
3573  return isValid( text, &context, errorMessage );
3574 }
3575 
3576 bool QgsExpression::isValid( const QString &text, const QgsExpressionContext *context, QString &errorMessage )
3577 {
3578  QgsExpression exp( text );
3579  exp.prepare( context );
3580  errorMessage = exp.parserErrorString();
3581  return !exp.hasParserError();
3582 }
3583 
3585 {
3586  detach();
3587  d->mRootNode = ::parseExpression( expression, d->mParserErrorString );
3588  d->mEvalErrorString = QString();
3589  d->mExp = expression;
3590 }
3591 
3592 void QgsExpression::setScale( double scale ) { d->mScale = scale; }
3593 
3594 double QgsExpression::scale() { return d->mScale; }
3595 
3597 {
3598  if ( !d->mExp.isNull() )
3599  return d->mExp;
3600  else
3601  return dump();
3602 }
3603 
3605 {
3606  QList<Function*> defs;
3608  {
3609  //check for special column group name
3610  QString group = gmSpecialColumnGroups.value( it.key(), "Record" );
3611  defs << new StaticFunction( it.key(), 0, static_cast< FcnEvalContext >( nullptr ), group );
3612  }
3613  return defs;
3614 }
3615 
3617 {
3618  return QString( "\"%1\"" ).arg( name.replace( '\"', "\"\"" ) );
3619 }
3620 
3622 {
3623  text.replace( '\'', "''" );
3624  text.replace( '\\', "\\\\" );
3625  text.replace( '\n', "\\n" );
3626  text.replace( '\t', "\\t" );
3627  return QString( "'%1'" ).arg( text );
3628 }
3629 
3631 {
3632  return quotedValue( value, value.type() );
3633 }
3634 
3635 QString QgsExpression::quotedValue( const QVariant& value, QVariant::Type type )
3636 {
3637  if ( value.isNull() )
3638  return "NULL";
3639 
3640  switch ( type )
3641  {
3642  case QVariant::Int:
3643  case QVariant::LongLong:
3644  case QVariant::Double:
3645  return value.toString();
3646 
3647  case QVariant::Bool:
3648  return value.toBool() ? "TRUE" : "FALSE";
3649 
3650  default:
3651  case QVariant::String:
3652  return quotedString( value.toString() );
3653  }
3654 
3655 }
3656 
3658 {
3659  return functionIndex( name ) != -1;
3660 }
3661 
3663 {
3664  int count = functionCount();
3665  for ( int i = 0; i < count; i++ )
3666  {
3667  if ( QString::compare( name, Functions()[i]->name(), Qt::CaseInsensitive ) == 0 )
3668  return i;
3669  Q_FOREACH ( const QString& alias, Functions()[i]->aliases() )
3670  {
3671  if ( QString::compare( name, alias, Qt::CaseInsensitive ) == 0 )
3672  return i;
3673  }
3674  }
3675  return -1;
3676 }
3677 
3679 {
3680  return Functions().size();
3681 }
3682 
3683 
3685  : d( new QgsExpressionPrivate )
3686 {
3687  d->mRootNode = ::parseExpression( expr, d->mParserErrorString );
3688  d->mExp = expr;
3689  Q_ASSERT( !d->mParserErrorString.isNull() || d->mRootNode );
3690 }
3691 
3693  : d( other.d )
3694 {
3695  d->ref.ref();
3696 }
3697 
3699 {
3700  d = other.d;
3701  d->ref.ref();
3702  return *this;
3703 }
3704 
3706  : d( new QgsExpressionPrivate )
3707 {
3708 }
3709 
3711 {
3712  Q_ASSERT( d );
3713  if ( !d->ref.deref() )
3714  delete d;
3715 }
3716 
3717 bool QgsExpression::operator==( const QgsExpression& other ) const
3718 {
3719  if ( d == other.d || d->mExp == other.d->mExp )
3720  return true;
3721  return false;
3722 }
3723 
3725 {
3726  return d->mRootNode;
3727 }
3728 
3729 bool QgsExpression::hasParserError() const { return !d->mParserErrorString.isNull(); }
3730 
3731 QString QgsExpression::parserErrorString() const { return d->mParserErrorString; }
3732 
3734 {
3735  if ( !d->mRootNode )
3736  return QStringList();
3737 
3738  QStringList columns = d->mRootNode->referencedColumns();
3739 
3740  // filter out duplicates
3741  for ( int i = 0; i < columns.count(); i++ )
3742  {
3743  QString col = columns.at( i );
3744  for ( int j = i + 1; j < columns.count(); j++ )
3745  {
3746  if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 )
3747  {
3748  // this column is repeated: remove it!
3749  columns.removeAt( j-- );
3750  }
3751  }
3752  }
3753 
3754  return columns;
3755 }
3756 
3758 {
3759  if ( !d->mRootNode )
3760  return false;
3761  return d->mRootNode->needsGeometry();
3762 }
3763 
3765 {
3766  if ( d->mCalc.data() )
3767  return;
3768 
3769  // Use planimetric as default
3771  d->mCalc->setEllipsoidalMode( false );
3772 }
3773 
3775 {
3776  Q_ASSERT( d );
3777 
3778  if ( d->ref > 1 )
3779  {
3780  ( void )d->ref.deref();
3781 
3782  d = new QgsExpressionPrivate( *d );
3783  }
3784 }
3785 
3787 {
3788  d->mCalc = QSharedPointer<QgsDistanceArea>( new QgsDistanceArea( calc ) );
3789 }
3790 
3791 bool QgsExpression::prepare( const QgsFields& fields )
3792 {
3793  detach();
3795  return prepare( &fc );
3796 }
3797 
3799 {
3800  detach();
3801  d->mEvalErrorString = QString();
3802  if ( !d->mRootNode )
3803  {
3804  //re-parse expression. Creation of QgsExpressionContexts may have added extra
3805  //known functions since this expression was created, so we have another try
3806  //at re-parsing it now that the context must have been created
3807  d->mRootNode = ::parseExpression( d->mExp, d->mParserErrorString );
3808  }
3809 
3810  if ( !d->mRootNode )
3811  {
3812  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3813  return false;
3814  }
3815 
3816  return d->mRootNode->prepare( this, context );
3817 }
3818 
3820 {
3821  d->mEvalErrorString = QString();
3822  if ( !d->mRootNode )
3823  {
3824  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3825  return QVariant();
3826  }
3827 
3829  return d->mRootNode->eval( this, &context );
3830 }
3831 
3833 {
3835  return evaluate( &f );
3837 }
3838 
3840 {
3841  // first prepare
3843  bool res = prepare( &context );
3844  if ( !res )
3845  return QVariant();
3846 
3847  // then evaluate
3848  return evaluate( &context );
3849 }
3850 
3851 inline QVariant QgsExpression::evaluate( const QgsFeature& f, const QgsFields& fields )
3852 {
3854  return evaluate( &f, fields );
3856 }
3857 
3859 {
3860  d->mEvalErrorString = QString();
3861  if ( !d->mRootNode )
3862  {
3863  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3864  return QVariant();
3865  }
3866 
3867  return d->mRootNode->eval( this, static_cast<const QgsExpressionContext*>( nullptr ) );
3868 }
3869 
3871 {
3872  d->mEvalErrorString = QString();
3873  if ( !d->mRootNode )
3874  {
3875  d->mEvalErrorString = tr( "No root node! Parsing failed?" );
3876  return QVariant();
3877  }
3878 
3879  return d->mRootNode->eval( this, context );
3880 }
3881 
3883 {
3884  return !d->mEvalErrorString.isNull();
3885 }
3886 
3888 {
3889  return d->mEvalErrorString;
3890 }
3891 
3893 {
3894  d->mEvalErrorString = str;
3895 }
3896 
3898 {
3899  d->mRowNumber = rowNumber;
3900 }
3901 
3902 int QgsExpression::currentRowNumber() { return d->mRowNumber; }
3903 
3905 {
3906  if ( !d->mRootNode )
3907  return QString();
3908 
3909  return d->mRootNode->dump();
3910 }
3911 
3913 {
3914  return d->mCalc.data();
3915 }
3916 
3918 {
3919  return d->mDistanceUnit;
3920 }
3921 
3923 {
3924  d->mDistanceUnit = unit;
3925 }
3926 
3928 {
3929  return d->mAreaUnit;
3930 }
3931 
3933 {
3934  d->mAreaUnit = unit;
3935 }
3936 
3938 {
3939  if ( d->mRootNode )
3940  d->mRootNode->accept( v );
3941 }
3942 
3944  QgsVectorLayer *layer,
3945  const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3946 {
3947  QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( feat ? *feat : QgsFeature(), layer ? layer->fields() : QgsFields() );
3948  return replaceExpressionText( action, &context, substitutionMap, distanceArea );
3949 }
3950 
3951 QString QgsExpression::replaceExpressionText( const QString &action, const QgsExpressionContext *context, const QMap<QString, QVariant> *substitutionMap, const QgsDistanceArea *distanceArea )
3952 {
3953  QString expr_action;
3954 
3955  QMap<QString, QVariant> savedValues;
3956  if ( substitutionMap )
3957  {
3958  // variables with a local scope (must be restored after evaluation)
3959  for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
3960  {
3962  QVariant oldValue = QgsExpression::specialColumn( sit.key() );
3963  if ( !oldValue.isNull() )
3964  savedValues.insert( sit.key(), oldValue );
3965 
3966  // set the new value
3967  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
3969  }
3970  }
3971 
3972  int index = 0;
3973  while ( index < action.size() )
3974  {
3975  QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
3976 
3977  int pos = rx.indexIn( action, index );
3978  if ( pos < 0 )
3979  break;
3980 
3981  int start = index;
3982  index = pos + rx.matchedLength();
3983  QString to_replace = rx.cap( 1 ).trimmed();
3984  QgsDebugMsg( "Found expression: " + to_replace );
3985 
3986  QgsExpression exp( to_replace );
3987  if ( exp.hasParserError() )
3988  {
3989  QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
3990  expr_action += action.midRef( start, index - start );
3991  continue;
3992  }
3993 
3994  if ( distanceArea )
3995  {
3996  //if QgsDistanceArea specified for area/distance conversion, use it
3997  exp.setGeomCalculator( *distanceArea );
3998  }
3999 
4000  QVariant result = exp.evaluate( context );
4001 
4002  if ( exp.hasEvalError() )
4003  {
4004  QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
4005  expr_action += action.midRef( start, index - start );
4006  continue;
4007  }
4008 
4009  QgsDebugMsg( "Expression result is: " + result.toString() );
4010  expr_action += action.mid( start, pos - start ) + result.toString();
4011  }
4012 
4013  expr_action += action.midRef( index );
4014 
4015  // restore overwritten local values
4017  for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
4018  {
4019  QgsExpression::setSpecialColumn( sit.key(), sit.value() );
4020  }
4022 
4023  return expr_action;
4024 }
4025 
4026 double QgsExpression::evaluateToDouble( const QString &text, const double fallbackValue )
4027 {
4028  bool ok;
4029  //first test if text is directly convertible to double
4030  double convertedValue = text.toDouble( &ok );
4031  if ( ok )
4032  {
4033  return convertedValue;
4034  }
4035 
4036  //otherwise try to evalute as expression
4037  QgsExpression expr( text );
4038 
4039  QgsExpressionContext context;
4042 
4043  QVariant result = expr.evaluate( &context );
4044  convertedValue = result.toDouble( &ok );
4045  if ( expr.hasEvalError() || !ok )
4046  {
4047  return fallbackValue;
4048  }
4049  return convertedValue;
4050 }
4051 
4052 
4054 // nodes
4055 
4057 {
4058  NodeList* nl = new NodeList;
4059  Q_FOREACH ( Node* node, mList )
4060  {
4061  nl->mList.append( node->clone() );
4062  }
4063  nl->mNameList = mNameList;
4064 
4065  return nl;
4066 }
4067 
4069 {
4070  QString msg;
4071  bool first = true;
4072  Q_FOREACH ( Node* n, mList )
4073  {
4074  if ( !first ) msg += ", ";
4075  else first = false;
4076  msg += n->dump();
4077  }
4078  return msg;
4079 }
4080 
4081 
4082 //
4083 
4085 {
4086  QVariant val = mOperand->eval( parent, context );
4088 
4089  switch ( mOp )
4090  {
4091  case uoNot:
4092  {
4093  TVL tvl = getTVLValue( val, parent );
4095  return tvl2variant( NOT[tvl] );
4096  }
4097 
4098  case uoMinus:
4099  if ( isIntSafe( val ) )
4100  return QVariant( - getIntValue( val, parent ) );
4101  else if ( isDoubleSafe( val ) )
4102  return QVariant( - getDoubleValue( val, parent ) );
4103  else
4104  SET_EVAL_ERROR( tr( "Unary minus only for numeric values." ) );
4105  default:
4106  Q_ASSERT( 0 && "unknown unary operation" );
4107  }
4108  return QVariant();
4109 }
4110 
4112 {
4113  return mOperand->prepare( parent, context );
4114 }
4115 
4117 {
4118  return QString( "%1 %2" ).arg( UnaryOperatorText[mOp], mOperand->dump() );
4119 }
4120 
4122 {
4123  return new NodeUnaryOperator( mOp, mOperand->clone() );
4124 }
4125 
4126 //
4127 
4129 {
4130  QVariant vL = mOpLeft->eval( parent, context );
4132  QVariant vR = mOpRight->eval( parent, context );
4134 
4135  switch ( mOp )
4136  {
4137  case boPlus:
4138  if ( vL.type() == QVariant::String && vR.type() == QVariant::String )
4139  {
4140  QString sL = isNull( vL ) ? QString() : getStringValue( vL, parent );
4142  QString sR = isNull( vR ) ? QString() : getStringValue( vR, parent );
4144  return QVariant( sL + sR );
4145  }
4146  //intentional fall-through
4147  FALLTHROUGH;
4148  case boMinus:
4149  case boMul:
4150  case boDiv:
4151  case boMod:
4152  {
4153  if ( isNull( vL ) || isNull( vR ) )
4154  return QVariant();
4155  else if ( mOp != boDiv && isIntSafe( vL ) && isIntSafe( vR ) )
4156  {
4157  // both are integers - let's use integer arithmetics
4158  int iL = getIntValue( vL, parent );
4160  int iR = getIntValue( vR, parent );
4162 
4163  if ( mOp == boMod && iR == 0 )
4164  return QVariant();
4165 
4166  return QVariant( computeInt( iL, iR ) );
4167  }
4168  else if ( isDateTimeSafe( vL ) && isIntervalSafe( vR ) )
4169  {
4170  QDateTime dL = getDateTimeValue( vL, parent );
4172  QgsInterval iL = getInterval( vR, parent );
4174  if ( mOp == boDiv || mOp == boMul || mOp == boMod )
4175  {
4176  parent->setEvalErrorString( tr( "Can't preform /, *, or % on DateTime and Interval" ) );
4177  return QVariant();
4178  }
4179  return QVariant( computeDateTimeFromInterval( dL, &iL ) );
4180  }
4181  else if ( mOp == boPlus && (( vL.type() == QVariant::Date && vR.type() == QVariant::Time ) ||
4182  ( vR.type() == QVariant::Date && vL.type() == QVariant::Time ) ) )
4183  {
4184  QDate date = getDateValue( vL.type() == QVariant::Date ? vL : vR, parent );
4186  QTime time = getTimeValue( vR.type() == QVariant::Time ? vR : vL, parent );
4188  QDateTime dt =