Skip to content

Commit

Permalink
Fix $length in labels (fixes #19355)
Browse files Browse the repository at this point in the history
Use the project expression scope to access project
parameters (ellipsoid and distance/area units)
  • Loading branch information
Hugo Mercier committed Feb 14, 2019
1 parent 88afe75 commit 8091966
Show file tree
Hide file tree
Showing 13 changed files with 64 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ Write the context's state to application settings.




/************************************************************************
* This file has been generated automatically from *
* *
Expand Down
33 changes: 27 additions & 6 deletions src/core/expression/qgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ void QgsExpression::setExpression( const QString &expression )
d->mRootNode = ::parseExpression( expression, d->mParserErrorString, d->mParserErrors );
d->mEvalErrorString = QString();
d->mExp = expression;
d->mIsPrepared = false;
}

QString QgsExpression::expression() const
Expand Down Expand Up @@ -313,13 +314,25 @@ bool QgsExpression::needsGeometry() const
return d->mRootNode->needsGeometry();
}

void QgsExpression::initGeomCalculator()
void QgsExpression::initGeomCalculator( const QgsExpressionContext *context )
{
if ( d->mCalc )
return;

// Use planimetric as default
d->mCalc = std::shared_ptr<QgsDistanceArea>( new QgsDistanceArea() );
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() )
{
d->mCalc->setSourceCrs( crs, tContext );
}
}

void QgsExpression::detach()
Expand Down Expand Up @@ -361,6 +374,8 @@ bool QgsExpression::prepare( const QgsExpressionContext *context )
return false;
}

initGeomCalculator( context );
d->mIsPrepared = true;
return d->mRootNode->prepare( this, context );
}

Expand All @@ -385,6 +400,12 @@ QVariant QgsExpression::evaluate( const QgsExpressionContext *context )
return QVariant();
}

if ( ! d->mIsPrepared )
{
qWarning( "QgsExpression::evaluate() called on an expression not yet prepared !" );
if ( ! prepare( context ) )
return QVariant();
}
return d->mRootNode->eval( this, context );
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/expression/qgsexpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ class CORE_EXPORT QgsExpression
#endif

private:
void initGeomCalculator();
void initGeomCalculator( const QgsExpressionContext *context );

struct HelpArg SIP_SKIP
{
Expand Down
5 changes: 5 additions & 0 deletions src/core/expression/qgsexpressioncontextutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ QgsExpressionContextScope *QgsExpressionContextUtils::projectScope( const QgsPro
QgsCoordinateReferenceSystem projectCrs = project->crs();
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj4(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_ellipsoid" ), project->ellipsoid(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_distance_units" ), QgsUnitTypes::toString( project->distanceUnits() ), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_area_units" ), QgsUnitTypes::toString( project->areaUnits() ), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_project_transform_context" ), QVariant::fromValue<QgsCoordinateTransformContext>( project->transformContext() ), true, true ) );

// metadata
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_author" ), project->metadata().author(), true, true ) );
Expand Down Expand Up @@ -335,6 +339,7 @@ QgsExpressionContextScope *QgsExpressionContextUtils::layerScope( const QgsMapLa

scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_layer_crs" ), QVariant::fromValue<QgsCoordinateReferenceSystem>( layer->crs() ), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsWeakMapLayerPointer >( QgsWeakMapLayerPointer( const_cast<QgsMapLayer *>( layer ) ) ), true, true ) );

const QgsVectorLayer *vLayer = qobject_cast< const QgsVectorLayer * >( layer );
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgscoordinatetransformcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "qgis_sip.h"
#include "qgsdatumtransform.h"

#include <QMetaType>
#include <QExplicitlySharedDataPointer>
class QgsCoordinateReferenceSystem;
class QgsReadWriteContext;
Expand Down Expand Up @@ -275,6 +276,8 @@ class CORE_EXPORT QgsCoordinateTransformContext

};

Q_DECLARE_METATYPE( QgsCoordinateTransformContext )

#endif // QGSCOORDINATETRANSFORMCONTEXT_H


Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsexpressionprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class QgsExpressionPrivate
std::shared_ptr<QgsDistanceArea> mCalc;
QgsUnitTypes::DistanceUnit mDistanceUnit = QgsUnitTypes::DistanceUnknownUnit;
QgsUnitTypes::AreaUnit mAreaUnit = QgsUnitTypes::AreaUnknownUnit;

//! Whether prepare() has been called before evaluate()
bool mIsPrepared = false;
};
///@endcond

Expand Down
1 change: 1 addition & 0 deletions tests/src/core/testqgslayoutitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,7 @@ void TestQgsLayoutItem::itemVariablesFunction()
map->setId( QStringLiteral( "Map_id" ) );

c = l.createExpressionContext();
e.prepare( &c );
r = e.evaluate( &c );
QGSCOMPARENEAR( r.toDouble(), 184764103, 100 );

Expand Down
3 changes: 3 additions & 0 deletions tests/src/core/testqgsmapsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,15 @@ void TestQgsMapSettings::testIsLayerVisible()
QCOMPARE( r.toBool(), false );

QgsProject::instance()->removeMapLayer( vlA );
e.prepare( &context );
r = e.evaluate( &context );
QCOMPARE( r.toBool(), false ); // layer is deleted
e2.prepare( &context );
r = e2.evaluate( &context );
QCOMPARE( r.toBool(), true ); // layer still exists

QgsProject::instance()->removeMapLayer( vlB );
e2.prepare( &context );
r = e2.evaluate( &context );
QCOMPARE( r.toBool(), false ); // layer is deleted

Expand Down
21 changes: 20 additions & 1 deletion tests/src/python/test_qgspallabeling_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
from qgis.PyQt.QtCore import Qt, QPointF, QSizeF
from qgis.PyQt.QtGui import QFont

from qgis.core import QgsLabelingEngineSettings, QgsPalLayerSettings, QgsUnitTypes, QgsTextBackgroundSettings
from qgis.core import QgsLabelingEngineSettings, QgsPalLayerSettings, QgsUnitTypes, QgsTextBackgroundSettings, QgsProject, QgsExpressionContextUtils, QgsExpressionContext
from qgis.core import QgsCoordinateReferenceSystem

from utilities import svgSymbolsPath

Expand Down Expand Up @@ -308,6 +309,24 @@ def test_curved_placement_below(self):
self.lyr.placementFlags = QgsPalLayerSettings.BelowLine | QgsPalLayerSettings.MapOrientation
self.checkTest()

def test_length_expression(self):
# compare length using the ellipsoid in kms and the planimetric distance in meters
self.lyr.fieldName = "round($length,5) || ' - ' || round(length($geometry),2)"
self.lyr.isExpression = True

QgsProject.instance().setCrs(QgsCoordinateReferenceSystem("EPSG:32613"))
QgsProject.instance().setEllipsoid("WGS84")
QgsProject.instance().setDistanceUnits(QgsUnitTypes.DistanceKilometers)

ctxt = QgsExpressionContext()
ctxt.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
ctxt.appendScope(QgsExpressionContextUtils.layerScope(self.layer))
self._TestMapSettings.setExpressionContext(ctxt)

self.lyr.placement = QgsPalLayerSettings.Curved
self.lyr.placementFlags = QgsPalLayerSettings.AboveLine | QgsPalLayerSettings.MapOrientation
self.checkTest()

# noinspection PyPep8Naming


Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8091966

Please sign in to comment.