Skip to content

Commit e9bc483

Browse files
committedMay 8, 2020
Lazily initialize QgsDistanceArea in expressions
This is barely ever used (only when the $perimeter, $length or $area functions are used in an expression), and is expensive to construct. We've been merrily creating them EVERY time we prepare an expression resulting in a lot of wasted effort. By lazily creating it only if needed we save a bunch of wasted processing and ultimately get MUCH faster expression preparation. (especially noticable when animating vector layers using data defined symbol settings or categorized/graduated/rule based renderers)
1 parent 753a684 commit e9bc483

File tree

2 files changed

+17
-9
lines changed

2 files changed

+17
-9
lines changed
 

‎src/core/expression/qgsexpression.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,15 +272,11 @@ void QgsExpression::initGeomCalculator( const QgsExpressionContext *context )
272272
// Set the geometry calculator from the context if it has not been set by setGeomCalculator()
273273
if ( context && ! d->mCalc )
274274
{
275-
QString ellipsoid = context->variable( QStringLiteral( "project_ellipsoid" ) ).toString();
276-
QgsCoordinateReferenceSystem crs = context->variable( QStringLiteral( "_layer_crs" ) ).value<QgsCoordinateReferenceSystem>();
277-
QgsCoordinateTransformContext tContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
278-
if ( crs.isValid() )
279-
{
280-
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
281-
d->mCalc->setEllipsoid( ellipsoid.isEmpty() ? geoNone() : ellipsoid );
282-
d->mCalc->setSourceCrs( crs, tContext );
283-
}
275+
// actually don't do it right away, cos it's expensive to create and only a very small number of expression
276+
// functions actually require it. Let's lazily construct it when needed
277+
d->mDaEllipsoid = context->variable( QStringLiteral( "project_ellipsoid" ) ).toString();
278+
d->mDaCrs = context->variable( QStringLiteral( "_layer_crs" ) ).value<QgsCoordinateReferenceSystem>();
279+
d->mDaTransformContext = context->variable( QStringLiteral( "_project_transform_context" ) ).value<QgsCoordinateTransformContext>();
284280
}
285281

286282
// Set the distance units from the context if it has not been set by setDistanceUnits()
@@ -397,6 +393,14 @@ QString QgsExpression::dump() const
397393

398394
QgsDistanceArea *QgsExpression::geomCalculator()
399395
{
396+
if ( !d->mCalc && d->mDaCrs.isValid() )
397+
{
398+
// calculator IS required, so initialize it now...
399+
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
400+
d->mCalc->setEllipsoid( d->mDaEllipsoid.isEmpty() ? geoNone() : d->mDaEllipsoid );
401+
d->mCalc->setSourceCrs( d->mDaCrs, d->mDaTransformContext );
402+
}
403+
400404
return d->mCalc.get();
401405
}
402406

‎src/core/expression/qgsexpression_p.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ class QgsExpressionPrivate
6767

6868
QString mExp;
6969

70+
QString mDaEllipsoid;
71+
QgsCoordinateReferenceSystem mDaCrs;
72+
QgsCoordinateTransformContext mDaTransformContext;
73+
7074
std::shared_ptr<QgsDistanceArea> mCalc;
7175
QgsUnitTypes::DistanceUnit mDistanceUnit = QgsUnitTypes::DistanceUnknownUnit;
7276
QgsUnitTypes::AreaUnit mAreaUnit = QgsUnitTypes::AreaUnknownUnit;

0 commit comments

Comments
 (0)
Please sign in to comment.