Skip to content

Commit 27ba739

Browse files
author
Hugo Mercier
committed
QgsExpression: set setGeomCalculator precedence
setGeomCalculator, setDistanceUnits and setAreaUnits have now precedence over expression scopes.
1 parent 61db810 commit 27ba739

File tree

3 files changed

+48
-21
lines changed

3 files changed

+48
-21
lines changed

python/core/auto_generated/expression/qgsexpression.sip.in

+10-2
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,12 @@ Returns calculator used for distance and area calculations
293293
void setGeomCalculator( const QgsDistanceArea *calc );
294294
%Docstring
295295
Sets the geometry calculator used for distance and area calculations in expressions.
296-
(used by $length, $area and $perimeter functions only). By default, no geometry
297-
calculator is set and all distance and area calculations are performed using simple
296+
(used by $length, $area and $perimeter functions only).
297+
If the geometry calculator is set to None (default), prepare() will read variables
298+
from the expression context ("project_ellipsoid", "_project_transform_context" and
299+
"_layer_crs") to build a geometry calculator.
300+
If these variables does not exist and if setGeomCalculator() is not called,
301+
all distance and area calculations are performed using simple
298302
Cartesian methods (ie no ellipsoidal calculations).
299303

300304
:param calc: geometry calculator. Ownership is not transferred. Set to a None to force
@@ -321,6 +325,8 @@ Returns the desired distance units for calculations involving geomCalculator(),
321325
void setDistanceUnits( QgsUnitTypes::DistanceUnit unit );
322326
%Docstring
323327
Sets the desired distance units for calculations involving geomCalculator(), e.g., "$length" and "$perimeter".
328+
If distance units are set to QgsUnitTypes.DistanceUnknownUnit (default), prepare() will read
329+
variables from the expression context ("project_distance_units") to determine distance units.
324330

325331
.. note::
326332

@@ -351,6 +357,8 @@ Returns the desired areal units for calculations involving geomCalculator(), e.g
351357
void setAreaUnits( QgsUnitTypes::AreaUnit unit );
352358
%Docstring
353359
Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
360+
If distance units are set to QgsUnitTypes.AreaUnknownUnit (default), prepare() will read
361+
variables from the expression context ("project_distance_units") to determine distance units.
354362

355363
.. note::
356364

src/core/expression/qgsexpression.cpp

+28-17
Original file line numberDiff line numberDiff line change
@@ -316,22 +316,34 @@ bool QgsExpression::needsGeometry() const
316316

