Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsexpressionfunction.cpp
3 : : -------------------
4 : : begin : May 2017
5 : : copyright : (C) 2017 Matthias Kuhn
6 : : email : matthias@opengis.ch
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 : :
17 : : #include <random>
18 : :
19 : : #include "qgscoordinateformatter.h"
20 : : #include "qgscoordinateutils.h"
21 : : #include "qgsexpressionfunction.h"
22 : : #include "qgsexpressionutils.h"
23 : : #include "qgsexpressionnodeimpl.h"
24 : : #include "qgsfeaturerequest.h"
25 : : #include "qgsstringutils.h"
26 : : #include "qgsmultipoint.h"
27 : : #include "qgsgeometryutils.h"
28 : : #include "qgshstoreutils.h"
29 : : #include "qgsmultilinestring.h"
30 : : #include "qgslinestring.h"
31 : : #include "qgscurvepolygon.h"
32 : : #include "qgsmaptopixelgeometrysimplifier.h"
33 : : #include "qgspolygon.h"
34 : : #include "qgstriangle.h"
35 : : #include "qgscurve.h"
36 : : #include "qgsregularpolygon.h"
37 : : #include "qgsquadrilateral.h"
38 : : #include "qgsmultipolygon.h"
39 : : #include "qgsogcutils.h"
40 : : #include "qgsdistancearea.h"
41 : : #include "qgsgeometryengine.h"
42 : : #include "qgsexpressionsorter.h"
43 : : #include "qgssymbollayerutils.h"
44 : : #include "qgsstyle.h"
45 : : #include "qgsexception.h"
46 : : #include "qgsmessagelog.h"
47 : : #include "qgsrasterlayer.h"
48 : : #include "qgsvectorlayer.h"
49 : : #include "qgsrasterbandstats.h"
50 : : #include "qgscolorramp.h"
51 : : #include "qgsfieldformatterregistry.h"
52 : : #include "qgsfieldformatter.h"
53 : : #include "qgsvectorlayerfeatureiterator.h"
54 : : #include "qgsproviderregistry.h"
55 : : #include "sqlite3.h"
56 : : #include "qgstransaction.h"
57 : : #include "qgsthreadingutils.h"
58 : : #include "qgsapplication.h"
59 : : #include "qgis.h"
60 : : #include "qgsexpressioncontextutils.h"
61 : : #include "qgsunittypes.h"
62 : : #include "qgsspatialindex.h"
63 : :
64 : : #include <QMimeDatabase>
65 : : #include <QProcessEnvironment>
66 : : #include <QCryptographicHash>
67 : : #include <QRegularExpression>
68 : : #include <QUuid>
69 : :
70 : : typedef QList<QgsExpressionFunction *> ExpressionFunctionList;
71 : :
72 : 15 : Q_GLOBAL_STATIC( ExpressionFunctionList, sOwnedFunctions )
73 : 0 : Q_GLOBAL_STATIC( QStringList, sBuiltinFunctions )
74 : 0 : Q_GLOBAL_STATIC( ExpressionFunctionList, sFunctions )
75 : :
76 : 0 : Q_DECLARE_METATYPE( QgsSpatialIndex )
77 : 0 : Q_DECLARE_METATYPE( QgsExpressionContext )
78 : : Q_DECLARE_METATYPE( std::shared_ptr<QgsVectorLayer> )
79 : :
80 : 0 : const QString QgsExpressionFunction::helpText() const
81 : : {
82 : 0 : return mHelpText.isEmpty() ? QgsExpression::helpText( mName ) : mHelpText;
83 : 0 : }
84 : :
85 : 0 : QVariant QgsExpressionFunction::run( QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
86 : : {
87 : : Q_UNUSED( node )
88 : : // evaluate arguments
89 : 0 : QVariantList argValues;
90 : 0 : if ( args )
91 : : {
92 : 0 : int arg = 0;
93 : 0 : const QList< QgsExpressionNode * > argList = args->list();
94 : 0 : for ( QgsExpressionNode *n : argList )
95 : : {
96 : 0 : QVariant v;
97 : 0 : if ( lazyEval() )
98 : : {
99 : : // Pass in the node for the function to eval as it needs.
100 : 0 : v = QVariant::fromValue( n );
101 : 0 : }
102 : : else
103 : : {
104 : 0 : v = n->eval( parent, context );
105 : 0 : ENSURE_NO_EVAL_ERROR
106 : 0 : bool defaultParamIsNull = mParameterList.count() > arg && mParameterList.at( arg ).optional() && !mParameterList.at( arg ).defaultValue().isValid();
107 : 0 : if ( QgsExpressionUtils::isNull( v ) && !defaultParamIsNull && !handlesNull() )
108 : 0 : return QVariant(); // all "normal" functions return NULL, when any QgsExpressionFunction::Parameter is NULL (so coalesce is abnormal)
109 : : }
110 : 0 : argValues.append( v );
111 : 0 : arg++;
112 : 0 : }
113 : 0 : }
114 : :
115 : 0 : return func( argValues, context, parent, node );
116 : 0 : }
117 : :
118 : 0 : bool QgsExpressionFunction::usesGeometry( const QgsExpressionNodeFunction *node ) const
119 : : {
120 : : Q_UNUSED( node )
121 : 0 : return true;
122 : : }
123 : :
124 : 0 : QStringList QgsExpressionFunction::aliases() const
125 : : {
126 : 0 : return QStringList();
127 : : }
128 : :
129 : 0 : bool QgsExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
130 : : {
131 : : Q_UNUSED( parent )
132 : : Q_UNUSED( context )
133 : : Q_UNUSED( node )
134 : 0 : return false;
135 : : }
136 : :
137 : 0 : bool QgsExpressionFunction::prepare( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
138 : : {
139 : : Q_UNUSED( parent )
140 : : Q_UNUSED( context )
141 : : Q_UNUSED( node )
142 : 0 : return true;
143 : : }
144 : :
145 : 0 : QSet<QString> QgsExpressionFunction::referencedColumns( const QgsExpressionNodeFunction *node ) const
146 : : {
147 : : Q_UNUSED( node )
148 : 0 : return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
149 : 0 : }
150 : :
151 : 0 : bool QgsExpressionFunction::isDeprecated() const
152 : : {
153 : 0 : return mGroups.isEmpty() ? false : mGroups.contains( QStringLiteral( "deprecated" ) );
154 : 0 : }
155 : :
156 : 0 : bool QgsExpressionFunction::operator==( const QgsExpressionFunction &other ) const
157 : : {
158 : 0 : return ( QString::compare( mName, other.mName, Qt::CaseInsensitive ) == 0 );
159 : : }
160 : :
161 : 0 : bool QgsExpressionFunction::handlesNull() const
162 : : {
163 : 0 : return mHandlesNull;
164 : : }
165 : :
166 : : // doxygen doesn't like this constructor for some reason (maybe the function arguments?)
167 : : ///@cond PRIVATE
168 : 0 : QgsStaticExpressionFunction::QgsStaticExpressionFunction( const QString &fnname, const QgsExpressionFunction::ParameterList ¶ms,
169 : : FcnEval fcn,
170 : : const QString &group,
171 : : const QString &helpText,
172 : : const std::function < bool ( const QgsExpressionNodeFunction *node ) > &usesGeometry,
173 : : const std::function < QSet<QString>( const QgsExpressionNodeFunction *node ) > &referencedColumns,
174 : : bool lazyEval,
175 : : const QStringList &aliases,
176 : : bool handlesNull )
177 : 0 : : QgsExpressionFunction( fnname, params, group, helpText, lazyEval, handlesNull, false )
178 : 0 : , mFnc( fcn )
179 : 0 : , mAliases( aliases )
180 : 0 : , mUsesGeometry( false )
181 : 0 : , mUsesGeometryFunc( usesGeometry )
182 : 0 : , mReferencedColumnsFunc( referencedColumns )
183 : 0 : {
184 : 0 : }
185 : : ///@endcond
186 : :
187 : 0 : QStringList QgsStaticExpressionFunction::aliases() const
188 : : {
189 : 0 : return mAliases;
190 : : }
191 : :
192 : 0 : bool QgsStaticExpressionFunction::usesGeometry( const QgsExpressionNodeFunction *node ) const
193 : : {
194 : 0 : if ( mUsesGeometryFunc )
195 : 0 : return mUsesGeometryFunc( node );
196 : : else
197 : 0 : return mUsesGeometry;
198 : 0 : }
199 : :
200 : 0 : QSet<QString> QgsStaticExpressionFunction::referencedColumns( const QgsExpressionNodeFunction *node ) const
201 : : {
202 : 0 : if ( mReferencedColumnsFunc )
203 : 0 : return mReferencedColumnsFunc( node );
204 : : else
205 : 0 : return mReferencedColumns;
206 : 0 : }
207 : :
208 : 0 : bool QgsStaticExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
209 : : {
210 : 0 : if ( mIsStaticFunc )
211 : 0 : return mIsStaticFunc( node, parent, context );
212 : : else
213 : 0 : return mIsStatic;
214 : 0 : }
215 : :
216 : 0 : bool QgsStaticExpressionFunction::prepare( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
217 : : {
218 : 0 : if ( mPrepareFunc )
219 : 0 : return mPrepareFunc( node, parent, context );
220 : :
221 : 0 : return true;
222 : 0 : }
223 : :
224 : 0 : void QgsStaticExpressionFunction::setIsStaticFunction( const std::function<bool ( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * )> &isStatic )
225 : : {
226 : 0 : mIsStaticFunc = isStatic;
227 : 0 : }
228 : :
229 : 0 : void QgsStaticExpressionFunction::setIsStatic( bool isStatic )
230 : : {
231 : 0 : mIsStaticFunc = nullptr;
232 : 0 : mIsStatic = isStatic;
233 : 0 : }
234 : :
235 : 0 : void QgsStaticExpressionFunction::setPrepareFunction( const std::function<bool ( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * )> &prepareFunc )
236 : : {
237 : 0 : mPrepareFunc = prepareFunc;
238 : 0 : }
239 : :
240 : 0 : bool QgsExpressionFunction::allParamsStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context )
241 : : {
242 : 0 : if ( node && node->args() )
243 : : {
244 : 0 : const QList< QgsExpressionNode * > argList = node->args()->list();
245 : 0 : for ( QgsExpressionNode *argNode : argList )
246 : : {
247 : 0 : if ( !argNode->isStatic( parent, context ) )
248 : 0 : return false;
249 : : }
250 : 0 : }
251 : :
252 : 0 : return true;
253 : 0 : }
254 : :
255 : 0 : static QVariant fcnGenerateSeries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
256 : : {
257 : 0 : double start = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
258 : 0 : double stop = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
259 : 0 : double step = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
260 : :
261 : 0 : if ( step == 0.0 || ( step > 0.0 && start > stop ) || ( step < 0.0 && start < stop ) )
262 : 0 : return QVariant();
263 : :
264 : 0 : QVariantList array;
265 : 0 : int length = 1;
266 : :
267 : 0 : array << start;
268 : 0 : double current = start + step;
269 : 0 : while ( ( ( step > 0.0 && current <= stop ) || ( step < 0.0 && current >= stop ) ) && length <= 1000000 )
270 : : {
271 : 0 : array << current;
272 : 0 : current += step;
273 : 0 : length++;
274 : : }
275 : :
276 : 0 : return array;
277 : 0 : }
278 : :
279 : 0 : static QVariant fcnGetVariable( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
280 : : {
281 : 0 : if ( !context )
282 : 0 : return QVariant();
283 : :
284 : 0 : QString name = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
285 : 0 : return context->variable( name );
286 : 0 : }
287 : :
288 : 0 : static QVariant fcnEvalTemplate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
289 : : {
290 : 0 : QString templateString = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
291 : 0 : return QgsExpression::replaceExpressionText( templateString, context );
292 : 0 : }
293 : :
294 : 0 : static QVariant fcnEval( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
295 : : {
296 : 0 : if ( !context )
297 : 0 : return QVariant();
298 : :
299 : 0 : QString expString = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
300 : 0 : QgsExpression expression( expString );
301 : 0 : return expression.evaluate( context );
302 : 0 : }
303 : :
304 : 0 : static QVariant fcnSqrt( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
305 : : {
306 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
307 : 0 : return QVariant( std::sqrt( x ) );
308 : : }
309 : :
310 : 0 : static QVariant fcnAbs( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
311 : : {
312 : 0 : double val = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
313 : 0 : return QVariant( std::fabs( val ) );
314 : : }
315 : :
316 : 0 : static QVariant fcnRadians( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
317 : : {
318 : 0 : double deg = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
319 : 0 : return ( deg * M_PI ) / 180;
320 : : }
321 : 0 : static QVariant fcnDegrees( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
322 : : {
323 : 0 : double rad = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
324 : 0 : return ( 180 * rad ) / M_PI;
325 : : }
326 : 0 : static QVariant fcnSin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
327 : : {
328 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
329 : 0 : return QVariant( std::sin( x ) );
330 : : }
331 : 0 : static QVariant fcnCos( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
332 : : {
333 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
334 : 0 : return QVariant( std::cos( x ) );
335 : : }
336 : 0 : static QVariant fcnTan( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
337 : : {
338 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
339 : 0 : return QVariant( std::tan( x ) );
340 : : }
341 : 0 : static QVariant fcnAsin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
342 : : {
343 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
344 : 0 : return QVariant( std::asin( x ) );
345 : : }
346 : 0 : static QVariant fcnAcos( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
347 : : {
348 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
349 : 0 : return QVariant( std::acos( x ) );
350 : : }
351 : 0 : static QVariant fcnAtan( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
352 : : {
353 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
354 : 0 : return QVariant( std::atan( x ) );
355 : : }
356 : 0 : static QVariant fcnAtan2( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
357 : : {
358 : 0 : double y = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
359 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
360 : 0 : return QVariant( std::atan2( y, x ) );
361 : : }
362 : 0 : static QVariant fcnExp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
363 : : {
364 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
365 : 0 : return QVariant( std::exp( x ) );
366 : : }
367 : 0 : static QVariant fcnLn( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
368 : : {
369 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
370 : 0 : if ( x <= 0 )
371 : 0 : return QVariant();
372 : 0 : return QVariant( std::log( x ) );
373 : 0 : }
374 : 0 : static QVariant fcnLog10( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
375 : : {
376 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
377 : 0 : if ( x <= 0 )
378 : 0 : return QVariant();
379 : 0 : return QVariant( log10( x ) );
380 : 0 : }
381 : 0 : static QVariant fcnLog( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
382 : : {
383 : 0 : double b = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
384 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
385 : 0 : if ( x <= 0 || b <= 0 )
386 : 0 : return QVariant();
387 : 0 : return QVariant( std::log( x ) / std::log( b ) );
388 : 0 : }
389 : 0 : static QVariant fcnRndF( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
390 : : {
391 : 0 : double min = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
392 : 0 : double max = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
393 : 0 : if ( max < min )
394 : 0 : return QVariant();
395 : :
396 : 0 : std::random_device rd;
397 : 0 : std::mt19937_64 generator( rd() );
398 : :
399 : 0 : if ( !QgsExpressionUtils::isNull( values.at( 2 ) ) )
400 : : {
401 : : quint32 seed;
402 : 0 : if ( QgsExpressionUtils::isIntSafe( values.at( 2 ) ) )
403 : : {
404 : : // if seed can be converted to int, we use as is
405 : 0 : seed = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
406 : 0 : }
407 : : else
408 : : {
409 : : // if not, we hash string representation to int
410 : 0 : QString seedStr = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
411 : : std::hash<std::string> hasher;
412 : 0 : seed = hasher( seedStr.toStdString() );
413 : 0 : }
414 : 0 : generator.seed( seed );
415 : 0 : }
416 : :
417 : : // Return a random double in the range [min, max] (inclusive)
418 : 0 : double f = static_cast< double >( generator() ) / static_cast< double >( generator.max() );
419 : 0 : return QVariant( min + f * ( max - min ) );
420 : 0 : }
421 : 0 : static QVariant fcnRnd( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
422 : : {
423 : 0 : qlonglong min = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
424 : 0 : qlonglong max = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
425 : 0 : if ( max < min )
426 : 0 : return QVariant();
427 : :
428 : 0 : std::random_device rd;
429 : 0 : std::mt19937_64 generator( rd() );
430 : :
431 : 0 : if ( !QgsExpressionUtils::isNull( values.at( 2 ) ) )
432 : : {
433 : : quint32 seed;
434 : 0 : if ( QgsExpressionUtils::isIntSafe( values.at( 2 ) ) )
435 : : {
436 : : // if seed can be converted to int, we use as is
437 : 0 : seed = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
438 : 0 : }
439 : : else
440 : : {
441 : : // if not, we hash string representation to int
442 : 0 : QString seedStr = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
443 : : std::hash<std::string> hasher;
444 : 0 : seed = hasher( seedStr.toStdString() );
445 : 0 : }
446 : 0 : generator.seed( seed );
447 : 0 : }
448 : :
449 : 0 : qint64 randomInteger = min + ( generator() % ( max - min + 1 ) );
450 : 0 : if ( randomInteger > std::numeric_limits<int>::max() || randomInteger < -std::numeric_limits<int>::max() )
451 : 0 : return QVariant( randomInteger );
452 : :
453 : : // Prevent wrong conversion of QVariant. See #36412
454 : 0 : return QVariant( int( randomInteger ) );
455 : 0 : }
456 : :
457 : 0 : static QVariant fcnLinearScale( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
458 : : {
459 : 0 : double val = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
460 : 0 : double domainMin = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
461 : 0 : double domainMax = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
462 : 0 : double rangeMin = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
463 : 0 : double rangeMax = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
464 : :
465 : 0 : if ( domainMin >= domainMax )
466 : : {
467 : 0 : parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
468 : 0 : return QVariant();
469 : : }
470 : :
471 : : // outside of domain?
472 : 0 : if ( val >= domainMax )
473 : : {
474 : 0 : return rangeMax;
475 : : }
476 : 0 : else if ( val <= domainMin )
477 : : {
478 : 0 : return rangeMin;
479 : : }
480 : :
481 : : // calculate linear scale
482 : 0 : double m = ( rangeMax - rangeMin ) / ( domainMax - domainMin );
483 : 0 : double c = rangeMin - ( domainMin * m );
484 : :
485 : : // Return linearly scaled value
486 : 0 : return QVariant( m * val + c );
487 : 0 : }
488 : :
489 : 0 : static QVariant fcnExpScale( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
490 : : {
491 : 0 : double val = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
492 : 0 : double domainMin = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
493 : 0 : double domainMax = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
494 : 0 : double rangeMin = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
495 : 0 : double rangeMax = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
496 : 0 : double exponent = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
497 : :
498 : 0 : if ( domainMin >= domainMax )
499 : : {
500 : 0 : parent->setEvalErrorString( QObject::tr( "Domain max must be greater than domain min" ) );
501 : 0 : return QVariant();
502 : : }
503 : 0 : if ( exponent <= 0 )
504 : : {
505 : 0 : parent->setEvalErrorString( QObject::tr( "Exponent must be greater than 0" ) );
506 : 0 : return QVariant();
507 : : }
508 : :
509 : : // outside of domain?
510 : 0 : if ( val >= domainMax )
511 : : {
512 : 0 : return rangeMax;
513 : : }
514 : 0 : else if ( val <= domainMin )
515 : : {
516 : 0 : return rangeMin;
517 : : }
518 : 0 :
519 : : // Return exponentially scaled value
520 : 0 : return QVariant( ( ( rangeMax - rangeMin ) / std::pow( domainMax - domainMin, exponent ) ) * std::pow( val - domainMin, exponent ) + rangeMin );
521 : 0 : }
522 : :
523 : 0 : static QVariant fcnMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
524 : : {
525 : 0 : QVariant result( QVariant::Double );
526 : 0 : double maxVal = std::numeric_limits<double>::quiet_NaN();
527 : 0 : for ( const QVariant &val : values )
528 : : {
529 : 0 : double testVal = val.isNull() ? std::numeric_limits<double>::quiet_NaN() : QgsExpressionUtils::getDoubleValue( val, parent );
530 : 0 : if ( std::isnan( maxVal ) )
531 : : {
532 : 0 : maxVal = testVal;
533 : 0 : }
534 : 0 : else if ( !std::isnan( testVal ) )
535 : : {
536 : 0 : maxVal = std::max( maxVal, testVal );
537 : 0 : }
538 : : }
539 : :
540 : 0 : if ( !std::isnan( maxVal ) )
541 : : {
542 : 0 : result = QVariant( maxVal );
543 : 0 : }
544 : 0 : return result;
545 : 0 : }
546 : :
547 : 0 : static QVariant fcnMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
548 : : {
549 : 0 : QVariant result( QVariant::Double );
550 : 0 : double minVal = std::numeric_limits<double>::quiet_NaN();
551 : 0 : for ( const QVariant &val : values )
552 : : {
553 : 0 : double testVal = val.isNull() ? std::numeric_limits<double>::quiet_NaN() : QgsExpressionUtils::getDoubleValue( val, parent );
554 : 0 : if ( std::isnan( minVal ) )
555 : : {
556 : 0 : minVal = testVal;
557 : 0 : }
558 : 0 : else if ( !std::isnan( testVal ) )
559 : : {
560 : 0 : minVal = std::min( minVal, testVal );
561 : 0 : }
562 : : }
563 : :
564 : 0 : if ( !std::isnan( minVal ) )
565 : : {
566 : 0 : result = QVariant( minVal );
567 : 0 : }
568 : 0 : return result;
569 : 0 : }
570 : :
571 : 0 : static QVariant fcnAggregate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
572 : : {
573 : : //lazy eval, so we need to evaluate nodes now
574 : :
575 : : //first node is layer id or name
576 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
577 : 0 : ENSURE_NO_EVAL_ERROR
578 : 0 : QVariant value = node->eval( parent, context );
579 : 0 : ENSURE_NO_EVAL_ERROR
580 : 0 : QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( value, parent );
581 : 0 : if ( !vl )
582 : : {
583 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot find layer with name or ID '%1'" ).arg( value.toString() ) );
584 : 0 : return QVariant();
585 : : }
586 : :
587 : : // second node is aggregate type
588 : 0 : node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
589 : 0 : ENSURE_NO_EVAL_ERROR
590 : 0 : value = node->eval( parent, context );
591 : 0 : ENSURE_NO_EVAL_ERROR
592 : 0 : bool ok = false;
593 : 0 : QgsAggregateCalculator::Aggregate aggregate = QgsAggregateCalculator::stringToAggregate( QgsExpressionUtils::getStringValue( value, parent ), &ok );
594 : 0 : if ( !ok )
595 : : {
596 : 0 : parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
597 : 0 : return QVariant();
598 : : }
599 : :
600 : : // third node is subexpression (or field name)
601 : 0 : node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
602 : 0 : ENSURE_NO_EVAL_ERROR
603 : 0 : QString subExpression = node->dump();
604 : :
605 : 0 : QgsAggregateCalculator::AggregateParameters parameters;
606 : : //optional forth node is filter
607 : 0 : if ( values.count() > 3 )
608 : : {
609 : 0 : node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
610 : 0 : ENSURE_NO_EVAL_ERROR
611 : 0 : QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
612 : 0 : if ( !nl || nl->value().isValid() )
613 : 0 : parameters.filter = node->dump();
614 : 0 : }
615 : :
616 : : //optional fifth node is concatenator
617 : 0 : if ( values.count() > 4 )
618 : : {
619 : 0 : node = QgsExpressionUtils::getNode( values.at( 4 ), parent );
620 : 0 : ENSURE_NO_EVAL_ERROR
621 : 0 : value = node->eval( parent, context );
622 : 0 : ENSURE_NO_EVAL_ERROR
623 : 0 : parameters.delimiter = value.toString();
624 : 0 : }
625 : :
626 : : //optional sixth node is order by
627 : 0 : QString orderBy;
628 : 0 : if ( values.count() > 5 )
629 : : {
630 : 0 : node = QgsExpressionUtils::getNode( values.at( 5 ), parent );
631 : 0 : ENSURE_NO_EVAL_ERROR
632 : 0 : QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
633 : 0 : if ( !nl || nl->value().isValid() )
634 : : {
635 : 0 : orderBy = node->dump();
636 : 0 : parameters.orderBy << QgsFeatureRequest::OrderByClause( orderBy );
637 : 0 : }
638 : 0 : }
639 : :
640 : 0 : QVariant result;
641 : 0 : if ( context )
642 : : {
643 : 0 : QString cacheKey;
644 : 0 : QgsExpression subExp( subExpression );
645 : 0 : QgsExpression filterExp( parameters.filter );
646 : :
647 : 0 : bool isStatic = true;
648 : 0 : if ( filterExp.referencedVariables().contains( QStringLiteral( "parent" ) )
649 : 0 : || filterExp.referencedVariables().contains( QString() )
650 : 0 : || subExp.referencedVariables().contains( QStringLiteral( "parent" ) )
651 : 0 : || subExp.referencedVariables().contains( QString() ) )
652 : : {
653 : 0 : isStatic = false;
654 : 0 : }
655 : : else
656 : : {
657 : 0 : const QSet<QString> refVars = filterExp.referencedVariables() + subExp.referencedVariables();
658 : 0 : for ( const QString &varName : refVars )
659 : : {
660 : 0 : const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
661 : 0 : if ( scope && !scope->isStatic( varName ) )
662 : : {
663 : 0 : isStatic = false;
664 : 0 : break;
665 : : }
666 : : }
667 : 0 : }
668 : :
669 : 0 : if ( !isStatic )
670 : : {
671 : 0 : cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4:%5%6:%7" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter,
672 : 0 : QString::number( context->feature().id() ), QString( qHash( context->feature() ) ), orderBy );
673 : 0 : }
674 : : else
675 : : {
676 : 0 : cacheKey = QStringLiteral( "aggfcn:%1:%2:%3:%4:%5" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter, orderBy );
677 : : }
678 : :
679 : 0 : if ( context && context->hasCachedValue( cacheKey ) )
680 : : {
681 : 0 : return context->cachedValue( cacheKey );
682 : : }
683 : :
684 : 0 : QgsExpressionContext subContext( *context );
685 : 0 : QgsExpressionContextScope *subScope = new QgsExpressionContextScope();
686 : 0 : subScope->setVariable( QStringLiteral( "parent" ), context->feature() );
687 : 0 : subContext.appendScope( subScope );
688 : 0 : result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
689 : :
690 : 0 : context->setCachedValue( cacheKey, result );
691 : 0 : }
692 : : else
693 : : {
694 : 0 : result = vl->aggregate( aggregate, subExpression, parameters, nullptr, &ok );
695 : : }
696 : 0 : if ( !ok )
697 : : {
698 : 0 : parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
699 : 0 : return QVariant();
700 : : }
701 : :
702 : 0 : return result;
703 : 0 : }
704 : :
705 : 0 : static QVariant fcnAggregateRelation( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
706 : : {
707 : 0 : if ( !context )
708 : : {
709 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
710 : 0 : return QVariant();
711 : : }
712 : :
713 : : // first step - find current layer
714 : 0 : QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
715 : 0 : if ( !vl )
716 : : {
717 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
718 : 0 : return QVariant();
719 : : }
720 : :
721 : : //lazy eval, so we need to evaluate nodes now
722 : :
723 : : //first node is relation name
724 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
725 : 0 : ENSURE_NO_EVAL_ERROR
726 : 0 : QVariant value = node->eval( parent, context );
727 : 0 : ENSURE_NO_EVAL_ERROR
728 : 0 : QString relationId = value.toString();
729 : : // check relation exists
730 : 0 : QgsRelation relation = QgsProject::instance()->relationManager()->relation( relationId );
731 : 0 : if ( !relation.isValid() || relation.referencedLayer() != vl )
732 : : {
733 : : // check for relations by name
734 : 0 : QList< QgsRelation > relations = QgsProject::instance()->relationManager()->relationsByName( relationId );
735 : 0 : if ( relations.isEmpty() || relations.at( 0 ).referencedLayer() != vl )
736 : : {
737 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot find relation with id '%1'" ).arg( relationId ) );
738 : 0 : return QVariant();
739 : : }
740 : : else
741 : : {
742 : 0 : relation = relations.at( 0 );
743 : : }
744 : 0 : }
745 : :
746 : 0 : QgsVectorLayer *childLayer = relation.referencingLayer();
747 : :
748 : : // second node is aggregate type
749 : 0 : node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
750 : 0 : ENSURE_NO_EVAL_ERROR
751 : 0 : value = node->eval( parent, context );
752 : 0 : ENSURE_NO_EVAL_ERROR
753 : 0 : bool ok = false;
754 : 0 : QgsAggregateCalculator::Aggregate aggregate = QgsAggregateCalculator::stringToAggregate( QgsExpressionUtils::getStringValue( value, parent ), &ok );
755 : 0 : if ( !ok )
756 : : {
757 : 0 : parent->setEvalErrorString( QObject::tr( "No such aggregate '%1'" ).arg( value.toString() ) );
758 : 0 : return QVariant();
759 : : }
760 : :
761 : : //third node is subexpression (or field name)
762 : 0 : node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
763 : 0 : ENSURE_NO_EVAL_ERROR
764 : 0 : QString subExpression = node->dump();
765 : :
766 : : //optional fourth node is concatenator
767 : 0 : QgsAggregateCalculator::AggregateParameters parameters;
768 : 0 : if ( values.count() > 3 )
769 : : {
770 : 0 : node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
771 : 0 : ENSURE_NO_EVAL_ERROR
772 : 0 : value = node->eval( parent, context );
773 : 0 : ENSURE_NO_EVAL_ERROR
774 : 0 : parameters.delimiter = value.toString();
775 : 0 : }
776 : :
777 : : //optional fifth node is order by
778 : 0 : QString orderBy;
779 : 0 : if ( values.count() > 4 )
780 : : {
781 : 0 : node = QgsExpressionUtils::getNode( values.at( 4 ), parent );
782 : 0 : ENSURE_NO_EVAL_ERROR
783 : 0 : QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
784 : 0 : if ( !nl || nl->value().isValid() )
785 : : {
786 : 0 : orderBy = node->dump();
787 : 0 : parameters.orderBy << QgsFeatureRequest::OrderByClause( orderBy );
788 : 0 : }
789 : 0 : }
790 : :
791 : 0 : if ( !context->hasFeature() )
792 : 0 : return QVariant();
793 : 0 : QgsFeature f = context->feature();
794 : :
795 : 0 : parameters.filter = relation.getRelatedFeaturesFilter( f );
796 : :
797 : 0 : QString cacheKey = QStringLiteral( "relagg:%1:%2:%3:%4:%5" ).arg( vl->id(),
798 : 0 : QString::number( static_cast< int >( aggregate ) ),
799 : : subExpression,
800 : 0 : parameters.filter,
801 : : orderBy );
802 : 0 : if ( context->hasCachedValue( cacheKey ) )
803 : 0 : return context->cachedValue( cacheKey );
804 : :
805 : 0 : QVariant result;
806 : 0 : ok = false;
807 : :
808 : :
809 : 0 : QgsExpressionContext subContext( *context );
810 : 0 : result = childLayer->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
811 : :
812 : 0 : if ( !ok )
813 : : {
814 : 0 : parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
815 : 0 : return QVariant();
816 : : }
817 : :
818 : : // cache value
819 : 0 : context->setCachedValue( cacheKey, result );
820 : 0 : return result;
821 : 0 : }
822 : :
823 : :
824 : 0 : static QVariant fcnAggregateGeneric( QgsAggregateCalculator::Aggregate aggregate, const QVariantList &values, QgsAggregateCalculator::AggregateParameters parameters, const QgsExpressionContext *context, QgsExpression *parent, int orderByPos = -1 )
825 : : {
826 : 0 : if ( !context )
827 : : {
828 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
829 : 0 : return QVariant();
830 : : }
831 : :
832 : : // first step - find current layer
833 : 0 : QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
834 : 0 : if ( !vl )
835 : : {
836 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
837 : 0 : return QVariant();
838 : : }
839 : :
840 : : //lazy eval, so we need to evaluate nodes now
841 : :
842 : : //first node is subexpression (or field name)
843 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
844 : 0 : ENSURE_NO_EVAL_ERROR
845 : 0 : QString subExpression = node->dump();
846 : :
847 : : //optional second node is group by
848 : 0 : QString groupBy;
849 : 0 : if ( values.count() > 1 )
850 : : {
851 : 0 : node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
852 : 0 : ENSURE_NO_EVAL_ERROR
853 : 0 : QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
854 : 0 : if ( !nl || nl->value().isValid() )
855 : 0 : groupBy = node->dump();
856 : 0 : }
857 : :
858 : : //optional third node is filter
859 : 0 : if ( values.count() > 2 )
860 : : {
861 : 0 : node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
862 : 0 : ENSURE_NO_EVAL_ERROR
863 : 0 : QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
864 : 0 : if ( !nl || nl->value().isValid() )
865 : 0 : parameters.filter = node->dump();
866 : 0 : }
867 : :
868 : : //optional order by node, if supported
869 : 0 : QString orderBy;
870 : 0 : if ( orderByPos >= 0 && values.count() > orderByPos )
871 : : {
872 : 0 : node = QgsExpressionUtils::getNode( values.at( orderByPos ), parent );
873 : 0 : ENSURE_NO_EVAL_ERROR
874 : 0 : QgsExpressionNodeLiteral *nl = dynamic_cast< QgsExpressionNodeLiteral * >( node );
875 : 0 : if ( !nl || nl->value().isValid() )
876 : : {
877 : 0 : orderBy = node->dump();
878 : 0 : parameters.orderBy << QgsFeatureRequest::OrderByClause( orderBy );
879 : 0 : }
880 : 0 : }
881 : :
882 : : // build up filter with group by
883 : :
884 : : // find current group by value
885 : 0 : if ( !groupBy.isEmpty() )
886 : : {
887 : 0 : QgsExpression groupByExp( groupBy );
888 : 0 : QVariant groupByValue = groupByExp.evaluate( context );
889 : 0 : QString groupByClause = QStringLiteral( "%1 %2 %3" ).arg( groupBy,
890 : 0 : groupByValue.isNull() ? QStringLiteral( "is" ) : QStringLiteral( "=" ),
891 : 0 : QgsExpression::quotedValue( groupByValue ) );
892 : 0 : if ( !parameters.filter.isEmpty() )
893 : 0 : parameters.filter = QStringLiteral( "(%1) AND (%2)" ).arg( parameters.filter, groupByClause );
894 : : else
895 : 0 : parameters.filter = groupByClause;
896 : 0 : }
897 : :
898 : 0 : QgsExpression subExp( subExpression );
899 : 0 : QgsExpression filterExp( parameters.filter );
900 : :
901 : 0 : bool isStatic = true;
902 : 0 : const QSet<QString> refVars = filterExp.referencedVariables() + subExp.referencedVariables();
903 : 0 : for ( const QString &varName : refVars )
904 : : {
905 : 0 : const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
906 : 0 : if ( scope && !scope->isStatic( varName ) )
907 : : {
908 : 0 : isStatic = false;
909 : 0 : break;
910 : : }
911 : : }
912 : :
913 : 0 : QString cacheKey;
914 : 0 : if ( !isStatic )
915 : : {
916 : 0 : cacheKey = QStringLiteral( "agg:%1:%2:%3:%4:%5%6:%7" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter,
917 : 0 : QString::number( context->feature().id() ), QString( qHash( context->feature() ) ), orderBy );
918 : 0 : }
919 : : else
920 : : {
921 : 0 : cacheKey = QStringLiteral( "agg:%1:%2:%3:%4:%5" ).arg( vl->id(), QString::number( aggregate ), subExpression, parameters.filter, orderBy );
922 : : }
923 : :
924 : 0 : if ( context->hasCachedValue( cacheKey ) )
925 : 0 : return context->cachedValue( cacheKey );
926 : :
927 : 0 : QVariant result;
928 : 0 : bool ok = false;
929 : :
930 : 0 : QgsExpressionContext subContext( *context );
931 : 0 : QgsExpressionContextScope *subScope = new QgsExpressionContextScope();
932 : 0 : subScope->setVariable( QStringLiteral( "parent" ), context->feature() );
933 : 0 : subContext.appendScope( subScope );
934 : 0 : result = vl->aggregate( aggregate, subExpression, parameters, &subContext, &ok );
935 : :
936 : 0 : if ( !ok )
937 : : {
938 : 0 : parent->setEvalErrorString( QObject::tr( "Could not calculate aggregate for: %1" ).arg( subExpression ) );
939 : 0 : return QVariant();
940 : : }
941 : :
942 : : // cache value
943 : 0 : context->setCachedValue( cacheKey, result );
944 : 0 : return result;
945 : 0 : }
946 : :
947 : :
948 : 0 : static QVariant fcnAggregateCount( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
949 : : {
950 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Count, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
951 : 0 : }
952 : :
953 : 0 : static QVariant fcnAggregateCountDistinct( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
954 : : {
955 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::CountDistinct, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
956 : 0 : }
957 : :
958 : 0 : static QVariant fcnAggregateCountMissing( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
959 : : {
960 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::CountMissing, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
961 : 0 : }
962 : :
963 : 0 : static QVariant fcnAggregateMin( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
964 : : {
965 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Min, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
966 : 0 : }
967 : :
968 : 0 : static QVariant fcnAggregateMax( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
969 : : {
970 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Max, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
971 : 0 : }
972 : :
973 : 0 : static QVariant fcnAggregateSum( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
974 : : {
975 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Sum, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
976 : 0 : }
977 : :
978 : 0 : static QVariant fcnAggregateMean( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
979 : : {
980 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Mean, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
981 : 0 : }
982 : :
983 : 0 : static QVariant fcnAggregateMedian( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
984 : : {
985 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Median, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
986 : 0 : }
987 : :
988 : 0 : static QVariant fcnAggregateStdev( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
989 : : {
990 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::StDevSample, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
991 : 0 : }
992 : :
993 : 0 : static QVariant fcnAggregateRange( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
994 : : {
995 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Range, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
996 : 0 : }
997 : :
998 : 0 : static QVariant fcnAggregateMinority( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
999 : : {
1000 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Minority, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1001 : 0 : }
1002 : :
1003 : 0 : static QVariant fcnAggregateMajority( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1004 : : {
1005 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::Majority, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1006 : 0 : }
1007 : :
1008 : 0 : static QVariant fcnAggregateQ1( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1009 : : {
1010 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::FirstQuartile, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1011 : 0 : }
1012 : :
1013 : 0 : static QVariant fcnAggregateQ3( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1014 : : {
1015 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::ThirdQuartile, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1016 : 0 : }
1017 : :
1018 : 0 : static QVariant fcnAggregateIQR( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1019 : : {
1020 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::InterQuartileRange, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1021 : 0 : }
1022 : :
1023 : 0 : static QVariant fcnAggregateMinLength( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1024 : : {
1025 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::StringMinimumLength, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1026 : 0 : }
1027 : :
1028 : 0 : static QVariant fcnAggregateMaxLength( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1029 : : {
1030 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::StringMaximumLength, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1031 : 0 : }
1032 : :
1033 : 0 : static QVariant fcnAggregateCollectGeometry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1034 : : {
1035 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::GeometryCollect, values, QgsAggregateCalculator::AggregateParameters(), context, parent );
1036 : 0 : }
1037 : :
1038 : 0 : static QVariant fcnAggregateStringConcat( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1039 : : {
1040 : 0 : QgsAggregateCalculator::AggregateParameters parameters;
1041 : :
1042 : : //fourth node is concatenator
1043 : 0 : if ( values.count() > 3 )
1044 : : {
1045 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
1046 : 0 : ENSURE_NO_EVAL_ERROR
1047 : 0 : QVariant value = node->eval( parent, context );
1048 : 0 : ENSURE_NO_EVAL_ERROR
1049 : 0 : parameters.delimiter = value.toString();
1050 : 0 : }
1051 : :
1052 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenate, values, parameters, context, parent, 4 );
1053 : 0 : }
1054 : :
1055 : 0 : static QVariant fcnAggregateStringConcatUnique( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1056 : : {
1057 : 0 : QgsAggregateCalculator::AggregateParameters parameters;
1058 : :
1059 : : //fourth node is concatenator
1060 : 0 : if ( values.count() > 3 )
1061 : : {
1062 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 3 ), parent );
1063 : 0 : ENSURE_NO_EVAL_ERROR
1064 : 0 : QVariant value = node->eval( parent, context );
1065 : 0 : ENSURE_NO_EVAL_ERROR
1066 : 0 : parameters.delimiter = value.toString();
1067 : 0 : }
1068 : :
1069 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::StringConcatenateUnique, values, parameters, context, parent, 4 );
1070 : 0 : }
1071 : :
1072 : 0 : static QVariant fcnAggregateArray( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1073 : : {
1074 : 0 : return fcnAggregateGeneric( QgsAggregateCalculator::ArrayAggregate, values, QgsAggregateCalculator::AggregateParameters(), context, parent, 3 );
1075 : 0 : }
1076 : :
1077 : 0 : static QVariant fcnMapScale( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
1078 : : {
1079 : 0 : if ( !context )
1080 : 0 : return QVariant();
1081 : :
1082 : 0 : QVariant scale = context->variable( QStringLiteral( "map_scale" ) );
1083 : 0 : bool ok = false;
1084 : 0 : if ( !scale.isValid() || scale.isNull() )
1085 : 0 : return QVariant();
1086 : :
1087 : 0 : const double v = scale.toDouble( &ok );
1088 : 0 : if ( ok )
1089 : 0 : return v;
1090 : 0 : return QVariant();
1091 : 0 : }
1092 : :
1093 : 0 : static QVariant fcnClamp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1094 : : {
1095 : 0 : double minValue = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1096 : 0 : double testValue = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
1097 : 0 : double maxValue = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
1098 : :
1099 : : // force testValue to sit inside the range specified by the min and max value
1100 : 0 : if ( testValue <= minValue )
1101 : : {
1102 : 0 : return QVariant( minValue );
1103 : : }
1104 : 0 : else if ( testValue >= maxValue )
1105 : : {
1106 : 0 : return QVariant( maxValue );
1107 : : }
1108 : : else
1109 : : {
1110 : 0 : return QVariant( testValue );
1111 : : }
1112 : 0 : }
1113 : :
1114 : 0 : static QVariant fcnFloor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1115 : : {
1116 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1117 : 0 : return QVariant( std::floor( x ) );
1118 : : }
1119 : :
1120 : 0 : static QVariant fcnCeil( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1121 : : {
1122 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1123 : 0 : return QVariant( std::ceil( x ) );
1124 : : }
1125 : :
1126 : 0 : static QVariant fcnToInt( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1127 : : {
1128 : 0 : return QVariant( QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) );
1129 : : }
1130 : 0 : static QVariant fcnToReal( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1131 : : {
1132 : 0 : return QVariant( QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent ) );
1133 : : }
1134 : 0 : static QVariant fcnToString( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1135 : : {
1136 : 0 : return QVariant( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ) );
1137 : 0 : }
1138 : :
1139 : 0 : static QVariant fcnToDateTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1140 : : {
1141 : 0 : QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1142 : 0 : QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1143 : 0 : if ( format.isEmpty() && !language.isEmpty() )
1144 : : {
1145 : 0 : parent->setEvalErrorString( QObject::tr( "A format is required to convert to DateTime when the language is specified" ) );
1146 : 0 : return QVariant( QDateTime() );
1147 : : }
1148 : :
1149 : 0 : if ( format.isEmpty() && language.isEmpty() )
1150 : 0 : return QVariant( QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent ) );
1151 : :
1152 : 0 : QString datetimestring = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1153 : 0 : QLocale locale = QLocale();
1154 : 0 : if ( !language.isEmpty() )
1155 : : {
1156 : 0 : locale = QLocale( language );
1157 : 0 : }
1158 : :
1159 : 0 : QDateTime datetime = locale.toDateTime( datetimestring, format );
1160 : 0 : if ( !datetime.isValid() )
1161 : : {
1162 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to DateTime" ).arg( datetimestring ) );
1163 : 0 : datetime = QDateTime();
1164 : 0 : }
1165 : 0 : return QVariant( datetime );
1166 : 0 : }
1167 : :
1168 : 0 : static QVariant fcnMakeDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1169 : : {
1170 : 0 : const int year = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
1171 : 0 : const int month = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1172 : 0 : const int day = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
1173 : :
1174 : 0 : const QDate date( year, month, day );
1175 : 0 : if ( !date.isValid() )
1176 : : {
1177 : 0 : parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid date" ).arg( year ).arg( month ).arg( day ) );
1178 : 0 : return QVariant();
1179 : : }
1180 : 0 : return QVariant( date );
1181 : 0 : }
1182 : :
1183 : 0 : static QVariant fcnMakeTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1184 : : {
1185 : 0 : const int hours = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
1186 : 0 : const int minutes = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1187 : 0 : const double seconds = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
1188 : :
1189 : 0 : const QTime time( hours, minutes, std::floor( seconds ), ( seconds - std::floor( seconds ) ) * 1000 );
1190 : 0 : if ( !time.isValid() )
1191 : : {
1192 : 0 : parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid time" ).arg( hours ).arg( minutes ).arg( seconds ) );
1193 : 0 : return QVariant();
1194 : : }
1195 : 0 : return QVariant( time );
1196 : 0 : }
1197 : :
1198 : 0 : static QVariant fcnMakeDateTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1199 : : {
1200 : 0 : const int year = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
1201 : 0 : const int month = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1202 : 0 : const int day = QgsExpressionUtils::getIntValue( values.at( 2 ), parent );
1203 : 0 : const int hours = QgsExpressionUtils::getIntValue( values.at( 3 ), parent );
1204 : 0 : const int minutes = QgsExpressionUtils::getIntValue( values.at( 4 ), parent );
1205 : 0 : const double seconds = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
1206 : :
1207 : 0 : const QDate date( year, month, day );
1208 : 0 : if ( !date.isValid() )
1209 : : {
1210 : 0 : parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid date" ).arg( year ).arg( month ).arg( day ) );
1211 : 0 : return QVariant();
1212 : : }
1213 : 0 : const QTime time( hours, minutes, std::floor( seconds ), ( seconds - std::floor( seconds ) ) * 1000 );
1214 : 0 : if ( !time.isValid() )
1215 : : {
1216 : 0 : parent->setEvalErrorString( QObject::tr( "'%1-%2-%3' is not a valid time" ).arg( hours ).arg( minutes ).arg( seconds ) );
1217 : 0 : return QVariant();
1218 : : }
1219 : 0 : return QVariant( QDateTime( date, time ) );
1220 : 0 : }
1221 : :
1222 : 0 : static QVariant fcnMakeInterval( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1223 : : {
1224 : 0 : const double years = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
1225 : 0 : const double months = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
1226 : 0 : const double weeks = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
1227 : 0 : const double days = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
1228 : 0 : const double hours = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
1229 : 0 : const double minutes = QgsExpressionUtils::getDoubleValue( values.at( 5 ), parent );
1230 : 0 : const double seconds = QgsExpressionUtils::getDoubleValue( values.at( 6 ), parent );
1231 : :
1232 : 0 : return QVariant::fromValue( QgsInterval( years, months, weeks, days, hours, minutes, seconds ) );
1233 : : }
1234 : :
1235 : 0 : static QVariant fcnCoalesce( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
1236 : : {
1237 : 0 : for ( const QVariant &value : values )
1238 : : {
1239 : 0 : if ( value.isNull() )
1240 : 0 : continue;
1241 : 0 : return value;
1242 : : }
1243 : 0 : return QVariant();
1244 : 0 : }
1245 : :
1246 : 0 : static QVariant fcnNullIf( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
1247 : : {
1248 : 0 : const QVariant val1 = values.at( 0 );
1249 : 0 : const QVariant val2 = values.at( 1 );
1250 : :
1251 : 0 : if ( val1 == val2 )
1252 : 0 : return QVariant();
1253 : : else
1254 : 0 : return val1;
1255 : 0 : }
1256 : :
1257 : 0 : static QVariant fcnLower( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1258 : : {
1259 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1260 : 0 : return QVariant( str.toLower() );
1261 : 0 : }
1262 : 0 : static QVariant fcnUpper( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1263 : : {
1264 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1265 : 0 : return QVariant( str.toUpper() );
1266 : 0 : }
1267 : 0 : static QVariant fcnTitle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1268 : : {
1269 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1270 : 0 : QStringList elems = str.split( ' ' );
1271 : 0 : for ( int i = 0; i < elems.size(); i++ )
1272 : : {
1273 : 0 : if ( elems[i].size() > 1 )
1274 : 0 : elems[i] = elems[i].at( 0 ).toUpper() + elems[i].mid( 1 ).toLower();
1275 : 0 : }
1276 : 0 : return QVariant( elems.join( QLatin1Char( ' ' ) ) );
1277 : 0 : }
1278 : :
1279 : 0 : static QVariant fcnTrim( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1280 : : {
1281 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1282 : 0 : return QVariant( str.trimmed() );
1283 : 0 : }
1284 : :
1285 : 0 : static QVariant fcnLevenshtein( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1286 : : {
1287 : 0 : QString string1 = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1288 : 0 : QString string2 = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1289 : 0 : return QVariant( QgsStringUtils::levenshteinDistance( string1, string2, true ) );
1290 : 0 : }
1291 : :
1292 : 0 : static QVariant fcnLCS( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1293 : : {
1294 : 0 : QString string1 = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1295 : 0 : QString string2 = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1296 : 0 : return QVariant( QgsStringUtils::longestCommonSubstring( string1, string2, true ) );
1297 : 0 : }
1298 : :
1299 : 0 : static QVariant fcnHamming( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1300 : : {
1301 : 0 : QString string1 = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1302 : 0 : QString string2 = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1303 : 0 : int dist = QgsStringUtils::hammingDistance( string1, string2 );
1304 : 0 : return ( dist < 0 ? QVariant() : QVariant( QgsStringUtils::hammingDistance( string1, string2, true ) ) );
1305 : 0 : }
1306 : :
1307 : 0 : static QVariant fcnSoundex( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1308 : : {
1309 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1310 : 0 : return QVariant( QgsStringUtils::soundex( string ) );
1311 : 0 : }
1312 : :
1313 : 0 : static QVariant fcnChar( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1314 : : {
1315 : 0 : QChar character = QChar( QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent ) );
1316 : 0 : return QVariant( QString( character ) );
1317 : 0 : }
1318 : :
1319 : 0 : static QVariant fcnAscii( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1320 : : {
1321 : 0 : QString value = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1322 : :
1323 : 0 : if ( value.isEmpty() )
1324 : : {
1325 : 0 : return QVariant();
1326 : : }
1327 : :
1328 : 0 : int res = value.at( 0 ).unicode();
1329 : 0 : return QVariant( res );
1330 : 0 : }
1331 : :
1332 : 0 : static QVariant fcnWordwrap( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1333 : : {
1334 : 0 : if ( values.length() == 2 || values.length() == 3 )
1335 : : {
1336 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1337 : 0 : qlonglong wrap = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
1338 : :
1339 : 0 : QString customdelimiter = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1340 : :
1341 : 0 : return QgsStringUtils::wordWrap( str, static_cast< int >( wrap ), wrap > 0, customdelimiter );
1342 : 0 : }
1343 : :
1344 : 0 : return QVariant();
1345 : 0 : }
1346 : :
1347 : 0 : static QVariant fcnLength( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1348 : : {
1349 : : // two variants, one for geometry, one for string
1350 : 0 : if ( values.at( 0 ).canConvert<QgsGeometry>() )
1351 : : {
1352 : : //geometry variant
1353 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
1354 : 0 : if ( geom.type() != QgsWkbTypes::LineGeometry )
1355 : 0 : return QVariant();
1356 : :
1357 : 0 : return QVariant( geom.length() );
1358 : 0 : }
1359 : :
1360 : : //otherwise fall back to string variant
1361 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1362 : 0 : return QVariant( str.length() );
1363 : 0 : }
1364 : :
1365 : 0 : static QVariant fcnLength3D( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1366 : : {
1367 : 0 : const QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
1368 : :
1369 : 0 : if ( geom.type() != QgsWkbTypes::LineGeometry )
1370 : 0 : return QVariant();
1371 : :
1372 : 0 : double totalLength = 0;
1373 : 0 : for ( auto it = geom.const_parts_begin(); it != geom.const_parts_end(); ++it )
1374 : : {
1375 : 0 : if ( const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( *it ) )
1376 : : {
1377 : 0 : totalLength += line->length3D();
1378 : 0 : }
1379 : : else
1380 : : {
1381 : 0 : std::unique_ptr< QgsLineString > segmentized( qgsgeometry_cast< const QgsCurve * >( *it )->curveToLine() );
1382 : 0 : totalLength += segmentized->length3D();
1383 : 0 : }
1384 : 0 : }
1385 : :
1386 : 0 : return totalLength;
1387 : 0 : }
1388 : :
1389 : 0 : static QVariant fcnReplace( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1390 : : {
1391 : 0 : if ( values.count() == 2 && values.at( 1 ).type() == QVariant::Map )
1392 : : {
1393 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1394 : 0 : QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 1 ), parent );
1395 : :
1396 : 0 : for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1397 : : {
1398 : 0 : str = str.replace( it.key(), it.value().toString() );
1399 : 0 : }
1400 : :
1401 : 0 : return QVariant( str );
1402 : 0 : }
1403 : 0 : else if ( values.count() == 3 )
1404 : : {
1405 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1406 : 0 : QVariantList before;
1407 : 0 : QVariantList after;
1408 : 0 : bool isSingleReplacement = false;
1409 : :
1410 : 0 : if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1411 : : {
1412 : 0 : before = QVariantList() << QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1413 : 0 : }
1414 : : else
1415 : : {
1416 : 0 : before = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
1417 : : }
1418 : :
1419 : 0 : if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1420 : : {
1421 : 0 : after = QVariantList() << QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1422 : 0 : isSingleReplacement = true;
1423 : 0 : }
1424 : : else
1425 : : {
1426 : 0 : after = QgsExpressionUtils::getListValue( values.at( 2 ), parent );
1427 : : }
1428 : :
1429 : 0 : if ( !isSingleReplacement && before.length() != after.length() )
1430 : : {
1431 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
1432 : 0 : return QVariant();
1433 : : }
1434 : :
1435 : 0 : for ( int i = 0; i < before.length(); i++ )
1436 : : {
1437 : 0 : str = str.replace( before.at( i ).toString(), after.at( isSingleReplacement ? 0 : i ).toString() );
1438 : 0 : }
1439 : :
1440 : 0 : return QVariant( str );
1441 : 0 : }
1442 : : else
1443 : : {
1444 : 0 : parent->setEvalErrorString( QObject::tr( "Function replace requires 2 or 3 arguments" ) );
1445 : 0 : return QVariant();
1446 : : }
1447 : 0 : }
1448 : :
1449 : 0 : static QVariant fcnRegexpReplace( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1450 : : {
1451 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1452 : 0 : QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1453 : 0 : QString after = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1454 : :
1455 : 0 : QRegularExpression re( regexp, QRegularExpression::UseUnicodePropertiesOption );
1456 : 0 : if ( !re.isValid() )
1457 : : {
1458 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1459 : 0 : return QVariant();
1460 : : }
1461 : 0 : return QVariant( str.replace( re, after ) );
1462 : 0 : }
1463 : :
1464 : 0 : static QVariant fcnRegexpMatch( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1465 : : {
1466 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1467 : 0 : QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1468 : :
1469 : 0 : QRegularExpression re( regexp, QRegularExpression::UseUnicodePropertiesOption );
1470 : 0 : if ( !re.isValid() )
1471 : : {
1472 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1473 : 0 : return QVariant();
1474 : : }
1475 : 0 : return QVariant( ( str.indexOf( re ) + 1 ) );
1476 : 0 : }
1477 : :
1478 : 0 : static QVariant fcnRegexpMatches( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1479 : : {
1480 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1481 : 0 : QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1482 : 0 : QString empty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
1483 : :
1484 : 0 : QRegularExpression re( regexp, QRegularExpression::UseUnicodePropertiesOption );
1485 : 0 : if ( !re.isValid() )
1486 : : {
1487 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1488 : 0 : return QVariant();
1489 : : }
1490 : :
1491 : 0 : QRegularExpressionMatch matches = re.match( str );
1492 : 0 : if ( matches.hasMatch() )
1493 : : {
1494 : 0 : QVariantList array;
1495 : 0 : QStringList list = matches.capturedTexts();
1496 : :
1497 : : // Skip the first string to only return captured groups
1498 : 0 : for ( QStringList::const_iterator it = ++list.constBegin(); it != list.constEnd(); ++it )
1499 : : {
1500 : 0 : array += ( !( *it ).isEmpty() ) ? *it : empty;
1501 : 0 : }
1502 : :
1503 : 0 : return QVariant( array );
1504 : 0 : }
1505 : : else
1506 : : {
1507 : 0 : return QVariant();
1508 : : }
1509 : 0 : }
1510 : :
1511 : 0 : static QVariant fcnRegexpSubstr( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1512 : : {
1513 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1514 : 0 : QString regexp = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1515 : :
1516 : 0 : QRegularExpression re( regexp, QRegularExpression::UseUnicodePropertiesOption );
1517 : 0 : if ( !re.isValid() )
1518 : : {
1519 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp, re.errorString() ) );
1520 : 0 : return QVariant();
1521 : : }
1522 : :
1523 : : // extract substring
1524 : 0 : QRegularExpressionMatch match = re.match( str );
1525 : 0 : if ( match.hasMatch() )
1526 : : {
1527 : : // return first capture
1528 : 0 : if ( match.lastCapturedIndex() > 0 )
1529 : : {
1530 : : // a capture group was present, so use that
1531 : 0 : return QVariant( match.captured( 1 ) );
1532 : : }
1533 : : else
1534 : : {
1535 : : // no capture group, so using all match
1536 : 0 : return QVariant( match.captured( 0 ) );
1537 : : }
1538 : : }
1539 : : else
1540 : : {
1541 : 0 : return QVariant( "" );
1542 : : }
1543 : 0 : }
1544 : :
1545 : 0 : static QVariant fcnUuid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
1546 : : {
1547 : 0 : QString uuid = QUuid::createUuid().toString();
1548 : 0 : if ( values.at( 0 ).toString().compare( QStringLiteral( "WithoutBraces" ), Qt::CaseInsensitive ) == 0 )
1549 : 0 : uuid = QUuid::createUuid().toString( QUuid::StringFormat::WithoutBraces );
1550 : 0 : else if ( values.at( 0 ).toString().compare( QStringLiteral( "Id128" ), Qt::CaseInsensitive ) == 0 )
1551 : 0 : uuid = QUuid::createUuid().toString( QUuid::StringFormat::Id128 );
1552 : 0 : return uuid;
1553 : 0 : }
1554 : :
1555 : 0 : static QVariant fcnSubstr( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1556 : : {
1557 : 0 : if ( !values.at( 0 ).isValid() || !values.at( 1 ).isValid() )
1558 : 0 : return QVariant();
1559 : :
1560 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1561 : 0 : int from = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
1562 : :
1563 : 0 : int len = 0;
1564 : 0 : if ( values.at( 2 ).isValid() )
1565 : 0 : len = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
1566 : : else
1567 : 0 : len = str.size();
1568 : :
1569 : 0 : if ( from < 0 )
1570 : : {
1571 : 0 : from = str.size() + from;
1572 : 0 : if ( from < 0 )
1573 : : {
1574 : 0 : from = 0;
1575 : 0 : }
1576 : 0 : }
1577 : 0 : else if ( from > 0 )
1578 : : {
1579 : : //account for the fact that substr() starts at 1
1580 : 0 : from -= 1;
1581 : 0 : }
1582 : :
1583 : 0 : if ( len < 0 )
1584 : : {
1585 : 0 : len = str.size() + len - from;
1586 : 0 : if ( len < 0 )
1587 : : {
1588 : 0 : len = 0;
1589 : 0 : }
1590 : 0 : }
1591 : :
1592 : 0 : return QVariant( str.mid( from, len ) );
1593 : 0 : }
1594 : 0 : static QVariant fcnFeatureId( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
1595 : : {
1596 : 0 : FEAT_FROM_CONTEXT( context, f )
1597 : : // TODO: handling of 64-bit feature ids?
1598 : 0 : return QVariant( static_cast< int >( f.id() ) );
1599 : 0 : }
1600 : :
1601 : 0 : static QVariant fcnRasterValue( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1602 : : {
1603 : 0 : QgsRasterLayer *layer = QgsExpressionUtils::getRasterLayer( values.at( 0 ), parent );
1604 : 0 : if ( !layer || !layer->dataProvider() )
1605 : : {
1606 : 0 : parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid raster layer." ) );
1607 : 0 : return QVariant();
1608 : : }
1609 : :
1610 : 0 : int bandNb = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
1611 : 0 : if ( bandNb < 1 || bandNb > layer->bandCount() )
1612 : : {
1613 : 0 : parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid raster band number." ) );
1614 : 0 : return QVariant();
1615 : : }
1616 : :
1617 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );
1618 : 0 : if ( geom.isNull() || geom.type() != QgsWkbTypes::PointGeometry )
1619 : : {
1620 : 0 : parent->setEvalErrorString( QObject::tr( "Function `raster_value` requires a valid point geometry." ) );
1621 : 0 : return QVariant();
1622 : : }
1623 : :
1624 : 0 : QgsPointXY point = geom.asPoint();
1625 : 0 : if ( geom.isMultipart() )
1626 : : {
1627 : 0 : QgsMultiPointXY multiPoint = geom.asMultiPoint();
1628 : 0 : if ( multiPoint.count() == 1 )
1629 : : {
1630 : 0 : point = multiPoint[0];
1631 : 0 : }
1632 : : else
1633 : : {
1634 : : // if the geometry contains more than one part, return an undefined value
1635 : 0 : return QVariant();
1636 : : }
1637 : 0 : }
1638 : :
1639 : 0 : double value = layer->dataProvider()->sample( point, bandNb );
1640 : 0 : return std::isnan( value ) ? QVariant() : value;
1641 : 0 : }
1642 : :
1643 : 0 : static QVariant fcnFeature( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
1644 : : {
1645 : 0 : if ( !context )
1646 : 0 : return QVariant();
1647 : :
1648 : 0 : return context->feature();
1649 : 0 : }
1650 : :
1651 : 0 : static QVariant fcnAttribute( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1652 : : {
1653 : 0 : QgsFeature feature;
1654 : 0 : QString attr;
1655 : 0 : if ( values.size() == 1 )
1656 : : {
1657 : 0 : attr = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
1658 : 0 : feature = context->feature();
1659 : 0 : }
1660 : 0 : else if ( values.size() == 2 )
1661 : : {
1662 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1663 : 0 : attr = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
1664 : 0 : }
1665 : : else
1666 : : {
1667 : 0 : parent->setEvalErrorString( QObject::tr( "Function `attribute` requires one or two parameters. %1 given." ).arg( values.length() ) );
1668 : 0 : return QVariant();
1669 : : }
1670 : :
1671 : 0 : return feature.attribute( attr );
1672 : 0 : }
1673 : :
1674 : 0 : static QVariant fcnAttributes( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1675 : : {
1676 : 0 : QgsFeature feature;
1677 : 0 : if ( values.size() == 0 || values.at( 0 ).isNull() )
1678 : : {
1679 : 0 : feature = context->feature();
1680 : 0 : }
1681 : : else
1682 : : {
1683 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1684 : : }
1685 : :
1686 : 0 : const QgsFields fields = feature.fields();
1687 : 0 : QVariantMap result;
1688 : 0 : for ( int i = 0; i < fields.count(); ++i )
1689 : : {
1690 : 0 : result.insert( fields.at( i ).name(), feature.attribute( i ) );
1691 : 0 : }
1692 : 0 : return result;
1693 : 0 : }
1694 : :
1695 : 0 : static QVariant fcnCoreFeatureMaptipDisplay( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const bool isMaptip )
1696 : : {
1697 : 0 : QgsVectorLayer *layer = nullptr;
1698 : 0 : QgsFeature feature;
1699 : 0 : bool evaluate = true;
1700 : :
1701 : 0 : if ( values.isEmpty() )
1702 : : {
1703 : 0 : feature = context->feature();
1704 : 0 : layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1705 : 0 : }
1706 : 0 : else if ( values.size() == 1 )
1707 : : {
1708 : 0 : layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1709 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1710 : 0 : }
1711 : 0 : else if ( values.size() == 2 )
1712 : : {
1713 : 0 : layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1714 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
1715 : 0 : }
1716 : 0 : else if ( values.size() == 3 )
1717 : : {
1718 : 0 : layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1719 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
1720 : 0 : evaluate = values.value( 2 ).toBool();
1721 : 0 : }
1722 : : else
1723 : : {
1724 : 0 : if ( isMaptip )
1725 : : {
1726 : 0 : parent->setEvalErrorString( QObject::tr( "Function `maptip` requires no more than three parameters. %1 given." ).arg( values.length() ) );
1727 : 0 : }
1728 : : else
1729 : : {
1730 : 0 : parent->setEvalErrorString( QObject::tr( "Function `display` requires no more than three parameters. %1 given." ).arg( values.length() ) );
1731 : : }
1732 : 0 : return QVariant();
1733 : : }
1734 : :
1735 : 0 : if ( !layer )
1736 : : {
1737 : 0 : parent->setEvalErrorString( QObject::tr( "The layer is not valid." ) );
1738 : 0 : return QVariant( );
1739 : : }
1740 : :
1741 : 0 : if ( !feature.isValid() )
1742 : : {
1743 : 0 : parent->setEvalErrorString( QObject::tr( "The feature is not valid." ) );
1744 : 0 : return QVariant( );
1745 : : }
1746 : :
1747 : 0 : if ( ! evaluate )
1748 : : {
1749 : 0 : if ( isMaptip )
1750 : : {
1751 : 0 : return layer->mapTipTemplate();
1752 : : }
1753 : : else
1754 : : {
1755 : 0 : return layer->displayExpression();
1756 : : }
1757 : : }
1758 : :
1759 : 0 : QgsExpressionContext subContext( *context );
1760 : 0 : subContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
1761 : 0 : subContext.setFeature( feature );
1762 : :
1763 : 0 : if ( isMaptip )
1764 : : {
1765 : 0 : return QgsExpression::replaceExpressionText( layer->mapTipTemplate(), &subContext );
1766 : : }
1767 : : else
1768 : : {
1769 : 0 : QgsExpression exp( layer->displayExpression() );
1770 : 0 : exp.prepare( &subContext );
1771 : 0 : return exp.evaluate( &subContext ).toString();
1772 : 0 : }
1773 : 0 : }
1774 : :
1775 : 0 : static QVariant fcnFeatureDisplayExpression( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1776 : : {
1777 : 0 : return fcnCoreFeatureMaptipDisplay( values, context, parent, false );
1778 : : }
1779 : :
1780 : 0 : static QVariant fcnFeatureMaptip( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1781 : : {
1782 : 0 : return fcnCoreFeatureMaptipDisplay( values, context, parent, true );
1783 : : }
1784 : :
1785 : 0 : static QVariant fcnIsSelected( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1786 : : {
1787 : 0 : QgsVectorLayer *layer = nullptr;
1788 : 0 : QgsFeature feature;
1789 : :
1790 : 0 : if ( values.isEmpty() )
1791 : : {
1792 : 0 : feature = context->feature();
1793 : 0 : layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1794 : 0 : }
1795 : 0 : else if ( values.size() == 1 )
1796 : : {
1797 : 0 : layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1798 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
1799 : 0 : }
1800 : 0 : else if ( values.size() == 2 )
1801 : : {
1802 : 0 : layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1803 : 0 : feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
1804 : 0 : }
1805 : : else
1806 : : {
1807 : 0 : parent->setEvalErrorString( QObject::tr( "Function `is_selected` requires no more than two parameters. %1 given." ).arg( values.length() ) );
1808 : 0 : return QVariant();
1809 : : }
1810 : :
1811 : 0 : if ( !layer || !feature.isValid() )
1812 : : {
1813 : 0 : return QVariant( QVariant::Bool );
1814 : : }
1815 : :
1816 : 0 : return layer->selectedFeatureIds().contains( feature.id() );
1817 : 0 : }
1818 : :
1819 : 0 : static QVariant fcnNumSelected( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
1820 : : {
1821 : 0 : QgsVectorLayer *layer = nullptr;
1822 : :
1823 : 0 : if ( values.isEmpty() )
1824 : 0 : layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
1825 : 0 : else if ( values.count() == 1 )
1826 : 0 : layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1827 : : else
1828 : : {
1829 : 0 : parent->setEvalErrorString( QObject::tr( "Function `num_selected` requires no more than one parameter. %1 given." ).arg( values.length() ) );
1830 : 0 : return QVariant();
1831 : : }
1832 : :
1833 : 0 : if ( !layer )
1834 : : {
1835 : 0 : return QVariant( QVariant::LongLong );
1836 : : }
1837 : :
1838 : 0 : return layer->selectedFeatureCount();
1839 : 0 : }
1840 : :
1841 : 0 : static QVariant fcnSqliteFetchAndIncrement( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
1842 : : {
1843 : 0 : static QMap<QString, qlonglong> counterCache;
1844 : 0 : QVariant functionResult;
1845 : :
1846 : 0 : std::function<void()> fetchAndIncrementFunc = [ =, &functionResult ]()
1847 : : {
1848 : 0 : QString database;
1849 : 0 : const QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
1850 : :
1851 : 0 : if ( layer )
1852 : : {
1853 : 0 : const QVariantMap decodedUri = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
1854 : 0 : database = decodedUri.value( QStringLiteral( "path" ) ).toString();
1855 : 0 : if ( database.isEmpty() )
1856 : : {
1857 : 0 : parent->setEvalErrorString( QObject::tr( "Could not extract file path from layer `%1`." ).arg( layer->name() ) );
1858 : 0 : }
1859 : 0 : }
1860 : : else
1861 : : {
1862 : 0 : database = values.at( 0 ).toString();
1863 : : }
1864 : :
1865 : 0 : const QString table = values.at( 1 ).toString();
1866 : 0 : const QString idColumn = values.at( 2 ).toString();
1867 : 0 : const QString filterAttribute = values.at( 3 ).toString();
1868 : 0 : const QVariant filterValue = values.at( 4 ).toString();
1869 : 0 : const QVariantMap defaultValues = values.at( 5 ).toMap();
1870 : :
1871 : : // read from database
1872 : 0 : sqlite3_database_unique_ptr sqliteDb;
1873 : 0 : sqlite3_statement_unique_ptr sqliteStatement;
1874 : :
1875 : 0 : if ( sqliteDb.open_v2( database, SQLITE_OPEN_READWRITE, nullptr ) != SQLITE_OK )
1876 : : {
1877 : 0 : parent->setEvalErrorString( QObject::tr( "Could not open sqlite database %1. Error %2. " ).arg( database, sqliteDb.errorMessage() ) );
1878 : 0 : functionResult = QVariant();
1879 : 0 : return;
1880 : : }
1881 : :
1882 : 0 : QString errorMessage;
1883 : 0 : QString currentValSql;
1884 : :
1885 : 0 : qlonglong nextId = 0;
1886 : 0 : bool cachedMode = false;
1887 : 0 : bool valueRetrieved = false;
1888 : :
1889 : 0 : QString cacheString = QStringLiteral( "%1:%2:%3:%4:%5" ).arg( database, table, idColumn, filterAttribute, filterValue.toString() );
1890 : :
1891 : : // Running in transaction mode, check for cached value first
1892 : 0 : if ( layer && layer->dataProvider() && layer->dataProvider()->transaction() )
1893 : : {
1894 : 0 : cachedMode = true;
1895 : :
1896 : 0 : auto cachedCounter = counterCache.find( cacheString );
1897 : :
1898 : 0 : if ( cachedCounter != counterCache.end() )
1899 : : {
1900 : 0 : qlonglong &cachedValue = cachedCounter.value();
1901 : 0 : nextId = cachedValue;
1902 : 0 : nextId += 1;
1903 : 0 : cachedValue = nextId;
1904 : 0 : valueRetrieved = true;
1905 : 0 : }
1906 : 0 : }
1907 : :
1908 : : // Either not in cached mode or no cached value found, obtain from DB
1909 : 0 : if ( !cachedMode || !valueRetrieved )
1910 : : {
1911 : 0 : int result = SQLITE_ERROR;
1912 : :
1913 : 0 : currentValSql = QStringLiteral( "SELECT %1 FROM %2" ).arg( QgsSqliteUtils::quotedIdentifier( idColumn ), QgsSqliteUtils::quotedIdentifier( table ) );
1914 : 0 : if ( !filterAttribute.isNull() )
1915 : : {
1916 : 0 : currentValSql += QStringLiteral( " WHERE %1 = %2" ).arg( QgsSqliteUtils::quotedIdentifier( filterAttribute ), QgsSqliteUtils::quotedValue( filterValue ) );
1917 : 0 : }
1918 : :
1919 : 0 : sqliteStatement = sqliteDb.prepare( currentValSql, result );
1920 : :
1921 : 0 : if ( result == SQLITE_OK )
1922 : : {
1923 : 0 : nextId = 0;
1924 : 0 : if ( sqliteStatement.step() == SQLITE_ROW )
1925 : : {
1926 : 0 : nextId = sqliteStatement.columnAsInt64( 0 ) + 1;
1927 : 0 : }
1928 : :
1929 : : // If in cached mode: add value to cache and connect to transaction
1930 : 0 : if ( cachedMode && result == SQLITE_OK )
1931 : : {
1932 : 0 : counterCache.insert( cacheString, nextId );
1933 : :
1934 : 0 : QObject::connect( layer->dataProvider()->transaction(), &QgsTransaction::destroyed, [cacheString]()
1935 : : {
1936 : 0 : counterCache.remove( cacheString );
1937 : 0 : } );
1938 : 0 : }
1939 : 0 : valueRetrieved = true;
1940 : 0 : }
1941 : 0 : }
1942 : :
1943 : 0 : if ( valueRetrieved )
1944 : : {
1945 : 0 : QString upsertSql;
1946 : 0 : upsertSql = QStringLiteral( "INSERT OR REPLACE INTO %1" ).arg( QgsSqliteUtils::quotedIdentifier( table ) );
1947 : 0 : QStringList cols;
1948 : 0 : QStringList vals;
1949 : 0 : cols << QgsSqliteUtils::quotedIdentifier( idColumn );
1950 : 0 : vals << QgsSqliteUtils::quotedValue( nextId );
1951 : :
1952 : 0 : if ( !filterAttribute.isNull() )
1953 : : {
1954 : 0 : cols << QgsSqliteUtils::quotedIdentifier( filterAttribute );
1955 : 0 : vals << QgsSqliteUtils::quotedValue( filterValue );
1956 : 0 : }
1957 : :
1958 : 0 : for ( QVariantMap::const_iterator iter = defaultValues.constBegin(); iter != defaultValues.constEnd(); ++iter )
1959 : : {
1960 : 0 : cols << QgsSqliteUtils::quotedIdentifier( iter.key() );
1961 : 0 : vals << iter.value().toString();
1962 : 0 : }
1963 : :
1964 : 0 : upsertSql += QLatin1String( " (" ) + cols.join( ',' ) + ')';
1965 : 0 : upsertSql += QLatin1String( " VALUES " );
1966 : 0 : upsertSql += '(' + vals.join( ',' ) + ')';
1967 : :
1968 : 0 : int result = SQLITE_ERROR;
1969 : 0 : if ( layer && layer->dataProvider() && layer->dataProvider()->transaction() )
1970 : : {
1971 : 0 : QgsTransaction *transaction = layer->dataProvider()->transaction();
1972 : 0 : if ( transaction->executeSql( upsertSql, errorMessage ) )
1973 : : {
1974 : 0 : result = SQLITE_OK;
1975 : 0 : }
1976 : 0 : }
1977 : : else
1978 : : {
1979 : 0 : result = sqliteDb.exec( upsertSql, errorMessage );
1980 : : }
1981 : 0 : if ( result == SQLITE_OK )
1982 : : {
1983 : 0 : functionResult = QVariant( nextId );
1984 : 0 : return;
1985 : : }
1986 : : else
1987 : : {
1988 : 0 : parent->setEvalErrorString( QStringLiteral( "Could not increment value: SQLite error: \"%1\" (%2)." ).arg( errorMessage, QString::number( result ) ) );
1989 : 0 : functionResult = QVariant();
1990 : 0 : return;
1991 : : }
1992 : 0 : }
1993 : :
1994 : 0 : functionResult = QVariant();
1995 : 0 : };
1996 : :
1997 : 0 : QgsThreadingUtils::runOnMainThread( fetchAndIncrementFunc );
1998 : :
1999 : 0 : return functionResult;
2000 : 0 : }
2001 : :
2002 : 0 : static QVariant fcnConcat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2003 : : {
2004 : 0 : QString concat;
2005 : 0 : for ( const QVariant &value : values )
2006 : : {
2007 : 0 : if ( !value.isNull() )
2008 : 0 : concat += QgsExpressionUtils::getStringValue( value, parent );
2009 : : }
2010 : 0 : return concat;
2011 : 0 : }
2012 : :
2013 : 0 : static QVariant fcnStrpos( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2014 : : {
2015 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2016 : 0 : return string.indexOf( QgsExpressionUtils::getStringValue( values.at( 1 ), parent ) ) + 1;
2017 : 0 : }
2018 : :
2019 : 0 : static QVariant fcnRight( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2020 : : {
2021 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2022 : 0 : int pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2023 : 0 : return string.right( pos );
2024 : 0 : }
2025 : :
2026 : 0 : static QVariant fcnLeft( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2027 : : {
2028 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2029 : 0 : int pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2030 : 0 : return string.left( pos );
2031 : 0 : }
2032 : :
2033 : 0 : static QVariant fcnRPad( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2034 : : {
2035 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2036 : 0 : int length = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2037 : 0 : QString fill = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2038 : 0 : return string.leftJustified( length, fill.at( 0 ), true );
2039 : 0 : }
2040 : :
2041 : 0 : static QVariant fcnLPad( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2042 : : {
2043 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2044 : 0 : int length = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2045 : 0 : QString fill = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2046 : 0 : return string.rightJustified( length, fill.at( 0 ), true );
2047 : 0 : }
2048 : :
2049 : 0 : static QVariant fcnFormatString( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2050 : : {
2051 : 0 : if ( values.size() < 1 )
2052 : : {
2053 : 0 : parent->setEvalErrorString( QObject::tr( "Function format requires at least 1 argument" ) );
2054 : 0 : return QVariant();
2055 : : }
2056 : :
2057 : 0 : QString string = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2058 : 0 : for ( int n = 1; n < values.length(); n++ )
2059 : : {
2060 : 0 : string = string.arg( QgsExpressionUtils::getStringValue( values.at( n ), parent ) );
2061 : 0 : }
2062 : 0 : return string;
2063 : 0 : }
2064 : :
2065 : :
2066 : 0 : static QVariant fcnNow( const QVariantList &, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
2067 : : {
2068 : 0 : return QVariant( QDateTime::currentDateTime() );
2069 : 0 : }
2070 : :
2071 : 0 : static QVariant fcnToDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2072 : : {
2073 : 0 : QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
2074 : 0 : QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2075 : 0 : if ( format.isEmpty() && !language.isEmpty() )
2076 : : {
2077 : 0 : parent->setEvalErrorString( QObject::tr( "A format is required to convert to Date when the language is specified" ) );
2078 : 0 : return QVariant( QDate() );
2079 : : }
2080 : :
2081 : 0 : if ( format.isEmpty() && language.isEmpty() )
2082 : 0 : return QVariant( QgsExpressionUtils::getDateValue( values.at( 0 ), parent ) );
2083 : :
2084 : 0 : QString datestring = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2085 : 0 : QLocale locale = QLocale();
2086 : 0 : if ( !language.isEmpty() )
2087 : : {
2088 : 0 : locale = QLocale( language );
2089 : 0 : }
2090 : :
2091 : 0 : QDate date = locale.toDate( datestring, format );
2092 : 0 : if ( !date.isValid() )
2093 : : {
2094 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Date" ).arg( datestring ) );
2095 : 0 : date = QDate();
2096 : 0 : }
2097 : 0 : return QVariant( date );
2098 : 0 : }
2099 : :
2100 : 0 : static QVariant fcnToTime( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2101 : : {
2102 : 0 : QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
2103 : 0 : QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
2104 : 0 : if ( format.isEmpty() && !language.isEmpty() )
2105 : : {
2106 : 0 : parent->setEvalErrorString( QObject::tr( "A format is required to convert to Time when the language is specified" ) );
2107 : 0 : return QVariant( QTime() );
2108 : : }
2109 : :
2110 : 0 : if ( format.isEmpty() && language.isEmpty() )
2111 : 0 : return QVariant( QgsExpressionUtils::getTimeValue( values.at( 0 ), parent ) );
2112 : :
2113 : 0 : QString timestring = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
2114 : 0 : QLocale locale = QLocale();
2115 : 0 : if ( !language.isEmpty() )
2116 : : {
2117 : 0 : locale = QLocale( language );
2118 : 0 : }
2119 : :
2120 : 0 : QTime time = locale.toTime( timestring, format );
2121 : 0 : if ( !time.isValid() )
2122 : : {
2123 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to Time" ).arg( timestring ) );
2124 : 0 : time = QTime();
2125 : 0 : }
2126 : 0 : return QVariant( time );
2127 : 0 : }
2128 : :
2129 : 0 : static QVariant fcnToInterval( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2130 : : {
2131 : 0 : return QVariant::fromValue( QgsExpressionUtils::getInterval( values.at( 0 ), parent ) );
2132 : : }
2133 : :
2134 : : /*
2135 : : * DMS functions
2136 : : */
2137 : :
2138 : 0 : static QVariant floatToDegreeFormat( const QgsCoordinateFormatter::Format format, const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2139 : : {
2140 : 0 : double value = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
2141 : 0 : QString axis = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
2142 : 0 : int precision = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
2143 : :
2144 : 0 : QString formatString;
2145 : 0 : if ( values.count() > 3 )
2146 : 0 : formatString = QgsExpressionUtils::getStringValue( values.at( 3 ), parent );
2147 : :
2148 : 0 : QgsCoordinateFormatter::FormatFlags flags = QgsCoordinateFormatter::FormatFlags();
2149 : 0 : if ( formatString.compare( QLatin1String( "suffix" ), Qt::CaseInsensitive ) == 0 )
2150 : : {
2151 : 0 : flags = QgsCoordinateFormatter::FlagDegreesUseStringSuffix;
2152 : 0 : }
2153 : 0 : else if ( formatString.compare( QLatin1String( "aligned" ), Qt::CaseInsensitive ) == 0 )
2154 : : {
2155 : 0 : flags = QgsCoordinateFormatter::FlagDegreesUseStringSuffix | QgsCoordinateFormatter::FlagDegreesPadMinutesSeconds;
2156 : 0 : }
2157 : 0 : else if ( ! formatString.isEmpty() )
2158 : : {
2159 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid formatting parameter: '%1'. It must be empty, or 'suffix' or 'aligned'." ).arg( formatString ) );
2160 : 0 : return QVariant();
2161 : : }
2162 : :
2163 : 0 : if ( axis.compare( QLatin1String( "x" ), Qt::CaseInsensitive ) == 0 )
2164 : : {
2165 : 0 : return QVariant::fromValue( QgsCoordinateFormatter::formatX( value, format, precision, flags ) );
2166 : : }
2167 : 0 : else if ( axis.compare( QLatin1String( "y" ), Qt::CaseInsensitive ) == 0 )
2168 : : {
2169 : 0 : return QVariant::fromValue( QgsCoordinateFormatter::formatY( value, format, precision, flags ) );
2170 : : }
2171 : : else
2172 : : {
2173 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid axis name: '%1'. It must be either 'x' or 'y'." ).arg( axis ) );
2174 : 0 : return QVariant();
2175 : : }
2176 : 0 : }
2177 : :
2178 : 0 : static QVariant fcnToDegreeMinute( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
2179 : : {
2180 : 0 : QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatDegreesMinutes;
2181 : 0 : return floatToDegreeFormat( format, values, context, parent, node );
2182 : : }
2183 : :
2184 : 0 : static QVariant fcnToDecimal( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2185 : : {
2186 : 0 : double value = 0.0;
2187 : 0 : bool ok = false;
2188 : 0 : value = QgsCoordinateUtils::dmsToDecimal( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), &ok );
2189 : :
2190 : 0 : return ok ? QVariant( value ) : QVariant();
2191 : 0 : }
2192 : :
2193 : 0 : static QVariant fcnToDegreeMinuteSecond( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
2194 : : {
2195 : 0 : QgsCoordinateFormatter::Format format = QgsCoordinateFormatter::FormatDegreesMinutesSeconds;
2196 : 0 : return floatToDegreeFormat( format, values, context, parent, node );
2197 : : }
2198 : :
2199 : 0 : static QVariant fcnAge( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2200 : : {
2201 : 0 : QDateTime d1 = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
2202 : 0 : QDateTime d2 = QgsExpressionUtils::getDateTimeValue( values.at( 1 ), parent );
2203 : 0 : qint64 seconds = d2.secsTo( d1 );
2204 : 0 : return QVariant::fromValue( QgsInterval( seconds ) );
2205 : 0 : }
2206 : :
2207 : 0 : static QVariant fcnDayOfWeek( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2208 : : {
2209 : 0 : if ( !values.at( 0 ).canConvert<QDate>() )
2210 : 0 : return QVariant();
2211 : :
2212 : 0 : QDate date = QgsExpressionUtils::getDateValue( values.at( 0 ), parent );
2213 : 0 : if ( !date.isValid() )
2214 : 0 : return QVariant();
2215 : :
2216 : : // return dayOfWeek() % 7 so that values range from 0 (sun) to 6 (sat)
2217 : : // (to match PostgreSQL behavior)
2218 : 0 : return date.dayOfWeek() % 7;
2219 : 0 : }
2220 : :
2221 : 0 : static QVariant fcnDay( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2222 : : {
2223 : 0 : QVariant value = values.at( 0 );
2224 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2225 : 0 : if ( inter.isValid() )
2226 : : {
2227 : 0 : return QVariant( inter.days() );
2228 : : }
2229 : : else
2230 : : {
2231 : 0 : QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2232 : 0 : return QVariant( d1.date().day() );
2233 : 0 : }
2234 : 0 : }
2235 : :
2236 : 0 : static QVariant fcnYear( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2237 : : {
2238 : 0 : QVariant value = values.at( 0 );
2239 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2240 : 0 : if ( inter.isValid() )
2241 : : {
2242 : 0 : return QVariant( inter.years() );
2243 : : }
2244 : : else
2245 : : {
2246 : 0 : QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2247 : 0 : return QVariant( d1.date().year() );
2248 : 0 : }
2249 : 0 : }
2250 : :
2251 : 0 : static QVariant fcnMonth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2252 : : {
2253 : 0 : QVariant value = values.at( 0 );
2254 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2255 : 0 : if ( inter.isValid() )
2256 : : {
2257 : 0 : return QVariant( inter.months() );
2258 : : }
2259 : : else
2260 : : {
2261 : 0 : QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2262 : 0 : return QVariant( d1.date().month() );
2263 : 0 : }
2264 : 0 : }
2265 : :
2266 : 0 : static QVariant fcnWeek( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2267 : : {
2268 : 0 : QVariant value = values.at( 0 );
2269 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2270 : 0 : if ( inter.isValid() )
2271 : : {
2272 : 0 : return QVariant( inter.weeks() );
2273 : : }
2274 : : else
2275 : : {
2276 : 0 : QDateTime d1 = QgsExpressionUtils::getDateTimeValue( value, parent );
2277 : 0 : return QVariant( d1.date().weekNumber() );
2278 : 0 : }
2279 : 0 : }
2280 : :
2281 : 0 : static QVariant fcnHour( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2282 : : {
2283 : 0 : QVariant value = values.at( 0 );
2284 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2285 : 0 : if ( inter.isValid() )
2286 : : {
2287 : 0 : return QVariant( inter.hours() );
2288 : : }
2289 : : else
2290 : : {
2291 : 0 : QTime t1 = QgsExpressionUtils::getTimeValue( value, parent );
2292 : 0 : return QVariant( t1.hour() );
2293 : : }
2294 : 0 : }
2295 : :
2296 : 0 : static QVariant fcnMinute( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2297 : : {
2298 : 0 : QVariant value = values.at( 0 );
2299 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2300 : 0 : if ( inter.isValid() )
2301 : : {
2302 : 0 : return QVariant( inter.minutes() );
2303 : : }
2304 : : else
2305 : : {
2306 : 0 : QTime t1 = QgsExpressionUtils::getTimeValue( value, parent );
2307 : 0 : return QVariant( t1.minute() );
2308 : : }
2309 : 0 : }
2310 : :
2311 : 0 : static QVariant fcnSeconds( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2312 : : {
2313 : 0 : QVariant value = values.at( 0 );
2314 : 0 : QgsInterval inter = QgsExpressionUtils::getInterval( value, parent, false );
2315 : 0 : if ( inter.isValid() )
2316 : : {
2317 : 0 : return QVariant( inter.seconds() );
2318 : : }
2319 : : else
2320 : : {
2321 : 0 : QTime t1 = QgsExpressionUtils::getTimeValue( value, parent );
2322 : 0 : return QVariant( t1.second() );
2323 : : }
2324 : 0 : }
2325 : :
2326 : 0 : static QVariant fcnEpoch( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2327 : : {
2328 : 0 : QDateTime dt = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
2329 : 0 : if ( dt.isValid() )
2330 : : {
2331 : 0 : return QVariant( dt.toMSecsSinceEpoch() );
2332 : : }
2333 : : else
2334 : : {
2335 : 0 : return QVariant();
2336 : : }
2337 : 0 : }
2338 : :
2339 : 0 : static QVariant fcnDateTimeFromEpoch( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2340 : : {
2341 : 0 : long long millisecs_since_epoch = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
2342 : : // no sense to check for strange values, as Qt behavior is undefined anyway (see docs)
2343 : 0 : return QVariant( QDateTime::fromMSecsSinceEpoch( millisecs_since_epoch ) );
2344 : 0 : }
2345 : :
2346 : : #define ENSURE_GEOM_TYPE(f, g, geomtype) \
2347 : : if ( !(f).hasGeometry() ) \
2348 : : return QVariant(); \
2349 : : QgsGeometry g = (f).geometry(); \
2350 : : if ( (g).type() != (geomtype) ) \
2351 : : return QVariant();
2352 : :
2353 : 0 : static QVariant fcnX( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
2354 : : {
2355 : 0 : FEAT_FROM_CONTEXT( context, f )
2356 : 0 : ENSURE_GEOM_TYPE( f, g, QgsWkbTypes::PointGeometry )
2357 : 0 : if ( g.isMultipart() )
2358 : : {
2359 : 0 : return g.asMultiPoint().at( 0 ).x();
2360 : : }
2361 : : else
2362 : : {
2363 : 0 : return g.asPoint().x();
2364 : : }
2365 : 0 : }
2366 : :
2367 : 0 : static QVariant fcnY( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
2368 : : {
2369 : 0 : FEAT_FROM_CONTEXT( context, f )
2370 : 0 : ENSURE_GEOM_TYPE( f, g, QgsWkbTypes::PointGeometry )
2371 : 0 : if ( g.isMultipart() )
2372 : : {
2373 : 0 : return g.asMultiPoint().at( 0 ).y();
2374 : : }
2375 : : else
2376 : : {
2377 : 0 : return g.asPoint().y();
2378 : : }
2379 : 0 : }
2380 : :
2381 : 0 : static QVariant fcnGeomIsValid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2382 : : {
2383 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2384 : 0 : if ( geom.isNull() )
2385 : 0 : return QVariant();
2386 : :
2387 : 0 : bool isValid = geom.isGeosValid();
2388 : :
2389 : 0 : return QVariant( isValid );
2390 : 0 : }
2391 : :
2392 : 0 : static QVariant fcnGeomX( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2393 : : {
2394 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2395 : 0 : if ( geom.isNull() )
2396 : 0 : return QVariant();
2397 : :
2398 : : //if single point, return the point's x coordinate
2399 : 0 : if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2400 : : {
2401 : 0 : return geom.asPoint().x();
2402 : : }
2403 : :
2404 : : //otherwise return centroid x
2405 : 0 : QgsGeometry centroid = geom.centroid();
2406 : 0 : QVariant result( centroid.asPoint().x() );
2407 : 0 : return result;
2408 : 0 : }
2409 : :
2410 : 0 : static QVariant fcnGeomY( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2411 : : {
2412 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2413 : 0 : if ( geom.isNull() )
2414 : 0 : return QVariant();
2415 : :
2416 : : //if single point, return the point's y coordinate
2417 : 0 : if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2418 : : {
2419 : 0 : return geom.asPoint().y();
2420 : : }
2421 : :
2422 : : //otherwise return centroid y
2423 : 0 : QgsGeometry centroid = geom.centroid();
2424 : 0 : QVariant result( centroid.asPoint().y() );
2425 : 0 : return result;
2426 : 0 : }
2427 : :
2428 : 0 : static QVariant fcnGeomZ( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2429 : : {
2430 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2431 : 0 : if ( geom.isNull() )
2432 : 0 : return QVariant(); //or 0?
2433 : :
2434 : 0 : if ( !geom.constGet()->is3D() )
2435 : 0 : return QVariant();
2436 : :
2437 : : //if single point, return the point's z coordinate
2438 : 0 : if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2439 : : {
2440 : 0 : const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2441 : 0 : if ( point )
2442 : 0 : return point->z();
2443 : 0 : }
2444 : 0 : else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
2445 : : {
2446 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2447 : : {
2448 : 0 : if ( collection->numGeometries() == 1 )
2449 : : {
2450 : 0 : if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
2451 : 0 : return point->z();
2452 : 0 : }
2453 : 0 : }
2454 : 0 : }
2455 : :
2456 : 0 : return QVariant();
2457 : 0 : }
2458 : :
2459 : 0 : static QVariant fcnGeomM( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2460 : : {
2461 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2462 : 0 : if ( geom.isNull() )
2463 : 0 : return QVariant(); //or 0?
2464 : :
2465 : 0 : if ( !geom.constGet()->isMeasure() )
2466 : 0 : return QVariant();
2467 : :
2468 : : //if single point, return the point's m value
2469 : 0 : if ( geom.type() == QgsWkbTypes::PointGeometry && !geom.isMultipart() )
2470 : : {
2471 : 0 : const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2472 : 0 : if ( point )
2473 : 0 : return point->m();
2474 : 0 : }
2475 : 0 : else if ( geom.type() == QgsWkbTypes::PointGeometry && geom.isMultipart() )
2476 : : {
2477 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2478 : : {
2479 : 0 : if ( collection->numGeometries() == 1 )
2480 : : {
2481 : 0 : if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) ) )
2482 : 0 : return point->m();
2483 : 0 : }
2484 : 0 : }
2485 : 0 : }
2486 : :
2487 : 0 : return QVariant();
2488 : 0 : }
2489 : :
2490 : 0 : static QVariant fcnPointN( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2491 : : {
2492 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2493 : :
2494 : 0 : if ( geom.isNull() )
2495 : 0 : return QVariant();
2496 : :
2497 : 0 : int idx = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
2498 : :
2499 : 0 : if ( idx < 0 )
2500 : : {
2501 : : //negative idx
2502 : 0 : int count = geom.constGet()->nCoordinates();
2503 : 0 : idx = count + idx;
2504 : 0 : }
2505 : : else
2506 : : {
2507 : : //positive idx is 1 based
2508 : 0 : idx -= 1;
2509 : : }
2510 : :
2511 : 0 : QgsVertexId vId;
2512 : 0 : if ( idx < 0 || !geom.vertexIdFromVertexNr( idx, vId ) )
2513 : : {
2514 : 0 : parent->setEvalErrorString( QObject::tr( "Point index is out of range" ) );
2515 : 0 : return QVariant();
2516 : : }
2517 : :
2518 : 0 : QgsPoint point = geom.constGet()->vertexAt( vId );
2519 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( point ) ) );
2520 : 0 : }
2521 : :
2522 : 0 : static QVariant fcnStartPoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2523 : : {
2524 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2525 : :
2526 : 0 : if ( geom.isNull() )
2527 : 0 : return QVariant();
2528 : :
2529 : 0 : QgsVertexId vId;
2530 : 0 : if ( !geom.vertexIdFromVertexNr( 0, vId ) )
2531 : : {
2532 : 0 : return QVariant();
2533 : : }
2534 : :
2535 : 0 : QgsPoint point = geom.constGet()->vertexAt( vId );
2536 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( point ) ) );
2537 : 0 : }
2538 : :
2539 : 0 : static QVariant fcnEndPoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2540 : : {
2541 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2542 : :
2543 : 0 : if ( geom.isNull() )
2544 : 0 : return QVariant();
2545 : :
2546 : 0 : QgsVertexId vId;
2547 : 0 : if ( !geom.vertexIdFromVertexNr( geom.constGet()->nCoordinates() - 1, vId ) )
2548 : : {
2549 : 0 : return QVariant();
2550 : : }
2551 : :
2552 : 0 : QgsPoint point = geom.constGet()->vertexAt( vId );
2553 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( point ) ) );
2554 : 0 : }
2555 : :
2556 : 0 : static QVariant fcnNodesToPoints( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2557 : : {
2558 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2559 : :
2560 : 0 : if ( geom.isNull() )
2561 : 0 : return QVariant();
2562 : :
2563 : 0 : bool ignoreClosing = false;
2564 : 0 : if ( values.length() > 1 )
2565 : : {
2566 : 0 : ignoreClosing = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
2567 : 0 : }
2568 : :
2569 : 0 : QgsMultiPoint *mp = new QgsMultiPoint();
2570 : :
2571 : 0 : const QgsCoordinateSequence sequence = geom.constGet()->coordinateSequence();
2572 : 0 : for ( const QgsRingSequence &part : sequence )
2573 : : {
2574 : 0 : for ( const QgsPointSequence &ring : part )
2575 : : {
2576 : 0 : bool skipLast = false;
2577 : 0 : if ( ignoreClosing && ring.count() > 2 && ring.first() == ring.last() )
2578 : : {
2579 : 0 : skipLast = true;
2580 : 0 : }
2581 : :
2582 : 0 : for ( int i = 0; i < ( skipLast ? ring.count() - 1 : ring.count() ); ++ i )
2583 : : {
2584 : 0 : mp->addGeometry( ring.at( i ).clone() );
2585 : 0 : }
2586 : : }
2587 : : }
2588 : :
2589 : 0 : return QVariant::fromValue( QgsGeometry( mp ) );
2590 : 0 : }
2591 : :
2592 : 0 : static QVariant fcnSegmentsToLines( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2593 : : {
2594 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2595 : :
2596 : 0 : if ( geom.isNull() )
2597 : 0 : return QVariant();
2598 : :
2599 : 0 : const QVector< QgsLineString * > linesToProcess = QgsGeometryUtils::extractLineStrings( geom.constGet() );
2600 : :
2601 : : //OK, now we have a complete list of segmentized lines from the geometry
2602 : 0 : QgsMultiLineString *ml = new QgsMultiLineString();
2603 : 0 : for ( QgsLineString *line : linesToProcess )
2604 : : {
2605 : 0 : for ( int i = 0; i < line->numPoints() - 1; ++i )
2606 : : {
2607 : 0 : QgsLineString *segment = new QgsLineString();
2608 : 0 : segment->setPoints( QgsPointSequence()
2609 : 0 : << line->pointN( i )
2610 : 0 : << line->pointN( i + 1 ) );
2611 : 0 : ml->addGeometry( segment );
2612 : 0 : }
2613 : 0 : delete line;
2614 : : }
2615 : :
2616 : 0 : return QVariant::fromValue( QgsGeometry( ml ) );
2617 : 0 : }
2618 : :
2619 : 0 : static QVariant fcnInteriorRingN( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2620 : : {
2621 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2622 : :
2623 : 0 : if ( geom.isNull() )
2624 : 0 : return QVariant();
2625 : :
2626 : 0 : const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
2627 : 0 : if ( !curvePolygon && geom.isMultipart() )
2628 : : {
2629 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2630 : : {
2631 : 0 : if ( collection->numGeometries() == 1 )
2632 : : {
2633 : 0 : curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
2634 : 0 : }
2635 : 0 : }
2636 : 0 : }
2637 : :
2638 : 0 : if ( !curvePolygon )
2639 : 0 : return QVariant();
2640 : :
2641 : : //idx is 1 based
2642 : 0 : qlonglong idx = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) - 1;
2643 : :
2644 : 0 : if ( idx >= curvePolygon->numInteriorRings() || idx < 0 )
2645 : 0 : return QVariant();
2646 : :
2647 : 0 : QgsCurve *curve = static_cast< QgsCurve * >( curvePolygon->interiorRing( static_cast< int >( idx ) )->clone() );
2648 : 0 : QVariant result = curve ? QVariant::fromValue( QgsGeometry( curve ) ) : QVariant();
2649 : 0 : return result;
2650 : 0 : }
2651 : :
2652 : 0 : static QVariant fcnGeometryN( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2653 : : {
2654 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2655 : :
2656 : 0 : if ( geom.isNull() )
2657 : 0 : return QVariant();
2658 : :
2659 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() );
2660 : 0 : if ( !collection )
2661 : 0 : return QVariant();
2662 : :
2663 : : //idx is 1 based
2664 : 0 : qlonglong idx = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) - 1;
2665 : :
2666 : 0 : if ( idx < 0 || idx >= collection->numGeometries() )
2667 : 0 : return QVariant();
2668 : :
2669 : 0 : QgsAbstractGeometry *part = collection->geometryN( static_cast< int >( idx ) )->clone();
2670 : 0 : QVariant result = part ? QVariant::fromValue( QgsGeometry( part ) ) : QVariant();
2671 : 0 : return result;
2672 : 0 : }
2673 : :
2674 : 0 : static QVariant fcnBoundary( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2675 : : {
2676 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2677 : :
2678 : 0 : if ( geom.isNull() )
2679 : 0 : return QVariant();
2680 : :
2681 : 0 : QgsAbstractGeometry *boundary = geom.constGet()->boundary();
2682 : 0 : if ( !boundary )
2683 : 0 : return QVariant();
2684 : :
2685 : 0 : return QVariant::fromValue( QgsGeometry( boundary ) );
2686 : 0 : }
2687 : :
2688 : 0 : static QVariant fcnLineMerge( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2689 : : {
2690 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2691 : :
2692 : 0 : if ( geom.isNull() )
2693 : 0 : return QVariant();
2694 : :
2695 : 0 : QgsGeometry merged = geom.mergeLines();
2696 : 0 : if ( merged.isNull() )
2697 : 0 : return QVariant();
2698 : :
2699 : 0 : return QVariant::fromValue( merged );
2700 : 0 : }
2701 : :
2702 : 0 : static QVariant fcnSimplify( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2703 : : {
2704 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2705 : :
2706 : 0 : if ( geom.isNull() )
2707 : 0 : return QVariant();
2708 : :
2709 : 0 : double tolerance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2710 : :
2711 : 0 : QgsGeometry simplified = geom.simplify( tolerance );
2712 : 0 : if ( simplified.isNull() )
2713 : 0 : return QVariant();
2714 : :
2715 : 0 : return simplified;
2716 : 0 : }
2717 : :
2718 : 0 : static QVariant fcnSimplifyVW( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2719 : : {
2720 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2721 : :
2722 : 0 : if ( geom.isNull() )
2723 : 0 : return QVariant();
2724 : :
2725 : 0 : double tolerance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2726 : :
2727 : 0 : QgsMapToPixelSimplifier simplifier( QgsMapToPixelSimplifier::SimplifyGeometry, tolerance, QgsMapToPixelSimplifier::Visvalingam );
2728 : :
2729 : 0 : QgsGeometry simplified = simplifier.simplify( geom );
2730 : 0 : if ( simplified.isNull() )
2731 : 0 : return QVariant();
2732 : :
2733 : 0 : return simplified;
2734 : 0 : }
2735 : :
2736 : 0 : static QVariant fcnSmooth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2737 : : {
2738 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2739 : :
2740 : 0 : if ( geom.isNull() )
2741 : 0 : return QVariant();
2742 : :
2743 : 0 : int iterations = std::min( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ), 10 );
2744 : 0 : double offset = std::clamp( QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent ), 0.0, 0.5 );
2745 : 0 : double minLength = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
2746 : 0 : double maxAngle = std::clamp( QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent ), 0.0, 180.0 );
2747 : :
2748 : 0 : QgsGeometry smoothed = geom.smooth( static_cast<unsigned int>( iterations ), offset, minLength, maxAngle );
2749 : 0 : if ( smoothed.isNull() )
2750 : 0 : return QVariant();
2751 : :
2752 : 0 : return smoothed;
2753 : 0 : }
2754 : :
2755 : 0 : static QVariant fcnCollectGeometries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2756 : : {
2757 : 0 : QVariantList list;
2758 : 0 : if ( values.size() == 1 && ( values.at( 0 ).type() == QVariant::List || values.at( 0 ).type() == QVariant::StringList ) )
2759 : : {
2760 : 0 : list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
2761 : 0 : }
2762 : : else
2763 : : {
2764 : 0 : list = values;
2765 : : }
2766 : :
2767 : 0 : QVector< QgsGeometry > parts;
2768 : 0 : parts.reserve( list.size() );
2769 : 0 : for ( const QVariant &value : std::as_const( list ) )
2770 : : {
2771 : 0 : if ( value.canConvert<QgsGeometry>() )
2772 : : {
2773 : 0 : parts << value.value<QgsGeometry>();
2774 : 0 : }
2775 : : else
2776 : : {
2777 : 0 : parent->setEvalErrorString( QStringLiteral( "Cannot convert to geometry" ) );
2778 : 0 : return QgsGeometry();
2779 : : }
2780 : : }
2781 : :
2782 : 0 : return QgsGeometry::collectGeometry( parts );
2783 : 0 : }
2784 : :
2785 : 0 : static QVariant fcnMakePoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2786 : : {
2787 : 0 : if ( values.count() < 2 || values.count() > 4 )
2788 : : {
2789 : 0 : parent->setEvalErrorString( QObject::tr( "Function make_point requires 2-4 arguments" ) );
2790 : 0 : return QVariant();
2791 : : }
2792 : :
2793 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
2794 : 0 : double y = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2795 : 0 : double z = values.count() >= 3 ? QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent ) : 0.0;
2796 : 0 : double m = values.count() >= 4 ? QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent ) : 0.0;
2797 : 0 : switch ( values.count() )
2798 : : {
2799 : : case 2:
2800 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( x, y ) ) );
2801 : : case 3:
2802 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( QgsWkbTypes::PointZ, x, y, z ) ) );
2803 : : case 4:
2804 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( QgsWkbTypes::PointZM, x, y, z, m ) ) );
2805 : : }
2806 : 0 : return QVariant(); //avoid warning
2807 : 0 : }
2808 : :
2809 : 0 : static QVariant fcnMakePointM( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2810 : : {
2811 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
2812 : 0 : double y = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2813 : 0 : double m = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
2814 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( QgsWkbTypes::PointM, x, y, 0.0, m ) ) );
2815 : 0 : }
2816 : :
2817 : 0 : static QVariant fcnMakeLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2818 : : {
2819 : 0 : if ( values.empty() )
2820 : : {
2821 : 0 : return QVariant();
2822 : : }
2823 : :
2824 : 0 : QVector<QgsPoint> points;
2825 : 0 : points.reserve( values.count() );
2826 : :
2827 : 0 : auto addPoint = [&points]( const QgsGeometry & geom )
2828 : : {
2829 : 0 : if ( geom.isNull() )
2830 : 0 : return;
2831 : :
2832 : 0 : if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2833 : 0 : return;
2834 : :
2835 : 0 : const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2836 : 0 : if ( !point )
2837 : 0 : return;
2838 : :
2839 : 0 : points << *point;
2840 : 0 : };
2841 : :
2842 : 0 : for ( const QVariant &value : values )
2843 : : {
2844 : 0 : if ( value.type() == QVariant::List )
2845 : : {
2846 : 0 : const QVariantList list = value.toList();
2847 : 0 : for ( const QVariant &v : list )
2848 : : {
2849 : 0 : addPoint( QgsExpressionUtils::getGeometry( v, parent ) );
2850 : : }
2851 : 0 : }
2852 : : else
2853 : : {
2854 : 0 : addPoint( QgsExpressionUtils::getGeometry( value, parent ) );
2855 : : }
2856 : : }
2857 : :
2858 : 0 : if ( points.count() < 2 )
2859 : 0 : return QVariant();
2860 : :
2861 : 0 : return QgsGeometry( new QgsLineString( points ) );
2862 : 0 : }
2863 : :
2864 : 0 : static QVariant fcnMakePolygon( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2865 : : {
2866 : 0 : if ( values.count() < 1 )
2867 : : {
2868 : 0 : parent->setEvalErrorString( QObject::tr( "Function make_polygon requires an argument" ) );
2869 : 0 : return QVariant();
2870 : : }
2871 : :
2872 : 0 : QgsGeometry outerRing = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2873 : 0 : if ( outerRing.type() != QgsWkbTypes::LineGeometry || outerRing.isNull() )
2874 : 0 : return QVariant();
2875 : :
2876 : 0 : std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
2877 : :
2878 : 0 : const QgsCurve *exteriorRing = qgsgeometry_cast< QgsCurve * >( outerRing.constGet() );
2879 : 0 : if ( !exteriorRing && outerRing.isMultipart() )
2880 : : {
2881 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( outerRing.constGet() ) )
2882 : : {
2883 : 0 : if ( collection->numGeometries() == 1 )
2884 : : {
2885 : 0 : exteriorRing = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2886 : 0 : }
2887 : 0 : }
2888 : 0 : }
2889 : :
2890 : 0 : if ( !exteriorRing )
2891 : 0 : return QVariant();
2892 : :
2893 : 0 : polygon->setExteriorRing( exteriorRing->segmentize() );
2894 : :
2895 : :
2896 : 0 : for ( int i = 1; i < values.count(); ++i )
2897 : : {
2898 : 0 : QgsGeometry ringGeom = QgsExpressionUtils::getGeometry( values.at( i ), parent );
2899 : 0 : if ( ringGeom.isNull() )
2900 : 0 : continue;
2901 : :
2902 : 0 : if ( ringGeom.type() != QgsWkbTypes::LineGeometry || ringGeom.isNull() )
2903 : 0 : continue;
2904 : :
2905 : 0 : const QgsCurve *ring = qgsgeometry_cast< QgsCurve * >( ringGeom.constGet() );
2906 : 0 : if ( !ring && ringGeom.isMultipart() )
2907 : : {
2908 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( ringGeom.constGet() ) )
2909 : : {
2910 : 0 : if ( collection->numGeometries() == 1 )
2911 : : {
2912 : 0 : ring = qgsgeometry_cast< QgsCurve * >( collection->geometryN( 0 ) );
2913 : 0 : }
2914 : 0 : }
2915 : 0 : }
2916 : :
2917 : 0 : if ( !ring )
2918 : 0 : continue;
2919 : :
2920 : 0 : polygon->addInteriorRing( ring->segmentize() );
2921 : 0 : }
2922 : :
2923 : 0 : return QVariant::fromValue( QgsGeometry( std::move( polygon ) ) );
2924 : 0 : }
2925 : :
2926 : 0 : static QVariant fcnMakeTriangle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2927 : : {
2928 : 0 : std::unique_ptr<QgsTriangle> tr( new QgsTriangle() );
2929 : 0 : std::unique_ptr<QgsLineString> lineString( new QgsLineString() );
2930 : 0 : lineString->clear();
2931 : :
2932 : 0 : for ( const QVariant &value : values )
2933 : : {
2934 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( value, parent );
2935 : 0 : if ( geom.isNull() )
2936 : 0 : return QVariant();
2937 : :
2938 : 0 : if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2939 : 0 : return QVariant();
2940 : :
2941 : 0 : const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2942 : 0 : if ( !point && geom.isMultipart() )
2943 : : {
2944 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2945 : : {
2946 : 0 : if ( collection->numGeometries() == 1 )
2947 : : {
2948 : 0 : point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2949 : 0 : }
2950 : 0 : }
2951 : 0 : }
2952 : :
2953 : 0 : if ( !point )
2954 : 0 : return QVariant();
2955 : :
2956 : 0 : lineString->addVertex( *point );
2957 : 0 : }
2958 : :
2959 : 0 : tr->setExteriorRing( lineString.release() );
2960 : :
2961 : 0 : return QVariant::fromValue( QgsGeometry( tr.release() ) );
2962 : 0 : }
2963 : :
2964 : 0 : static QVariant fcnMakeCircle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
2965 : : {
2966 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
2967 : 0 : if ( geom.isNull() )
2968 : 0 : return QVariant();
2969 : :
2970 : 0 : if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
2971 : 0 : return QVariant();
2972 : :
2973 : 0 : double radius = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
2974 : 0 : int segment = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
2975 : :
2976 : 0 : if ( segment < 3 )
2977 : : {
2978 : 0 : parent->setEvalErrorString( QObject::tr( "Segment must be greater than 2" ) );
2979 : 0 : return QVariant();
2980 : : }
2981 : 0 : const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
2982 : 0 : if ( !point && geom.isMultipart() )
2983 : : {
2984 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
2985 : : {
2986 : 0 : if ( collection->numGeometries() == 1 )
2987 : : {
2988 : 0 : point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
2989 : 0 : }
2990 : 0 : }
2991 : 0 : }
2992 : 0 : if ( !point )
2993 : 0 : return QVariant();
2994 : :
2995 : 0 : QgsCircle circ( *point, radius );
2996 : 0 : return QVariant::fromValue( QgsGeometry( circ.toPolygon( static_cast<unsigned int>( segment ) ) ) );
2997 : 0 : }
2998 : :
2999 : 0 : static QVariant fcnMakeEllipse( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3000 : : {
3001 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3002 : 0 : if ( geom.isNull() )
3003 : 0 : return QVariant();
3004 : :
3005 : 0 : if ( geom.type() != QgsWkbTypes::PointGeometry || geom.isMultipart() )
3006 : 0 : return QVariant();
3007 : :
3008 : 0 : double majorAxis = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3009 : 0 : double minorAxis = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3010 : 0 : double azimuth = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3011 : 0 : int segment = QgsExpressionUtils::getNativeIntValue( values.at( 4 ), parent );
3012 : 0 : if ( segment < 3 )
3013 : : {
3014 : 0 : parent->setEvalErrorString( QObject::tr( "Segment must be greater than 2" ) );
3015 : 0 : return QVariant();
3016 : : }
3017 : 0 : const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( geom.constGet() );
3018 : 0 : if ( !point && geom.isMultipart() )
3019 : : {
3020 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() ) )
3021 : : {
3022 : 0 : if ( collection->numGeometries() == 1 )
3023 : : {
3024 : 0 : point = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3025 : 0 : }
3026 : 0 : }
3027 : 0 : }
3028 : 0 : if ( !point )
3029 : 0 : return QVariant();
3030 : :
3031 : 0 : QgsEllipse elp( *point, majorAxis, minorAxis, azimuth );
3032 : 0 : return QVariant::fromValue( QgsGeometry( elp.toPolygon( static_cast<unsigned int>( segment ) ) ) );
3033 : 0 : }
3034 : :
3035 : 0 : static QVariant fcnMakeRegularPolygon( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3036 : : {
3037 : :
3038 : 0 : QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3039 : 0 : if ( pt1.isNull() )
3040 : 0 : return QVariant();
3041 : :
3042 : 0 : if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
3043 : 0 : return QVariant();
3044 : :
3045 : 0 : QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3046 : 0 : if ( pt2.isNull() )
3047 : 0 : return QVariant();
3048 : :
3049 : 0 : if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
3050 : 0 : return QVariant();
3051 : :
3052 : 0 : unsigned int nbEdges = static_cast<unsigned int>( QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) );
3053 : 0 : if ( nbEdges < 3 )
3054 : : {
3055 : 0 : parent->setEvalErrorString( QObject::tr( "Number of edges/sides must be greater than 2" ) );
3056 : 0 : return QVariant();
3057 : : }
3058 : :
3059 : 0 : QgsRegularPolygon::ConstructionOption option = static_cast< QgsRegularPolygon::ConstructionOption >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3060 : 0 : if ( ( option < QgsRegularPolygon::InscribedCircle ) || ( option > QgsRegularPolygon::CircumscribedCircle ) )
3061 : : {
3062 : 0 : parent->setEvalErrorString( QObject::tr( "Option can be 0 (inscribed) or 1 (circumscribed)" ) );
3063 : 0 : return QVariant();
3064 : : }
3065 : :
3066 : 0 : const QgsPoint *center = qgsgeometry_cast< const QgsPoint * >( pt1.constGet() );
3067 : 0 : if ( !center && pt1.isMultipart() )
3068 : : {
3069 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt1.constGet() ) )
3070 : : {
3071 : 0 : if ( collection->numGeometries() == 1 )
3072 : : {
3073 : 0 : center = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3074 : 0 : }
3075 : 0 : }
3076 : 0 : }
3077 : 0 : if ( !center )
3078 : 0 : return QVariant();
3079 : :
3080 : 0 : const QgsPoint *corner = qgsgeometry_cast< const QgsPoint * >( pt2.constGet() );
3081 : 0 : if ( !corner && pt2.isMultipart() )
3082 : : {
3083 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( pt2.constGet() ) )
3084 : : {
3085 : 0 : if ( collection->numGeometries() == 1 )
3086 : : {
3087 : 0 : corner = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3088 : 0 : }
3089 : 0 : }
3090 : 0 : }
3091 : 0 : if ( !corner )
3092 : 0 : return QVariant();
3093 : :
3094 : 0 : QgsRegularPolygon rp = QgsRegularPolygon( *center, *corner, nbEdges, option );
3095 : :
3096 : 0 : return QVariant::fromValue( QgsGeometry( rp.toPolygon() ) );
3097 : :
3098 : 0 : }
3099 : :
3100 : 0 : static QVariant fcnMakeSquare( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3101 : : {
3102 : 0 : QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3103 : 0 : if ( pt1.isNull() )
3104 : 0 : return QVariant();
3105 : 0 : if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
3106 : 0 : return QVariant();
3107 : :
3108 : 0 : QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3109 : 0 : if ( pt2.isNull() )
3110 : 0 : return QVariant();
3111 : 0 : if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
3112 : 0 : return QVariant();
3113 : :
3114 : 0 : const QgsPoint *point1 = qgsgeometry_cast< const QgsPoint *>( pt1.constGet() );
3115 : 0 : const QgsPoint *point2 = qgsgeometry_cast< const QgsPoint *>( pt2.constGet() );
3116 : 0 : QgsQuadrilateral square = QgsQuadrilateral::squareFromDiagonal( *point1, *point2 );
3117 : :
3118 : 0 : return QVariant::fromValue( QgsGeometry( square.toPolygon() ) );
3119 : 0 : }
3120 : :
3121 : 0 : static QVariant fcnMakeRectangleFrom3Points( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3122 : : {
3123 : 0 : QgsGeometry pt1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3124 : 0 : if ( pt1.isNull() )
3125 : 0 : return QVariant();
3126 : 0 : if ( pt1.type() != QgsWkbTypes::PointGeometry || pt1.isMultipart() )
3127 : 0 : return QVariant();
3128 : :
3129 : 0 : QgsGeometry pt2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3130 : 0 : if ( pt2.isNull() )
3131 : 0 : return QVariant();
3132 : 0 : if ( pt2.type() != QgsWkbTypes::PointGeometry || pt2.isMultipart() )
3133 : 0 : return QVariant();
3134 : :
3135 : 0 : QgsGeometry pt3 = QgsExpressionUtils::getGeometry( values.at( 2 ), parent );
3136 : 0 : if ( pt3.isNull() )
3137 : 0 : return QVariant();
3138 : 0 : if ( pt3.type() != QgsWkbTypes::PointGeometry || pt3.isMultipart() )
3139 : 0 : return QVariant();
3140 : :
3141 : 0 : QgsQuadrilateral::ConstructionOption option = static_cast< QgsQuadrilateral::ConstructionOption >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3142 : 0 : if ( ( option < QgsQuadrilateral::Distance ) || ( option > QgsQuadrilateral::Projected ) )
3143 : : {
3144 : 0 : parent->setEvalErrorString( QObject::tr( "Option can be 0 (distance) or 1 (projected)" ) );
3145 : 0 : return QVariant();
3146 : : }
3147 : 0 : const QgsPoint *point1 = qgsgeometry_cast< const QgsPoint *>( pt1.constGet() );
3148 : 0 : const QgsPoint *point2 = qgsgeometry_cast< const QgsPoint *>( pt2.constGet() );
3149 : 0 : const QgsPoint *point3 = qgsgeometry_cast< const QgsPoint *>( pt3.constGet() );
3150 : 0 : QgsQuadrilateral rect = QgsQuadrilateral::rectangleFrom3Points( *point1, *point2, *point3, option );
3151 : 0 : return QVariant::fromValue( QgsGeometry( rect.toPolygon() ) );
3152 : 0 : }
3153 : :
3154 : 0 : static QVariant pointAt( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent ) // helper function
3155 : : {
3156 : 0 : FEAT_FROM_CONTEXT( context, f )
3157 : 0 : int idx = QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent );
3158 : 0 : QgsGeometry g = f.geometry();
3159 : 0 : if ( g.isNull() )
3160 : 0 : return QVariant();
3161 : :
3162 : 0 : if ( idx < 0 )
3163 : : {
3164 : 0 : idx += g.constGet()->nCoordinates();
3165 : 0 : }
3166 : 0 : if ( idx < 0 || idx >= g.constGet()->nCoordinates() )
3167 : : {
3168 : 0 : parent->setEvalErrorString( QObject::tr( "Index is out of range" ) );
3169 : 0 : return QVariant();
3170 : : }
3171 : :
3172 : 0 : QgsPointXY p = g.vertexAt( idx );
3173 : 0 : return QVariant( QPointF( p.x(), p.y() ) );
3174 : 0 : }
3175 : :
3176 : 0 : static QVariant fcnXat( const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent, const QgsExpressionNodeFunction * )
3177 : : {
3178 : 0 : QVariant v = pointAt( values, f, parent );
3179 : 0 : if ( v.type() == QVariant::PointF )
3180 : 0 : return QVariant( v.toPointF().x() );
3181 : : else
3182 : 0 : return QVariant();
3183 : 0 : }
3184 : 0 : static QVariant fcnYat( const QVariantList &values, const QgsExpressionContext *f, QgsExpression *parent, const QgsExpressionNodeFunction * )
3185 : : {
3186 : 0 : QVariant v = pointAt( values, f, parent );
3187 : 0 : if ( v.type() == QVariant::PointF )
3188 : 0 : return QVariant( v.toPointF().y() );
3189 : : else
3190 : 0 : return QVariant();
3191 : 0 : }
3192 : 0 : static QVariant fcnGeometry( const QVariantList &, const QgsExpressionContext *context, QgsExpression *, const QgsExpressionNodeFunction * )
3193 : : {
3194 : 0 : FEAT_FROM_CONTEXT( context, f )
3195 : 0 : QgsGeometry geom = f.geometry();
3196 : 0 : if ( !geom.isNull() )
3197 : 0 : return QVariant::fromValue( geom );
3198 : : else
3199 : 0 : return QVariant();
3200 : 0 : }
3201 : :
3202 : 0 : static QVariant fcnGeomFromWKT( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3203 : : {
3204 : 0 : QString wkt = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
3205 : 0 : QgsGeometry geom = QgsGeometry::fromWkt( wkt );
3206 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3207 : 0 : return result;
3208 : 0 : }
3209 : :
3210 : 0 : static QVariant fcnGeomFromWKB( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3211 : : {
3212 : 0 : const QByteArray wkb = QgsExpressionUtils::getBinaryValue( values.at( 0 ), parent );
3213 : 0 : if ( wkb.isNull() )
3214 : 0 : return QVariant();
3215 : :
3216 : 0 : QgsGeometry geom;
3217 : 0 : geom.fromWkb( wkb );
3218 : 0 : return !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3219 : 0 : }
3220 : :
3221 : 0 : static QVariant fcnGeomFromGML( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3222 : : {
3223 : 0 : QString gml = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
3224 : 0 : QgsOgcUtils::Context ogcContext;
3225 : 0 : if ( context )
3226 : : {
3227 : 0 : QgsWeakMapLayerPointer mapLayerPtr {context->variable( QStringLiteral( "layer" ) ).value<QgsWeakMapLayerPointer>() };
3228 : 0 : if ( mapLayerPtr )
3229 : : {
3230 : 0 : ogcContext.layer = mapLayerPtr.data();
3231 : 0 : ogcContext.transformContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
3232 : 0 : }
3233 : 0 : }
3234 : 0 : QgsGeometry geom = QgsOgcUtils::geometryFromGML( gml, ogcContext );
3235 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3236 : 0 : return result;
3237 : 0 : }
3238 : :
3239 : 0 : static QVariant fcnGeomArea( const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3240 : : {
3241 : 0 : FEAT_FROM_CONTEXT( context, f )
3242 : 0 : ENSURE_GEOM_TYPE( f, g, QgsWkbTypes::PolygonGeometry )
3243 : 0 : QgsDistanceArea *calc = parent->geomCalculator();
3244 : 0 : if ( calc )
3245 : : {
3246 : 0 : double area = calc->measureArea( f.geometry() );
3247 : 0 : area = calc->convertAreaMeasurement( area, parent->areaUnits() );
3248 : 0 : return QVariant( area );
3249 : : }
3250 : : else
3251 : : {
3252 : 0 : return QVariant( f.geometry().area() );
3253 : : }
3254 : 0 : }
3255 : :
3256 : 0 : static QVariant fcnArea( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3257 : : {
3258 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3259 : :
3260 : 0 : if ( geom.type() != QgsWkbTypes::PolygonGeometry )
3261 : 0 : return QVariant();
3262 : :
3263 : 0 : return QVariant( geom.area() );
3264 : 0 : }
3265 : :
3266 : 0 : static QVariant fcnGeomLength( const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3267 : : {
3268 : 0 : FEAT_FROM_CONTEXT( context, f )
3269 : 0 : ENSURE_GEOM_TYPE( f, g, QgsWkbTypes::LineGeometry )
3270 : 0 : QgsDistanceArea *calc = parent->geomCalculator();
3271 : 0 : if ( calc )
3272 : : {
3273 : 0 : double len = calc->measureLength( f.geometry() );
3274 : 0 : len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
3275 : 0 : return QVariant( len );
3276 : : }
3277 : : else
3278 : : {
3279 : 0 : return QVariant( f.geometry().length() );
3280 : : }
3281 : 0 : }
3282 : :
3283 : 0 : static QVariant fcnGeomPerimeter( const QVariantList &, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
3284 : : {
3285 : 0 : FEAT_FROM_CONTEXT( context, f )
3286 : 0 : ENSURE_GEOM_TYPE( f, g, QgsWkbTypes::PolygonGeometry )
3287 : 0 : QgsDistanceArea *calc = parent->geomCalculator();
3288 : 0 : if ( calc )
3289 : : {
3290 : 0 : double len = calc->measurePerimeter( f.geometry() );
3291 : 0 : len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
3292 : 0 : return QVariant( len );
3293 : : }
3294 : : else
3295 : : {
3296 : 0 : return f.geometry().isNull() ? QVariant( 0 ) : QVariant( f.geometry().constGet()->perimeter() );
3297 : : }
3298 : 0 : }
3299 : :
3300 : 0 : static QVariant fcnPerimeter( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3301 : : {
3302 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3303 : :
3304 : 0 : if ( geom.type() != QgsWkbTypes::PolygonGeometry )
3305 : 0 : return QVariant();
3306 : :
3307 : : //length for polygons = perimeter
3308 : 0 : return QVariant( geom.length() );
3309 : 0 : }
3310 : :
3311 : 0 : static QVariant fcnGeomNumPoints( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3312 : : {
3313 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3314 : 0 : return QVariant( geom.isNull() ? 0 : geom.constGet()->nCoordinates() );
3315 : 0 : }
3316 : :
3317 : 0 : static QVariant fcnGeomNumGeometries( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3318 : : {
3319 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3320 : 0 : if ( geom.isNull() )
3321 : 0 : return QVariant();
3322 : :
3323 : 0 : return QVariant( geom.constGet()->partCount() );
3324 : 0 : }
3325 : :
3326 : 0 : static QVariant fcnGeomIsMultipart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3327 : : {
3328 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3329 : 0 : if ( geom.isNull() )
3330 : 0 : return QVariant();
3331 : :
3332 : 0 : return QVariant( geom.isMultipart() );
3333 : 0 : }
3334 : :
3335 : 0 : static QVariant fcnGeomNumInteriorRings( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3336 : : {
3337 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3338 : :
3339 : 0 : if ( geom.isNull() )
3340 : 0 : return QVariant();
3341 : :
3342 : 0 : const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
3343 : 0 : if ( curvePolygon )
3344 : 0 : return QVariant( curvePolygon->numInteriorRings() );
3345 : :
3346 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() );
3347 : 0 : if ( collection )
3348 : : {
3349 : : //find first CurvePolygon in collection
3350 : 0 : for ( int i = 0; i < collection->numGeometries(); ++i )
3351 : : {
3352 : 0 : curvePolygon = qgsgeometry_cast< const QgsCurvePolygon *>( collection->geometryN( i ) );
3353 : 0 : if ( !curvePolygon )
3354 : 0 : continue;
3355 : :
3356 : 0 : return QVariant( curvePolygon->isEmpty() ? 0 : curvePolygon->numInteriorRings() );
3357 : : }
3358 : 0 : }
3359 : :
3360 : 0 : return QVariant();
3361 : 0 : }
3362 : :
3363 : 0 : static QVariant fcnGeomNumRings( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3364 : : {
3365 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3366 : :
3367 : 0 : if ( geom.isNull() )
3368 : 0 : return QVariant();
3369 : :
3370 : 0 : const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( geom.constGet() );
3371 : 0 : if ( curvePolygon )
3372 : 0 : return QVariant( curvePolygon->ringCount() );
3373 : :
3374 : 0 : bool foundPoly = false;
3375 : 0 : int ringCount = 0;
3376 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() );
3377 : 0 : if ( collection )
3378 : : {
3379 : : //find CurvePolygons in collection
3380 : 0 : for ( int i = 0; i < collection->numGeometries(); ++i )
3381 : : {
3382 : 0 : curvePolygon = qgsgeometry_cast< QgsCurvePolygon *>( collection->geometryN( i ) );
3383 : 0 : if ( !curvePolygon )
3384 : 0 : continue;
3385 : :
3386 : 0 : foundPoly = true;
3387 : 0 : ringCount += curvePolygon->ringCount();
3388 : 0 : }
3389 : 0 : }
3390 : :
3391 : 0 : if ( !foundPoly )
3392 : 0 : return QVariant();
3393 : :
3394 : 0 : return QVariant( ringCount );
3395 : 0 : }
3396 : :
3397 : 0 : static QVariant fcnBounds( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3398 : : {
3399 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3400 : 0 : QgsGeometry geomBounds = QgsGeometry::fromRect( geom.boundingBox() );
3401 : 0 : QVariant result = !geomBounds.isNull() ? QVariant::fromValue( geomBounds ) : QVariant();
3402 : 0 : return result;
3403 : 0 : }
3404 : :
3405 : 0 : static QVariant fcnBoundsWidth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3406 : : {
3407 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3408 : 0 : return QVariant::fromValue( geom.boundingBox().width() );
3409 : 0 : }
3410 : :
3411 : 0 : static QVariant fcnBoundsHeight( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3412 : : {
3413 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3414 : 0 : return QVariant::fromValue( geom.boundingBox().height() );
3415 : 0 : }
3416 : :
3417 : 0 : static QVariant fcnXMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3418 : : {
3419 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3420 : 0 : return QVariant::fromValue( geom.boundingBox().xMinimum() );
3421 : 0 : }
3422 : :
3423 : 0 : static QVariant fcnXMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3424 : : {
3425 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3426 : 0 : return QVariant::fromValue( geom.boundingBox().xMaximum() );
3427 : 0 : }
3428 : :
3429 : 0 : static QVariant fcnYMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3430 : : {
3431 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3432 : 0 : return QVariant::fromValue( geom.boundingBox().yMinimum() );
3433 : 0 : }
3434 : :
3435 : 0 : static QVariant fcnYMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3436 : : {
3437 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3438 : 0 : return QVariant::fromValue( geom.boundingBox().yMaximum() );
3439 : 0 : }
3440 : :
3441 : 0 : static QVariant fcnZMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3442 : : {
3443 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3444 : :
3445 : 0 : if ( geom.isNull() || geom.isEmpty( ) )
3446 : 0 : return QVariant();
3447 : :
3448 : 0 : if ( !geom.constGet()->is3D() )
3449 : 0 : return QVariant();
3450 : :
3451 : 0 : double max = std::numeric_limits< double >::lowest();
3452 : :
3453 : 0 : for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3454 : : {
3455 : 0 : double z = ( *it ).z();
3456 : :
3457 : 0 : if ( max < z )
3458 : 0 : max = z;
3459 : 0 : }
3460 : :
3461 : 0 : if ( max == std::numeric_limits< double >::lowest() )
3462 : 0 : return QVariant( QVariant::Double );
3463 : :
3464 : 0 : return QVariant( max );
3465 : 0 : }
3466 : :
3467 : 0 : static QVariant fcnZMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3468 : : {
3469 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3470 : :
3471 : 0 : if ( geom.isNull() || geom.isEmpty() )
3472 : 0 : return QVariant();
3473 : :
3474 : 0 : if ( !geom.constGet()->is3D() )
3475 : 0 : return QVariant();
3476 : :
3477 : 0 : double min = std::numeric_limits< double >::max();
3478 : :
3479 : 0 : for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3480 : : {
3481 : 0 : double z = ( *it ).z();
3482 : :
3483 : 0 : if ( z < min )
3484 : 0 : min = z;
3485 : 0 : }
3486 : :
3487 : 0 : if ( min == std::numeric_limits< double >::max() )
3488 : 0 : return QVariant( QVariant::Double );
3489 : :
3490 : 0 : return QVariant( min );
3491 : 0 : }
3492 : :
3493 : 0 : static QVariant fcnMMin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3494 : : {
3495 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3496 : :
3497 : 0 : if ( geom.isNull() || geom.isEmpty() )
3498 : 0 : return QVariant();
3499 : :
3500 : 0 : if ( !geom.constGet()->isMeasure() )
3501 : 0 : return QVariant();
3502 : :
3503 : 0 : double min = std::numeric_limits< double >::max();
3504 : :
3505 : 0 : for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3506 : : {
3507 : 0 : double m = ( *it ).m();
3508 : :
3509 : 0 : if ( m < min )
3510 : 0 : min = m;
3511 : 0 : }
3512 : :
3513 : 0 : if ( min == std::numeric_limits< double >::max() )
3514 : 0 : return QVariant( QVariant::Double );
3515 : :
3516 : 0 : return QVariant( min );
3517 : 0 : }
3518 : :
3519 : 0 : static QVariant fcnMMax( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3520 : : {
3521 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3522 : :
3523 : 0 : if ( geom.isNull() || geom.isEmpty() )
3524 : 0 : return QVariant();
3525 : :
3526 : 0 : if ( !geom.constGet()->isMeasure() )
3527 : 0 : return QVariant();
3528 : :
3529 : 0 : double max = std::numeric_limits< double >::lowest();
3530 : :
3531 : 0 : for ( auto it = geom.vertices_begin(); it != geom.vertices_end(); ++it )
3532 : : {
3533 : 0 : double m = ( *it ).m();
3534 : :
3535 : 0 : if ( max < m )
3536 : 0 : max = m;
3537 : 0 : }
3538 : :
3539 : 0 : if ( max == std::numeric_limits< double >::lowest() )
3540 : 0 : return QVariant( QVariant::Double );
3541 : :
3542 : 0 : return QVariant( max );
3543 : 0 : }
3544 : :
3545 : 0 : static QVariant fcnFlipCoordinates( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3546 : : {
3547 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3548 : 0 : if ( geom.isNull() )
3549 : 0 : return QVariant();
3550 : :
3551 : 0 : std::unique_ptr< QgsAbstractGeometry > flipped( geom.constGet()->clone() );
3552 : 0 : flipped->swapXy();
3553 : 0 : return QVariant::fromValue( QgsGeometry( std::move( flipped ) ) );
3554 : 0 : }
3555 : :
3556 : 0 : static QVariant fcnIsClosed( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3557 : : {
3558 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3559 : 0 : if ( fGeom.isNull() )
3560 : 0 : return QVariant();
3561 : :
3562 : 0 : const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( fGeom.constGet() );
3563 : 0 : if ( !curve && fGeom.isMultipart() )
3564 : : {
3565 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
3566 : : {
3567 : 0 : if ( collection->numGeometries() == 1 )
3568 : : {
3569 : 0 : curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
3570 : 0 : }
3571 : 0 : }
3572 : 0 : }
3573 : :
3574 : 0 : if ( !curve )
3575 : 0 : return QVariant();
3576 : :
3577 : 0 : return QVariant::fromValue( curve->isClosed() );
3578 : 0 : }
3579 : :
3580 : 0 : static QVariant fcnCloseLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3581 : : {
3582 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3583 : :
3584 : 0 : if ( geom.isNull() )
3585 : 0 : return QVariant();
3586 : :
3587 : 0 : QVariant result;
3588 : 0 : if ( !geom.isMultipart() )
3589 : : {
3590 : 0 : const QgsLineString *line = qgsgeometry_cast<const QgsLineString * >( geom.constGet() );
3591 : :
3592 : 0 : if ( !line )
3593 : 0 : return QVariant();
3594 : :
3595 : 0 : std::unique_ptr< QgsLineString > closedLine( line->clone() );
3596 : 0 : closedLine->close();
3597 : :
3598 : 0 : result = QVariant::fromValue( QgsGeometry( std::move( closedLine ) ) );
3599 : 0 : }
3600 : : else
3601 : : {
3602 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( geom.constGet() );
3603 : :
3604 : 0 : std::unique_ptr< QgsGeometryCollection > closed( collection->createEmptyWithSameType() );
3605 : :
3606 : 0 : for ( int i = 0; i < collection->numGeometries(); ++i )
3607 : : {
3608 : 0 : if ( const QgsLineString *line = qgsgeometry_cast<const QgsLineString * >( collection->geometryN( i ) ) )
3609 : : {
3610 : 0 : std::unique_ptr< QgsLineString > closedLine( line->clone() );
3611 : 0 : closedLine->close();
3612 : :
3613 : 0 : closed->addGeometry( closedLine.release() );
3614 : 0 : }
3615 : 0 : }
3616 : 0 : result = QVariant::fromValue( QgsGeometry( std::move( closed ) ) );
3617 : 0 : }
3618 : :
3619 : 0 : return result;
3620 : 0 : }
3621 : :
3622 : 0 : static QVariant fcnIsEmpty( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3623 : : {
3624 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3625 : 0 : if ( fGeom.isNull() )
3626 : 0 : return QVariant();
3627 : :
3628 : 0 : return QVariant::fromValue( fGeom.isEmpty() );
3629 : 0 : }
3630 : :
3631 : 0 : static QVariant fcnIsEmptyOrNull( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3632 : : {
3633 : 0 : if ( values.at( 0 ).isNull() )
3634 : 0 : return QVariant::fromValue( true );
3635 : :
3636 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3637 : 0 : return QVariant::fromValue( fGeom.isNull() || fGeom.isEmpty() );
3638 : 0 : }
3639 : :
3640 : 0 : static QVariant fcnRelate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3641 : : {
3642 : 0 : if ( values.length() < 2 || values.length() > 3 )
3643 : 0 : return QVariant();
3644 : :
3645 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3646 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3647 : :
3648 : 0 : if ( fGeom.isNull() || sGeom.isNull() )
3649 : 0 : return QVariant();
3650 : :
3651 : 0 : std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( fGeom.constGet() ) );
3652 : :
3653 : 0 : if ( values.length() == 2 )
3654 : : {
3655 : : //two geometry arguments, return relation
3656 : 0 : QString result = engine->relate( sGeom.constGet() );
3657 : 0 : return QVariant::fromValue( result );
3658 : 0 : }
3659 : : else
3660 : : {
3661 : : //three arguments, test pattern
3662 : 0 : QString pattern = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
3663 : 0 : bool result = engine->relatePattern( sGeom.constGet(), pattern );
3664 : 0 : return QVariant::fromValue( result );
3665 : 0 : }
3666 : 0 : }
3667 : :
3668 : 0 : static QVariant fcnBbox( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3669 : : {
3670 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3671 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3672 : 0 : return fGeom.intersects( sGeom.boundingBox() ) ? TVL_True : TVL_False;
3673 : 0 : }
3674 : 0 : static QVariant fcnDisjoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3675 : : {
3676 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3677 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3678 : 0 : return fGeom.disjoint( sGeom ) ? TVL_True : TVL_False;
3679 : 0 : }
3680 : 0 : static QVariant fcnIntersects( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3681 : : {
3682 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3683 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3684 : 0 : return fGeom.intersects( sGeom ) ? TVL_True : TVL_False;
3685 : 0 : }
3686 : 0 : static QVariant fcnTouches( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3687 : : {
3688 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3689 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3690 : 0 : return fGeom.touches( sGeom ) ? TVL_True : TVL_False;
3691 : 0 : }
3692 : 0 : static QVariant fcnCrosses( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3693 : : {
3694 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3695 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3696 : 0 : return fGeom.crosses( sGeom ) ? TVL_True : TVL_False;
3697 : 0 : }
3698 : 0 : static QVariant fcnContains( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3699 : : {
3700 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3701 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3702 : 0 : return fGeom.contains( sGeom ) ? TVL_True : TVL_False;
3703 : 0 : }
3704 : 0 : static QVariant fcnOverlaps( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3705 : : {
3706 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3707 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3708 : 0 : return fGeom.overlaps( sGeom ) ? TVL_True : TVL_False;
3709 : 0 : }
3710 : 0 : static QVariant fcnWithin( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3711 : : {
3712 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3713 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3714 : 0 : return fGeom.within( sGeom ) ? TVL_True : TVL_False;
3715 : 0 : }
3716 : 0 : static QVariant fcnBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3717 : : {
3718 : 0 : if ( values.length() < 2 || values.length() > 3 )
3719 : 0 : return QVariant();
3720 : :
3721 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3722 : 0 : double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3723 : 0 : int seg = 8;
3724 : 0 : if ( values.length() == 3 )
3725 : 0 : seg = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
3726 : :
3727 : 0 : QgsGeometry geom = fGeom.buffer( dist, seg );
3728 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3729 : 0 : return result;
3730 : 0 : }
3731 : :
3732 : 0 : static QVariant fcnForceRHR( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3733 : : {
3734 : 0 : const QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3735 : 0 : const QgsGeometry reoriented = fGeom.forceRHR();
3736 : 0 : return !reoriented.isNull() ? QVariant::fromValue( reoriented ) : QVariant();
3737 : 0 : }
3738 : :
3739 : 0 : static QVariant fcnWedgeBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3740 : : {
3741 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3742 : 0 : const QgsPoint *pt = qgsgeometry_cast<const QgsPoint *>( fGeom.constGet() );
3743 : 0 : if ( !pt && fGeom.isMultipart() )
3744 : : {
3745 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
3746 : : {
3747 : 0 : if ( collection->numGeometries() == 1 )
3748 : : {
3749 : 0 : pt = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
3750 : 0 : }
3751 : 0 : }
3752 : 0 : }
3753 : :
3754 : 0 : if ( !pt )
3755 : : {
3756 : 0 : parent->setEvalErrorString( QObject::tr( "Function `wedge_buffer` requires a point value for the center." ) );
3757 : 0 : return QVariant();
3758 : : }
3759 : :
3760 : 0 : double azimuth = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3761 : 0 : double width = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3762 : 0 : double outerRadius = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3763 : 0 : double innerRadius = QgsExpressionUtils::getDoubleValue( values.at( 4 ), parent );
3764 : :
3765 : 0 : QgsGeometry geom = QgsGeometry::createWedgeBuffer( *pt, azimuth, width, outerRadius, innerRadius );
3766 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3767 : 0 : return result;
3768 : 0 : }
3769 : :
3770 : 0 : static QVariant fcnTaperedBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3771 : : {
3772 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3773 : 0 : if ( fGeom.type() != QgsWkbTypes::LineGeometry )
3774 : : {
3775 : 0 : parent->setEvalErrorString( QObject::tr( "Function `tapered_buffer` requires a line geometry." ) );
3776 : 0 : return QVariant();
3777 : : }
3778 : :
3779 : 0 : double startWidth = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3780 : 0 : double endWidth = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3781 : 0 : int segments = static_cast< int >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3782 : :
3783 : 0 : QgsGeometry geom = fGeom.taperedBuffer( startWidth, endWidth, segments );
3784 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3785 : 0 : return result;
3786 : 0 : }
3787 : :
3788 : 0 : static QVariant fcnBufferByM( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3789 : : {
3790 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3791 : 0 : if ( fGeom.type() != QgsWkbTypes::LineGeometry )
3792 : : {
3793 : 0 : parent->setEvalErrorString( QObject::tr( "Function `buffer_by_m` requires a line geometry." ) );
3794 : 0 : return QVariant();
3795 : : }
3796 : :
3797 : 0 : int segments = static_cast< int >( QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) );
3798 : :
3799 : 0 : QgsGeometry geom = fGeom.variableWidthBufferByM( segments );
3800 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3801 : 0 : return result;
3802 : 0 : }
3803 : :
3804 : 0 : static QVariant fcnOffsetCurve( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3805 : : {
3806 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3807 : 0 : double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3808 : 0 : int segments = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
3809 : 0 : QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3810 : 0 : if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
3811 : 0 : return QVariant();
3812 : 0 : double miterLimit = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3813 : :
3814 : 0 : QgsGeometry geom = fGeom.offsetCurve( dist, segments, join, miterLimit );
3815 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3816 : 0 : return result;
3817 : 0 : }
3818 : :
3819 : 0 : static QVariant fcnSingleSidedBuffer( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3820 : : {
3821 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3822 : 0 : double dist = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3823 : 0 : int segments = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
3824 : 0 : QgsGeometry::JoinStyle join = static_cast< QgsGeometry::JoinStyle >( QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) );
3825 : 0 : if ( join < QgsGeometry::JoinStyleRound || join > QgsGeometry::JoinStyleBevel )
3826 : 0 : return QVariant();
3827 : 0 : double miterLimit = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
3828 : :
3829 : 0 : QgsGeometry geom = fGeom.singleSidedBuffer( dist, segments, QgsGeometry::SideLeft, join, miterLimit );
3830 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3831 : 0 : return result;
3832 : 0 : }
3833 : :
3834 : 0 : static QVariant fcnExtend( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3835 : : {
3836 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3837 : 0 : double distStart = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3838 : 0 : double distEnd = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3839 : :
3840 : 0 : QgsGeometry geom = fGeom.extendLine( distStart, distEnd );
3841 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3842 : 0 : return result;
3843 : 0 : }
3844 : :
3845 : 0 : static QVariant fcnTranslate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3846 : : {
3847 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3848 : 0 : double dx = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3849 : 0 : double dy = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
3850 : 0 : fGeom.translate( dx, dy );
3851 : 0 : return QVariant::fromValue( fGeom );
3852 : 0 : }
3853 : :
3854 : 0 : static QVariant fcnRotate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3855 : : {
3856 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3857 : 0 : const double rotation = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3858 : 0 : const QgsGeometry center = values.at( 2 ).isValid() ? QgsExpressionUtils::getGeometry( values.at( 2 ), parent )
3859 : 0 : : QgsGeometry();
3860 : :
3861 : 0 : QgsPointXY pt;
3862 : 0 : if ( center.isNull() )
3863 : : {
3864 : : // if center wasn't specified, use bounding box centroid
3865 : 0 : pt = fGeom.boundingBox().center();
3866 : 0 : }
3867 : 0 : else if ( center.type() != QgsWkbTypes::PointGeometry )
3868 : : {
3869 : 0 : parent->setEvalErrorString( QObject::tr( "Function 'rotate' requires a point value for the center" ) );
3870 : 0 : return QVariant();
3871 : : }
3872 : 0 : else if ( center.isMultipart() )
3873 : : {
3874 : 0 : QgsMultiPointXY multiPoint = center.asMultiPoint();
3875 : 0 : if ( multiPoint.count() == 1 )
3876 : : {
3877 : 0 : pt = multiPoint[0];
3878 : 0 : }
3879 : : else
3880 : : {
3881 : 0 : parent->setEvalErrorString( QObject::tr( "Function 'rotate' requires a point value for the center" ) );
3882 : 0 : return QVariant();
3883 : : }
3884 : 0 : }
3885 : : else
3886 : : {
3887 : 0 : pt = center.asPoint();
3888 : : }
3889 : :
3890 : 0 : fGeom.rotate( rotation, pt );
3891 : 0 : return QVariant::fromValue( fGeom );
3892 : 0 : }
3893 : :
3894 : 0 : static QVariant fcnCentroid( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3895 : : {
3896 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3897 : 0 : QgsGeometry geom = fGeom.centroid();
3898 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3899 : 0 : return result;
3900 : 0 : }
3901 : 0 : static QVariant fcnPointOnSurface( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3902 : : {
3903 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3904 : 0 : QgsGeometry geom = fGeom.pointOnSurface();
3905 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3906 : 0 : return result;
3907 : 0 : }
3908 : :
3909 : 0 : static QVariant fcnPoleOfInaccessibility( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3910 : : {
3911 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3912 : 0 : double tolerance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
3913 : 0 : QgsGeometry geom = fGeom.poleOfInaccessibility( tolerance );
3914 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3915 : 0 : return result;
3916 : 0 : }
3917 : :
3918 : 0 : static QVariant fcnConvexHull( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3919 : : {
3920 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3921 : 0 : QgsGeometry geom = fGeom.convexHull();
3922 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3923 : 0 : return result;
3924 : 0 : }
3925 : :
3926 : :
3927 : 0 : static QVariant fcnMinimalCircle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3928 : : {
3929 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3930 : 0 : int segments = 36;
3931 : 0 : if ( values.length() == 2 )
3932 : 0 : segments = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
3933 : 0 : if ( segments < 0 )
3934 : : {
3935 : 0 : parent->setEvalErrorString( QObject::tr( "Parameter can not be negative." ) );
3936 : 0 : return QVariant();
3937 : : }
3938 : :
3939 : 0 : QgsGeometry geom = fGeom.minimalEnclosingCircle( static_cast<unsigned int>( segments ) );
3940 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3941 : 0 : return result;
3942 : 0 : }
3943 : :
3944 : 0 : static QVariant fcnOrientedBBox( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3945 : : {
3946 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3947 : 0 : QgsGeometry geom = fGeom.orientedMinimumBoundingBox( );
3948 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3949 : 0 : return result;
3950 : 0 : }
3951 : :
3952 : 0 : static QVariant fcnMainAngle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3953 : : {
3954 : 0 : const QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3955 : :
3956 : : // we use the angle of the oriented minimum bounding box to calculate the polygon main angle.
3957 : : // While ArcGIS uses a different approach ("the angle of longest collection of segments that have similar orientation"), this
3958 : : // yields similar results to OMBB approach under the same constraints ("this tool is meant for primarily orthogonal polygons rather than organically shaped ones.")
3959 : :
3960 : : double area, angle, width, height;
3961 : 0 : const QgsGeometry geom = fGeom.orientedMinimumBoundingBox( area, angle, width, height );
3962 : :
3963 : 0 : if ( geom.isNull() )
3964 : : {
3965 : 0 : parent->setEvalErrorString( QObject::tr( "Error calculating polygon main angle: %1" ).arg( geom.lastError() ) );
3966 : 0 : return QVariant();
3967 : : }
3968 : 0 : return angle;
3969 : 0 : }
3970 : :
3971 : 0 : static QVariant fcnDifference( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3972 : : {
3973 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3974 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
3975 : 0 : QgsGeometry geom = fGeom.difference( sGeom );
3976 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
3977 : 0 : return result;
3978 : 0 : }
3979 : :
3980 : 0 : static QVariant fcnReverse( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
3981 : : {
3982 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
3983 : 0 : if ( fGeom.isNull() )
3984 : 0 : return QVariant();
3985 : :
3986 : 0 : QVariant result;
3987 : 0 : if ( !fGeom.isMultipart() )
3988 : : {
3989 : 0 : const QgsCurve *curve = qgsgeometry_cast<const QgsCurve * >( fGeom.constGet() );
3990 : 0 : if ( !curve )
3991 : 0 : return QVariant();
3992 : :
3993 : 0 : QgsCurve *reversed = curve->reversed();
3994 : 0 : result = reversed ? QVariant::fromValue( QgsGeometry( reversed ) ) : QVariant();
3995 : 0 : }
3996 : : else
3997 : : {
3998 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection *>( fGeom.constGet() );
3999 : 0 : std::unique_ptr< QgsGeometryCollection > reversed( collection->createEmptyWithSameType() );
4000 : 0 : for ( int i = 0; i < collection->numGeometries(); ++i )
4001 : : {
4002 : 0 : if ( const QgsCurve *curve = qgsgeometry_cast<const QgsCurve * >( collection->geometryN( i ) ) )
4003 : : {
4004 : 0 : reversed->addGeometry( curve->reversed() );
4005 : 0 : }
4006 : : else
4007 : : {
4008 : 0 : reversed->addGeometry( collection->geometryN( i )->clone() );
4009 : : }
4010 : 0 : }
4011 : 0 : result = reversed ? QVariant::fromValue( QgsGeometry( std::move( reversed ) ) ) : QVariant();
4012 : 0 : }
4013 : 0 : return result;
4014 : 0 : }
4015 : :
4016 : 0 : static QVariant fcnExteriorRing( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4017 : : {
4018 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4019 : 0 : if ( fGeom.isNull() )
4020 : 0 : return QVariant();
4021 : :
4022 : 0 : const QgsCurvePolygon *curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( fGeom.constGet() );
4023 : 0 : if ( !curvePolygon && fGeom.isMultipart() )
4024 : : {
4025 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom.constGet() ) )
4026 : : {
4027 : 0 : if ( collection->numGeometries() == 1 )
4028 : : {
4029 : 0 : curvePolygon = qgsgeometry_cast< const QgsCurvePolygon * >( collection->geometryN( 0 ) );
4030 : 0 : }
4031 : 0 : }
4032 : 0 : }
4033 : :
4034 : 0 : if ( !curvePolygon || !curvePolygon->exteriorRing() )
4035 : 0 : return QVariant();
4036 : :
4037 : 0 : QgsCurve *exterior = static_cast< QgsCurve * >( curvePolygon->exteriorRing()->clone() );
4038 : 0 : QVariant result = exterior ? QVariant::fromValue( QgsGeometry( exterior ) ) : QVariant();
4039 : 0 : return result;
4040 : 0 : }
4041 : :
4042 : 0 : static QVariant fcnDistance( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4043 : : {
4044 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4045 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4046 : 0 : return QVariant( fGeom.distance( sGeom ) );
4047 : 0 : }
4048 : :
4049 : 0 : static QVariant fcnHausdorffDistance( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4050 : : {
4051 : 0 : QgsGeometry g1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4052 : 0 : QgsGeometry g2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4053 : :
4054 : 0 : double res = -1;
4055 : 0 : if ( values.length() == 3 && values.at( 2 ).isValid() )
4056 : : {
4057 : 0 : double densify = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4058 : 0 : densify = std::clamp( densify, 0.0, 1.0 );
4059 : 0 : res = g1.hausdorffDistanceDensify( g2, densify );
4060 : 0 : }
4061 : : else
4062 : : {
4063 : 0 : res = g1.hausdorffDistance( g2 );
4064 : : }
4065 : :
4066 : 0 : return res > -1 ? QVariant( res ) : QVariant();
4067 : 0 : }
4068 : :
4069 : 0 : static QVariant fcnIntersection( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4070 : : {
4071 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4072 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4073 : 0 : QgsGeometry geom = fGeom.intersection( sGeom );
4074 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4075 : 0 : return result;
4076 : 0 : }
4077 : 0 : static QVariant fcnSymDifference( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4078 : : {
4079 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4080 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4081 : 0 : QgsGeometry geom = fGeom.symDifference( sGeom );
4082 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4083 : 0 : return result;
4084 : 0 : }
4085 : 0 : static QVariant fcnCombine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4086 : : {
4087 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4088 : 0 : QgsGeometry sGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4089 : 0 : QgsGeometry geom = fGeom.combine( sGeom );
4090 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4091 : 0 : return result;
4092 : 0 : }
4093 : :
4094 : 0 : static QVariant fcnGeomToWKT( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4095 : : {
4096 : 0 : if ( values.length() < 1 || values.length() > 2 )
4097 : 0 : return QVariant();
4098 : :
4099 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4100 : 0 : int prec = 8;
4101 : 0 : if ( values.length() == 2 )
4102 : 0 : prec = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4103 : 0 : QString wkt = fGeom.asWkt( prec );
4104 : 0 : return QVariant( wkt );
4105 : 0 : }
4106 : :
4107 : 0 : static QVariant fcnGeomToWKB( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4108 : : {
4109 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4110 : 0 : return fGeom.isNull() ? QVariant() : QVariant( fGeom.asWkb() );
4111 : 0 : }
4112 : :
4113 : 0 : static QVariant fcnAzimuth( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4114 : : {
4115 : 0 : if ( values.length() != 2 )
4116 : : {
4117 : 0 : parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires exactly two parameters. %1 given." ).arg( values.length() ) );
4118 : 0 : return QVariant();
4119 : : }
4120 : :
4121 : 0 : QgsGeometry fGeom1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4122 : 0 : QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4123 : :
4124 : 0 : const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
4125 : 0 : if ( !pt1 && fGeom1.isMultipart() )
4126 : : {
4127 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
4128 : : {
4129 : 0 : if ( collection->numGeometries() == 1 )
4130 : : {
4131 : 0 : pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4132 : 0 : }
4133 : 0 : }
4134 : 0 : }
4135 : :
4136 : 0 : const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
4137 : 0 : if ( !pt2 && fGeom2.isMultipart() )
4138 : : {
4139 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
4140 : : {
4141 : 0 : if ( collection->numGeometries() == 1 )
4142 : : {
4143 : 0 : pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4144 : 0 : }
4145 : 0 : }
4146 : 0 : }
4147 : :
4148 : 0 : if ( !pt1 || !pt2 )
4149 : : {
4150 : 0 : parent->setEvalErrorString( QObject::tr( "Function `azimuth` requires two points as arguments." ) );
4151 : 0 : return QVariant();
4152 : : }
4153 : :
4154 : : // Code from PostGIS
4155 : 0 : if ( qgsDoubleNear( pt1->x(), pt2->x() ) )
4156 : : {
4157 : 0 : if ( pt1->y() < pt2->y() )
4158 : 0 : return 0.0;
4159 : 0 : else if ( pt1->y() > pt2->y() )
4160 : 0 : return M_PI;
4161 : : else
4162 : 0 : return 0;
4163 : : }
4164 : :
4165 : 0 : if ( qgsDoubleNear( pt1->y(), pt2->y() ) )
4166 : : {
4167 : 0 : if ( pt1->x() < pt2->x() )
4168 : 0 : return M_PI_2;
4169 : 0 : else if ( pt1->x() > pt2->x() )
4170 : 0 : return M_PI + ( M_PI_2 );
4171 : : else
4172 : 0 : return 0;
4173 : : }
4174 : :
4175 : 0 : if ( pt1->x() < pt2->x() )
4176 : : {
4177 : 0 : if ( pt1->y() < pt2->y() )
4178 : : {
4179 : 0 : return std::atan( std::fabs( pt1->x() - pt2->x() ) / std::fabs( pt1->y() - pt2->y() ) );
4180 : : }
4181 : : else /* ( pt1->y() > pt2->y() ) - equality case handled above */
4182 : : {
4183 : 0 : return std::atan( std::fabs( pt1->y() - pt2->y() ) / std::fabs( pt1->x() - pt2->x() ) )
4184 : 0 : + ( M_PI_2 );
4185 : : }
4186 : : }
4187 : :
4188 : : else /* ( pt1->x() > pt2->x() ) - equality case handled above */
4189 : : {
4190 : 0 : if ( pt1->y() > pt2->y() )
4191 : : {
4192 : 0 : return std::atan( std::fabs( pt1->x() - pt2->x() ) / std::fabs( pt1->y() - pt2->y() ) )
4193 : 0 : + M_PI;
4194 : : }
4195 : : else /* ( pt1->y() < pt2->y() ) - equality case handled above */
4196 : : {
4197 : 0 : return std::atan( std::fabs( pt1->y() - pt2->y() ) / std::fabs( pt1->x() - pt2->x() ) )
4198 : 0 : + ( M_PI + ( M_PI_2 ) );
4199 : : }
4200 : : }
4201 : 0 : }
4202 : :
4203 : 0 : static QVariant fcnProject( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4204 : : {
4205 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4206 : :
4207 : 0 : if ( geom.type() != QgsWkbTypes::PointGeometry )
4208 : : {
4209 : 0 : parent->setEvalErrorString( QStringLiteral( "'project' requires a point geometry" ) );
4210 : 0 : return QVariant();
4211 : : }
4212 : :
4213 : 0 : double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4214 : 0 : double azimuth = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4215 : 0 : double inclination = QgsExpressionUtils::getDoubleValue( values.at( 3 ), parent );
4216 : :
4217 : 0 : const QgsPoint *p = static_cast<const QgsPoint *>( geom.constGet() );
4218 : 0 : QgsPoint newPoint = p->project( distance, 180.0 * azimuth / M_PI, 180.0 * inclination / M_PI );
4219 : :
4220 : 0 : return QVariant::fromValue( QgsGeometry( new QgsPoint( newPoint ) ) );
4221 : 0 : }
4222 : :
4223 : 0 : static QVariant fcnInclination( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4224 : : {
4225 : 0 : QgsGeometry fGeom1 = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4226 : 0 : QgsGeometry fGeom2 = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4227 : :
4228 : 0 : const QgsPoint *pt1 = qgsgeometry_cast<const QgsPoint *>( fGeom1.constGet() );
4229 : 0 : if ( !pt1 && fGeom1.isMultipart() )
4230 : : {
4231 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom1.constGet() ) )
4232 : : {
4233 : 0 : if ( collection->numGeometries() == 1 )
4234 : : {
4235 : 0 : pt1 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4236 : 0 : }
4237 : 0 : }
4238 : 0 : }
4239 : 0 : const QgsPoint *pt2 = qgsgeometry_cast<const QgsPoint *>( fGeom2.constGet() );
4240 : 0 : if ( !pt2 && fGeom2.isMultipart() )
4241 : : {
4242 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( fGeom2.constGet() ) )
4243 : : {
4244 : 0 : if ( collection->numGeometries() == 1 )
4245 : : {
4246 : 0 : pt2 = qgsgeometry_cast< const QgsPoint * >( collection->geometryN( 0 ) );
4247 : 0 : }
4248 : 0 : }
4249 : 0 : }
4250 : :
4251 : 0 : if ( ( fGeom1.type() != QgsWkbTypes::PointGeometry ) || ( fGeom2.type() != QgsWkbTypes::PointGeometry ) ||
4252 : 0 : !pt1 || !pt2 )
4253 : : {
4254 : 0 : parent->setEvalErrorString( QStringLiteral( "Function 'inclination' requires two points as arguments." ) );
4255 : 0 : return QVariant();
4256 : : }
4257 : :
4258 : 0 : return pt1->inclination( *pt2 );
4259 : :
4260 : 0 : }
4261 : :
4262 : 0 : static QVariant fcnExtrude( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4263 : : {
4264 : 0 : if ( values.length() != 3 )
4265 : 0 : return QVariant();
4266 : :
4267 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4268 : 0 : double x = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4269 : 0 : double y = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4270 : :
4271 : 0 : QgsGeometry geom = fGeom.extrude( x, y );
4272 : :
4273 : 0 : QVariant result = geom.constGet() ? QVariant::fromValue( geom ) : QVariant();
4274 : 0 : return result;
4275 : 0 : }
4276 : :
4277 : 0 : static QVariant fcnOrderParts( const QVariantList &values, const QgsExpressionContext *ctx, QgsExpression *parent, const QgsExpressionNodeFunction * )
4278 : : {
4279 : 0 : if ( values.length() < 2 )
4280 : 0 : return QVariant();
4281 : :
4282 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4283 : :
4284 : 0 : if ( !fGeom.isMultipart() )
4285 : 0 : return values.at( 0 );
4286 : :
4287 : 0 : QString expString = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4288 : 0 : QVariant cachedExpression;
4289 : 0 : if ( ctx )
4290 : 0 : cachedExpression = ctx->cachedValue( expString );
4291 : 0 : QgsExpression expression;
4292 : :
4293 : 0 : if ( cachedExpression.isValid() )
4294 : : {
4295 : 0 : expression = cachedExpression.value<QgsExpression>();
4296 : 0 : }
4297 : : else
4298 : 0 : expression = QgsExpression( expString );
4299 : :
4300 : 0 : bool asc = values.value( 2 ).toBool();
4301 : :
4302 : 0 : QgsExpressionContext *unconstedContext = nullptr;
4303 : 0 : QgsFeature f;
4304 : 0 : if ( ctx )
4305 : : {
4306 : : // ExpressionSorter wants a modifiable expression context, but it will return it in the same shape after
4307 : : // so no reason to worry
4308 : 0 : unconstedContext = const_cast<QgsExpressionContext *>( ctx );
4309 : 0 : f = ctx->feature();
4310 : 0 : }
4311 : : else
4312 : : {
4313 : : // If there's no context provided, create a fake one
4314 : 0 : unconstedContext = new QgsExpressionContext();
4315 : : }
4316 : :
4317 : 0 : const QgsGeometryCollection *collection = qgsgeometry_cast<const QgsGeometryCollection *>( fGeom.constGet() );
4318 : : Q_ASSERT( collection ); // Should have failed the multipart check above
4319 : :
4320 : 0 : QgsFeatureRequest::OrderBy orderBy;
4321 : 0 : orderBy.append( QgsFeatureRequest::OrderByClause( expression, asc ) );
4322 : 0 : QgsExpressionSorter sorter( orderBy );
4323 : :
4324 : 0 : QList<QgsFeature> partFeatures;
4325 : 0 : partFeatures.reserve( collection->partCount() );
4326 : 0 : for ( int i = 0; i < collection->partCount(); ++i )
4327 : : {
4328 : 0 : f.setGeometry( QgsGeometry( collection->geometryN( i )->clone() ) );
4329 : 0 : partFeatures << f;
4330 : 0 : }
4331 : :
4332 : 0 : sorter.sortFeatures( partFeatures, unconstedContext );
4333 : :
4334 : 0 : QgsGeometryCollection *orderedGeom = qgsgeometry_cast<QgsGeometryCollection *>( fGeom.constGet()->clone() );
4335 : :
4336 : : Q_ASSERT( orderedGeom );
4337 : :
4338 : 0 : while ( orderedGeom->partCount() )
4339 : 0 : orderedGeom->removeGeometry( 0 );
4340 : :
4341 : 0 : for ( const QgsFeature &feature : std::as_const( partFeatures ) )
4342 : : {
4343 : 0 : orderedGeom->addGeometry( feature.geometry().constGet()->clone() );
4344 : : }
4345 : :
4346 : 0 : QVariant result = QVariant::fromValue( QgsGeometry( orderedGeom ) );
4347 : :
4348 : 0 : if ( !ctx )
4349 : 0 : delete unconstedContext;
4350 : :
4351 : 0 : return result;
4352 : 0 : }
4353 : :
4354 : 0 : static QVariant fcnClosestPoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4355 : : {
4356 : 0 : QgsGeometry fromGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4357 : 0 : QgsGeometry toGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4358 : :
4359 : 0 : QgsGeometry geom = fromGeom.nearestPoint( toGeom );
4360 : :
4361 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4362 : 0 : return result;
4363 : 0 : }
4364 : :
4365 : 0 : static QVariant fcnShortestLine( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4366 : : {
4367 : 0 : QgsGeometry fromGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4368 : 0 : QgsGeometry toGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4369 : :
4370 : 0 : QgsGeometry geom = fromGeom.shortestLine( toGeom );
4371 : :
4372 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4373 : 0 : return result;
4374 : 0 : }
4375 : :
4376 : 0 : static QVariant fcnLineInterpolatePoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4377 : : {
4378 : 0 : QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4379 : 0 : double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4380 : :
4381 : 0 : QgsGeometry geom = lineGeom.interpolate( distance );
4382 : :
4383 : 0 : QVariant result = !geom.isNull() ? QVariant::fromValue( geom ) : QVariant();
4384 : 0 : return result;
4385 : 0 : }
4386 : :
4387 : 0 : static QVariant fcnLineSubset( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4388 : : {
4389 : 0 : QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4390 : 0 : if ( lineGeom.type() != QgsWkbTypes::LineGeometry )
4391 : : {
4392 : 0 : parent->setEvalErrorString( QObject::tr( "line_substring requires a curve geometry input" ) );
4393 : 0 : return QVariant();
4394 : : }
4395 : :
4396 : 0 : const QgsCurve *curve = nullptr;
4397 : 0 : if ( !lineGeom.isMultipart() )
4398 : 0 : curve = qgsgeometry_cast< const QgsCurve * >( lineGeom.constGet() );
4399 : : else
4400 : : {
4401 : 0 : if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( lineGeom.constGet() ) )
4402 : : {
4403 : 0 : if ( collection->numGeometries() > 0 )
4404 : : {
4405 : 0 : curve = qgsgeometry_cast< const QgsCurve * >( collection->geometryN( 0 ) );
4406 : 0 : }
4407 : 0 : }
4408 : : }
4409 : 0 : if ( !curve )
4410 : 0 : return QVariant();
4411 : :
4412 : 0 : double startDistance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4413 : 0 : double endDistance = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4414 : :
4415 : 0 : std::unique_ptr< QgsCurve > substring( curve->curveSubstring( startDistance, endDistance ) );
4416 : 0 : QgsGeometry result( std::move( substring ) );
4417 : 0 : return !result.isNull() ? QVariant::fromValue( result ) : QVariant();
4418 : 0 : }
4419 : :
4420 : 0 : static QVariant fcnLineInterpolateAngle( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4421 : : {
4422 : 0 : QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4423 : 0 : double distance = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4424 : :
4425 : 0 : return lineGeom.interpolateAngle( distance ) * 180.0 / M_PI;
4426 : 0 : }
4427 : :
4428 : 0 : static QVariant fcnAngleAtVertex( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4429 : : {
4430 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4431 : 0 : int vertex = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4432 : 0 : if ( vertex < 0 )
4433 : : {
4434 : : //negative idx
4435 : 0 : int count = geom.constGet()->nCoordinates();
4436 : 0 : vertex = count + vertex;
4437 : 0 : }
4438 : :
4439 : 0 : return geom.angleAtVertex( vertex ) * 180.0 / M_PI;
4440 : 0 : }
4441 : :
4442 : 0 : static QVariant fcnDistanceToVertex( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4443 : : {
4444 : 0 : QgsGeometry geom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4445 : 0 : int vertex = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4446 : 0 : if ( vertex < 0 )
4447 : : {
4448 : : //negative idx
4449 : 0 : int count = geom.constGet()->nCoordinates();
4450 : 0 : vertex = count + vertex;
4451 : 0 : }
4452 : :
4453 : 0 : return geom.distanceToVertex( vertex );
4454 : 0 : }
4455 : :
4456 : 0 : static QVariant fcnLineLocatePoint( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4457 : : {
4458 : 0 : QgsGeometry lineGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4459 : 0 : QgsGeometry pointGeom = QgsExpressionUtils::getGeometry( values.at( 1 ), parent );
4460 : :
4461 : 0 : double distance = lineGeom.lineLocatePoint( pointGeom );
4462 : :
4463 : 0 : return distance >= 0 ? distance : QVariant();
4464 : 0 : }
4465 : :
4466 : 0 : static QVariant fcnRound( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4467 : : {
4468 : 0 : if ( values.length() == 2 && values.at( 1 ).toInt() != 0 )
4469 : : {
4470 : 0 : double number = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
4471 : 0 : return qgsRound( number, QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
4472 : : }
4473 : :
4474 : 0 : if ( values.length() >= 1 )
4475 : : {
4476 : 0 : double number = QgsExpressionUtils::getIntValue( values.at( 0 ), parent );
4477 : 0 : return QVariant( qlonglong( std::round( number ) ) );
4478 : : }
4479 : :
4480 : 0 : return QVariant();
4481 : 0 : }
4482 : :
4483 : 0 : static QVariant fcnPi( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4484 : : {
4485 : 0 : Q_UNUSED( values )
4486 : : Q_UNUSED( parent )
4487 : 0 : return M_PI;
4488 : : }
4489 : :
4490 : 0 : static QVariant fcnFormatNumber( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4491 : : {
4492 : 0 : const double value = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
4493 : 0 : const int places = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4494 : 0 : const QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
4495 : 0 : if ( places < 0 )
4496 : : {
4497 : 0 : parent->setEvalErrorString( QObject::tr( "Number of places must be positive" ) );
4498 : 0 : return QVariant();
4499 : : }
4500 : :
4501 : 0 : QLocale locale = !language.isEmpty() ? QLocale( language ) : QLocale();
4502 : 0 : locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
4503 : 0 : return locale.toString( value, 'f', places );
4504 : 0 : }
4505 : :
4506 : 0 : static QVariant fcnFormatDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4507 : : {
4508 : 0 : const QDateTime datetime = QgsExpressionUtils::getDateTimeValue( values.at( 0 ), parent );
4509 : 0 : const QString format = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4510 : 0 : const QString language = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
4511 : :
4512 : 0 : QLocale locale = !language.isEmpty() ? QLocale( language ) : QLocale();
4513 : 0 : return locale.toString( datetime, format );
4514 : 0 : }
4515 : :
4516 : 0 : static QVariant fcnColorGrayscaleAverage( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
4517 : : {
4518 : 0 : QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4519 : 0 : int avg = ( color.red() + color.green() + color.blue() ) / 3;
4520 : 0 : int alpha = color.alpha();
4521 : :
4522 : 0 : color.setRgb( avg, avg, avg, alpha );
4523 : :
4524 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4525 : 0 : }
4526 : :
4527 : 0 : static QVariant fcnColorMixRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4528 : : {
4529 : 0 : QColor color1 = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4530 : 0 : QColor color2 = QgsSymbolLayerUtils::decodeColor( values.at( 1 ).toString() );
4531 : 0 : double ratio = QgsExpressionUtils::getDoubleValue( values.at( 2 ), parent );
4532 : 0 : if ( ratio > 1 )
4533 : : {
4534 : 0 : ratio = 1;
4535 : 0 : }
4536 : 0 : else if ( ratio < 0 )
4537 : : {
4538 : 0 : ratio = 0;
4539 : 0 : }
4540 : :
4541 : 0 : int red = static_cast<int>( color1.red() * ( 1 - ratio ) + color2.red() * ratio );
4542 : 0 : int green = static_cast<int>( color1.green() * ( 1 - ratio ) + color2.green() * ratio );
4543 : 0 : int blue = static_cast<int>( color1.blue() * ( 1 - ratio ) + color2.blue() * ratio );
4544 : 0 : int alpha = static_cast<int>( color1.alpha() * ( 1 - ratio ) + color2.alpha() * ratio );
4545 : :
4546 : 0 : QColor newColor( red, green, blue, alpha );
4547 : :
4548 : 0 : return QgsSymbolLayerUtils::encodeColor( newColor );
4549 : 0 : }
4550 : :
4551 : 0 : static QVariant fcnColorRgb( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4552 : : {
4553 : 0 : int red = QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent );
4554 : 0 : int green = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4555 : 0 : int blue = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
4556 : 0 : QColor color = QColor( red, green, blue );
4557 : 0 : if ( ! color.isValid() )
4558 : : {
4559 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( red ).arg( green ).arg( blue ) );
4560 : 0 : color = QColor( 0, 0, 0 );
4561 : 0 : }
4562 : :
4563 : 0 : return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4564 : 0 : }
4565 : :
4566 : 0 : static QVariant fcnTry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4567 : : {
4568 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
4569 : 0 : QVariant value = node->eval( parent, context );
4570 : 0 : if ( parent->hasEvalError() )
4571 : : {
4572 : 0 : parent->setEvalErrorString( QString() );
4573 : 0 : node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
4574 : 0 : ENSURE_NO_EVAL_ERROR
4575 : 0 : value = node->eval( parent, context );
4576 : 0 : ENSURE_NO_EVAL_ERROR
4577 : 0 : }
4578 : 0 : return value;
4579 : 0 : }
4580 : :
4581 : 0 : static QVariant fcnIf( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4582 : : {
4583 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
4584 : 0 : ENSURE_NO_EVAL_ERROR
4585 : 0 : QVariant value = node->eval( parent, context );
4586 : 0 : ENSURE_NO_EVAL_ERROR
4587 : 0 : if ( value.toBool() )
4588 : : {
4589 : 0 : node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
4590 : 0 : ENSURE_NO_EVAL_ERROR
4591 : 0 : value = node->eval( parent, context );
4592 : 0 : ENSURE_NO_EVAL_ERROR
4593 : 0 : }
4594 : : else
4595 : : {
4596 : 0 : node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
4597 : 0 : ENSURE_NO_EVAL_ERROR
4598 : 0 : value = node->eval( parent, context );
4599 : 0 : ENSURE_NO_EVAL_ERROR
4600 : : }
4601 : 0 : return value;
4602 : 0 : }
4603 : :
4604 : 0 : static QVariant fncColorRgba( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4605 : : {
4606 : 0 : int red = QgsExpressionUtils::getNativeIntValue( values.at( 0 ), parent );
4607 : 0 : int green = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
4608 : 0 : int blue = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
4609 : 0 : int alpha = QgsExpressionUtils::getNativeIntValue( values.at( 3 ), parent );
4610 : 0 : QColor color = QColor( red, green, blue, alpha );
4611 : 0 : if ( ! color.isValid() )
4612 : : {
4613 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( red ).arg( green ).arg( blue ).arg( alpha ) );
4614 : 0 : color = QColor( 0, 0, 0 );
4615 : 0 : }
4616 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4617 : 0 : }
4618 : :
4619 : 0 : QVariant fcnRampColor( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4620 : : {
4621 : 0 : QgsGradientColorRamp expRamp;
4622 : 0 : const QgsColorRamp *ramp = nullptr;
4623 : 0 : if ( values.at( 0 ).canConvert<QgsGradientColorRamp>() )
4624 : : {
4625 : 0 : expRamp = QgsExpressionUtils::getRamp( values.at( 0 ), parent );
4626 : 0 : ramp = &expRamp;
4627 : 0 : }
4628 : : else
4629 : : {
4630 : 0 : QString rampName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
4631 : 0 : ramp = QgsStyle::defaultStyle()->colorRampRef( rampName );
4632 : 0 : if ( ! ramp )
4633 : : {
4634 : 0 : parent->setEvalErrorString( QObject::tr( "\"%1\" is not a valid color ramp" ).arg( rampName ) );
4635 : 0 : return QVariant();
4636 : : }
4637 : 0 : }
4638 : :
4639 : 0 : double value = QgsExpressionUtils::getDoubleValue( values.at( 1 ), parent );
4640 : 0 : QColor color = ramp->color( value );
4641 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4642 : 0 : }
4643 : :
4644 : 0 : static QVariant fcnColorHsl( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4645 : : {
4646 : : // Hue ranges from 0 - 360
4647 : 0 : double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4648 : : // Saturation ranges from 0 - 100
4649 : 0 : double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4650 : : // Lightness ranges from 0 - 100
4651 : 0 : double lightness = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4652 : :
4653 : 0 : QColor color = QColor::fromHslF( hue, saturation, lightness );
4654 : :
4655 : 0 : if ( ! color.isValid() )
4656 : : {
4657 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( lightness ) );
4658 : 0 : color = QColor( 0, 0, 0 );
4659 : 0 : }
4660 : :
4661 : 0 : return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4662 : 0 : }
4663 : :
4664 : 0 : static QVariant fncColorHsla( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4665 : : {
4666 : : // Hue ranges from 0 - 360
4667 : 0 : double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4668 : : // Saturation ranges from 0 - 100
4669 : 0 : double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4670 : : // Lightness ranges from 0 - 100
4671 : 0 : double lightness = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4672 : : // Alpha ranges from 0 - 255
4673 : 0 : double alpha = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 255.0;
4674 : :
4675 : 0 : QColor color = QColor::fromHslF( hue, saturation, lightness, alpha );
4676 : 0 : if ( ! color.isValid() )
4677 : : {
4678 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( lightness ).arg( alpha ) );
4679 : 0 : color = QColor( 0, 0, 0 );
4680 : 0 : }
4681 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4682 : 0 : }
4683 : :
4684 : 0 : static QVariant fcnColorHsv( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4685 : : {
4686 : : // Hue ranges from 0 - 360
4687 : 0 : double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4688 : : // Saturation ranges from 0 - 100
4689 : 0 : double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4690 : : // Value ranges from 0 - 100
4691 : 0 : double value = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4692 : :
4693 : 0 : QColor color = QColor::fromHsvF( hue, saturation, value );
4694 : :
4695 : 0 : if ( ! color.isValid() )
4696 : : {
4697 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3' to color" ).arg( hue ).arg( saturation ).arg( value ) );
4698 : 0 : color = QColor( 0, 0, 0 );
4699 : 0 : }
4700 : :
4701 : 0 : return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4702 : 0 : }
4703 : :
4704 : 0 : static QVariant fncColorHsva( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4705 : : {
4706 : : // Hue ranges from 0 - 360
4707 : 0 : double hue = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 360.0;
4708 : : // Saturation ranges from 0 - 100
4709 : 0 : double saturation = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4710 : : // Value ranges from 0 - 100
4711 : 0 : double value = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4712 : : // Alpha ranges from 0 - 255
4713 : 0 : double alpha = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 255.0;
4714 : :
4715 : 0 : QColor color = QColor::fromHsvF( hue, saturation, value, alpha );
4716 : 0 : if ( ! color.isValid() )
4717 : : {
4718 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( hue ).arg( saturation ).arg( value ).arg( alpha ) );
4719 : 0 : color = QColor( 0, 0, 0 );
4720 : 0 : }
4721 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4722 : 0 : }
4723 : :
4724 : 0 : static QVariant fcnColorCmyk( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4725 : : {
4726 : : // Cyan ranges from 0 - 100
4727 : 0 : double cyan = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 100.0;
4728 : : // Magenta ranges from 0 - 100
4729 : 0 : double magenta = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4730 : : // Yellow ranges from 0 - 100
4731 : 0 : double yellow = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4732 : : // Black ranges from 0 - 100
4733 : 0 : double black = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 100.0;
4734 : :
4735 : 0 : QColor color = QColor::fromCmykF( cyan, magenta, yellow, black );
4736 : :
4737 : 0 : if ( ! color.isValid() )
4738 : : {
4739 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ) );
4740 : 0 : color = QColor( 0, 0, 0 );
4741 : 0 : }
4742 : :
4743 : 0 : return QStringLiteral( "%1,%2,%3" ).arg( color.red() ).arg( color.green() ).arg( color.blue() );
4744 : 0 : }
4745 : :
4746 : 0 : static QVariant fncColorCmyka( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4747 : : {
4748 : : // Cyan ranges from 0 - 100
4749 : 0 : double cyan = QgsExpressionUtils::getIntValue( values.at( 0 ), parent ) / 100.0;
4750 : : // Magenta ranges from 0 - 100
4751 : 0 : double magenta = QgsExpressionUtils::getIntValue( values.at( 1 ), parent ) / 100.0;
4752 : : // Yellow ranges from 0 - 100
4753 : 0 : double yellow = QgsExpressionUtils::getIntValue( values.at( 2 ), parent ) / 100.0;
4754 : : // Black ranges from 0 - 100
4755 : 0 : double black = QgsExpressionUtils::getIntValue( values.at( 3 ), parent ) / 100.0;
4756 : : // Alpha ranges from 0 - 255
4757 : 0 : double alpha = QgsExpressionUtils::getIntValue( values.at( 4 ), parent ) / 255.0;
4758 : :
4759 : 0 : QColor color = QColor::fromCmykF( cyan, magenta, yellow, black, alpha );
4760 : 0 : if ( ! color.isValid() )
4761 : : {
4762 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1:%2:%3:%4:%5' to color" ).arg( cyan ).arg( magenta ).arg( yellow ).arg( black ).arg( alpha ) );
4763 : 0 : color = QColor( 0, 0, 0 );
4764 : 0 : }
4765 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4766 : 0 : }
4767 : :
4768 : 0 : static QVariant fncColorPart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4769 : : {
4770 : 0 : QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4771 : 0 : if ( ! color.isValid() )
4772 : : {
4773 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4774 : 0 : return QVariant();
4775 : : }
4776 : :
4777 : 0 : QString part = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4778 : 0 : if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
4779 : 0 : return color.red();
4780 : 0 : else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
4781 : 0 : return color.green();
4782 : 0 : else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
4783 : 0 : return color.blue();
4784 : 0 : else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
4785 : 0 : return color.alpha();
4786 : 0 : else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
4787 : 0 : return color.hsvHueF() * 360;
4788 : 0 : else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
4789 : 0 : return color.hsvSaturationF() * 100;
4790 : 0 : else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
4791 : 0 : return color.valueF() * 100;
4792 : 0 : else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
4793 : 0 : return color.hslHueF() * 360;
4794 : 0 : else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
4795 : 0 : return color.hslSaturationF() * 100;
4796 : 0 : else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
4797 : 0 : return color.lightnessF() * 100;
4798 : 0 : else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
4799 : 0 : return color.cyanF() * 100;
4800 : 0 : else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
4801 : 0 : return color.magentaF() * 100;
4802 : 0 : else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
4803 : 0 : return color.yellowF() * 100;
4804 : 0 : else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
4805 : 0 : return color.blackF() * 100;
4806 : :
4807 : 0 : parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
4808 : 0 : return QVariant();
4809 : 0 : }
4810 : :
4811 : 0 : static QVariant fcnCreateRamp( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4812 : : {
4813 : 0 : const QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
4814 : 0 : if ( map.count() < 1 )
4815 : : {
4816 : 0 : parent->setEvalErrorString( QObject::tr( "A minimum of two colors is required to create a ramp" ) );
4817 : 0 : return QVariant();
4818 : : }
4819 : :
4820 : 0 : QList< QColor > colors;
4821 : 0 : QgsGradientStopsList stops;
4822 : 0 : for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
4823 : : {
4824 : 0 : colors << QgsSymbolLayerUtils::decodeColor( it.value().toString() );
4825 : 0 : if ( !colors.last().isValid() )
4826 : : {
4827 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( it.value().toString() ) );
4828 : 0 : return QVariant();
4829 : : }
4830 : :
4831 : 0 : double step = it.key().toDouble();
4832 : 0 : if ( it == map.constBegin() )
4833 : : {
4834 : 0 : if ( step != 0.0 )
4835 : 0 : stops << QgsGradientStop( step, colors.last() );
4836 : 0 : }
4837 : 0 : else if ( it == map.constEnd() )
4838 : : {
4839 : 0 : if ( step != 1.0 )
4840 : 0 : stops << QgsGradientStop( step, colors.last() );
4841 : 0 : }
4842 : : else
4843 : : {
4844 : 0 : stops << QgsGradientStop( step, colors.last() );
4845 : : }
4846 : 0 : }
4847 : 0 : bool discrete = values.at( 1 ).toBool();
4848 : :
4849 : 0 : return QVariant::fromValue( QgsGradientColorRamp( colors.first(), colors.last(), discrete, stops ) );
4850 : 0 : }
4851 : :
4852 : 0 : static QVariant fncSetColorPart( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4853 : : {
4854 : 0 : QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4855 : 0 : if ( ! color.isValid() )
4856 : : {
4857 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4858 : 0 : return QVariant();
4859 : : }
4860 : :
4861 : 0 : QString part = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4862 : 0 : int value = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
4863 : 0 : if ( part.compare( QLatin1String( "red" ), Qt::CaseInsensitive ) == 0 )
4864 : 0 : color.setRed( value );
4865 : 0 : else if ( part.compare( QLatin1String( "green" ), Qt::CaseInsensitive ) == 0 )
4866 : 0 : color.setGreen( value );
4867 : 0 : else if ( part.compare( QLatin1String( "blue" ), Qt::CaseInsensitive ) == 0 )
4868 : 0 : color.setBlue( value );
4869 : 0 : else if ( part.compare( QLatin1String( "alpha" ), Qt::CaseInsensitive ) == 0 )
4870 : 0 : color.setAlpha( value );
4871 : 0 : else if ( part.compare( QLatin1String( "hue" ), Qt::CaseInsensitive ) == 0 )
4872 : 0 : color.setHsv( value, color.hsvSaturation(), color.value(), color.alpha() );
4873 : 0 : else if ( part.compare( QLatin1String( "saturation" ), Qt::CaseInsensitive ) == 0 )
4874 : 0 : color.setHsvF( color.hsvHueF(), value / 100.0, color.valueF(), color.alphaF() );
4875 : 0 : else if ( part.compare( QLatin1String( "value" ), Qt::CaseInsensitive ) == 0 )
4876 : 0 : color.setHsvF( color.hsvHueF(), color.hsvSaturationF(), value / 100.0, color.alphaF() );
4877 : 0 : else if ( part.compare( QLatin1String( "hsl_hue" ), Qt::CaseInsensitive ) == 0 )
4878 : 0 : color.setHsl( value, color.hslSaturation(), color.lightness(), color.alpha() );
4879 : 0 : else if ( part.compare( QLatin1String( "hsl_saturation" ), Qt::CaseInsensitive ) == 0 )
4880 : 0 : color.setHslF( color.hslHueF(), value / 100.0, color.lightnessF(), color.alphaF() );
4881 : 0 : else if ( part.compare( QLatin1String( "lightness" ), Qt::CaseInsensitive ) == 0 )
4882 : 0 : color.setHslF( color.hslHueF(), color.hslSaturationF(), value / 100.0, color.alphaF() );
4883 : 0 : else if ( part.compare( QLatin1String( "cyan" ), Qt::CaseInsensitive ) == 0 )
4884 : 0 : color.setCmykF( value / 100.0, color.magentaF(), color.yellowF(), color.blackF(), color.alphaF() );
4885 : 0 : else if ( part.compare( QLatin1String( "magenta" ), Qt::CaseInsensitive ) == 0 )
4886 : 0 : color.setCmykF( color.cyanF(), value / 100.0, color.yellowF(), color.blackF(), color.alphaF() );
4887 : 0 : else if ( part.compare( QLatin1String( "yellow" ), Qt::CaseInsensitive ) == 0 )
4888 : 0 : color.setCmykF( color.cyanF(), color.magentaF(), value / 100.0, color.blackF(), color.alphaF() );
4889 : 0 : else if ( part.compare( QLatin1String( "black" ), Qt::CaseInsensitive ) == 0 )
4890 : 0 : color.setCmykF( color.cyanF(), color.magentaF(), color.yellowF(), value / 100.0, color.alphaF() );
4891 : : else
4892 : : {
4893 : 0 : parent->setEvalErrorString( QObject::tr( "Unknown color component '%1'" ).arg( part ) );
4894 : 0 : return QVariant();
4895 : : }
4896 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4897 : 0 : }
4898 : :
4899 : 0 : static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4900 : : {
4901 : 0 : QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4902 : 0 : if ( ! color.isValid() )
4903 : : {
4904 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4905 : 0 : return QVariant();
4906 : : }
4907 : :
4908 : 0 : color = color.darker( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
4909 : :
4910 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4911 : 0 : }
4912 : :
4913 : 0 : static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4914 : : {
4915 : 0 : QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() );
4916 : 0 : if ( ! color.isValid() )
4917 : : {
4918 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) );
4919 : 0 : return QVariant();
4920 : : }
4921 : :
4922 : 0 : color = color.lighter( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
4923 : :
4924 : 0 : return QgsSymbolLayerUtils::encodeColor( color );
4925 : 0 : }
4926 : :
4927 : 0 : static QVariant fcnGetGeometry( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4928 : : {
4929 : 0 : QgsFeature feat = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
4930 : 0 : QgsGeometry geom = feat.geometry();
4931 : 0 : if ( !geom.isNull() )
4932 : 0 : return QVariant::fromValue( geom );
4933 : 0 : return QVariant();
4934 : 0 : }
4935 : :
4936 : 0 : static QVariant fcnTransformGeometry( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4937 : : {
4938 : 0 : QgsGeometry fGeom = QgsExpressionUtils::getGeometry( values.at( 0 ), parent );
4939 : 0 : QString sAuthId = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
4940 : 0 : QString dAuthId = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
4941 : :
4942 : 0 : QgsCoordinateReferenceSystem s = QgsCoordinateReferenceSystem::fromOgcWmsCrs( sAuthId );
4943 : 0 : if ( ! s.isValid() )
4944 : 0 : return QVariant::fromValue( fGeom );
4945 : 0 : QgsCoordinateReferenceSystem d = QgsCoordinateReferenceSystem::fromOgcWmsCrs( dAuthId );
4946 : 0 : if ( ! d.isValid() )
4947 : 0 : return QVariant::fromValue( fGeom );
4948 : :
4949 : 0 : QgsCoordinateTransformContext tContext;
4950 : 0 : if ( context )
4951 : 0 : tContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
4952 : 0 : QgsCoordinateTransform t( s, d, tContext );
4953 : : try
4954 : : {
4955 : 0 : if ( fGeom.transform( t ) == 0 )
4956 : 0 : return QVariant::fromValue( fGeom );
4957 : 0 : }
4958 : : catch ( QgsCsException &cse )
4959 : : {
4960 : 0 : QgsMessageLog::logMessage( QObject::tr( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
4961 : 0 : return QVariant();
4962 : 0 : }
4963 : 0 : return QVariant();
4964 : 0 : }
4965 : :
4966 : :
4967 : 0 : static QVariant fcnGetFeatureById( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
4968 : : {
4969 : 0 : QVariant result;
4970 : 0 : QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
4971 : 0 : if ( vl )
4972 : : {
4973 : 0 : QgsFeatureId fid = QgsExpressionUtils::getIntValue( values.at( 1 ), parent );
4974 : :
4975 : 0 : QgsFeatureRequest req;
4976 : 0 : req.setFilterFid( fid );
4977 : 0 : req.setTimeout( 10000 );
4978 : 0 : req.setRequestMayBeNested( true );
4979 : 0 : QgsFeatureIterator fIt = vl->getFeatures( req );
4980 : :
4981 : 0 : QgsFeature fet;
4982 : 0 : if ( fIt.nextFeature( fet ) )
4983 : 0 : result = QVariant::fromValue( fet );
4984 : 0 : }
4985 : :
4986 : 0 : return result;
4987 : 0 : }
4988 : :
4989 : 0 : static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
4990 : : {
4991 : : //arguments: 1. layer id / name, 2. key attribute, 3. eq value
4992 : :
4993 : 0 : std::unique_ptr<QgsVectorLayerFeatureSource> featureSource = QgsExpressionUtils::getFeatureSource( values.at( 0 ), parent );
4994 : :
4995 : : //no layer found
4996 : 0 : if ( !featureSource )
4997 : : {
4998 : 0 : return QVariant();
4999 : : }
5000 : :
5001 : 0 : QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5002 : 0 : int attributeId = featureSource->fields().lookupField( attribute );
5003 : 0 : if ( attributeId == -1 )
5004 : : {
5005 : 0 : return QVariant();
5006 : : }
5007 : :
5008 : 0 : const QVariant &attVal = values.at( 2 );
5009 : :
5010 : 0 : const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( featureSource->id(), QString::number( attributeId ), attVal.toString() );
5011 : 0 : if ( context && context->hasCachedValue( cacheValueKey ) )
5012 : : {
5013 : 0 : return context->cachedValue( cacheValueKey );
5014 : : }
5015 : :
5016 : 0 : QgsFeatureRequest req;
5017 : 0 : req.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( attribute ),
5018 : 0 : QgsExpression::quotedString( attVal.toString() ) ) );
5019 : 0 : req.setLimit( 1 );
5020 : 0 : req.setTimeout( 10000 );
5021 : 0 : req.setRequestMayBeNested( true );
5022 : 0 : if ( !parent->needsGeometry() )
5023 : : {
5024 : 0 : req.setFlags( QgsFeatureRequest::NoGeometry );
5025 : 0 : }
5026 : 0 : QgsFeatureIterator fIt = featureSource->getFeatures( req );
5027 : :
5028 : 0 : QgsFeature fet;
5029 : 0 : QVariant res;
5030 : 0 : if ( fIt.nextFeature( fet ) )
5031 : : {
5032 : 0 : res = QVariant::fromValue( fet );
5033 : 0 : }
5034 : :
5035 : 0 : if ( context )
5036 : 0 : context->setCachedValue( cacheValueKey, res );
5037 : 0 : return res;
5038 : 0 : }
5039 : :
5040 : 0 : static QVariant fcnRepresentValue( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
5041 : : {
5042 : 0 : QVariant result;
5043 : 0 : QString fieldName;
5044 : :
5045 : 0 : if ( context )
5046 : : {
5047 : 0 : if ( !values.isEmpty() )
5048 : : {
5049 : 0 : QgsExpressionNodeColumnRef *col = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
5050 : 0 : if ( col && ( values.size() == 1 || !values.at( 1 ).isValid() ) )
5051 : 0 : fieldName = col->name();
5052 : 0 : else if ( values.size() == 2 )
5053 : 0 : fieldName = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5054 : 0 : }
5055 : :
5056 : 0 : QVariant value = values.at( 0 );
5057 : :
5058 : 0 : const QgsFields fields = context->fields();
5059 : 0 : int fieldIndex = fields.lookupField( fieldName );
5060 : :
5061 : 0 : if ( fieldIndex == -1 )
5062 : : {
5063 : 0 : parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: Field not found %2" ).arg( QStringLiteral( "represent_value" ), fieldName ) );
5064 : 0 : }
5065 : : else
5066 : : {
5067 : 0 : QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
5068 : :
5069 : 0 : const QString cacheValueKey = QStringLiteral( "repvalfcnval:%1:%2:%3" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName, value.toString() );
5070 : 0 : if ( context->hasCachedValue( cacheValueKey ) )
5071 : : {
5072 : 0 : return context->cachedValue( cacheValueKey );
5073 : : }
5074 : :
5075 : 0 : const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
5076 : 0 : const QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
5077 : :
5078 : 0 : const QString cacheKey = QStringLiteral( "repvalfcn:%1:%2" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName );
5079 : :
5080 : 0 : QVariant cache;
5081 : 0 : if ( !context->hasCachedValue( cacheKey ) )
5082 : : {
5083 : 0 : cache = formatter->createCache( layer, fieldIndex, setup.config() );
5084 : 0 : context->setCachedValue( cacheKey, cache );
5085 : 0 : }
5086 : : else
5087 : 0 : cache = context->cachedValue( cacheKey );
5088 : :
5089 : 0 : result = formatter->representValue( layer, fieldIndex, setup.config(), cache, value );
5090 : :
5091 : 0 : context->setCachedValue( cacheValueKey, result );
5092 : 0 : }
5093 : 0 : }
5094 : : else
5095 : : {
5096 : 0 : parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: function cannot be evaluated without a context." ).arg( QStringLiteral( "represent_value" ), fieldName ) );
5097 : : }
5098 : :
5099 : 0 : return result;
5100 : 0 : }
5101 : :
5102 : 0 : static QVariant fcnMimeType( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
5103 : : {
5104 : 0 : const QVariant data = values.at( 0 );
5105 : 0 : const QMimeDatabase db;
5106 : 0 : return db.mimeTypeForData( data.toByteArray() ).name();
5107 : 0 : }
5108 : :
5109 : 0 : static QVariant fcnGetLayerProperty( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5110 : : {
5111 : 0 : QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
5112 : :
5113 : 0 : if ( !layer )
5114 : 0 : return QVariant();
5115 : :
5116 : : // here, we always prefer the layer metadata values over the older server-specific published values
5117 : 0 : QString layerProperty = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5118 : 0 : if ( QString::compare( layerProperty, QStringLiteral( "name" ), Qt::CaseInsensitive ) == 0 )
5119 : 0 : return layer->name();
5120 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "id" ), Qt::CaseInsensitive ) == 0 )
5121 : 0 : return layer->id();
5122 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "title" ), Qt::CaseInsensitive ) == 0 )
5123 : 0 : return !layer->metadata().title().isEmpty() ? layer->metadata().title() : layer->title();
5124 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "abstract" ), Qt::CaseInsensitive ) == 0 )
5125 : 0 : return !layer->metadata().abstract().isEmpty() ? layer->metadata().abstract() : layer->abstract();
5126 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "keywords" ), Qt::CaseInsensitive ) == 0 )
5127 : : {
5128 : 0 : QStringList keywords;
5129 : 0 : const QgsAbstractMetadataBase::KeywordMap keywordMap = layer->metadata().keywords();
5130 : 0 : for ( auto it = keywordMap.constBegin(); it != keywordMap.constEnd(); ++it )
5131 : : {
5132 : 0 : keywords.append( it.value() );
5133 : 0 : }
5134 : 0 : if ( !keywords.isEmpty() )
5135 : 0 : return keywords;
5136 : 0 : return layer->keywordList();
5137 : 0 : }
5138 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "data_url" ), Qt::CaseInsensitive ) == 0 )
5139 : 0 : return layer->dataUrl();
5140 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "attribution" ), Qt::CaseInsensitive ) == 0 )
5141 : : {
5142 : 0 : return !layer->metadata().rights().isEmpty() ? QVariant( layer->metadata().rights() ) : QVariant( layer->attribution() );
5143 : : }
5144 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "attribution_url" ), Qt::CaseInsensitive ) == 0 )
5145 : 0 : return layer->attributionUrl();
5146 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "source" ), Qt::CaseInsensitive ) == 0 )
5147 : 0 : return layer->publicSource();
5148 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "min_scale" ), Qt::CaseInsensitive ) == 0 )
5149 : 0 : return layer->minimumScale();
5150 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "max_scale" ), Qt::CaseInsensitive ) == 0 )
5151 : 0 : return layer->maximumScale();
5152 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "is_editable" ), Qt::CaseInsensitive ) == 0 )
5153 : 0 : return layer->isEditable();
5154 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "crs" ), Qt::CaseInsensitive ) == 0 )
5155 : 0 : return layer->crs().authid();
5156 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "crs_definition" ), Qt::CaseInsensitive ) == 0 )
5157 : 0 : return layer->crs().toProj();
5158 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "crs_description" ), Qt::CaseInsensitive ) == 0 )
5159 : 0 : return layer->crs().description();
5160 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "extent" ), Qt::CaseInsensitive ) == 0 )
5161 : : {
5162 : 0 : QgsGeometry extentGeom = QgsGeometry::fromRect( layer->extent() );
5163 : 0 : QVariant result = QVariant::fromValue( extentGeom );
5164 : 0 : return result;
5165 : 0 : }
5166 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "distance_units" ), Qt::CaseInsensitive ) == 0 )
5167 : 0 : return QgsUnitTypes::encodeUnit( layer->crs().mapUnits() );
5168 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "type" ), Qt::CaseInsensitive ) == 0 )
5169 : : {
5170 : 0 : switch ( layer->type() )
5171 : : {
5172 : : case QgsMapLayerType::VectorLayer:
5173 : 0 : return QCoreApplication::translate( "expressions", "Vector" );
5174 : : case QgsMapLayerType::RasterLayer:
5175 : 0 : return QCoreApplication::translate( "expressions", "Raster" );
5176 : : case QgsMapLayerType::MeshLayer:
5177 : 0 : return QCoreApplication::translate( "expressions", "Mesh" );
5178 : : case QgsMapLayerType::VectorTileLayer:
5179 : 0 : return QCoreApplication::translate( "expressions", "Vector Tile" );
5180 : : case QgsMapLayerType::PluginLayer:
5181 : 0 : return QCoreApplication::translate( "expressions", "Plugin" );
5182 : : case QgsMapLayerType::AnnotationLayer:
5183 : 0 : return QCoreApplication::translate( "expressions", "Annotation" );
5184 : : case QgsMapLayerType::PointCloudLayer:
5185 : 0 : return QCoreApplication::translate( "expressions", "Point Cloud" );
5186 : : }
5187 : 0 : }
5188 : : else
5189 : : {
5190 : : //vector layer methods
5191 : 0 : QgsVectorLayer *vLayer = qobject_cast< QgsVectorLayer * >( layer );
5192 : 0 : if ( vLayer )
5193 : : {
5194 : 0 : if ( QString::compare( layerProperty, QStringLiteral( "storage_type" ), Qt::CaseInsensitive ) == 0 )
5195 : 0 : return vLayer->storageType();
5196 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "geometry_type" ), Qt::CaseInsensitive ) == 0 )
5197 : 0 : return QgsWkbTypes::geometryDisplayString( vLayer->geometryType() );
5198 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "feature_count" ), Qt::CaseInsensitive ) == 0 )
5199 : 0 : return QVariant::fromValue( vLayer->featureCount() );
5200 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "path" ), Qt::CaseInsensitive ) == 0 )
5201 : : {
5202 : 0 : if ( vLayer->dataProvider() )
5203 : : {
5204 : 0 : const QVariantMap decodedUri = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
5205 : 0 : return decodedUri.value( QStringLiteral( "path" ) );
5206 : 0 : }
5207 : 0 : }
5208 : 0 : }
5209 : : }
5210 : :
5211 : 0 : return QVariant();
5212 : 0 : }
5213 : :
5214 : 0 : static QVariant fcnDecodeUri( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5215 : : {
5216 : 0 : QgsMapLayer *layer = QgsExpressionUtils::getMapLayer( values.at( 0 ), parent );
5217 : 0 : if ( !layer )
5218 : : {
5219 : 0 : parent->setEvalErrorString( QObject::tr( "Cannot find layer %1" ).arg( values.at( 0 ).toString() ) );
5220 : 0 : return QVariant();
5221 : : }
5222 : :
5223 : 0 : if ( !layer->dataProvider() )
5224 : : {
5225 : 0 : parent->setEvalErrorString( QObject::tr( "Layer %1 has invalid data provider" ).arg( layer->name() ) );
5226 : 0 : return QVariant();
5227 : : }
5228 : :
5229 : 0 : const QString uriPart = values.at( 1 ).toString();
5230 : :
5231 : 0 : const QVariantMap decodedUri = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->dataProvider()->dataSourceUri() );
5232 : :
5233 : 0 : if ( !uriPart.isNull() )
5234 : : {
5235 : 0 : return decodedUri.value( values.at( 1 ).toString() );
5236 : : }
5237 : : else
5238 : : {
5239 : 0 : return decodedUri;
5240 : : }
5241 : 0 : }
5242 : :
5243 : 0 : static QVariant fcnGetRasterBandStat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5244 : : {
5245 : 0 : QString layerIdOrName = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5246 : :
5247 : : //try to find a matching layer by name
5248 : 0 : QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerIdOrName ); //search by id first
5249 : 0 : if ( !layer )
5250 : : {
5251 : 0 : QList<QgsMapLayer *> layersByName = QgsProject::instance()->mapLayersByName( layerIdOrName );
5252 : 0 : if ( !layersByName.isEmpty() )
5253 : : {
5254 : 0 : layer = layersByName.at( 0 );
5255 : 0 : }
5256 : 0 : }
5257 : :
5258 : 0 : if ( !layer )
5259 : 0 : return QVariant();
5260 : :
5261 : 0 : QgsRasterLayer *rl = qobject_cast< QgsRasterLayer * >( layer );
5262 : 0 : if ( !rl )
5263 : 0 : return QVariant();
5264 : :
5265 : 0 : int band = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
5266 : 0 : if ( band < 1 || band > rl->bandCount() )
5267 : : {
5268 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid band number %1 for layer %2" ).arg( band ).arg( layerIdOrName ) );
5269 : 0 : return QVariant();
5270 : : }
5271 : :
5272 : 0 : QString layerProperty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
5273 : 0 : int stat = 0;
5274 : :
5275 : 0 : if ( QString::compare( layerProperty, QStringLiteral( "avg" ), Qt::CaseInsensitive ) == 0 )
5276 : 0 : stat = QgsRasterBandStats::Mean;
5277 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "stdev" ), Qt::CaseInsensitive ) == 0 )
5278 : 0 : stat = QgsRasterBandStats::StdDev;
5279 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "min" ), Qt::CaseInsensitive ) == 0 )
5280 : 0 : stat = QgsRasterBandStats::Min;
5281 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "max" ), Qt::CaseInsensitive ) == 0 )
5282 : 0 : stat = QgsRasterBandStats::Max;
5283 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "range" ), Qt::CaseInsensitive ) == 0 )
5284 : 0 : stat = QgsRasterBandStats::Range;
5285 : 0 : else if ( QString::compare( layerProperty, QStringLiteral( "sum" ), Qt::CaseInsensitive ) == 0 )
5286 : 0 : stat = QgsRasterBandStats::Sum;
5287 : : else
5288 : : {
5289 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid raster statistic: '%1'" ).arg( layerProperty ) );
5290 : 0 : return QVariant();
5291 : : }
5292 : :
5293 : 0 : QgsRasterBandStats stats = rl->dataProvider()->bandStatistics( band, stat );
5294 : 0 : switch ( stat )
5295 : : {
5296 : : case QgsRasterBandStats::Mean:
5297 : 0 : return stats.mean;
5298 : : case QgsRasterBandStats::StdDev:
5299 : 0 : return stats.stdDev;
5300 : : case QgsRasterBandStats::Min:
5301 : 0 : return stats.minimumValue;
5302 : : case QgsRasterBandStats::Max:
5303 : 0 : return stats.maximumValue;
5304 : : case QgsRasterBandStats::Range:
5305 : 0 : return stats.range;
5306 : : case QgsRasterBandStats::Sum:
5307 : 0 : return stats.sum;
5308 : : }
5309 : 0 : return QVariant();
5310 : 0 : }
5311 : :
5312 : 0 : static QVariant fcnArray( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
5313 : : {
5314 : 0 : return values;
5315 : : }
5316 : :
5317 : 0 : static QVariant fcnArraySort( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5318 : : {
5319 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5320 : 0 : bool ascending = values.value( 1 ).toBool();
5321 : 0 : std::sort( list.begin(), list.end(), [ascending]( QVariant a, QVariant b ) -> bool { return ( !ascending ? qgsVariantLessThan( b, a ) : qgsVariantLessThan( a, b ) ); } );
5322 : 0 : return list;
5323 : 0 : }
5324 : :
5325 : 0 : static QVariant fcnArrayLength( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5326 : : {
5327 : 0 : return QgsExpressionUtils::getListValue( values.at( 0 ), parent ).length();
5328 : 0 : }
5329 : :
5330 : 0 : static QVariant fcnArrayContains( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5331 : : {
5332 : 0 : return QVariant( QgsExpressionUtils::getListValue( values.at( 0 ), parent ).contains( values.at( 1 ) ) );
5333 : 0 : }
5334 : :
5335 : 0 : static QVariant fcnArrayCount( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5336 : : {
5337 : 0 : return QVariant( QgsExpressionUtils::getListValue( values.at( 0 ), parent ).count( values.at( 1 ) ) );
5338 : 0 : }
5339 : :
5340 : 0 : static QVariant fcnArrayAll( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5341 : : {
5342 : 0 : QVariantList listA = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5343 : 0 : QVariantList listB = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
5344 : 0 : int match = 0;
5345 : 0 : for ( const auto &item : listB )
5346 : : {
5347 : 0 : if ( listA.contains( item ) )
5348 : 0 : match++;
5349 : : }
5350 : :
5351 : 0 : return QVariant( match == listB.count() );
5352 : 0 : }
5353 : :
5354 : 0 : static QVariant fcnArrayFind( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5355 : : {
5356 : 0 : return QgsExpressionUtils::getListValue( values.at( 0 ), parent ).indexOf( values.at( 1 ) );
5357 : 0 : }
5358 : :
5359 : 0 : static QVariant fcnArrayGet( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5360 : : {
5361 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5362 : 0 : const int pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
5363 : 0 : if ( pos < list.length() && pos >= 0 ) return list.at( pos );
5364 : 0 : else if ( pos < 0 && ( list.length() + pos ) >= 0 )
5365 : 0 : return list.at( list.length() + pos );
5366 : 0 : return QVariant();
5367 : 0 : }
5368 : :
5369 : 0 : static QVariant fcnArrayFirst( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5370 : : {
5371 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5372 : 0 : return list.value( 0 );
5373 : 0 : }
5374 : :
5375 : 0 : static QVariant fcnArrayLast( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5376 : : {
5377 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5378 : 0 : return list.value( list.size() - 1 );
5379 : 0 : }
5380 : :
5381 : 0 : static QVariant fcnArrayMinimum( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5382 : : {
5383 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5384 : 0 : return list.isEmpty() ? QVariant() : *std::min_element( list.constBegin(), list.constEnd(), []( QVariant a, QVariant b ) -> bool { return ( qgsVariantLessThan( a, b ) ); } );
5385 : 0 : }
5386 : :
5387 : 0 : static QVariant fcnArrayMaximum( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5388 : : {
5389 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5390 : 0 : return list.isEmpty() ? QVariant() : *std::max_element( list.constBegin(), list.constEnd(), []( QVariant a, QVariant b ) -> bool { return ( qgsVariantLessThan( a, b ) ); } );
5391 : 0 : }
5392 : :
5393 : 0 : static QVariant fcnArrayMean( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5394 : : {
5395 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5396 : 0 : int i = 0;
5397 : 0 : double total = 0.0;
5398 : 0 : for ( const QVariant &item : list )
5399 : : {
5400 : 0 : switch ( item.userType() )
5401 : : {
5402 : : case QMetaType::Int:
5403 : : case QMetaType::UInt:
5404 : : case QMetaType::LongLong:
5405 : : case QMetaType::ULongLong:
5406 : : case QMetaType::Float:
5407 : : case QMetaType::Double:
5408 : 0 : total += item.toDouble();
5409 : 0 : ++i;
5410 : 0 : break;
5411 : : }
5412 : : }
5413 : 0 : return i == 0 ? QVariant() : total / i;
5414 : 0 : }
5415 : :
5416 : 0 : static QVariant fcnArrayMedian( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5417 : : {
5418 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5419 : 0 : QVariantList numbers;
5420 : 0 : for ( const auto &item : list )
5421 : : {
5422 : 0 : switch ( item.userType() )
5423 : : {
5424 : : case QMetaType::Int:
5425 : : case QMetaType::UInt:
5426 : : case QMetaType::LongLong:
5427 : : case QMetaType::ULongLong:
5428 : : case QMetaType::Float:
5429 : : case QMetaType::Double:
5430 : 0 : numbers.append( item );
5431 : 0 : break;
5432 : : }
5433 : : }
5434 : 0 : std::sort( numbers.begin(), numbers.end(), []( QVariant a, QVariant b ) -> bool { return ( qgsVariantLessThan( a, b ) ); } );
5435 : 0 : const int count = numbers.count();
5436 : 0 : if ( count == 0 )
5437 : : {
5438 : 0 : return QVariant();
5439 : : }
5440 : 0 : else if ( count % 2 )
5441 : : {
5442 : 0 : return numbers.at( count / 2 );
5443 : : }
5444 : : else
5445 : : {
5446 : 0 : return ( numbers.at( count / 2 - 1 ).toDouble() + numbers.at( count / 2 ).toDouble() ) / 2;
5447 : : }
5448 : 0 : }
5449 : :
5450 : 0 : static QVariant fcnArraySum( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5451 : : {
5452 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5453 : 0 : int i = 0;
5454 : 0 : double total = 0.0;
5455 : 0 : for ( const QVariant &item : list )
5456 : : {
5457 : 0 : switch ( item.userType() )
5458 : : {
5459 : : case QMetaType::Int:
5460 : : case QMetaType::UInt:
5461 : : case QMetaType::LongLong:
5462 : : case QMetaType::ULongLong:
5463 : : case QMetaType::Float:
5464 : : case QMetaType::Double:
5465 : 0 : total += item.toDouble();
5466 : 0 : ++i;
5467 : 0 : break;
5468 : : }
5469 : : }
5470 : 0 : return i == 0 ? QVariant() : total;
5471 : 0 : }
5472 : :
5473 : 0 : static QVariant convertToSameType( const QVariant &value, QVariant::Type type )
5474 : : {
5475 : 0 : QVariant result = value;
5476 : 0 : result.convert( static_cast<int>( type ) );
5477 : 0 : return result;
5478 : 0 : }
5479 : :
5480 : 0 : static QVariant fcnArrayMajority( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
5481 : : {
5482 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5483 : 0 : QHash< QVariant, int > hash;
5484 : 0 : for ( const auto &item : list )
5485 : : {
5486 : 0 : ++hash[item];
5487 : : }
5488 : 0 : const QList< int > occurrences = hash.values();
5489 : 0 : const int maxValue = *std::max_element( occurrences.constBegin(), occurrences.constEnd() );
5490 : :
5491 : 0 : const QString option = values.at( 1 ).toString();
5492 : 0 : if ( option.compare( QLatin1String( "all" ), Qt::CaseInsensitive ) == 0 )
5493 : : {
5494 : 0 : return convertToSameType( hash.keys( maxValue ), values.at( 0 ).type() );
5495 : : }
5496 : 0 : else if ( option.compare( QLatin1String( "any" ), Qt::CaseInsensitive ) == 0 )
5497 : : {
5498 : 0 : if ( hash.isEmpty() )
5499 : 0 : return QVariant();
5500 : :
5501 : 0 : return QVariant( hash.keys( maxValue ).first() );
5502 : : }
5503 : 0 : else if ( option.compare( QLatin1String( "median" ), Qt::CaseInsensitive ) == 0 )
5504 : : {
5505 : 0 : return fcnArrayMedian( QVariantList() << convertToSameType( hash.keys( maxValue ), values.at( 0 ).type() ), context, parent, node );
5506 : : }
5507 : 0 : else if ( option.compare( QLatin1String( "real_majority" ), Qt::CaseInsensitive ) == 0 )
5508 : : {
5509 : 0 : if ( maxValue * 2 <= list.size() )
5510 : 0 : return QVariant();
5511 : :
5512 : 0 : return QVariant( hash.keys( maxValue ).first() );
5513 : : }
5514 : : else
5515 : : {
5516 : 0 : parent->setEvalErrorString( QObject::tr( "No such option '%1'" ).arg( option ) );
5517 : 0 : return QVariant();
5518 : : }
5519 : 0 : }
5520 : :
5521 : 0 : static QVariant fcnArrayMinority( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
5522 : : {
5523 : 0 : const QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5524 : 0 : QHash< QVariant, int > hash;
5525 : 0 : for ( const auto &item : list )
5526 : : {
5527 : 0 : ++hash[item];
5528 : : }
5529 : 0 : const QList< int > occurrences = hash.values();
5530 : 0 : const int minValue = *std::min_element( occurrences.constBegin(), occurrences.constEnd() );
5531 : :
5532 : 0 : const QString option = values.at( 1 ).toString();
5533 : 0 : if ( option.compare( QLatin1String( "all" ), Qt::CaseInsensitive ) == 0 )
5534 : : {
5535 : 0 : return convertToSameType( hash.keys( minValue ), values.at( 0 ).type() );
5536 : : }
5537 : 0 : else if ( option.compare( QLatin1String( "any" ), Qt::CaseInsensitive ) == 0 )
5538 : : {
5539 : 0 : if ( hash.isEmpty() )
5540 : 0 : return QVariant();
5541 : :
5542 : 0 : return QVariant( hash.keys( minValue ).first() );
5543 : : }
5544 : 0 : else if ( option.compare( QLatin1String( "median" ), Qt::CaseInsensitive ) == 0 )
5545 : : {
5546 : 0 : return fcnArrayMedian( QVariantList() << convertToSameType( hash.keys( minValue ), values.at( 0 ).type() ), context, parent, node );
5547 : : }
5548 : 0 : else if ( option.compare( QLatin1String( "real_minority" ), Qt::CaseInsensitive ) == 0 )
5549 : : {
5550 : 0 : if ( hash.keys().isEmpty() )
5551 : 0 : return QVariant();
5552 : :
5553 : : // Remove the majority, all others are minority
5554 : 0 : const int maxValue = *std::max_element( occurrences.constBegin(), occurrences.constEnd() );
5555 : 0 : if ( maxValue * 2 > list.size() )
5556 : 0 : hash.remove( hash.key( maxValue ) );
5557 : :
5558 : 0 : return convertToSameType( hash.keys(), values.at( 0 ).type() );
5559 : : }
5560 : : else
5561 : : {
5562 : 0 : parent->setEvalErrorString( QObject::tr( "No such option '%1'" ).arg( option ) );
5563 : 0 : return QVariant();
5564 : : }
5565 : 0 : }
5566 : :
5567 : 0 : static QVariant fcnArrayAppend( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5568 : : {
5569 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5570 : 0 : list.append( values.at( 1 ) );
5571 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5572 : 0 : }
5573 : :
5574 : 0 : static QVariant fcnArrayPrepend( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5575 : : {
5576 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5577 : 0 : list.prepend( values.at( 1 ) );
5578 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5579 : 0 : }
5580 : :
5581 : 0 : static QVariant fcnArrayInsert( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5582 : : {
5583 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5584 : 0 : list.insert( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ), values.at( 2 ) );
5585 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5586 : 0 : }
5587 : :
5588 : 0 : static QVariant fcnArrayRemoveAt( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5589 : : {
5590 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5591 : 0 : list.removeAt( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) );
5592 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5593 : 0 : }
5594 : :
5595 : 0 : static QVariant fcnArrayRemoveAll( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5596 : : {
5597 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5598 : 0 : list.removeAll( values.at( 1 ) );
5599 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5600 : 0 : }
5601 : :
5602 : 0 : static QVariant fcnArrayReplace( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5603 : : {
5604 : 0 : if ( values.count() == 2 && values.at( 1 ).type() == QVariant::Map )
5605 : : {
5606 : 0 : QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 1 ), parent );
5607 : :
5608 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5609 : 0 : for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
5610 : : {
5611 : 0 : int index = list.indexOf( it.key() );
5612 : 0 : while ( index >= 0 )
5613 : : {
5614 : 0 : list.replace( index, it.value() );
5615 : 0 : index = list.indexOf( it.key() );
5616 : : }
5617 : 0 : }
5618 : :
5619 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5620 : 0 : }
5621 : 0 : else if ( values.count() == 3 )
5622 : : {
5623 : 0 : QVariantList before;
5624 : 0 : QVariantList after;
5625 : 0 : bool isSingleReplacement = false;
5626 : :
5627 : 0 : if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
5628 : : {
5629 : 0 : before = QVariantList() << values.at( 1 );
5630 : 0 : }
5631 : : else
5632 : : {
5633 : 0 : before = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
5634 : : }
5635 : :
5636 : 0 : if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
5637 : : {
5638 : 0 : after = QVariantList() << values.at( 2 );
5639 : 0 : isSingleReplacement = true;
5640 : 0 : }
5641 : : else
5642 : : {
5643 : 0 : after = QgsExpressionUtils::getListValue( values.at( 2 ), parent );
5644 : : }
5645 : :
5646 : 0 : if ( !isSingleReplacement && before.length() != after.length() )
5647 : : {
5648 : 0 : parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
5649 : 0 : return QVariant();
5650 : : }
5651 : :
5652 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5653 : 0 : for ( int i = 0; i < before.length(); i++ )
5654 : : {
5655 : 0 : int index = list.indexOf( before.at( i ) );
5656 : 0 : while ( index >= 0 )
5657 : : {
5658 : 0 : list.replace( index, after.at( isSingleReplacement ? 0 : i ) );
5659 : 0 : index = list.indexOf( before.at( i ) );
5660 : : }
5661 : 0 : }
5662 : :
5663 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5664 : 0 : }
5665 : : else
5666 : : {
5667 : 0 : parent->setEvalErrorString( QObject::tr( "Function array_replace requires 2 or 3 arguments" ) );
5668 : 0 : return QVariant();
5669 : : }
5670 : 0 : }
5671 : :
5672 : 0 : static QVariant fcnArrayPrioritize( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5673 : : {
5674 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5675 : 0 : QVariantList list_new;
5676 : :
5677 : 0 : for ( const QVariant &cur : QgsExpressionUtils::getListValue( values.at( 1 ), parent ) )
5678 : : {
5679 : 0 : while ( list.removeOne( cur ) )
5680 : : {
5681 : 0 : list_new.append( cur );
5682 : : }
5683 : : }
5684 : :
5685 : 0 : list_new.append( list );
5686 : :
5687 : 0 : return convertToSameType( list_new, values.at( 0 ).type() );
5688 : 0 : }
5689 : :
5690 : 0 : static QVariant fcnArrayCat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5691 : : {
5692 : 0 : QVariantList list;
5693 : 0 : for ( const QVariant &cur : values )
5694 : : {
5695 : 0 : list += QgsExpressionUtils::getListValue( cur, parent );
5696 : : }
5697 : 0 : return convertToSameType( list, values.at( 0 ).type() );
5698 : 0 : }
5699 : :
5700 : 0 : static QVariant fcnArraySlice( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5701 : : {
5702 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5703 : 0 : int start_pos = QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent );
5704 : 0 : const int end_pos = QgsExpressionUtils::getNativeIntValue( values.at( 2 ), parent );
5705 : 0 : int slice_length = 0;
5706 : : // negative positions means positions taken relative to the end of the array
5707 : 0 : if ( start_pos < 0 )
5708 : : {
5709 : 0 : start_pos = list.length() + start_pos;
5710 : 0 : }
5711 : 0 : if ( end_pos >= 0 )
5712 : : {
5713 : 0 : slice_length = end_pos - start_pos + 1;
5714 : 0 : }
5715 : : else
5716 : : {
5717 : 0 : slice_length = list.length() + end_pos - start_pos + 1;
5718 : : }
5719 : : //avoid negative lengths in QList.mid function
5720 : 0 : if ( slice_length < 0 )
5721 : : {
5722 : 0 : slice_length = 0;
5723 : 0 : }
5724 : 0 : list = list.mid( start_pos, slice_length );
5725 : 0 : return list;
5726 : 0 : }
5727 : :
5728 : 0 : static QVariant fcnArrayReverse( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5729 : : {
5730 : 0 : QVariantList list = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5731 : 0 : std::reverse( list.begin(), list.end() );
5732 : 0 : return list;
5733 : 0 : }
5734 : :
5735 : 0 : static QVariant fcnArrayIntersect( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5736 : : {
5737 : 0 : const QVariantList array1 = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5738 : 0 : const QVariantList array2 = QgsExpressionUtils::getListValue( values.at( 1 ), parent );
5739 : 0 : for ( const QVariant &cur : array2 )
5740 : : {
5741 : 0 : if ( array1.contains( cur ) )
5742 : 0 : return QVariant( true );
5743 : : }
5744 : 0 : return QVariant( false );
5745 : 0 : }
5746 : :
5747 : 0 : static QVariant fcnArrayDistinct( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5748 : : {
5749 : 0 : QVariantList array = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5750 : :
5751 : 0 : QVariantList distinct;
5752 : :
5753 : 0 : for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
5754 : : {
5755 : 0 : if ( !distinct.contains( *it ) )
5756 : : {
5757 : 0 : distinct += ( *it );
5758 : 0 : }
5759 : 0 : }
5760 : :
5761 : 0 : return distinct;
5762 : 0 : }
5763 : :
5764 : 0 : static QVariant fcnArrayToString( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5765 : : {
5766 : 0 : QVariantList array = QgsExpressionUtils::getListValue( values.at( 0 ), parent );
5767 : 0 : QString delimiter = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5768 : 0 : QString empty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
5769 : :
5770 : 0 : QString str;
5771 : :
5772 : 0 : for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
5773 : : {
5774 : 0 : str += ( !( *it ).toString().isEmpty() ) ? ( *it ).toString() : empty;
5775 : 0 : if ( it != ( array.constEnd() - 1 ) )
5776 : : {
5777 : 0 : str += delimiter;
5778 : 0 : }
5779 : 0 : }
5780 : :
5781 : 0 : return QVariant( str );
5782 : 0 : }
5783 : :
5784 : 0 : static QVariant fcnStringToArray( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5785 : : {
5786 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5787 : 0 : QString delimiter = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
5788 : 0 : QString empty = QgsExpressionUtils::getStringValue( values.at( 2 ), parent );
5789 : :
5790 : 0 : QStringList list = str.split( delimiter );
5791 : 0 : QVariantList array;
5792 : :
5793 : 0 : for ( QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
5794 : : {
5795 : 0 : array += ( !( *it ).isEmpty() ) ? *it : empty;
5796 : 0 : }
5797 : :
5798 : 0 : return array;
5799 : 0 : }
5800 : :
5801 : 0 : static QVariant fcnLoadJson( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5802 : : {
5803 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5804 : 0 : QJsonDocument document = QJsonDocument::fromJson( str.toUtf8() );
5805 : 0 : if ( document.isNull() )
5806 : 0 : return QVariant();
5807 : :
5808 : 0 : return document.toVariant();
5809 : 0 : }
5810 : :
5811 : 0 : static QVariant fcnWriteJson( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5812 : : {
5813 : : Q_UNUSED( parent )
5814 : 0 : QJsonDocument document = QJsonDocument::fromVariant( values.at( 0 ) );
5815 : 0 : return document.toJson( QJsonDocument::Compact );
5816 : 0 : }
5817 : :
5818 : 0 : static QVariant fcnHstoreToMap( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5819 : : {
5820 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5821 : 0 : if ( str.isEmpty() )
5822 : 0 : return QVariantMap();
5823 : 0 : str = str.trimmed();
5824 : :
5825 : 0 : return QgsHstoreUtils::parse( str );
5826 : 0 : }
5827 : :
5828 : 0 : static QVariant fcnMapToHstore( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5829 : : {
5830 : 0 : QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
5831 : 0 : return QgsHstoreUtils::build( map );
5832 : 0 : }
5833 : :
5834 : 0 : static QVariant fcnMap( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5835 : : {
5836 : 0 : QVariantMap result;
5837 : 0 : for ( int i = 0; i + 1 < values.length(); i += 2 )
5838 : : {
5839 : 0 : result.insert( QgsExpressionUtils::getStringValue( values.at( i ), parent ), values.at( i + 1 ) );
5840 : 0 : }
5841 : 0 : return result;
5842 : 0 : }
5843 : :
5844 : 0 : static QVariant fcnMapGet( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5845 : : {
5846 : 0 : return QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).value( values.at( 1 ).toString() );
5847 : 0 : }
5848 : :
5849 : 0 : static QVariant fcnMapExist( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5850 : : {
5851 : 0 : return QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).contains( values.at( 1 ).toString() );
5852 : 0 : }
5853 : :
5854 : 0 : static QVariant fcnMapDelete( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5855 : : {
5856 : 0 : QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
5857 : 0 : map.remove( values.at( 1 ).toString() );
5858 : 0 : return map;
5859 : 0 : }
5860 : :
5861 : 0 : static QVariant fcnMapInsert( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5862 : : {
5863 : 0 : QVariantMap map = QgsExpressionUtils::getMapValue( values.at( 0 ), parent );
5864 : 0 : map.insert( values.at( 1 ).toString(), values.at( 2 ) );
5865 : 0 : return map;
5866 : 0 : }
5867 : :
5868 : 0 : static QVariant fcnMapConcat( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5869 : : {
5870 : 0 : QVariantMap result;
5871 : 0 : for ( const QVariant &cur : values )
5872 : : {
5873 : 0 : const QVariantMap curMap = QgsExpressionUtils::getMapValue( cur, parent );
5874 : 0 : for ( QVariantMap::const_iterator it = curMap.constBegin(); it != curMap.constEnd(); ++it )
5875 : 0 : result.insert( it.key(), it.value() );
5876 : 0 : }
5877 : 0 : return result;
5878 : 0 : }
5879 : :
5880 : 0 : static QVariant fcnMapAKeys( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5881 : : {
5882 : 0 : return QStringList( QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).keys() );
5883 : 0 : }
5884 : :
5885 : 0 : static QVariant fcnMapAVals( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5886 : : {
5887 : 0 : return QgsExpressionUtils::getMapValue( values.at( 0 ), parent ).values();
5888 : 0 : }
5889 : :
5890 : 0 : static QVariant fcnEnvVar( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
5891 : : {
5892 : 0 : QString envVarName = values.at( 0 ).toString();
5893 : 0 : return QProcessEnvironment::systemEnvironment().value( envVarName );
5894 : 0 : }
5895 : :
5896 : 0 : static QVariant fcnBaseFileName( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5897 : : {
5898 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5899 : 0 : return QFileInfo( file ).completeBaseName();
5900 : 0 : }
5901 : :
5902 : 0 : static QVariant fcnFileSuffix( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5903 : : {
5904 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5905 : 0 : return QFileInfo( file ).completeSuffix();
5906 : 0 : }
5907 : :
5908 : 0 : static QVariant fcnFileExists( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5909 : : {
5910 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5911 : 0 : return QFileInfo::exists( file );
5912 : 0 : }
5913 : :
5914 : 0 : static QVariant fcnFileName( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5915 : : {
5916 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5917 : 0 : return QFileInfo( file ).fileName();
5918 : 0 : }
5919 : :
5920 : 0 : static QVariant fcnPathIsFile( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5921 : : {
5922 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5923 : 0 : return QFileInfo( file ).isFile();
5924 : 0 : }
5925 : :
5926 : 0 : static QVariant fcnPathIsDir( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5927 : : {
5928 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5929 : 0 : return QFileInfo( file ).isDir();
5930 : 0 : }
5931 : :
5932 : 0 : static QVariant fcnFilePath( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5933 : : {
5934 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5935 : 0 : return QDir::toNativeSeparators( QFileInfo( file ).path() );
5936 : 0 : }
5937 : :
5938 : 0 : static QVariant fcnFileSize( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5939 : : {
5940 : 0 : const QString file = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5941 : 0 : return QFileInfo( file ).size();
5942 : 0 : }
5943 : :
5944 : 0 : static QVariant fcnHash( const QString str, const QCryptographicHash::Algorithm algorithm )
5945 : : {
5946 : 0 : return QString( QCryptographicHash::hash( str.toUtf8(), algorithm ).toHex() );
5947 : 0 : }
5948 : :
5949 : 0 : static QVariant fcnGenericHash( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
5950 : : {
5951 : 0 : QVariant hash;
5952 : 0 : QString str = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
5953 : 0 : QString method = QgsExpressionUtils::getStringValue( values.at( 1 ), parent ).toLower();
5954 : :
5955 : 0 : if ( method == QLatin1String( "md4" ) )
5956 : : {
5957 : 0 : hash = fcnHash( str, QCryptographicHash::Md4 );
5958 : 0 : }
5959 : 0 : else if ( method == QLatin1String( "md5" ) )
5960 : : {
5961 : 0 : hash = fcnHash( str, QCryptographicHash::Md5 );
5962 : 0 : }
5963 : 0 : else if ( method == QLatin1String( "sha1" ) )
5964 : : {
5965 : 0 : hash = fcnHash( str, QCryptographicHash::Sha1 );
5966 : 0 : }
5967 : 0 : else if ( method == QLatin1String( "sha224" ) )
5968 : : {
5969 : 0 : hash = fcnHash( str, QCryptographicHash::Sha224 );
5970 : 0 : }
5971 : 0 : else if ( method == QLatin1String( "sha256" ) )
5972 : : {
5973 : 0 : hash = fcnHash( str, QCryptographicHash::Sha256 );
5974 : 0 : }
5975 : 0 : else if ( method == QLatin1String( "sha384" ) )
5976 : : {
5977 : 0 : hash = fcnHash( str, QCryptographicHash::Sha384 );
5978 : 0 : }
5979 : 0 : else if ( method == QLatin1String( "sha512" ) )
5980 : : {
5981 : 0 : hash = fcnHash( str, QCryptographicHash::Sha512 );
5982 : 0 : }
5983 : 0 : else if ( method == QLatin1String( "sha3_224" ) )
5984 : : {
5985 : 0 : hash = fcnHash( str, QCryptographicHash::Sha3_224 );
5986 : 0 : }
5987 : 0 : else if ( method == QLatin1String( "sha3_256" ) )
5988 : : {
5989 : 0 : hash = fcnHash( str, QCryptographicHash::Sha3_256 );
5990 : 0 : }
5991 : 0 : else if ( method == QLatin1String( "sha3_384" ) )
5992 : : {
5993 : 0 : hash = fcnHash( str, QCryptographicHash::Sha3_384 );
5994 : 0 : }
5995 : 0 : else if ( method == QLatin1String( "sha3_512" ) )
5996 : : {
5997 : 0 : hash = fcnHash( str, QCryptographicHash::Sha3_512 );
5998 : 0 : }
5999 : 0 : else if ( method == QLatin1String( "keccak_224" ) )
6000 : : {
6001 : 0 : hash = fcnHash( str, QCryptographicHash::Keccak_224 );
6002 : 0 : }
6003 : 0 : else if ( method == QLatin1String( "keccak_256" ) )
6004 : : {
6005 : 0 : hash = fcnHash( str, QCryptographicHash::Keccak_256 );
6006 : 0 : }
6007 : 0 : else if ( method == QLatin1String( "keccak_384" ) )
6008 : : {
6009 : 0 : hash = fcnHash( str, QCryptographicHash::Keccak_384 );
6010 : 0 : }
6011 : 0 : else if ( method == QLatin1String( "keccak_512" ) )
6012 : : {
6013 : 0 : hash = fcnHash( str, QCryptographicHash::Keccak_512 );
6014 : 0 : }
6015 : : else
6016 : : {
6017 : 0 : parent->setEvalErrorString( QObject::tr( "Hash method %1 is not available on this system." ).arg( str ) );
6018 : : }
6019 : 0 : return hash;
6020 : 0 : }
6021 : :
6022 : 0 : static QVariant fcnHashMd5( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
6023 : : {
6024 : 0 : return fcnHash( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), QCryptographicHash::Md5 );
6025 : 0 : }
6026 : :
6027 : 0 : static QVariant fcnHashSha256( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
6028 : : {
6029 : 0 : return fcnHash( QgsExpressionUtils::getStringValue( values.at( 0 ), parent ), QCryptographicHash::Sha256 );
6030 : 0 : }
6031 : :
6032 : 0 : static QVariant fcnToBase64( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
6033 : : {
6034 : 0 : const QByteArray input = values.at( 0 ).toByteArray();
6035 : 0 : return QVariant( QString( input.toBase64() ) );
6036 : 0 : }
6037 : :
6038 : 0 : static QVariant fcnFromBase64( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
6039 : : {
6040 : 0 : const QString value = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
6041 : 0 : const QByteArray base64 = value.toLocal8Bit();
6042 : 0 : const QByteArray decoded = QByteArray::fromBase64( base64 );
6043 : 0 : return QVariant( decoded );
6044 : 0 : }
6045 : :
6046 : : typedef bool ( QgsGeometry::*RelationFunction )( const QgsGeometry &geometry ) const;
6047 : :
6048 : 0 : static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const RelationFunction &relationFunction, bool invert = false, double bboxGrow = 0, bool isNearestFunc = false )
6049 : : {
6050 : :
6051 : 0 : const QVariant sourceLayerRef = context->variable( QStringLiteral( "layer" ) ); //used to detect if sourceLayer and targetLayer are the same
6052 : 0 : QgsVectorLayer *sourceLayer = QgsExpressionUtils::getVectorLayer( sourceLayerRef, parent );
6053 : :
6054 : 0 : QgsFeatureRequest request;
6055 : 0 : request.setTimeout( 10000 );
6056 : 0 : request.setRequestMayBeNested( true );
6057 : :
6058 : : // First parameter is the overlay layer
6059 : 0 : QgsExpressionNode *node = QgsExpressionUtils::getNode( values.at( 0 ), parent );
6060 : 0 : ENSURE_NO_EVAL_ERROR
6061 : :
6062 : 0 : const bool layerCanBeCached = node->isStatic( parent, context );
6063 : 0 : QVariant targetLayerValue = node->eval( parent, context );
6064 : 0 : ENSURE_NO_EVAL_ERROR
6065 : :
6066 : : // Second parameter is the expression to evaluate (or null for testonly)
6067 : 0 : node = QgsExpressionUtils::getNode( values.at( 1 ), parent );
6068 : 0 : ENSURE_NO_EVAL_ERROR
6069 : 0 : QString subExpString = node->dump();
6070 : :
6071 : 0 : bool testOnly = ( subExpString == "NULL" );
6072 : 0 : QgsVectorLayer *targetLayer = QgsExpressionUtils::getVectorLayer( targetLayerValue, parent );
6073 : 0 : if ( !targetLayer ) // No layer, no joy
6074 : : {
6075 : 0 : parent->setEvalErrorString( QObject::tr( "Layer '%1' could not be loaded." ).arg( targetLayerValue.toString() ) );
6076 : 0 : return QVariant();
6077 : : }
6078 : :
6079 : : // Third parameter is the filtering expression
6080 : 0 : node = QgsExpressionUtils::getNode( values.at( 2 ), parent );
6081 : 0 : ENSURE_NO_EVAL_ERROR
6082 : 0 : QString filterString = node->dump();
6083 : 0 : if ( filterString != "NULL" )
6084 : : {
6085 : 0 : request.setFilterExpression( filterString ); //filter cached features
6086 : 0 : }
6087 : :
6088 : : // Fourth parameter is the limit
6089 : 0 : node = QgsExpressionUtils::getNode( values.at( 3 ), parent ); //in expressions overlay functions throw the exception: Eval Error: Cannot convert '' to int
6090 : 0 : ENSURE_NO_EVAL_ERROR
6091 : 0 : QVariant limitValue = node->eval( parent, context );
6092 : 0 : ENSURE_NO_EVAL_ERROR
6093 : 0 : qlonglong limit = QgsExpressionUtils::getIntValue( limitValue, parent );
6094 : :
6095 : : // Fifth parameter (for nearest only) is the max distance
6096 : 0 : double max_distance = 0;
6097 : 0 : if ( isNearestFunc ) //maxdistance param handling
6098 : : {
6099 : 0 : node = QgsExpressionUtils::getNode( values.at( 4 ), parent );
6100 : 0 : ENSURE_NO_EVAL_ERROR
6101 : 0 : QVariant distanceValue = node->eval( parent, context );
6102 : 0 : ENSURE_NO_EVAL_ERROR
6103 : 0 : max_distance = QgsExpressionUtils::getDoubleValue( distanceValue, parent );
6104 : 0 : }
6105 : :
6106 : : // Fifth or sixth (for nearest only) parameter is the cache toggle
6107 : 0 : node = QgsExpressionUtils::getNode( values.at( isNearestFunc ? 5 : 4 ), parent );
6108 : 0 : ENSURE_NO_EVAL_ERROR
6109 : 0 : QVariant cacheValue = node->eval( parent, context );
6110 : 0 : ENSURE_NO_EVAL_ERROR
6111 : 0 : bool cacheEnabled = cacheValue.toBool();
6112 : :
6113 : :
6114 : 0 : FEAT_FROM_CONTEXT( context, feat )
6115 : 0 : const QgsGeometry geometry = feat.geometry();
6116 : :
6117 : 0 : if ( sourceLayer && targetLayer->crs() != sourceLayer->crs() )
6118 : : {
6119 : 0 : QgsCoordinateTransformContext TransformContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
6120 : 0 : request.setDestinationCrs( sourceLayer->crs(), TransformContext ); //if crs are not the same, cached target will be reprojected to source crs
6121 : 0 : }
6122 : :
6123 : 0 : bool sameLayers = ( sourceLayer && sourceLayer->id() == targetLayer->id() );
6124 : :
6125 : 0 : QgsRectangle intDomain = geometry.boundingBox();
6126 : 0 : if ( bboxGrow != 0 )
6127 : : {
6128 : 0 : intDomain.grow( bboxGrow ); //optional parameter to enlarge boundary context for touches and equals methods
6129 : 0 : }
6130 : :
6131 : 0 : const QString cacheBase { QStringLiteral( "%1:%2" ).arg( targetLayer->id(), subExpString ) };
6132 : :
6133 : : // Cache (a local spatial index) is always enabled for nearest function (as we need QgsSpatialIndex::nearestNeighbor)
6134 : : // Otherwise, it can be toggled by the user
6135 : 0 : QgsSpatialIndex spatialIndex;
6136 : : QgsVectorLayer *cachedTarget;
6137 : 0 : QList<QgsFeature> features;
6138 : 0 : if ( isNearestFunc || ( layerCanBeCached && cacheEnabled ) )
6139 : : {
6140 : : // If the cache (local spatial index) is enabled, we materialize the whole
6141 : : // layer, then do the request on that layer instead.
6142 : 0 : const QString cacheLayer { QStringLiteral( "ovrlaylyr:%1" ).arg( cacheBase ) };
6143 : 0 : const QString cacheIndex { QStringLiteral( "ovrlayidx:%1" ).arg( cacheBase ) };
6144 : :
6145 : 0 : if ( !context->hasCachedValue( cacheLayer ) ) // should check for same crs. if not the same we could think to reproject target layer before charging cache
6146 : : {
6147 : 0 : cachedTarget = targetLayer->materialize( request );
6148 : 0 : if ( layerCanBeCached )
6149 : 0 : context->setCachedValue( cacheLayer, QVariant::fromValue( cachedTarget ) );
6150 : 0 : }
6151 : : else
6152 : : {
6153 : 0 : cachedTarget = context->cachedValue( cacheLayer ).value<QgsVectorLayer *>();
6154 : : }
6155 : :
6156 : 0 : if ( !context->hasCachedValue( cacheIndex ) )
6157 : : {
6158 : 0 : spatialIndex = QgsSpatialIndex( cachedTarget->getFeatures(), nullptr, QgsSpatialIndex::FlagStoreFeatureGeometries );
6159 : 0 : if ( layerCanBeCached )
6160 : 0 : context->setCachedValue( cacheIndex, QVariant::fromValue( spatialIndex ) );
6161 : 0 : }
6162 : : else
6163 : : {
6164 : 0 : spatialIndex = context->cachedValue( cacheIndex ).value<QgsSpatialIndex>();
6165 : : }
6166 : :
6167 : 0 : QList<QgsFeatureId> fidsList;
6168 : 0 : if ( isNearestFunc )
6169 : : {
6170 : 0 : fidsList = spatialIndex.nearestNeighbor( geometry, sameLayers ? limit + 1 : limit, max_distance );
6171 : 0 : }
6172 : : else
6173 : : {
6174 : 0 : fidsList = spatialIndex.intersects( intDomain );
6175 : : }
6176 : :
6177 : 0 : QListIterator<QgsFeatureId> i( fidsList );
6178 : 0 : while ( i.hasNext() )
6179 : : {
6180 : 0 : QgsFeatureId fId2 = i.next();
6181 : 0 : if ( sameLayers && feat.id() == fId2 )
6182 : 0 : continue;
6183 : 0 : features.append( cachedTarget->getFeature( fId2 ) );
6184 : : }
6185 : :
6186 : 0 : }
6187 : : else
6188 : : {
6189 : : // If the cache (local spatial index) is not enabled, we directly
6190 : : // get the features from the target layer
6191 : 0 : request.setFilterRect( intDomain );
6192 : 0 : QgsFeatureIterator fit = targetLayer->getFeatures( request );
6193 : 0 : QgsFeature feat2;
6194 : 0 : while ( fit.nextFeature( feat2 ) )
6195 : : {
6196 : 0 : if ( sameLayers && feat.id() == feat2.id() )
6197 : 0 : continue;
6198 : 0 : features.append( feat2 );
6199 : : }
6200 : 0 : }
6201 : :
6202 : 0 : QgsExpression subExpression;
6203 : 0 : QgsExpressionContext subContext;
6204 : 0 : if ( !testOnly )
6205 : : {
6206 : 0 : const QString expCacheKey { QStringLiteral( "exp:%1" ).arg( cacheBase ) };
6207 : 0 : const QString ctxCacheKey { QStringLiteral( "ctx:%1" ).arg( cacheBase ) };
6208 : :
6209 : 0 : if ( !context->hasCachedValue( expCacheKey ) || !context->hasCachedValue( ctxCacheKey ) )
6210 : : {
6211 : 0 : subExpression = QgsExpression( subExpString );
6212 : 0 : subContext = QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( targetLayer ) );
6213 : 0 : subExpression.prepare( &subContext );
6214 : 0 : }
6215 : : else
6216 : : {
6217 : 0 : subExpression = context->cachedValue( expCacheKey ).value<QgsExpression>();
6218 : 0 : subContext = context->cachedValue( ctxCacheKey ).value<QgsExpressionContext>();
6219 : : }
6220 : 0 : }
6221 : :
6222 : :
6223 : 0 : bool found = false;
6224 : 0 : int foundCount = 0;
6225 : 0 : QVariantList results;
6226 : :
6227 : 0 : QListIterator<QgsFeature> i( features );
6228 : 0 : while ( i.hasNext() && ( limit == -1 || foundCount < limit ) )
6229 : : {
6230 : 0 : QgsFeature feat2 = i.next();
6231 : :
6232 : 0 : if ( ! relationFunction || ( geometry.*relationFunction )( feat2.geometry() ) ) // Calls the method provided as template argument for the function (e.g. QgsGeometry::intersects)
6233 : : {
6234 : 0 : found = true;
6235 : 0 : foundCount++;
6236 : :
6237 : : // We just want a single boolean result if there is any intersect: finish and return true
6238 : 0 : if ( testOnly )
6239 : 0 : break;
6240 : :
6241 : 0 : if ( !invert )
6242 : : {
6243 : : // We want a list of attributes / geometries / other expression values, evaluate now
6244 : 0 : subContext.setFeature( feat2 );
6245 : 0 : results.append( subExpression.evaluate( &subContext ) );
6246 : 0 : }
6247 : : else
6248 : : {
6249 : : // If not, results is a list of found ids, which we'll inverse and evaluate below
6250 : 0 : results.append( feat2.id() );
6251 : : }
6252 : 0 : }
6253 : 0 : }
6254 : :
6255 : 0 : if ( testOnly )
6256 : : {
6257 : 0 : if ( invert )
6258 : 0 : found = !found;//for disjoint condition
6259 : 0 : return found;
6260 : : }
6261 : :
6262 : 0 : if ( !invert )
6263 : 0 : return results;
6264 : :
6265 : : // for disjoint condition returns the results for cached layers not intersected feats
6266 : 0 : QVariantList disjoint_results;
6267 : 0 : QgsFeature feat2;
6268 : 0 : QgsFeatureRequest request2;
6269 : 0 : request2.setLimit( limit );
6270 : 0 : QgsFeatureIterator fi = targetLayer->getFeatures( request2 );
6271 : 0 : while ( fi.nextFeature( feat2 ) )
6272 : : {
6273 : 0 : if ( !results.contains( feat2.id() ) )
6274 : : {
6275 : 0 : subContext.setFeature( feat2 );
6276 : 0 : disjoint_results.append( subExpression.evaluate( &subContext ) );
6277 : 0 : }
6278 : : }
6279 : 0 : return disjoint_results;
6280 : :
6281 : 0 : }
6282 : :
6283 : : // Intersect functions:
6284 : :
6285 : 0 : static QVariant fcnGeomOverlayIntersects( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6286 : : {
6287 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::intersects );
6288 : : }
6289 : :
6290 : 0 : static QVariant fcnGeomOverlayContains( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6291 : : {
6292 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::contains );
6293 : : }
6294 : :
6295 : 0 : static QVariant fcnGeomOverlayCrosses( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6296 : : {
6297 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::crosses );
6298 : : }
6299 : :
6300 : 0 : static QVariant fcnGeomOverlayEquals( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6301 : : {
6302 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::equals, false, 0.01 ); //grow amount should adapt to current units
6303 : : }
6304 : :
6305 : 0 : static QVariant fcnGeomOverlayTouches( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6306 : : {
6307 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::touches, false, 0.01 ); //grow amount should adapt to current units
6308 : : }
6309 : :
6310 : 0 : static QVariant fcnGeomOverlayWithin( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6311 : : {
6312 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::within );
6313 : : }
6314 : :
6315 : 0 : static QVariant fcnGeomOverlayDisjoint( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6316 : : {
6317 : 0 : return executeGeomOverlay( values, context, parent, &QgsGeometry::intersects, true );
6318 : : }
6319 : :
6320 : 0 : static QVariant fcnGeomOverlayNearest( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
6321 : : {
6322 : 0 : return executeGeomOverlay( values, context, parent, nullptr, false, 0, true );
6323 : : }
6324 : :
6325 : 0 : const QList<QgsExpressionFunction *> &QgsExpression::Functions()
6326 : : {
6327 : : // The construction of the list isn't thread-safe, and without the mutex,
6328 : : // crashes in the WFS provider may occur, since it can parse expressions
6329 : : // in parallel.
6330 : : // The mutex needs to be recursive.
6331 : 0 : static QMutex sFunctionsMutex( QMutex::Recursive );
6332 : 0 : QMutexLocker locker( &sFunctionsMutex );
6333 : :
6334 : 0 : QList<QgsExpressionFunction *> &functions = *sFunctions();
6335 : :
6336 : 0 : if ( functions.isEmpty() )
6337 : : {
6338 : 0 : QgsExpressionFunction::ParameterList aggParams = QgsExpressionFunction::ParameterList()
6339 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) )
6340 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "group_by" ), true )
6341 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true );
6342 : :
6343 : 0 : QgsExpressionFunction::ParameterList aggParamsConcat = aggParams;
6344 : 0 : aggParamsConcat << QgsExpressionFunction::Parameter( QStringLiteral( "concatenator" ), true )
6345 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true );
6346 : :
6347 : 0 : QgsExpressionFunction::ParameterList aggParamsArray = aggParams;
6348 : 0 : aggParamsArray << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true );
6349 : :
6350 : 0 : functions
6351 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "sqrt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnSqrt, QStringLiteral( "Math" ) )
6352 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "radians" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "degrees" ) ), fcnRadians, QStringLiteral( "Math" ) )
6353 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "degrees" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "radians" ) ), fcnDegrees, QStringLiteral( "Math" ) )
6354 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "azimuth" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point_b" ) ), fcnAzimuth, QStringList() << QStringLiteral( "Math" ) << QStringLiteral( "GeometryGroup" ) )
6355 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "inclination" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point_b" ) ), fcnInclination, QStringList() << QStringLiteral( "Math" ) << QStringLiteral( "GeometryGroup" ) )
6356 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "project" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "elevation" ), true, M_PI_2 ), fcnProject, QStringLiteral( "GeometryGroup" ) )
6357 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "abs" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAbs, QStringLiteral( "Math" ) )
6358 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "cos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "angle" ) ), fcnCos, QStringLiteral( "Math" ) )
6359 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "sin" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "angle" ) ), fcnSin, QStringLiteral( "Math" ) )
6360 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "tan" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "angle" ) ), fcnTan, QStringLiteral( "Math" ) )
6361 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "asin" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAsin, QStringLiteral( "Math" ) )
6362 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "acos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAcos, QStringLiteral( "Math" ) )
6363 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "atan" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnAtan, QStringLiteral( "Math" ) )
6364 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "atan2" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "dx" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "dy" ) ), fcnAtan2, QStringLiteral( "Math" ) )
6365 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "exp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnExp, QStringLiteral( "Math" ) )
6366 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "ln" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLn, QStringLiteral( "Math" ) )
6367 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "log10" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLog10, QStringLiteral( "Math" ) )
6368 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "log" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "base" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLog, QStringLiteral( "Math" ) )
6369 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "round" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "places" ), true, 0 ), fcnRound, QStringLiteral( "Math" ) );
6370 : :
6371 : 0 : QgsStaticExpressionFunction *randFunc = new QgsStaticExpressionFunction( QStringLiteral( "rand" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "max" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "seed" ), true ), fcnRnd, QStringLiteral( "Math" ) );
6372 : 0 : randFunc->setIsStatic( false );
6373 : 0 : functions << randFunc;
6374 : :
6375 : 0 : QgsStaticExpressionFunction *randfFunc = new QgsStaticExpressionFunction( QStringLiteral( "randf" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "min" ), true, 0.0 ) << QgsExpressionFunction::Parameter( QStringLiteral( "max" ), true, 1.0 ) << QgsExpressionFunction::Parameter( QStringLiteral( "seed" ), true ), fcnRndF, QStringLiteral( "Math" ) );
6376 : 0 : randfFunc->setIsStatic( false );
6377 : 0 : functions << randfFunc;
6378 : :
6379 : 0 : functions
6380 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "max" ), -1, fcnMax, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList(), /* handlesNull = */ true )
6381 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "min" ), -1, fcnMin, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList(), /* handlesNull = */ true )
6382 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "clamp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "max" ) ), fcnClamp, QStringLiteral( "Math" ) )
6383 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "scale_linear" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "domain_min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "domain_max" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "range_min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "range_max" ) ), fcnLinearScale, QStringLiteral( "Math" ) )
6384 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "scale_exp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "domain_min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "domain_max" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "range_min" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "range_max" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "exponent" ) ), fcnExpScale, QStringLiteral( "Math" ) )
6385 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "floor" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnFloor, QStringLiteral( "Math" ) )
6386 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "ceil" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnCeil, QStringLiteral( "Math" ) )
6387 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "pi" ), 0, fcnPi, QStringLiteral( "Math" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$pi" ) )
6388 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_int" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToInt, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toint" ) )
6389 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_real" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToReal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "toreal" ) )
6390 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_string" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToString, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tostring" ) )
6391 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_datetime" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "format" ), true, QVariant() ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnToDateTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todatetime" ) )
6392 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "format" ), true, QVariant() ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnToDate, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todate" ) )
6393 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_time" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "format" ), true, QVariant() ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnToTime, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "totime" ) )
6394 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_interval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToInterval, QStringList() << QStringLiteral( "Conversions" ) << QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "tointerval" ) )
6395 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_dm" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinute, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todm" ) )
6396 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_dms" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "axis" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "formatting" ), true ), fcnToDegreeMinuteSecond, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todms" ) )
6397 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_decimal" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnToDecimal, QStringLiteral( "Conversions" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "todecimal" ) )
6398 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "coalesce" ), -1, fcnCoalesce, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6399 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "nullif" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value2" ) ), fcnNullIf, QStringLiteral( "Conditionals" ) )
6400 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "if" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "condition" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "result_when_true" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "result_when_false" ) ), fcnIf, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )
6401 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "try" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "alternative" ), true, QVariant() ), fcnTry, QStringLiteral( "Conditionals" ), QString(), false, QSet<QString>(), true )
6402 : :
6403 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "aggregate" ),
6404 : 0 : QgsExpressionFunction::ParameterList()
6405 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6406 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "aggregate" ) )
6407 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), false, QVariant(), true )
6408 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true, QVariant(), true )
6409 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "concatenator" ), true )
6410 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true ),
6411 : : fcnAggregate,
6412 : 0 : QStringLiteral( "Aggregates" ),
6413 : 0 : QString(),
6414 : 0 : []( const QgsExpressionNodeFunction * node )
6415 : : {
6416 : : // usesGeometry callback: return true if @parent variable is referenced
6417 : :
6418 : 0 : if ( !node )
6419 : 0 : return true;
6420 : :
6421 : 0 : if ( !node->args() )
6422 : 0 : return false;
6423 : :
6424 : 0 : QSet<QString> referencedVars;
6425 : 0 : if ( node->args()->count() > 2 )
6426 : : {
6427 : 0 : QgsExpressionNode *subExpressionNode = node->args()->at( 2 );
6428 : 0 : referencedVars = subExpressionNode->referencedVariables();
6429 : 0 : }
6430 : :
6431 : 0 : if ( node->args()->count() > 3 )
6432 : : {
6433 : 0 : QgsExpressionNode *filterNode = node->args()->at( 3 );
6434 : 0 : referencedVars.unite( filterNode->referencedVariables() );
6435 : 0 : }
6436 : 0 : return referencedVars.contains( QStringLiteral( "parent" ) ) || referencedVars.contains( QString() );
6437 : 0 : },
6438 : 0 : []( const QgsExpressionNodeFunction * node )
6439 : : {
6440 : : // referencedColumns callback: return AllAttributes if @parent variable is referenced
6441 : :
6442 : 0 : if ( !node )
6443 : 0 : return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
6444 : :
6445 : 0 : if ( !node->args() )
6446 : 0 : return QSet<QString>();
6447 : :
6448 : 0 : QSet<QString> referencedCols;
6449 : 0 : QSet<QString> referencedVars;
6450 : :
6451 : 0 : if ( node->args()->count() > 2 )
6452 : : {
6453 : 0 : QgsExpressionNode *subExpressionNode = node->args()->at( 2 );
6454 : 0 : referencedVars = subExpressionNode->referencedVariables();
6455 : 0 : referencedCols = subExpressionNode->referencedColumns();
6456 : 0 : }
6457 : 0 : if ( node->args()->count() > 3 )
6458 : : {
6459 : 0 : QgsExpressionNode *filterNode = node->args()->at( 3 );
6460 : 0 : referencedVars = filterNode->referencedVariables();
6461 : 0 : referencedCols.unite( filterNode->referencedColumns() );
6462 : 0 : }
6463 : :
6464 : 0 : if ( referencedVars.contains( QStringLiteral( "parent" ) ) || referencedVars.contains( QString() ) )
6465 : 0 : return QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES;
6466 : : else
6467 : 0 : return referencedCols;
6468 : 0 : },
6469 : : true
6470 : : )
6471 : :
6472 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "relation_aggregate" ), QgsExpressionFunction::ParameterList()
6473 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "relation" ) )
6474 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "aggregate" ) )
6475 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), false, QVariant(), true )
6476 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "concatenator" ), true )
6477 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "order_by" ), true, QVariant(), true ),
6478 : 0 : fcnAggregateRelation, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true )
6479 : :
6480 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "count" ), aggParams, fcnAggregateCount, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6481 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "count_distinct" ), aggParams, fcnAggregateCountDistinct, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6482 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "count_missing" ), aggParams, fcnAggregateCountMissing, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6483 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "minimum" ), aggParams, fcnAggregateMin, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6484 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "maximum" ), aggParams, fcnAggregateMax, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6485 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "sum" ), aggParams, fcnAggregateSum, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6486 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "mean" ), aggParams, fcnAggregateMean, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6487 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "median" ), aggParams, fcnAggregateMedian, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6488 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "stdev" ), aggParams, fcnAggregateStdev, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6489 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "range" ), aggParams, fcnAggregateRange, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6490 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "minority" ), aggParams, fcnAggregateMinority, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6491 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "majority" ), aggParams, fcnAggregateMajority, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6492 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "q1" ), aggParams, fcnAggregateQ1, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6493 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "q3" ), aggParams, fcnAggregateQ3, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6494 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "iqr" ), aggParams, fcnAggregateIQR, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6495 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "min_length" ), aggParams, fcnAggregateMinLength, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6496 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "max_length" ), aggParams, fcnAggregateMaxLength, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6497 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "collect" ), aggParams, fcnAggregateCollectGeometry, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6498 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "concatenate" ), aggParamsConcat, fcnAggregateStringConcat, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6499 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "concatenate_unique" ), aggParamsConcat, fcnAggregateStringConcatUnique, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6500 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_agg" ), aggParamsArray, fcnAggregateArray, QStringLiteral( "Aggregates" ), QString(), false, QSet<QString>(), true )
6501 : :
6502 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "regexp_match" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ), fcnRegexpMatch, QStringList() << QStringLiteral( "Conditionals" ) << QStringLiteral( "String" ) )
6503 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "regexp_matches" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnRegexpMatches, QStringLiteral( "Arrays" ) )
6504 : :
6505 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "now" ), 0, fcnNow, QStringLiteral( "Date and Time" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$now" ) )
6506 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "age" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime1" ) )
6507 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "datetime2" ) ),
6508 : 0 : fcnAge, QStringLiteral( "Date and Time" ) )
6509 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "year" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnYear, QStringLiteral( "Date and Time" ) )
6510 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "month" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnMonth, QStringLiteral( "Date and Time" ) )
6511 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "week" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnWeek, QStringLiteral( "Date and Time" ) )
6512 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "day" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnDay, QStringLiteral( "Date and Time" ) )
6513 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "hour" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnHour, QStringLiteral( "Date and Time" ) )
6514 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "minute" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnMinute, QStringLiteral( "Date and Time" ) )
6515 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "second" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ), fcnSeconds, QStringLiteral( "Date and Time" ) )
6516 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "epoch" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnEpoch, QStringLiteral( "Date and Time" ) )
6517 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "datetime_from_epoch" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "long" ) ), fcnDateTimeFromEpoch, QStringLiteral( "Date and Time" ) )
6518 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "day_of_week" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "date" ) ), fcnDayOfWeek, QStringLiteral( "Date and Time" ) )
6519 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "year" ) )
6520 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "month" ) )
6521 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "day" ) ),
6522 : 0 : fcnMakeDate, QStringLiteral( "Date and Time" ) )
6523 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_time" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hour" ) )
6524 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "minute" ) )
6525 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "second" ) ),
6526 : 0 : fcnMakeTime, QStringLiteral( "Date and Time" ) )
6527 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_datetime" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "year" ) )
6528 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "month" ) )
6529 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "day" ) )
6530 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "hour" ) )
6531 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "minute" ) )
6532 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "second" ) ),
6533 : 0 : fcnMakeDateTime, QStringLiteral( "Date and Time" ) )
6534 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_interval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "years" ), true, 0 )
6535 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "months" ), true, 0 )
6536 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "weeks" ), true, 0 )
6537 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "days" ), true, 0 )
6538 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "hours" ), true, 0 )
6539 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "minutes" ), true, 0 )
6540 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "seconds" ), true, 0 ),
6541 : 0 : fcnMakeInterval, QStringLiteral( "Date and Time" ) )
6542 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "lower" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnLower, QStringLiteral( "String" ) )
6543 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "upper" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnUpper, QStringLiteral( "String" ) )
6544 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "title" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTitle, QStringLiteral( "String" ) )
6545 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "trim" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTrim, QStringLiteral( "String" ) )
6546 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "levenshtein" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnLevenshtein, QStringLiteral( "Fuzzy Matching" ) )
6547 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "longest_common_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnLCS, QStringLiteral( "Fuzzy Matching" ) )
6548 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "hamming_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "string2" ) ), fcnHamming, QStringLiteral( "Fuzzy Matching" ) )
6549 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "soundex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnSoundex, QStringLiteral( "Fuzzy Matching" ) )
6550 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "char" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "code" ) ), fcnChar, QStringLiteral( "String" ) )
6551 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "ascii" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnAscii, QStringLiteral( "String" ) )
6552 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "wordwrap" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "" ), fcnWordwrap, QStringLiteral( "String" ) )
6553 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "length" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ), true, "" ), fcnLength, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "GeometryGroup" ) )
6554 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "length3D" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnLength3D, QStringLiteral( "GeometryGroup" ) )
6555 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "replace" ), -1, fcnReplace, QStringLiteral( "String" ) )
6556 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "regexp_replace" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "input_string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) )
6557 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "replacement" ) ), fcnRegexpReplace, QStringLiteral( "String" ) )
6558 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "regexp_substr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "input_string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "regex" ) ), fcnRegexpSubstr, QStringLiteral( "String" ) )
6559 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "substr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "start " ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ), true ), fcnSubstr, QStringLiteral( "String" ), QString(),
6560 : 0 : false, QSet< QString >(), false, QStringList(), true )
6561 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "concat" ), -1, fcnConcat, QStringLiteral( "String" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6562 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "strpos" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "haystack" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "needle" ) ), fcnStrpos, QStringLiteral( "String" ) )
6563 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "left" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ), fcnLeft, QStringLiteral( "String" ) )
6564 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "right" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "length" ) ), fcnRight, QStringLiteral( "String" ) )
6565 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "rpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnRPad, QStringLiteral( "String" ) )
6566 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "lpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnLPad, QStringLiteral( "String" ) )
6567 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "format" ), -1, fcnFormatString, QStringLiteral( "String" ) )
6568 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "format_number" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "number" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "places" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatNumber, QStringLiteral( "String" ) )
6569 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "format_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "format" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatDate, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "Date and Time" ) )
6570 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_grayscale_average" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ), fcnColorGrayscaleAverage, QStringLiteral( "Color" ) )
6571 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_mix_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color1" ) )
6572 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "color2" ) )
6573 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "ratio" ) ),
6574 : 0 : fcnColorMixRgb, QStringLiteral( "Color" ) )
6575 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "red" ) )
6576 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "green" ) )
6577 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "blue" ) ),
6578 : 0 : fcnColorRgb, QStringLiteral( "Color" ) )
6579 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_rgba" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "red" ) )
6580 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "green" ) )
6581 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "blue" ) )
6582 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6583 : 0 : fncColorRgba, QStringLiteral( "Color" ) )
6584 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "ramp_color" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "ramp_name" ) )
6585 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6586 : 0 : fcnRampColor, QStringLiteral( "Color" ) )
6587 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "create_ramp" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) )
6588 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "discrete" ), true, false ),
6589 : 0 : fcnCreateRamp, QStringLiteral( "Color" ) )
6590 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_hsl" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6591 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6592 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "lightness" ) ),
6593 : 0 : fcnColorHsl, QStringLiteral( "Color" ) )
6594 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_hsla" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6595 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6596 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "lightness" ) )
6597 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6598 : 0 : fncColorHsla, QStringLiteral( "Color" ) )
6599 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_hsv" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6600 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6601 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6602 : 0 : fcnColorHsv, QStringLiteral( "Color" ) )
6603 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_hsva" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "hue" ) )
6604 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "saturation" ) )
6605 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) )
6606 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6607 : 0 : fncColorHsva, QStringLiteral( "Color" ) )
6608 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_cmyk" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "cyan" ) )
6609 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "magenta" ) )
6610 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "yellow" ) )
6611 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "black" ) ),
6612 : 0 : fcnColorCmyk, QStringLiteral( "Color" ) )
6613 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_cmyka" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "cyan" ) )
6614 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "magenta" ) )
6615 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "yellow" ) )
6616 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "black" ) )
6617 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "alpha" ) ),
6618 : 0 : fncColorCmyka, QStringLiteral( "Color" ) )
6619 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "color_part" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
6620 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "component" ) ),
6621 : 0 : fncColorPart, QStringLiteral( "Color" ) )
6622 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "darker" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
6623 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "factor" ) ),
6624 : 0 : fncDarker, QStringLiteral( "Color" ) )
6625 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "lighter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) )
6626 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "factor" ) ),
6627 : 0 : fncLighter, QStringLiteral( "Color" ) )
6628 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "set_color_part" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "component" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fncSetColorPart, QStringLiteral( "Color" ) )
6629 : :
6630 : : // file info
6631 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "base_file_name" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6632 : 0 : fcnBaseFileName, QStringLiteral( "Files and Paths" ) )
6633 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "file_suffix" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6634 : 0 : fcnFileSuffix, QStringLiteral( "Files and Paths" ) )
6635 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "file_exists" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6636 : 0 : fcnFileExists, QStringLiteral( "Files and Paths" ) )
6637 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "file_name" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6638 : 0 : fcnFileName, QStringLiteral( "Files and Paths" ) )
6639 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_file" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6640 : 0 : fcnPathIsFile, QStringLiteral( "Files and Paths" ) )
6641 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_directory" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6642 : 0 : fcnPathIsDir, QStringLiteral( "Files and Paths" ) )
6643 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "file_path" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6644 : 0 : fcnFilePath, QStringLiteral( "Files and Paths" ) )
6645 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "file_size" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "path" ) ),
6646 : 0 : fcnFileSize, QStringLiteral( "Files and Paths" ) )
6647 : :
6648 : : // hash
6649 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "hash" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "method" ) ),
6650 : 0 : fcnGenericHash, QStringLiteral( "Conversions" ) )
6651 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "md5" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
6652 : 0 : fcnHashMd5, QStringLiteral( "Conversions" ) )
6653 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "sha256" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
6654 : 0 : fcnHashSha256, QStringLiteral( "Conversions" ) )
6655 : :
6656 : : //base64
6657 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_base64" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
6658 : 0 : fcnToBase64, QStringLiteral( "Conversions" ) )
6659 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "from_base64" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ),
6660 : 0 : fcnFromBase64, QStringLiteral( "Conversions" ) )
6661 : :
6662 : : // deprecated stuff - hidden from users
6663 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "$scale" ), QgsExpressionFunction::ParameterList(), fcnMapScale, QStringLiteral( "deprecated" ) );
6664 : :
6665 : 0 : QgsStaticExpressionFunction *geomFunc = new QgsStaticExpressionFunction( QStringLiteral( "$geometry" ), 0, fcnGeometry, QStringLiteral( "GeometryGroup" ), QString(), true );
6666 : 0 : geomFunc->setIsStatic( false );
6667 : 0 : functions << geomFunc;
6668 : :
6669 : 0 : QgsStaticExpressionFunction *areaFunc = new QgsStaticExpressionFunction( QStringLiteral( "$area" ), 0, fcnGeomArea, QStringLiteral( "GeometryGroup" ), QString(), true );
6670 : 0 : areaFunc->setIsStatic( false );
6671 : 0 : functions << areaFunc;
6672 : :
6673 : 0 : functions << new QgsStaticExpressionFunction( QStringLiteral( "area" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnArea, QStringLiteral( "GeometryGroup" ) );
6674 : :
6675 : 0 : QgsStaticExpressionFunction *lengthFunc = new QgsStaticExpressionFunction( QStringLiteral( "$length" ), 0, fcnGeomLength, QStringLiteral( "GeometryGroup" ), QString(), true );
6676 : 0 : lengthFunc->setIsStatic( false );
6677 : 0 : functions << lengthFunc;
6678 : :
6679 : 0 : QgsStaticExpressionFunction *perimeterFunc = new QgsStaticExpressionFunction( QStringLiteral( "$perimeter" ), 0, fcnGeomPerimeter, QStringLiteral( "GeometryGroup" ), QString(), true );
6680 : 0 : perimeterFunc->setIsStatic( false );
6681 : 0 : functions << perimeterFunc;
6682 : :
6683 : 0 : functions << new QgsStaticExpressionFunction( QStringLiteral( "perimeter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnPerimeter, QStringLiteral( "GeometryGroup" ) );
6684 : :
6685 : 0 : QgsStaticExpressionFunction *xFunc = new QgsStaticExpressionFunction( QStringLiteral( "$x" ), 0, fcnX, QStringLiteral( "GeometryGroup" ), QString(), true );
6686 : 0 : xFunc->setIsStatic( false );
6687 : 0 : functions << xFunc;
6688 : :
6689 : 0 : QgsStaticExpressionFunction *yFunc = new QgsStaticExpressionFunction( QStringLiteral( "$y" ), 0, fcnY, QStringLiteral( "GeometryGroup" ), QString(), true );
6690 : 0 : yFunc->setIsStatic( false );
6691 : 0 : functions << yFunc;
6692 : :
6693 : 0 : QMap< QString, QgsExpressionFunction::FcnEval > geometry_overlay_definitions
6694 : 0 : {
6695 : 0 : { QStringLiteral( "overlay_intersects" ), fcnGeomOverlayIntersects },
6696 : 0 : { QStringLiteral( "overlay_contains" ), fcnGeomOverlayContains },
6697 : 0 : { QStringLiteral( "overlay_crosses" ), fcnGeomOverlayCrosses },
6698 : 0 : { QStringLiteral( "overlay_equals" ), fcnGeomOverlayEquals },
6699 : 0 : { QStringLiteral( "overlay_touches" ), fcnGeomOverlayTouches },
6700 : 0 : { QStringLiteral( "overlay_disjoint" ), fcnGeomOverlayDisjoint },
6701 : 0 : { QStringLiteral( "overlay_within" ), fcnGeomOverlayWithin },
6702 : : };
6703 : 0 : QMapIterator< QString, QgsExpressionFunction::FcnEval > i( geometry_overlay_definitions );
6704 : 0 : while ( i.hasNext() )
6705 : : {
6706 : 0 : i.next();
6707 : 0 : QgsStaticExpressionFunction *fcnGeomOverlayFunc = new QgsStaticExpressionFunction( i.key(), QgsExpressionFunction::ParameterList()
6708 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6709 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), true, QVariant(), true )
6710 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true, QVariant(), true )
6711 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "limit" ), true, QVariant( -1 ), true )
6712 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "cache" ), true, QVariant( false ), false ),
6713 : 0 : i.value(), QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true );
6714 : :
6715 : : // The current feature is accessed for the geometry, so this should not be cached
6716 : 0 : fcnGeomOverlayFunc->setIsStatic( false );
6717 : 0 : functions << fcnGeomOverlayFunc;
6718 : : }
6719 : :
6720 : 0 : QgsStaticExpressionFunction *fcnGeomOverlayNearestFunc = new QgsStaticExpressionFunction( QStringLiteral( "overlay_nearest" ), QgsExpressionFunction::ParameterList()
6721 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
6722 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ), true, QVariant(), true )
6723 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "filter" ), true, QVariant(), true )
6724 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "limit" ), true, QVariant( 1 ), true )
6725 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "max_distance" ), true, 0 )
6726 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "cache" ), true, QVariant( false ), false ),
6727 : 0 : fcnGeomOverlayNearest, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES, true );
6728 : : // The current feature is accessed for the geometry, so this should not be cached
6729 : 0 : fcnGeomOverlayNearestFunc->setIsStatic( false );
6730 : 0 : functions << fcnGeomOverlayNearestFunc;
6731 : :
6732 : 0 : functions
6733 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_valid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomIsValid, QStringLiteral( "GeometryGroup" ) )
6734 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "x" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomX, QStringLiteral( "GeometryGroup" ) )
6735 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "y" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomY, QStringLiteral( "GeometryGroup" ) )
6736 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "z" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomZ, QStringLiteral( "GeometryGroup" ) )
6737 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomM, QStringLiteral( "GeometryGroup" ) )
6738 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "point_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ), fcnPointN, QStringLiteral( "GeometryGroup" ) )
6739 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "start_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnStartPoint, QStringLiteral( "GeometryGroup" ) )
6740 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "end_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnEndPoint, QStringLiteral( "GeometryGroup" ) )
6741 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "nodes_to_points" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6742 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "ignore_closing_nodes" ), true, false ),
6743 : 0 : fcnNodesToPoints, QStringLiteral( "GeometryGroup" ) )
6744 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "segments_to_lines" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnSegmentsToLines, QStringLiteral( "GeometryGroup" ) )
6745 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "collect_geometries" ), -1, fcnCollectGeometries, QStringLiteral( "GeometryGroup" ) )
6746 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_point" ), -1, fcnMakePoint, QStringLiteral( "GeometryGroup" ) )
6747 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_point_m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "x" ) )
6748 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "y" ) )
6749 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "m" ) ),
6750 : 0 : fcnMakePointM, QStringLiteral( "GeometryGroup" ) )
6751 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_line" ), -1, fcnMakeLine, QStringLiteral( "GeometryGroup" ) )
6752 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_polygon" ), -1, fcnMakePolygon, QStringLiteral( "GeometryGroup" ) )
6753 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_triangle" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6754 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) )
6755 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point3" ) ),
6756 : 0 : fcnMakeTriangle, QStringLiteral( "GeometryGroup" ) )
6757 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_circle" ), QgsExpressionFunction::ParameterList()
6758 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6759 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "radius" ) )
6760 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6761 : 0 : fcnMakeCircle, QStringLiteral( "GeometryGroup" ) )
6762 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_ellipse" ), QgsExpressionFunction::ParameterList()
6763 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6764 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "semi_major_axis" ) )
6765 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "semi_minor_axis" ) )
6766 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
6767 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6768 : 0 : fcnMakeEllipse, QStringLiteral( "GeometryGroup" ) )
6769 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_regular_polygon" ), QgsExpressionFunction::ParameterList()
6770 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6771 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "radius" ) )
6772 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "number_sides" ) )
6773 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "circle" ), true, 0 ),
6774 : 0 : fcnMakeRegularPolygon, QStringLiteral( "GeometryGroup" ) )
6775 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_square" ), QgsExpressionFunction::ParameterList()
6776 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6777 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) ),
6778 : 0 : fcnMakeSquare, QStringLiteral( "GeometryGroup" ) )
6779 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "make_rectangle_3points" ), QgsExpressionFunction::ParameterList()
6780 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point1" ) )
6781 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point2" ) )
6782 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point3" ) )
6783 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "option" ), true, 0 ),
6784 : 0 : fcnMakeRectangleFrom3Points, QStringLiteral( "GeometryGroup" ) );
6785 : 0 : QgsStaticExpressionFunction *xAtFunc = new QgsStaticExpressionFunction( QStringLiteral( "$x_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "i" ) ), fcnXat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "xat" ) << QStringLiteral( "x_at" ) );
6786 : 0 : xAtFunc->setIsStatic( false );
6787 : 0 : functions << xAtFunc;
6788 : :
6789 : 0 : QgsStaticExpressionFunction *yAtFunc = new QgsStaticExpressionFunction( QStringLiteral( "$y_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "i" ) ), fcnYat, QStringLiteral( "GeometryGroup" ), QString(), true, QSet<QString>(), false, QStringList() << QStringLiteral( "yat" ) << QStringLiteral( "y_at" ) );
6790 : 0 : yAtFunc->setIsStatic( false );
6791 : 0 : functions << yAtFunc;
6792 : :
6793 : 0 : functions
6794 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "x_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnXMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmin" ) )
6795 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "x_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnXMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "xmax" ) )
6796 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "y_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnYMin, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymin" ) )
6797 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "y_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnYMax, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "ymax" ) )
6798 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_wkt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "text" ) ), fcnGeomFromWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromWKT" ) )
6799 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_wkb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "binary" ) ), fcnGeomFromWKB, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false )
6800 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geom_from_gml" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "gml" ) ), fcnGeomFromGML, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomFromGML" ) )
6801 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "flip_coordinates" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnFlipCoordinates, QStringLiteral( "GeometryGroup" ) )
6802 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "relate" ), -1, fcnRelate, QStringLiteral( "GeometryGroup" ) )
6803 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "intersects_bbox" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ), fcnBbox, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "bbox" ) )
6804 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "disjoint" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6805 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6806 : 0 : fcnDisjoint, QStringLiteral( "GeometryGroup" ) )
6807 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "intersects" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6808 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6809 : 0 : fcnIntersects, QStringLiteral( "GeometryGroup" ) )
6810 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "touches" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6811 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6812 : 0 : fcnTouches, QStringLiteral( "GeometryGroup" ) )
6813 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "crosses" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6814 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6815 : 0 : fcnCrosses, QStringLiteral( "GeometryGroup" ) )
6816 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "contains" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6817 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6818 : 0 : fcnContains, QStringLiteral( "GeometryGroup" ) )
6819 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "overlaps" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6820 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6821 : 0 : fcnOverlaps, QStringLiteral( "GeometryGroup" ) )
6822 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "within" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6823 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6824 : 0 : fcnWithin, QStringLiteral( "GeometryGroup" ) )
6825 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "translate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6826 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "dx" ) )
6827 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "dy" ) ),
6828 : 0 : fcnTranslate, QStringLiteral( "GeometryGroup" ) )
6829 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "rotate" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6830 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "rotation" ) )
6831 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "center" ), true ),
6832 : 0 : fcnRotate, QStringLiteral( "GeometryGroup" ) )
6833 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6834 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6835 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8 ),
6836 : 0 : fcnBuffer, QStringLiteral( "GeometryGroup" ) )
6837 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "force_rhr" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6838 : 0 : fcnForceRHR, QStringLiteral( "GeometryGroup" ) )
6839 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "wedge_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "center" ) )
6840 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "azimuth" ) )
6841 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) )
6842 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "outer_radius" ) )
6843 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "inner_radius" ), true, 0.0 ), fcnWedgeBuffer, QStringLiteral( "GeometryGroup" ) )
6844 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "tapered_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6845 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "start_width" ) )
6846 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "end_width" ) )
6847 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6848 : 0 : , fcnTaperedBuffer, QStringLiteral( "GeometryGroup" ) )
6849 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "buffer_by_m" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6850 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6851 : 0 : , fcnBufferByM, QStringLiteral( "GeometryGroup" ) )
6852 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "offset_curve" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6853 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6854 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6855 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
6856 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2.0 ),
6857 : 0 : fcnOffsetCurve, QStringLiteral( "GeometryGroup" ) )
6858 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "single_sided_buffer" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6859 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) )
6860 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 8.0 )
6861 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "join" ), true, QgsGeometry::JoinStyleRound )
6862 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "miter_limit" ), true, 2.0 ),
6863 : 0 : fcnSingleSidedBuffer, QStringLiteral( "GeometryGroup" ) )
6864 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "extend" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6865 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) )
6866 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ),
6867 : 0 : fcnExtend, QStringLiteral( "GeometryGroup" ) )
6868 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "centroid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnCentroid, QStringLiteral( "GeometryGroup" ) )
6869 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "point_on_surface" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnPointOnSurface, QStringLiteral( "GeometryGroup" ) )
6870 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "pole_of_inaccessibility" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6871 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnPoleOfInaccessibility, QStringLiteral( "GeometryGroup" ) )
6872 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "reverse" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnReverse, QStringLiteral( "GeometryGroup" ) )
6873 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "exterior_ring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnExteriorRing, QStringLiteral( "GeometryGroup" ) )
6874 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "interior_ring_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6875 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ),
6876 : 0 : fcnInteriorRingN, QStringLiteral( "GeometryGroup" ) )
6877 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geometry_n" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6878 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "index" ) ),
6879 : 0 : fcnGeometryN, QStringLiteral( "GeometryGroup" ) )
6880 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "boundary" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundary, QStringLiteral( "GeometryGroup" ) )
6881 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "line_merge" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnLineMerge, QStringLiteral( "GeometryGroup" ) )
6882 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "bounds" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBounds, QStringLiteral( "GeometryGroup" ) )
6883 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "simplify" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnSimplify, QStringLiteral( "GeometryGroup" ) )
6884 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "simplify_vw" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "tolerance" ) ), fcnSimplifyVW, QStringLiteral( "GeometryGroup" ) )
6885 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "smooth" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "iterations" ), true, 1 )
6886 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "offset" ), true, 0.25 )
6887 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "min_length" ), true, -1 )
6888 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "max_angle" ), true, 180 ), fcnSmooth, QStringLiteral( "GeometryGroup" ) )
6889 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "num_points" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumPoints, QStringLiteral( "GeometryGroup" ) )
6890 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "num_interior_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumInteriorRings, QStringLiteral( "GeometryGroup" ) )
6891 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "num_rings" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumRings, QStringLiteral( "GeometryGroup" ) )
6892 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "num_geometries" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnGeomNumGeometries, QStringLiteral( "GeometryGroup" ) )
6893 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "bounds_width" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundsWidth, QStringLiteral( "GeometryGroup" ) )
6894 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "bounds_height" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnBoundsHeight, QStringLiteral( "GeometryGroup" ) )
6895 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_closed" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnIsClosed, QStringLiteral( "GeometryGroup" ) )
6896 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "close_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnCloseLine, QStringLiteral( "GeometryGroup" ) )
6897 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_empty" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnIsEmpty, QStringLiteral( "GeometryGroup" ) )
6898 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_empty_or_null" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnIsEmptyOrNull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList(), true )
6899 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "convex_hull" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ), fcnConvexHull, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "convexHull" ) )
6900 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "oriented_bbox" ), QgsExpressionFunction::ParameterList()
6901 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6902 : 0 : fcnOrientedBBox, QStringLiteral( "GeometryGroup" ) )
6903 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "main_angle" ), QgsExpressionFunction::ParameterList()
6904 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6905 : 0 : fcnMainAngle, QStringLiteral( "GeometryGroup" ) )
6906 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "minimal_circle" ), QgsExpressionFunction::ParameterList()
6907 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6908 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "segments" ), true, 36 ),
6909 : 0 : fcnMinimalCircle, QStringLiteral( "GeometryGroup" ) )
6910 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "difference" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6911 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6912 : 0 : fcnDifference, QStringLiteral( "GeometryGroup" ) )
6913 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6914 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6915 : 0 : fcnDistance, QStringLiteral( "GeometryGroup" ) )
6916 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "hausdorff_distance" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) )
6917 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "densify_fraction" ), true ),
6918 : 0 : fcnHausdorffDistance, QStringLiteral( "GeometryGroup" ) )
6919 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "intersection" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6920 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6921 : 0 : fcnIntersection, QStringLiteral( "GeometryGroup" ) )
6922 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "sym_difference" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6923 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6924 : 0 : fcnSymDifference, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "symDifference" ) )
6925 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "combine" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6926 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6927 : 0 : fcnCombine, QStringLiteral( "GeometryGroup" ) )
6928 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "union" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
6929 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
6930 : 0 : fcnCombine, QStringLiteral( "GeometryGroup" ) )
6931 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geom_to_wkt" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6932 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "precision" ), true, 8.0 ),
6933 : 0 : fcnGeomToWKT, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "geomToWKT" ) )
6934 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geom_to_wkb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6935 : 0 : fcnGeomToWKB, QStringLiteral( "GeometryGroup" ), QString(), false, QSet<QString>(), false )
6936 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "geometry" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ) ), fcnGetGeometry, QStringLiteral( "GeometryGroup" ), QString(), true )
6937 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "transform" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6938 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "source_auth_id" ) )
6939 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "dest_auth_id" ) ),
6940 : 0 : fcnTransformGeometry, QStringLiteral( "GeometryGroup" ) )
6941 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "extrude" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6942 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "x" ) )
6943 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "y" ) ),
6944 : 0 : fcnExtrude, QStringLiteral( "GeometryGroup" ), QString() )
6945 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "is_multipart" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6946 : 0 : fcnGeomIsMultipart, QStringLiteral( "GeometryGroup" ) )
6947 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "z_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6948 : 0 : fcnZMax, QStringLiteral( "GeometryGroup" ) )
6949 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "z_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6950 : 0 : fcnZMin, QStringLiteral( "GeometryGroup" ) )
6951 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "m_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6952 : 0 : fcnMMax, QStringLiteral( "GeometryGroup" ) )
6953 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "m_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) ),
6954 : 0 : fcnMMin, QStringLiteral( "GeometryGroup" ) );
6955 : :
6956 : :
6957 : 0 : QgsStaticExpressionFunction *orderPartsFunc = new QgsStaticExpressionFunction( QStringLiteral( "order_parts" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
6958 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "orderby" ) )
6959 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "ascending" ) ),
6960 : 0 : fcnOrderParts, QStringLiteral( "GeometryGroup" ), QString() );
6961 : :
6962 : 0 : orderPartsFunc->setIsStaticFunction(
6963 : 0 : []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6964 : : {
6965 : 0 : const QList< QgsExpressionNode *> argList = node->args()->list();
6966 : 0 : for ( QgsExpressionNode *argNode : argList )
6967 : : {
6968 : 0 : if ( !argNode->isStatic( parent, context ) )
6969 : 0 : return false;
6970 : : }
6971 : :
6972 : 0 : if ( node->args()->count() > 1 )
6973 : : {
6974 : 0 : QgsExpressionNode *argNode = node->args()->at( 1 );
6975 : :
6976 : 0 : QString expString = argNode->eval( parent, context ).toString();
6977 : :
6978 : 0 : QgsExpression e( expString );
6979 : :
6980 : 0 : if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) )
6981 : 0 : return true;
6982 : 0 : }
6983 : :
6984 : 0 : return true;
6985 : 0 : } );
6986 : :
6987 : 0 : orderPartsFunc->setPrepareFunction( []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
6988 : : {
6989 : 0 : if ( node->args()->count() > 1 )
6990 : : {
6991 : 0 : QgsExpressionNode *argNode = node->args()->at( 1 );
6992 : 0 : QString expression = argNode->eval( parent, context ).toString();
6993 : 0 : QgsExpression e( expression );
6994 : 0 : e.prepare( context );
6995 : 0 : context->setCachedValue( expression, QVariant::fromValue( e ) );
6996 : 0 : }
6997 : 0 : return true;
6998 : 0 : }
6999 : : );
7000 : 0 : functions << orderPartsFunc;
7001 : :
7002 : 0 : functions
7003 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "closest_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
7004 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
7005 : 0 : fcnClosestPoint, QStringLiteral( "GeometryGroup" ) )
7006 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "shortest_line" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry1" ) )
7007 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "geometry2" ) ),
7008 : 0 : fcnShortestLine, QStringLiteral( "GeometryGroup" ) )
7009 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "line_interpolate_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
7010 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolatePoint, QStringLiteral( "GeometryGroup" ) )
7011 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "line_interpolate_angle" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
7012 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "distance" ) ), fcnLineInterpolateAngle, QStringLiteral( "GeometryGroup" ) )
7013 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "line_locate_point" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
7014 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnLineLocatePoint, QStringLiteral( "GeometryGroup" ) )
7015 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "angle_at_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
7016 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
7017 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "distance_to_vertex" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
7018 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
7019 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "line_substring" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "geometry" ) )
7020 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "start_distance" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_distance" ) ), fcnLineSubset, QStringLiteral( "GeometryGroup" ) );
7021 : :
7022 : :
7023 : : // **Record** functions
7024 : :
7025 : 0 : QgsStaticExpressionFunction *idFunc = new QgsStaticExpressionFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record and Attributes" ) );
7026 : 0 : idFunc->setIsStatic( false );
7027 : 0 : functions << idFunc;
7028 : :
7029 : 0 : QgsStaticExpressionFunction *currentFeatureFunc = new QgsStaticExpressionFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record and Attributes" ) );
7030 : 0 : currentFeatureFunc->setIsStatic( false );
7031 : 0 : functions << currentFeatureFunc;
7032 : :
7033 : 0 : QgsStaticExpressionFunction *uuidFunc = new QgsStaticExpressionFunction( QStringLiteral( "uuid" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "format" ), true, QStringLiteral( "WithBraces" ) ), fcnUuid, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) );
7034 : 0 : uuidFunc->setIsStatic( false );
7035 : 0 : functions << uuidFunc;
7036 : :
7037 : 0 : functions
7038 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "get_feature" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
7039 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) )
7040 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ),
7041 : 0 : fcnGetFeature, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "QgsExpressionUtils::getFeature" ) )
7042 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "get_feature_by_id" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
7043 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "feature_id" ) ),
7044 : 0 : fcnGetFeatureById, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>(), false );
7045 : :
7046 : 0 : QgsStaticExpressionFunction *attributesFunc = new QgsStaticExpressionFunction( QStringLiteral( "attributes" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ), true ),
7047 : 0 : fcnAttributes, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
7048 : 0 : attributesFunc->setIsStatic( false );
7049 : 0 : functions << attributesFunc;
7050 : :
7051 : 0 : QgsStaticExpressionFunction *maptipFunc = new QgsStaticExpressionFunction(
7052 : 0 : QStringLiteral( "maptip" ),
7053 : : -1,
7054 : : fcnFeatureMaptip,
7055 : 0 : QStringLiteral( "Record and Attributes" ),
7056 : 0 : QString(),
7057 : : false,
7058 : 0 : QSet<QString>()
7059 : : );
7060 : 0 : maptipFunc->setIsStatic( false );
7061 : 0 : functions << maptipFunc;
7062 : :
7063 : 0 : QgsStaticExpressionFunction *displayFunc = new QgsStaticExpressionFunction(
7064 : 0 : QStringLiteral( "display_expression" ),
7065 : : -1,
7066 : : fcnFeatureDisplayExpression,
7067 : 0 : QStringLiteral( "Record and Attributes" ),
7068 : 0 : QString(),
7069 : : false,
7070 : 0 : QSet<QString>()
7071 : : );
7072 : 0 : displayFunc->setIsStatic( false );
7073 : 0 : functions << displayFunc;
7074 : :
7075 : 0 : QgsStaticExpressionFunction *isSelectedFunc = new QgsStaticExpressionFunction(
7076 : 0 : QStringLiteral( "is_selected" ),
7077 : : -1,
7078 : : fcnIsSelected,
7079 : 0 : QStringLiteral( "Record and Attributes" ),
7080 : 0 : QString(),
7081 : : false,
7082 : 0 : QSet<QString>()
7083 : : );
7084 : 0 : isSelectedFunc->setIsStatic( false );
7085 : 0 : functions << isSelectedFunc;
7086 : :
7087 : 0 : functions
7088 : 0 : << new QgsStaticExpressionFunction(
7089 : 0 : QStringLiteral( "num_selected" ),
7090 : : -1,
7091 : : fcnNumSelected,
7092 : 0 : QStringLiteral( "Record and Attributes" ),
7093 : 0 : QString(),
7094 : : false,
7095 : 0 : QSet<QString>()
7096 : : );
7097 : :
7098 : 0 : functions
7099 : 0 : << new QgsStaticExpressionFunction(
7100 : 0 : QStringLiteral( "sqlite_fetch_and_increment" ),
7101 : 0 : QgsExpressionFunction::ParameterList()
7102 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "database" ) )
7103 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "table" ) )
7104 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "id_field" ) )
7105 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "filter_attribute" ) )
7106 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "filter_value" ) )
7107 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "default_values" ), true ),
7108 : : fcnSqliteFetchAndIncrement,
7109 : 0 : QStringLiteral( "Record and Attributes" )
7110 : : );
7111 : :
7112 : : // **Fields and Values** functions
7113 : 0 : QgsStaticExpressionFunction *representValueFunc = new QgsStaticExpressionFunction( QStringLiteral( "represent_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "attribute" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "field_name" ), true ), fcnRepresentValue, QStringLiteral( "Record and Attributes" ) );
7114 : :
7115 : 0 : representValueFunc->setPrepareFunction( []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
7116 : : {
7117 : : Q_UNUSED( context )
7118 : 0 : if ( node->args()->count() == 1 )
7119 : : {
7120 : 0 : QgsExpressionNodeColumnRef *colRef = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
7121 : 0 : if ( colRef )
7122 : : {
7123 : 0 : return true;
7124 : : }
7125 : : else
7126 : : {
7127 : 0 : parent->setEvalErrorString( tr( "If represent_value is called with 1 parameter, it must be an attribute." ) );
7128 : 0 : return false;
7129 : : }
7130 : : }
7131 : 0 : else if ( node->args()->count() == 2 )
7132 : : {
7133 : 0 : return true;
7134 : : }
7135 : : else
7136 : : {
7137 : 0 : parent->setEvalErrorString( tr( "represent_value must be called with exactly 1 or 2 parameters." ) );
7138 : 0 : return false;
7139 : : }
7140 : 0 : }
7141 : : );
7142 : :
7143 : 0 : functions << representValueFunc;
7144 : :
7145 : : // **General** functions
7146 : 0 : functions
7147 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "layer_property" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
7148 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "property" ) ),
7149 : 0 : fcnGetLayerProperty, QStringLiteral( "Map Layers" ) )
7150 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "decode_uri" ),
7151 : 0 : QgsExpressionFunction::ParameterList()
7152 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
7153 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "part" ), true ),
7154 : 0 : fcnDecodeUri, QStringLiteral( "Map Layers" ) )
7155 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "mime_type" ),
7156 : 0 : QgsExpressionFunction::ParameterList()
7157 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "binary_data" ) ),
7158 : 0 : fcnMimeType, QStringLiteral( "General" ) )
7159 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "raster_statistic" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) )
7160 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) )
7161 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "statistic" ) ), fcnGetRasterBandStat, QStringLiteral( "Rasters" ) );
7162 : :
7163 : : // **var** function
7164 : 0 : QgsStaticExpressionFunction *varFunction = new QgsStaticExpressionFunction( QStringLiteral( "var" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnGetVariable, QStringLiteral( "General" ) );
7165 : 0 : varFunction->setIsStaticFunction(
7166 : 0 : []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
7167 : : {
7168 : : /* A variable node is static if it has a static name and the name can be found at prepare
7169 : : * time and is tagged with isStatic.
7170 : : * It is not static if a variable is set during iteration or not tagged isStatic.
7171 : : * (e.g. geom_part variable)
7172 : : */
7173 : 0 : if ( node->args()->count() > 0 )
7174 : : {
7175 : 0 : QgsExpressionNode *argNode = node->args()->at( 0 );
7176 : :
7177 : 0 : if ( !argNode->isStatic( parent, context ) )
7178 : 0 : return false;
7179 : :
7180 : 0 : QString varName = argNode->eval( parent, context ).toString();
7181 : :
7182 : 0 : const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
7183 : 0 : return scope ? scope->isStatic( varName ) : false;
7184 : 0 : }
7185 : 0 : return false;
7186 : 0 : }
7187 : : );
7188 : :
7189 : 0 : functions
7190 : 0 : << varFunction;
7191 : :
7192 : 0 : functions << new QgsStaticExpressionFunction( QStringLiteral( "eval_template" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "template" ) ), fcnEvalTemplate, QStringLiteral( "General" ), QString(), true );
7193 : :
7194 : 0 : QgsStaticExpressionFunction *evalFunc = new QgsStaticExpressionFunction( QStringLiteral( "eval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ), fcnEval, QStringLiteral( "General" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
7195 : 0 : evalFunc->setIsStaticFunction(
7196 : 0 : []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
7197 : : {
7198 : 0 : if ( node->args()->count() > 0 )
7199 : : {
7200 : 0 : QgsExpressionNode *argNode = node->args()->at( 0 );
7201 : :
7202 : 0 : if ( argNode->isStatic( parent, context ) )
7203 : : {
7204 : 0 : QString expString = argNode->eval( parent, context ).toString();
7205 : :
7206 : 0 : QgsExpression e( expString );
7207 : :
7208 : 0 : if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) )
7209 : 0 : return true;
7210 : 0 : }
7211 : 0 : }
7212 : :
7213 : 0 : return false;
7214 : 0 : } );
7215 : :
7216 : 0 : functions << evalFunc;
7217 : :
7218 : 0 : QgsStaticExpressionFunction *attributeFunc = new QgsStaticExpressionFunction( QStringLiteral( "attribute" ), -1, fcnAttribute, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
7219 : 0 : attributeFunc->setIsStaticFunction(
7220 : 0 : []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
7221 : : {
7222 : 0 : const QList< QgsExpressionNode *> argList = node->args()->list();
7223 : 0 : for ( QgsExpressionNode *argNode : argList )
7224 : : {
7225 : 0 : if ( !argNode->isStatic( parent, context ) )
7226 : 0 : return false;
7227 : : }
7228 : :
7229 : 0 : if ( node->args()->count() == 1 )
7230 : : {
7231 : : // not static -- this is the variant which uses the current feature taken direct from the expression context
7232 : 0 : return false;
7233 : : }
7234 : :
7235 : 0 : return true;
7236 : 0 : } );
7237 : 0 : functions << attributeFunc;
7238 : :
7239 : 0 : functions
7240 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "env" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), fcnEnvVar, QStringLiteral( "General" ), QString() )
7241 : 0 : << new QgsWithVariableExpressionFunction()
7242 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "raster_value" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "layer" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "band" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "point" ) ), fcnRasterValue, QStringLiteral( "Rasters" ) )
7243 : :
7244 : : // functions for arrays
7245 : 0 : << new QgsArrayForeachExpressionFunction()
7246 : 0 : << new QgsArrayFilterExpressionFunction()
7247 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array" ), -1, fcnArray, QStringLiteral( "Arrays" ), QString(), false, QSet<QString>(), false, QStringList(), true )
7248 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_sort" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "ascending" ), true, true ), fcnArraySort, QStringLiteral( "Arrays" ) )
7249 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_length" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayLength, QStringLiteral( "Arrays" ) )
7250 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_contains" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayContains, QStringLiteral( "Arrays" ) )
7251 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_count" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayCount, QStringLiteral( "Arrays" ) )
7252 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_all" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array_a" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array_b" ) ), fcnArrayAll, QStringLiteral( "Arrays" ) )
7253 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_find" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayFind, QStringLiteral( "Arrays" ) )
7254 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_get" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ), fcnArrayGet, QStringLiteral( "Arrays" ) )
7255 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_first" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayFirst, QStringLiteral( "Arrays" ) )
7256 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_last" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayLast, QStringLiteral( "Arrays" ) )
7257 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_min" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayMinimum, QStringLiteral( "Arrays" ) )
7258 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_max" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayMaximum, QStringLiteral( "Arrays" ) )
7259 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_mean" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayMean, QStringLiteral( "Arrays" ) )
7260 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_median" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayMedian, QStringLiteral( "Arrays" ) )
7261 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_majority" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "option" ), true, QVariant( "all" ) ), fcnArrayMajority, QStringLiteral( "Arrays" ) )
7262 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_minority" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "option" ), true, QVariant( "all" ) ), fcnArrayMinority, QStringLiteral( "Arrays" ) )
7263 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_sum" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArraySum, QStringLiteral( "Arrays" ) )
7264 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_append" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayAppend, QStringLiteral( "Arrays" ) )
7265 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_prepend" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayPrepend, QStringLiteral( "Arrays" ) )
7266 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_insert" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayInsert, QStringLiteral( "Arrays" ) )
7267 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_remove_at" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "pos" ) ), fcnArrayRemoveAt, QStringLiteral( "Arrays" ) )
7268 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_remove_all" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnArrayRemoveAll, QStringLiteral( "Arrays" ) )
7269 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_replace" ), -1, fcnArrayReplace, QStringLiteral( "Arrays" ) )
7270 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_prioritize" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array_prioritize" ) ), fcnArrayPrioritize, QStringLiteral( "Arrays" ) )
7271 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_cat" ), -1, fcnArrayCat, QStringLiteral( "Arrays" ) )
7272 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_slice" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "start_pos" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "end_pos" ) ), fcnArraySlice, QStringLiteral( "Arrays" ) )
7273 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_reverse" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayReverse, QStringLiteral( "Arrays" ) )
7274 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_intersect" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array1" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "array2" ) ), fcnArrayIntersect, QStringLiteral( "Arrays" ) )
7275 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_distinct" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ), fcnArrayDistinct, QStringLiteral( "Arrays" ) )
7276 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "array_to_string" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "," ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnArrayToString, QStringLiteral( "Arrays" ) )
7277 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "string_to_array" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "delimiter" ), true, "," ) << QgsExpressionFunction::Parameter( QStringLiteral( "emptyvalue" ), true, "" ), fcnStringToArray, QStringLiteral( "Arrays" ) )
7278 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "generate_series" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "start" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "stop" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "step" ), true, 1.0 ), fcnGenerateSeries, QStringLiteral( "Arrays" ) )
7279 : :
7280 : : //functions for maps
7281 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "from_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnLoadJson, QStringLiteral( "Maps" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "json_to_map" ) )
7282 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "to_json" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "json_string" ) ), fcnWriteJson, QStringLiteral( "Maps" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "map_to_json" ) )
7283 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "hstore_to_map" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnHstoreToMap, QStringLiteral( "Maps" ) )
7284 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_to_hstore" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapToHstore, QStringLiteral( "Maps" ) )
7285 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map" ), -1, fcnMap, QStringLiteral( "Maps" ) )
7286 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_get" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapGet, QStringLiteral( "Maps" ) )
7287 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_exist" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapExist, QStringLiteral( "Maps" ) )
7288 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_delete" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ), fcnMapDelete, QStringLiteral( "Maps" ) )
7289 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_insert" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "key" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) ), fcnMapInsert, QStringLiteral( "Maps" ) )
7290 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_concat" ), -1, fcnMapConcat, QStringLiteral( "Maps" ) )
7291 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_akeys" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapAKeys, QStringLiteral( "Maps" ) )
7292 : 0 : << new QgsStaticExpressionFunction( QStringLiteral( "map_avals" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "map" ) ), fcnMapAVals, QStringLiteral( "Maps" ) )
7293 : : ;
7294 : :
7295 : 0 : QgsExpressionContextUtils::registerContextFunctions();
7296 : :
7297 : : //QgsExpression has ownership of all built-in functions
7298 : 0 : for ( QgsExpressionFunction *func : std::as_const( functions ) )
7299 : : {
7300 : 0 : *sOwnedFunctions() << func;
7301 : 0 : *sBuiltinFunctions() << func->name();
7302 : 0 : sBuiltinFunctions()->append( func->aliases() );
7303 : : }
7304 : 0 : }
7305 : 0 : return functions;
7306 : 0 : }
7307 : :
7308 : 0 : bool QgsExpression::registerFunction( QgsExpressionFunction *function, bool transferOwnership )
7309 : : {
7310 : 0 : int fnIdx = functionIndex( function->name() );
7311 : 0 : if ( fnIdx != -1 )
7312 : : {
7313 : 0 : return false;
7314 : : }
7315 : 0 : sFunctions()->append( function );
7316 : 0 : if ( transferOwnership )
7317 : 0 : sOwnedFunctions()->append( function );
7318 : 0 : return true;
7319 : 0 : }
7320 : :
7321 : 0 : bool QgsExpression::unregisterFunction( const QString &name )
7322 : : {
7323 : : // You can never override the built in functions.
7324 : 0 : if ( QgsExpression::BuiltinFunctions().contains( name ) )
7325 : : {
7326 : 0 : return false;
7327 : : }
7328 : 0 : int fnIdx = functionIndex( name );
7329 : 0 : if ( fnIdx != -1 )
7330 : : {
7331 : 0 : sFunctions()->removeAt( fnIdx );
7332 : 0 : return true;
7333 : : }
7334 : 0 : return false;
7335 : 0 : }
7336 : :
7337 : 3 : void QgsExpression::cleanRegisteredFunctions()
7338 : : {
7339 : 3 : qDeleteAll( *sOwnedFunctions() );
7340 : 3 : sOwnedFunctions()->clear();
7341 : 3 : }
7342 : :
7343 : 0 : const QStringList &QgsExpression::BuiltinFunctions()
7344 : : {
7345 : 0 : if ( sBuiltinFunctions()->isEmpty() )
7346 : : {
7347 : 0 : Functions(); // this method builds the gmBuiltinFunctions as well
7348 : 0 : }
7349 : 0 : return *sBuiltinFunctions();
7350 : : }
7351 : :
7352 : :
7353 : 0 : QgsArrayForeachExpressionFunction::QgsArrayForeachExpressionFunction()
7354 : 0 : : QgsExpressionFunction( QStringLiteral( "array_foreach" ), QgsExpressionFunction::ParameterList() // skip-keyword-check
7355 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) )
7356 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
7357 : 0 : QStringLiteral( "Arrays" ) )
7358 : 0 : {
7359 : :
7360 : 0 : }
7361 : :
7362 : 0 : bool QgsArrayForeachExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
7363 : : {
7364 : 0 : bool isStatic = false;
7365 : :
7366 : 0 : QgsExpressionNode::NodeList *args = node->args();
7367 : :
7368 : 0 : if ( args->count() < 2 )
7369 : 0 : return false;
7370 : :
7371 : 0 : if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
7372 : : {
7373 : 0 : isStatic = true;
7374 : 0 : }
7375 : 0 : return isStatic;
7376 : 0 : }
7377 : :
7378 : 0 : QVariant QgsArrayForeachExpressionFunction::run( QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7379 : : {
7380 : : Q_UNUSED( node )
7381 : 0 : QVariantList result;
7382 : :
7383 : 0 : if ( args->count() < 2 )
7384 : : // error
7385 : 0 : return result;
7386 : :
7387 : 0 : QVariantList array = args->at( 0 )->eval( parent, context ).toList();
7388 : :
7389 : 0 : QgsExpressionContext *subContext = const_cast<QgsExpressionContext *>( context );
7390 : 0 : std::unique_ptr< QgsExpressionContext > tempContext;
7391 : 0 : if ( !subContext )
7392 : : {
7393 : 0 : tempContext = std::make_unique< QgsExpressionContext >();
7394 : 0 : subContext = tempContext.get();
7395 : 0 : }
7396 : :
7397 : 0 : QgsExpressionContextScope *subScope = new QgsExpressionContextScope();
7398 : 0 : subContext->appendScope( subScope );
7399 : :
7400 : 0 : for ( QVariantList::const_iterator it = array.constBegin(); it != array.constEnd(); ++it )
7401 : : {
7402 : 0 : subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), *it, true ) );
7403 : 0 : result << args->at( 1 )->eval( parent, subContext );
7404 : 0 : }
7405 : :
7406 : 0 : if ( context )
7407 : 0 : delete subContext->popScope();
7408 : :
7409 : 0 : return result;
7410 : 0 : }
7411 : :
7412 : 0 : QVariant QgsArrayForeachExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7413 : : {
7414 : : // This is a dummy function, all the real handling is in run
7415 : 0 : Q_UNUSED( values )
7416 : : Q_UNUSED( context )
7417 : : Q_UNUSED( parent )
7418 : : Q_UNUSED( node )
7419 : :
7420 : : Q_ASSERT( false );
7421 : 0 : return QVariant();
7422 : : }
7423 : :
7424 : 0 : bool QgsArrayForeachExpressionFunction::prepare( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
7425 : : {
7426 : 0 : QgsExpressionNode::NodeList *args = node->args();
7427 : :
7428 : 0 : if ( args->count() < 2 )
7429 : : // error
7430 : 0 : return false;
7431 : :
7432 : 0 : args->at( 0 )->prepare( parent, context );
7433 : :
7434 : 0 : QgsExpressionContext subContext;
7435 : 0 : if ( context )
7436 : 0 : subContext = *context;
7437 : :
7438 : 0 : QgsExpressionContextScope *subScope = new QgsExpressionContextScope();
7439 : 0 : subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), QVariant(), true ) );
7440 : 0 : subContext.appendScope( subScope );
7441 : :
7442 : 0 : args->at( 1 )->prepare( parent, &subContext );
7443 : :
7444 : 0 : return true;
7445 : 0 : }
7446 : :
7447 : 0 : QgsArrayFilterExpressionFunction::QgsArrayFilterExpressionFunction()
7448 : 0 : : QgsExpressionFunction( QStringLiteral( "array_filter" ), QgsExpressionFunction::ParameterList()
7449 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "array" ) )
7450 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) )
7451 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "limit" ), true, 0 ),
7452 : 0 : QStringLiteral( "Arrays" ) )
7453 : 0 : {
7454 : :
7455 : 0 : }
7456 : :
7457 : 0 : bool QgsArrayFilterExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
7458 : : {
7459 : 0 : bool isStatic = false;
7460 : :
7461 : 0 : QgsExpressionNode::NodeList *args = node->args();
7462 : :
7463 : 0 : if ( args->count() < 2 )
7464 : 0 : return false;
7465 : :
7466 : 0 : if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
7467 : : {
7468 : 0 : isStatic = true;
7469 : 0 : }
7470 : 0 : return isStatic;
7471 : 0 : }
7472 : :
7473 : 0 : QVariant QgsArrayFilterExpressionFunction::run( QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7474 : : {
7475 : : Q_UNUSED( node )
7476 : 0 : QVariantList result;
7477 : :
7478 : 0 : if ( args->count() < 2 )
7479 : : // error
7480 : 0 : return result;
7481 : :
7482 : 0 : const QVariantList array = args->at( 0 )->eval( parent, context ).toList();
7483 : :
7484 : 0 : QgsExpressionContext *subContext = const_cast<QgsExpressionContext *>( context );
7485 : 0 : std::unique_ptr< QgsExpressionContext > tempContext;
7486 : 0 : if ( !subContext )
7487 : : {
7488 : 0 : tempContext = std::make_unique< QgsExpressionContext >();
7489 : 0 : subContext = tempContext.get();
7490 : 0 : }
7491 : :
7492 : 0 : QgsExpressionContextScope *subScope = new QgsExpressionContextScope();
7493 : 0 : subContext->appendScope( subScope );
7494 : :
7495 : 0 : int limit = 0;
7496 : 0 : if ( args->count() >= 3 )
7497 : : {
7498 : 0 : const QVariant limitVar = args->at( 2 )->eval( parent, context );
7499 : :
7500 : 0 : if ( QgsExpressionUtils::isIntSafe( limitVar ) )
7501 : : {
7502 : 0 : limit = limitVar.toInt();
7503 : 0 : }
7504 : : else
7505 : : {
7506 : 0 : return result;
7507 : : }
7508 : 0 : }
7509 : :
7510 : 0 : for ( const QVariant &value : array )
7511 : : {
7512 : 0 : subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), value, true ) );
7513 : 0 : if ( args->at( 1 )->eval( parent, subContext ).toBool() )
7514 : : {
7515 : 0 : result << value;
7516 : :
7517 : 0 : if ( limit > 0 && limit == result.size() )
7518 : 0 : break;
7519 : 0 : }
7520 : : }
7521 : :
7522 : 0 : if ( context )
7523 : 0 : delete subContext->popScope();
7524 : :
7525 : 0 : return result;
7526 : 0 : }
7527 : :
7528 : 0 : QVariant QgsArrayFilterExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7529 : : {
7530 : : // This is a dummy function, all the real handling is in run
7531 : 0 : Q_UNUSED( values )
7532 : : Q_UNUSED( context )
7533 : : Q_UNUSED( parent )
7534 : : Q_UNUSED( node )
7535 : :
7536 : : Q_ASSERT( false );
7537 : 0 : return QVariant();
7538 : : }
7539 : :
7540 : 0 : bool QgsArrayFilterExpressionFunction::prepare( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
7541 : : {
7542 : 0 : QgsExpressionNode::NodeList *args = node->args();
7543 : :
7544 : 0 : if ( args->count() < 2 )
7545 : : // error
7546 : 0 : return false;
7547 : :
7548 : 0 : args->at( 0 )->prepare( parent, context );
7549 : :
7550 : 0 : QgsExpressionContext subContext;
7551 : 0 : if ( context )
7552 : 0 : subContext = *context;
7553 : :
7554 : 0 : QgsExpressionContextScope *subScope = new QgsExpressionContextScope();
7555 : 0 : subScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "element" ), QVariant(), true ) );
7556 : 0 : subContext.appendScope( subScope );
7557 : :
7558 : 0 : args->at( 1 )->prepare( parent, &subContext );
7559 : :
7560 : 0 : return true;
7561 : 0 : }
7562 : 0 : QgsWithVariableExpressionFunction::QgsWithVariableExpressionFunction()
7563 : 0 : : QgsExpressionFunction( QStringLiteral( "with_variable" ), QgsExpressionFunction::ParameterList() <<
7564 : 0 : QgsExpressionFunction::Parameter( QStringLiteral( "name" ) )
7565 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "value" ) )
7566 : 0 : << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ),
7567 : 0 : QStringLiteral( "General" ) )
7568 : 0 : {
7569 : :
7570 : 0 : }
7571 : :
7572 : 0 : bool QgsWithVariableExpressionFunction::isStatic( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
7573 : : {
7574 : 0 : bool isStatic = false;
7575 : :
7576 : 0 : QgsExpressionNode::NodeList *args = node->args();
7577 : :
7578 : 0 : if ( args->count() < 3 )
7579 : 0 : return false;
7580 : :
7581 : : // We only need to check if the node evaluation is static, if both - name and value - are static.
7582 : 0 : if ( args->at( 0 )->isStatic( parent, context ) && args->at( 1 )->isStatic( parent, context ) )
7583 : : {
7584 : 0 : QVariant name = args->at( 0 )->eval( parent, context );
7585 : 0 : QVariant value = args->at( 1 )->eval( parent, context );
7586 : :
7587 : : // Temporarily append a new scope to provide the variable
7588 : 0 : appendTemporaryVariable( context, name.toString(), value );
7589 : 0 : if ( args->at( 2 )->isStatic( parent, context ) )
7590 : 0 : isStatic = true;
7591 : 0 : popTemporaryVariable( context );
7592 : 0 : }
7593 : :
7594 : 0 : return isStatic;
7595 : 0 : }
7596 : :
7597 : 0 : QVariant QgsWithVariableExpressionFunction::run( QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7598 : : {
7599 : : Q_UNUSED( node )
7600 : 0 : QVariant result;
7601 : :
7602 : 0 : if ( args->count() < 3 )
7603 : : // error
7604 : 0 : return result;
7605 : :
7606 : 0 : QVariant name = args->at( 0 )->eval( parent, context );
7607 : 0 : QVariant value = args->at( 1 )->eval( parent, context );
7608 : :
7609 : 0 : const QgsExpressionContext *updatedContext = context;
7610 : 0 : std::unique_ptr< QgsExpressionContext > tempContext;
7611 : 0 : if ( !updatedContext )
7612 : : {
7613 : 0 : tempContext = std::make_unique< QgsExpressionContext >();
7614 : 0 : updatedContext = tempContext.get();
7615 : 0 : }
7616 : :
7617 : 0 : appendTemporaryVariable( updatedContext, name.toString(), value );
7618 : 0 : result = args->at( 2 )->eval( parent, updatedContext );
7619 : :
7620 : 0 : if ( context )
7621 : 0 : popTemporaryVariable( updatedContext );
7622 : :
7623 : 0 : return result;
7624 : 0 : }
7625 : :
7626 : 0 : QVariant QgsWithVariableExpressionFunction::func( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node )
7627 : : {
7628 : : // This is a dummy function, all the real handling is in run
7629 : 0 : Q_UNUSED( values )
7630 : : Q_UNUSED( context )
7631 : : Q_UNUSED( parent )
7632 : : Q_UNUSED( node )
7633 : :
7634 : : Q_ASSERT( false );
7635 : 0 : return QVariant();
7636 : : }
7637 : :
7638 : 0 : bool QgsWithVariableExpressionFunction::prepare( const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const
7639 : : {
7640 : 0 : QgsExpressionNode::NodeList *args = node->args();
7641 : :
7642 : 0 : if ( args->count() < 3 )
7643 : : // error
7644 : 0 : return false;
7645 : :
7646 : 0 : QVariant name = args->at( 0 )->prepare( parent, context );
7647 : 0 : QVariant value = args->at( 1 )->prepare( parent, context );
7648 : :
7649 : 0 : const QgsExpressionContext *updatedContext = context;
7650 : 0 : std::unique_ptr< QgsExpressionContext > tempContext;
7651 : 0 : if ( !updatedContext )
7652 : : {
7653 : 0 : tempContext = std::make_unique< QgsExpressionContext >();
7654 : 0 : updatedContext = tempContext.get();
7655 : 0 : }
7656 : :
7657 : 0 : appendTemporaryVariable( updatedContext, name.toString(), value );
7658 : 0 : args->at( 2 )->prepare( parent, updatedContext );
7659 : :
7660 : 0 : if ( context )
7661 : 0 : popTemporaryVariable( updatedContext );
7662 : :
7663 : 0 : return true;
7664 : 0 : }
7665 : :
7666 : 0 : void QgsWithVariableExpressionFunction::popTemporaryVariable( const QgsExpressionContext *context ) const
7667 : : {
7668 : 0 : QgsExpressionContext *updatedContext = const_cast<QgsExpressionContext *>( context );
7669 : 0 : delete updatedContext->popScope();
7670 : 0 : }
7671 : :
7672 : 0 : void QgsWithVariableExpressionFunction::appendTemporaryVariable( const QgsExpressionContext *context, const QString &name, const QVariant &value ) const
7673 : : {
7674 : 0 : QgsExpressionContextScope *scope = new QgsExpressionContextScope();
7675 : 0 : scope->addVariable( QgsExpressionContextScope::StaticVariable( name, value, true ) );
7676 : :
7677 : 0 : QgsExpressionContext *updatedContext = const_cast<QgsExpressionContext *>( context );
7678 : 0 : updatedContext->appendScope( scope );
7679 : 0 : }
|