Skip to content

Commit

Permalink
QgsExpression: set setGeomCalculator precedence
Browse files Browse the repository at this point in the history
setGeomCalculator, setDistanceUnits and setAreaUnits have now
 precedence over expression scopes.
  • Loading branch information
Hugo Mercier committed Feb 18, 2019
1 parent 61db810 commit 27ba739
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 21 deletions.
12 changes: 10 additions & 2 deletions python/core/auto_generated/expression/qgsexpression.sip.in
Expand Up @@ -293,8 +293,12 @@ Returns calculator used for distance and area calculations
void setGeomCalculator( const QgsDistanceArea *calc );
%Docstring
Sets the geometry calculator used for distance and area calculations in expressions.
(used by $length, $area and $perimeter functions only). By default, no geometry
calculator is set and all distance and area calculations are performed using simple
(used by $length, $area and $perimeter functions only).
If the geometry calculator is set to None (default), prepare() will read variables
from the expression context ("project_ellipsoid", "_project_transform_context" and
"_layer_crs") to build a geometry calculator.
If these variables does not exist and if setGeomCalculator() is not called,
all distance and area calculations are performed using simple
Cartesian methods (ie no ellipsoidal calculations).

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

.. note::

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

.. note::

Expand Down
45 changes: 28 additions & 17 deletions src/core/expression/qgsexpression.cpp
Expand Up @@ -316,22 +316,34 @@ bool QgsExpression::needsGeometry() const

void QgsExpression::initGeomCalculator( const QgsExpressionContext *context )
{
if ( ! d->mCalc )
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
QString ellipsoid = context->variable( "project_ellipsoid" ).toString();
QString distanceUnitsStr = context->variable( "project_distance_units" ).toString();
QString areaUnitsStr = context->variable( "project_area_units" ).toString();
QgsCoordinateReferenceSystem crs = context->variable( "_layer_crs" ).value<QgsCoordinateReferenceSystem>();
QgsCoordinateTransformContext tContext = context->variable( "_project_transform_context" ).value<QgsCoordinateTransformContext>();

d->mCalc->setEllipsoid( ellipsoid.isEmpty() ? GEO_NONE : ellipsoid );
if ( ! distanceUnitsStr.isEmpty() )
setDistanceUnits( QgsUnitTypes::stringToDistanceUnit( distanceUnitsStr ) );
if ( ! areaUnitsStr.isEmpty() )
setAreaUnits( QgsUnitTypes::stringToAreaUnit( areaUnitsStr ) );
if ( crs.isValid() )
// Set the geometry calculator from the context if it has not been set by setGeomCalculator()
if ( context && ! d->mCalc )
{
d->mCalc->setSourceCrs( crs, tContext );
QString ellipsoid = context->variable( "project_ellipsoid" ).toString();
QgsCoordinateReferenceSystem crs = context->variable( "_layer_crs" ).value<QgsCoordinateReferenceSystem>();
QgsCoordinateTransformContext tContext = context->variable( "_project_transform_context" ).value<QgsCoordinateTransformContext>();
if ( crs.isValid() )
{
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
d->mCalc->setEllipsoid( ellipsoid.isEmpty() ? GEO_NONE : ellipsoid );
d->mCalc->setSourceCrs( crs, tContext );
}
}

// Set the distance units from the context if it has not been set by setDistanceUnits()
if ( context && distanceUnits() == QgsUnitTypes::DistanceUnknownUnit )
{
QString distanceUnitsStr = context->variable( "project_distance_units" ).toString();
if ( ! distanceUnitsStr.isEmpty() )
setDistanceUnits( QgsUnitTypes::stringToDistanceUnit( distanceUnitsStr ) );
}

// Set the area units from the context if it has not been set by setAreaUnits()
if ( context && areaUnits() == QgsUnitTypes::AreaUnknownUnit )
{
QString areaUnitsStr = context->variable( "project_area_units" ).toString();
if ( ! areaUnitsStr.isEmpty() )
setAreaUnits( QgsUnitTypes::stringToAreaUnit( areaUnitsStr ) );
}
}

Expand Down Expand Up @@ -403,8 +415,7 @@ QVariant QgsExpression::evaluate( const QgsExpressionContext *context )
if ( ! d->mIsPrepared )
{
qWarning( "QgsExpression::evaluate() called on an expression not yet prepared !" );
if ( ! prepare( context ) )
return QVariant();
prepare( context );
}
return d->mRootNode->eval( this, context );
}
Expand Down
12 changes: 10 additions & 2 deletions src/core/expression/qgsexpression.h
Expand Up @@ -379,8 +379,12 @@ class CORE_EXPORT QgsExpression

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

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

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

0 comments on commit 27ba739

Please sign in to comment.