317317
void QgsExpression::initGeomCalculator( const QgsExpressionContext *context )
318318
{
319-
if ( ! d->mCalc )
320-
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
321-
QString ellipsoid = context->variable( "project_ellipsoid" ).toString();
322-
QString distanceUnitsStr = context->variable( "project_distance_units" ).toString();
323-
QString areaUnitsStr = context->variable( "project_area_units" ).toString();
324-
QgsCoordinateReferenceSystem crs = context->variable( "_layer_crs" ).value<QgsCoordinateReferenceSystem>();
325-
QgsCoordinateTransformContext tContext = context->variable( "_project_transform_context" ).value<QgsCoordinateTransformContext>();
326-
327-
d->mCalc->setEllipsoid( ellipsoid.isEmpty() ? GEO_NONE : ellipsoid );
328-
if ( ! distanceUnitsStr.isEmpty() )
329-
setDistanceUnits( QgsUnitTypes::stringToDistanceUnit( distanceUnitsStr ) );
330-
if ( ! areaUnitsStr.isEmpty() )
331-
setAreaUnits( QgsUnitTypes::stringToAreaUnit( areaUnitsStr ) );
332-
if ( crs.isValid() )
319+
// Set the geometry calculator from the context if it has not been set by setGeomCalculator()
320+
if ( context && ! d->mCalc )
333321
{
334-
d->mCalc->setSourceCrs( crs, tContext );
322+
QString ellipsoid = context->variable( "project_ellipsoid" ).toString();
323+
QgsCoordinateReferenceSystem crs = context->variable( "_layer_crs" ).value<QgsCoordinateReferenceSystem>();
324+
QgsCoordinateTransformContext tContext = context->variable( "_project_transform_context" ).value<QgsCoordinateTransformContext>();
325+
if ( crs.isValid() )
326+
{
327+
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
328+
d->mCalc->setEllipsoid( ellipsoid.isEmpty() ? GEO_NONE : ellipsoid );
329+
d->mCalc->setSourceCrs( crs, tContext );
330+
}
331+
}
332+
333+
// Set the distance units from the context if it has not been set by setDistanceUnits()
334+
if ( context && distanceUnits() == QgsUnitTypes::DistanceUnknownUnit )
335+
{
336+
QString distanceUnitsStr = context->variable( "project_distance_units" ).toString();
337+
if ( ! distanceUnitsStr.isEmpty() )
338+
setDistanceUnits( QgsUnitTypes::stringToDistanceUnit( distanceUnitsStr ) );
339+
}
340+
341+
// Set the area units from the context if it has not been set by setAreaUnits()
342+
if ( context && areaUnits() == QgsUnitTypes::AreaUnknownUnit )
343+
{
344+
QString areaUnitsStr = context->variable( "project_area_units" ).toString();
345+
if ( ! areaUnitsStr.isEmpty() )
346+
setAreaUnits( QgsUnitTypes::stringToAreaUnit( areaUnitsStr ) );
335347
}
336348
}
337349

@@ -403,8 +415,7 @@ QVariant QgsExpression::evaluate( const QgsExpressionContext *context )
403415
if ( ! d->mIsPrepared )
404416
{
405417
qWarning( "QgsExpression::evaluate() called on an expression not yet prepared !" );
406-
if ( ! prepare( context ) )
407-
return QVariant();
418+
prepare( context );
408419
}
409420
return d->mRootNode->eval( this, context );
410421
}

src/core/expression/qgsexpression.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,12 @@ class CORE_EXPORT QgsExpression
379379

380380
/**
381381
* Sets the geometry calculator used for distance and area calculations in expressions.
382-
* (used by $length, $area and $perimeter functions only). By default, no geometry
383-
* calculator is set and all distance and area calculations are performed using simple
382+
* (used by $length, $area and $perimeter functions only).
383+
* If the geometry calculator is set to nullptr (default), prepare() will read variables
384+
* from the expression context ("project_ellipsoid", "_project_transform_context" and
385+
* "_layer_crs") to build a geometry calculator.
386+
* If these variables does not exist and if setGeomCalculator() is not called,
387+
* all distance and area calculations are performed using simple
384388
* Cartesian methods (ie no ellipsoidal calculations).
385389
* \param calc geometry calculator. Ownership is not transferred. Set to a nullptr to force
386390
* Cartesian calculations.
@@ -399,6 +403,8 @@ class CORE_EXPORT QgsExpression
399403

400404
/**
401405
* Sets the desired distance units for calculations involving geomCalculator(), e.g., "$length" and "$perimeter".
406+
* If distance units are set to QgsUnitTypes::DistanceUnknownUnit (default), prepare() will read
407+
* variables from the expression context ("project_distance_units") to determine distance units.
402408
* \note distances are only converted when a geomCalculator() has been set
403409
* \see distanceUnits()
404410
* \see setAreaUnits()
@@ -417,6 +423,8 @@ class CORE_EXPORT QgsExpression
417423

418424
/**
419425
* Sets the desired areal units for calculations involving geomCalculator(), e.g., "$area".
426+
* If distance units are set to QgsUnitTypes::AreaUnknownUnit (default), prepare() will read
427+
* variables from the expression context ("project_distance_units") to determine distance units.
420428
* \note areas are only converted when a geomCalculator() has been set
421429
* \see areaUnits()
422430
* \see setDistanceUnits()

0 commit comments

Comments
 (0)